lib/hexp/nokogiri/equality.rb
module Hexp
module Nokogiri
# Used in test to see if two Nokogiri objects have the same content,
# i.e. are equivalent as far as we are concerned
#
class Equality
CLASSES = [
::Nokogiri::HTML::Document,
::Nokogiri::HTML::DocumentFragment,
::Nokogiri::XML::Document,
::Nokogiri::XML::Node,
::Nokogiri::XML::Text,
::Nokogiri::XML::Element,
::Nokogiri::XML::DocumentFragment,
::Nokogiri::XML::DTD,
]
# Create a new equality tester for two Nokogiri objects
#
# (see Hexp::Nokogiri::Equality::CLASSES for all possible objects that can
# be passed in)
#
# @example
# doc = Nokogiri::HTML::Document.new
# this_node = Nokogiri::XML::Element.new("div", doc)
# that_node = Nokogiri::XML::Element.new("span", doc)
# Hexp::Nokogiri::Equality.new(this_node, that_node).call #=> false
#
# @param this [Object] The first object to compare
# @param that [Object] The second object to compare
#
# @api public
#
def initialize(this, that)
@this, @that = this, that
[this, that].each do |input|
raise "#{input.class} is not a Nokogiri element." unless CLASSES.include?(input.class)
end
end
# Perform the comparison
#
# @return [Boolean]
#
# @api public
#
def call
[ equal_class?,
equal_name?,
equal_children?,
equal_attributes?,
equal_text? ].all?
end
# Are the two elements instances of the same class
#
# @return [Boolean]
#
# @api public
#
def equal_class?
@this.class == @that.class
end
# Do both elements have the same tag name
#
# @return [Boolean]
#
# @api public
#
def equal_name?
@this.name == @that.name
end
# Do the elements under comparison have the same child elements
#
# @return [Boolean]
#
# @api public
#
def equal_children?
return true unless @this.respond_to? :children
@this.children.count == @that.children.count &&
compare_children.all?
end
# Compare the child elements, assuming both elements respond_to? :children
#
# @return [Boolean]
#
# @api public
#
def compare_children
@this.children.map.with_index do |child, idx|
self.class.new(child, @that.children[idx]).call
end
end
# Do the elements under comparison have the same attributes
#
# @return [Boolean]
#
# @api public
#
def equal_attributes?
return true unless @this.respond_to? :attributes
@this.attributes.keys.all? do |key|
@this[key] == @that[key]
end
end
# Compare the text of text elements
#
# If the elements are not of type Nokogiri::XML::Text, return true
#
# @return [Boolean]
#
# @api public
#
def equal_text?
return true unless @this.instance_of?(::Nokogiri::XML::Text)
@this.text == @that.text
end
end
end
end