Cache output of Element#available_namespaces
This cache is flushed whenever Element#register_namespace is called. When this cache is flushed it's also recursively flushed for all child elements. This makes calls to Element#register_namespace a bit more expensive but in turn calls to Element#available_namespaces will be a lot faster.
This commit is contained in:
parent
fa838154fc
commit
b42f9aaf32
|
@ -299,14 +299,17 @@ module Oga
|
||||||
#
|
#
|
||||||
# @param [String] name
|
# @param [String] name
|
||||||
# @param [String] uri
|
# @param [String] uri
|
||||||
|
# @param [TrueClass|FalseClass] flush
|
||||||
# @see [Oga::XML::Namespace#initialize]
|
# @see [Oga::XML::Namespace#initialize]
|
||||||
#
|
#
|
||||||
def register_namespace(name, uri)
|
def register_namespace(name, uri, flush = true)
|
||||||
if namespaces[name]
|
if namespaces[name]
|
||||||
raise ArgumentError, "The namespace #{name.inspect} already exists"
|
raise ArgumentError, "The namespace #{name.inspect} already exists"
|
||||||
end
|
end
|
||||||
|
|
||||||
namespaces[name] = Namespace.new(:name => name, :uri => uri)
|
namespaces[name] = Namespace.new(:name => name, :uri => uri)
|
||||||
|
|
||||||
|
flush_namespaces_cache if flush
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -316,8 +319,10 @@ module Oga
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
#
|
#
|
||||||
def available_namespaces
|
def available_namespaces
|
||||||
return {} if html? # HTML(5) completely ignores namespaces
|
# HTML(5) completely ignores namespaces
|
||||||
|
if html?
|
||||||
|
return @available_namespaces ||= {}
|
||||||
|
elsif !@available_namespaces
|
||||||
merged = namespaces.dup
|
merged = namespaces.dup
|
||||||
node = parent
|
node = parent
|
||||||
|
|
||||||
|
@ -329,7 +334,10 @@ module Oga
|
||||||
node = node.parent
|
node = node.parent
|
||||||
end
|
end
|
||||||
|
|
||||||
return merged
|
@available_namespaces = merged
|
||||||
|
end
|
||||||
|
|
||||||
|
return @available_namespaces
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -349,19 +357,40 @@ module Oga
|
||||||
return self_closing
|
return self_closing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Flushes the namespaces cache of the current element and all its child
|
||||||
|
# elements.
|
||||||
|
#
|
||||||
|
def flush_namespaces_cache
|
||||||
|
@available_namespaces = nil
|
||||||
|
@namespace = nil
|
||||||
|
|
||||||
|
children.each do |child|
|
||||||
|
child.flush_namespaces_cache if child.is_a?(Element)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
##
|
##
|
||||||
# Registers namespaces based on any "xmlns" attributes.
|
# Registers namespaces based on any "xmlns" attributes.
|
||||||
#
|
#
|
||||||
def register_namespaces_from_attributes
|
def register_namespaces_from_attributes
|
||||||
|
flush = false
|
||||||
|
|
||||||
attributes.each do |attr|
|
attributes.each do |attr|
|
||||||
# We're using `namespace_name` opposed to `namespace.name` as "xmlns"
|
# We're using `namespace_name` opposed to `namespace.name` as "xmlns"
|
||||||
# is not a registered namespace.
|
# is not a registered namespace.
|
||||||
if attr.name == XMLNS_PREFIX or attr.namespace_name == XMLNS_PREFIX
|
if attr.name == XMLNS_PREFIX or attr.namespace_name == XMLNS_PREFIX
|
||||||
register_namespace(attr.name, attr.value)
|
flush = true
|
||||||
|
|
||||||
|
# Ensures we only flush the cache once instead of flushing it on
|
||||||
|
# every register_namespace call.
|
||||||
|
register_namespace(attr.name, attr.value, false)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
flush_namespaces_cache if flush
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -488,6 +488,25 @@ describe Oga::XML::Element do
|
||||||
|
|
||||||
block.should raise_error(ArgumentError)
|
block.should raise_error(ArgumentError)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'flushes the cache when registering a namespace' do
|
||||||
|
@element.available_namespaces.should == {
|
||||||
|
'foo' => @element.namespaces['foo']
|
||||||
|
}
|
||||||
|
|
||||||
|
@element.register_namespace('bar', 'http://exmaple.com')
|
||||||
|
|
||||||
|
@element.available_namespaces.should == {
|
||||||
|
'foo' => @element.namespaces['foo'],
|
||||||
|
'bar' => @element.namespaces['bar']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not flush the cache when "flush" is set to false' do
|
||||||
|
@element.should_not receive(:flush_namespaces_cache)
|
||||||
|
|
||||||
|
@element.register_namespace('bar', 'http://example.com', false)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#available_namespaces' do
|
describe '#available_namespaces' do
|
||||||
|
@ -564,4 +583,29 @@ describe Oga::XML::Element do
|
||||||
element.should_not be_self_closing
|
element.should_not be_self_closing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#flush_namespaces_cache' do
|
||||||
|
it 'flushes the namespaces cache of the current element' do
|
||||||
|
element = described_class.new(:name => 'a')
|
||||||
|
|
||||||
|
element.available_namespaces.should == {}
|
||||||
|
|
||||||
|
element.register_namespace('foo', 'bar', false)
|
||||||
|
|
||||||
|
element.flush_namespaces_cache
|
||||||
|
|
||||||
|
element.available_namespaces.should == {
|
||||||
|
'foo' => element.namespaces['foo']
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'flushes the namespace cache of all child elements' do
|
||||||
|
child = described_class.new(:name => 'b')
|
||||||
|
parent = described_class.new(:name => 'a', :children => [child])
|
||||||
|
|
||||||
|
child.should_receive(:flush_namespaces_cache)
|
||||||
|
|
||||||
|
parent.flush_namespaces_cache
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue