From ac06670c24d7a3433fbfcc1714cef3a20e92b78c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 27 Aug 2014 23:38:47 +0200 Subject: [PATCH] Better conversion of types to numbers. The XPath number() function should also be capable of converting booleans to numbers, something it previously was not able to do. In order to do this reliably we can't rely on the string() function as this would make it impossible to distinguish between literal string values and booleans. This is due to true(), which returns a TrueClass, being converted to the string "true". This string in turn can't be converted to a float. --- lib/oga/xpath/evaluator.rb | 25 ++++++++++++++++--- spec/oga/xpath/evaluator/calls/number_spec.rb | 12 +++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index fad3207..8f561a7 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -780,7 +780,7 @@ module Oga convert = process(expression, context) if convert.is_a?(XML::NodeSet) - convert = convert.first + convert = convert[0] end else convert = current_node @@ -815,9 +815,28 @@ module Oga # @return [Float] # def on_call_number(context, expression = nil) - str_val = on_call_string(context, expression) + convert = nil - return Float(str_val) rescue Float::NAN + if expression + exp_retval = process(expression, context) + + if exp_retval.is_a?(XML::NodeSet) + convert = first_node_text(exp_retval) + + elsif exp_retval == true + convert = 1.0 + + elsif exp_retval == false + convert = 0.0 + + elsif exp_retval + convert = exp_retval + end + else + convert = current_node.text + end + + return Float(convert) rescue Float::NAN end ## diff --git a/spec/oga/xpath/evaluator/calls/number_spec.rb b/spec/oga/xpath/evaluator/calls/number_spec.rb index 7f856e1..231ec6d 100644 --- a/spec/oga/xpath/evaluator/calls/number_spec.rb +++ b/spec/oga/xpath/evaluator/calls/number_spec.rb @@ -15,6 +15,14 @@ describe Oga::XPath::Evaluator do @evaluator.evaluate('number("10.5")').should == 10.5 end + example 'convert boolean true to a number' do + @evaluator.evaluate('number(true())').should == 1.0 + end + + example 'convert boolean false to a number' do + @evaluator.evaluate('number(false())').should be_zero + end + example 'convert a node set to a number' do @evaluator.evaluate('number(root/a)').should == 10.0 end @@ -30,5 +38,9 @@ describe Oga::XPath::Evaluator do example 'return NaN for values that can not be converted to floats' do @evaluator.evaluate('number("a")').should be_nan end + + example 'return NaN for empty node sets' do + @evaluator.evaluate('number(foo)').should be_nan + end end end