Proper namespace support for attributes.

This separates namespace handling into namespace names and namespace objects.
The namespace objects are retrieved from the element an attribute belongs to.
Once retrieved the namespace is cached, due to the overhead of retrieving
namespaces in large documents.
This commit is contained in:
Yorick Peterse 2014-08-11 00:40:17 +02:00
parent fe8f77cf45
commit 04cbbdcf9e
4 changed files with 63 additions and 36 deletions

View File

@ -7,35 +7,44 @@ module Oga
# The name of the attribute.
# @return [String]
#
# @!attribute [rw] namespace
# The namespace of the attribute.
# @return [Oga::XML::Namespace]
# @!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, :value
attr_accessor :name, :namespace_name, :element, :value
##
# @param [Hash] options
#
# @option options [String] :name
# @option options [Oga::XML::Namespace] :namespace
# @option options [String] :namespace_name
# @option options [String] :value
# @option options [Oga::XML::Element] :element
#
def initialize(options = {})
if options[:namespace] and !options[:namespace].is_a?(Namespace)
raise(
TypeError,
':namespace must be an instance of Oga::XML::Namespace'
)
@name = options[:name]
@value = options[:value]
@element = options[:element]
@namespace_name = options[:namespace_name]
end
@name = options[:name]
@namespace = options[:namespace]
@value = options[:value]
##
# Returns the {Oga::XML::Namespace} instance for the current namespace
# name.
#
# @return [Oga::XML::Namespace]
#
def namespace
return @namespace ||= element.available_namespaces[namespace_name]
end
##

View File

@ -4,16 +4,24 @@ module Oga
# The Namespace class contains information about XML namespaces such as the
# name and URI.
#
# @!attribute [r] name
# @return [String]
#
# @!attribute [r] uri
# @return [String]
#
class Namespace
attr_accessor :name
attr_accessor :name, :uri
##
# @param [Hash] options
#
# @option options [String] :name
# @option options [String] :uri
#
def initialize(options = {})
@name = options[:name]
@uri = options[:uri]
end
##
@ -27,7 +35,7 @@ module Oga
# @return [String]
#
def inspect
return "Namespace(name: #{name.inspect})"
return "Namespace(name: #{name.inspect} uri: #{uri.inspect})"
end
end # Namespace
end # XML

View File

@ -150,9 +150,7 @@ rule
# foo:bar
| T_ATTR_NS T_ATTR
{
ns = Namespace.new(:name => val[0])
Attribute.new(:namespace => ns, :name => val[1])
Attribute.new(:namespace_name => val[0], :name => val[1])
}
;

View File

@ -6,24 +6,31 @@ describe Oga::XML::Attribute do
described_class.new(:name => 'a').name.should == 'a'
end
example 'set the namespace' do
ns = Oga::XML::Namespace.new(:name => 'foo')
attr = described_class.new(:namespace => ns)
attr.namespace.should == ns
end
example 'raise TypeError when using a String for the namespace' do
block = lambda { described_class.new(:namespace => 'x') }
block.should raise_error(TypeError)
end
example 'set the value' do
described_class.new(:value => 'a').value.should == 'a'
end
end
context '#namespace' do
before do
@namespace = Oga::XML::Namespace.new(:name => 'b')
element = Oga::XML::Element.new(
:namespaces => {'b' => @namespace}
)
@attribute = described_class.new(
:namespace_name => 'b',
:name => 'a',
:element => element
)
end
example 'return a Namespace instance' do
@attribute.namespace.should == @namespace
end
end
context '#to_s' do
example 'return an empty String when there is no value' do
described_class.new.to_s.should == ''
@ -44,14 +51,19 @@ describe Oga::XML::Attribute do
context '#inspect' do
example 'return the inspect value' do
element = Oga::XML::Element.new(
:namespaces => {'b' => Oga::XML::Namespace.new(:name => 'b')}
)
obj = described_class.new(
:namespace_name => 'b',
:name => 'a',
:namespace => Oga::XML::Namespace.new(:name => 'b'),
:value => 'c'
:value => 'c',
:element => element
)
obj.inspect.should == <<-EOF.strip
Attribute(name: "a" namespace: Namespace(name: "b") value: "c")
Attribute(name: "a" namespace: Namespace(name: "b" uri: nil) value: "c")
EOF
end
end