From 6a1010c287674ca452687d5fef7ebb7407d72939 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Tue, 7 Apr 2015 21:18:22 +0200 Subject: [PATCH] Fixed decoding entities in attribute values This was broken by introducing the process of lazy decoding of XML/HTML entities. The new setup works similar to how XML::Text#text decodes any entities that may be present. Fixes #91 --- lib/oga/xml/attribute.rb | 37 +++++++++++++++++---- spec/oga/xml/attribute_spec.rb | 60 ++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/lib/oga/xml/attribute.rb b/lib/oga/xml/attribute.rb index 07c3666..e42fe96 100644 --- a/lib/oga/xml/attribute.rb +++ b/lib/oga/xml/attribute.rb @@ -10,16 +10,12 @@ module Oga # @!attribute [rw] namespace_name # @return [String] # - # @!attribute [rw] value - # The value of the attribute. - # @return [String] - # # @!attribute [r] element # The element this attribute belongs to. # @return [Oga::XML::Element] # class Attribute - attr_accessor :name, :namespace_name, :element, :value + attr_accessor :name, :namespace_name, :element ## # The default namespace available to all attributes. This namespace can @@ -67,8 +63,28 @@ module Oga end ## - # Returns the value of the attribute. + # @param [String] value # + def value=(value) + @value = value + @decoded = false + end + + ## + # Returns the value of the attribute or nil if no explicit value was set. + # + # @return [String|NilClass] + # + def value + if !@decoded and @value + @value = EntityDecoder.try_decode(@value, html?) + @decoded = true + end + + return @value + end + + ## # @return [String] # def text @@ -108,6 +124,15 @@ module Oga return "Attribute(#{segments.join(' ')})" end + + private + + ## + # @return [TrueClass|FalseClass] + # + def html? + return !!@element && @element.html? + end end # Attribute end # XML end # Oga diff --git a/spec/oga/xml/attribute_spec.rb b/spec/oga/xml/attribute_spec.rb index 686e1bf..b4add2d 100644 --- a/spec/oga/xml/attribute_spec.rb +++ b/spec/oga/xml/attribute_spec.rb @@ -37,6 +37,66 @@ describe Oga::XML::Attribute do end end + describe '#value=' do + it 'sets the value of an attribute' do + attr = described_class.new + + attr.value = 'foo' + + attr.value.should == 'foo' + end + + it 'flushes the decoded cache when setting a new value' do + attr = described_class.new(:value => '<') + + attr.value.should == Oga::XML::Entities::DECODE_MAPPING['<'] + + attr.value = '>' + + attr.value.should == Oga::XML::Entities::DECODE_MAPPING['>'] + end + end + + describe '#value' do + it 'returns the value of an attribute' do + described_class.new(:value => 'foo').value.should == 'foo' + end + + describe 'using an XML document' do + before do + @el = Oga::XML::Element.new(:name => 'a') + @doc = Oga::XML::Document.new(:children => [@el], :type => :xml) + end + + it 'returns a String with decoded XML entities' do + attr = described_class.new( + :name => 'class', + :value => '<', + :element => @el + ) + + attr.value.should == '<' + end + end + + describe 'using HTML documents' do + before do + @el = Oga::XML::Element.new(:name => 'a') + @doc = Oga::XML::Document.new(:children => [@el], :type => :html) + end + + it 'returns a String with decoded HTML entities' do + attr = described_class.new( + :name => 'class', + :value => '©', + :element => @el + ) + + attr.value.should == Oga::HTML::Entities::DECODE_MAPPING['©'] + end + end + end + describe '#text' do it 'returns an empty String when there is no value' do described_class.new.text.should == ''