Support for the XPath "=" operator.
This commit is contained in:
		
							parent
							
								
									1a6c0f0d35
								
							
						
					
					
						commit
						9e5f15787d
					
				|  | @ -706,6 +706,42 @@ module Oga | ||||||
|         return on_call_number(context, left) - on_call_number(context, right) |         return on_call_number(context, left) - on_call_number(context, right) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  |       ## | ||||||
|  |       # Processes the `=` operator. | ||||||
|  |       # | ||||||
|  |       # This operator evaluates the expression on the left and right and returns | ||||||
|  |       # `true` if they are equal. This operator can be used to compare strings, | ||||||
|  |       # numbers and node sets. When using node sets the text of the set is | ||||||
|  |       # compared instead of the nodes themselves. That is, nodes with different | ||||||
|  |       # names but the same text are considered to be equal. | ||||||
|  |       # | ||||||
|  |       # @param [Oga::XPath::Node] ast_node | ||||||
|  |       # @param [Oga::XML::NodeSet] context | ||||||
|  |       # @return [TrueClass|FalseClass] | ||||||
|  |       # | ||||||
|  |       def on_eq(ast_node, context) | ||||||
|  |         left  = process(ast_node.children[0], context) | ||||||
|  |         right = process(ast_node.children[1], context) | ||||||
|  | 
 | ||||||
|  |         if left.is_a?(XML::NodeSet) | ||||||
|  |           left = left.text | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if right.is_a?(XML::NodeSet) | ||||||
|  |           right = right.text | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if left.is_a?(Numeric) and !right.is_a?(Numeric) | ||||||
|  |           right = to_float(right) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         if left.is_a?(String) and !right.is_a?(String) | ||||||
|  |           right = to_string(right) | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         return left == right | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|       ## |       ## | ||||||
|       # Delegates function calls to specific handlers. |       # Delegates function calls to specific handlers. | ||||||
|       # |       # | ||||||
|  | @ -903,14 +939,7 @@ module Oga | ||||||
|         if convert.respond_to?(:text) |         if convert.respond_to?(:text) | ||||||
|           return convert.text |           return convert.text | ||||||
|         else |         else | ||||||
|           # If we have a number that has a zero decimal (e.g. 10.0) we want to |           return to_string(convert) | ||||||
|           # get rid of that decimal. For this we'll first convert the number to |  | ||||||
|           # an integer. |  | ||||||
|           if convert.is_a?(Float) and convert.modulo(1).zero? |  | ||||||
|             convert = convert.to_i |  | ||||||
|           end |  | ||||||
| 
 |  | ||||||
|           return convert.to_s |  | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  | @ -950,7 +979,7 @@ module Oga | ||||||
|           convert = current_node.text |           convert = current_node.text | ||||||
|         end |         end | ||||||
| 
 | 
 | ||||||
|         return Float(convert) rescue Float::NAN |         return to_float(convert) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|       ## |       ## | ||||||
|  | @ -1528,6 +1557,35 @@ module Oga | ||||||
|         return ast_node.respond_to?(:parent) && !!ast_node.parent |         return ast_node.respond_to?(:parent) && !!ast_node.parent | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  |       ## | ||||||
|  |       # Converts the given value to a float. If the value can't be converted to | ||||||
|  |       # a float NaN is returned instead. | ||||||
|  |       # | ||||||
|  |       # @param [Mixed] value | ||||||
|  |       # @return [Float] | ||||||
|  |       # | ||||||
|  |       def to_float(value) | ||||||
|  |         return Float(value) rescue Float::NAN | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|  |       ## | ||||||
|  |       # Converts the given value to a string according to the XPath string | ||||||
|  |       # conversion rules. | ||||||
|  |       # | ||||||
|  |       # @param [Mixed] value | ||||||
|  |       # @return [String] | ||||||
|  |       # | ||||||
|  |       def to_string(value) | ||||||
|  |         # If we have a number that has a zero decimal (e.g. 10.0) we want to | ||||||
|  |         # get rid of that decimal. For this we'll first convert the number to | ||||||
|  |         # an integer. | ||||||
|  |         if value.is_a?(Float) and value.modulo(1).zero? | ||||||
|  |           value = value.to_i | ||||||
|  |         end | ||||||
|  | 
 | ||||||
|  |         return value.to_s | ||||||
|  |       end | ||||||
|  | 
 | ||||||
|       ## |       ## | ||||||
|       # Stores the node in the node stack, yields the block and removes the node |       # Stores the node in the node stack, yields the block and removes the node | ||||||
|       # from the stack. |       # from the stack. | ||||||
|  |  | ||||||
|  | @ -154,4 +154,24 @@ describe Oga::XPath::Evaluator do | ||||||
|       @evaluator.has_parent?(@parent).should == false |       @evaluator.has_parent?(@parent).should == false | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  | 
 | ||||||
|  |   context '#to_string' do | ||||||
|  |     example 'convert a float to a string' do | ||||||
|  |       @evaluator.to_string(10.5).should == '10.5' | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'convert a float without decimals to a string' do | ||||||
|  |       @evaluator.to_string(10.0).should == '10' | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | 
 | ||||||
|  |   context '#to_float' do | ||||||
|  |     example 'convert a string to a float' do | ||||||
|  |       @evaluator.to_float('10').should == 10.0 | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example "return NaN for values that can't be converted to floats" do | ||||||
|  |       @evaluator.to_float('a').should be_nan | ||||||
|  |     end | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  | @ -0,0 +1,50 @@ | ||||||
|  | require 'spec_helper' | ||||||
|  | 
 | ||||||
|  | describe Oga::XPath::Evaluator do | ||||||
|  |   context 'equal operator' do | ||||||
|  |     before do | ||||||
|  |       @document  = parse('<root><a>10</a><b>10</b></root>') | ||||||
|  |       @evaluator = described_class.new(@document) | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if two numbers are equal' do | ||||||
|  |       @evaluator.evaluate('10 = 10').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return false if two numbers are not equal' do | ||||||
|  |       @evaluator.evaluate('10 = 15').should == false | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if a number and a string are equal' do | ||||||
|  |       @evaluator.evaluate('10 = "10"').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if two strings are equal' do | ||||||
|  |       @evaluator.evaluate('"10" = "10"').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if a string and a number are equal' do | ||||||
|  |       @evaluator.evaluate('"10" = 10').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return false if two strings are not equal' do | ||||||
|  |       @evaluator.evaluate('"a" = "b"').should == false | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if two node sets are equal' do | ||||||
|  |       @evaluator.evaluate('root/a = root/b').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return false if two node sets are not equal' do | ||||||
|  |       @evaluator.evaluate('root/a = root/c').should == false | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if a node set and a number are equal' do | ||||||
|  |       @evaluator.evaluate('root/a = 10').should == true | ||||||
|  |     end | ||||||
|  | 
 | ||||||
|  |     example 'return true if a node set and a string are equal' do | ||||||
|  |       @evaluator.evaluate('root/a = "10"').should == true | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
		Loading…
	
		Reference in New Issue