From 4fa40b58cfce114eab2738370dc24d376c8d635c Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 28 Aug 2014 21:01:12 +0200 Subject: [PATCH] Support for the XPath "or" operator. --- lib/oga/xpath/evaluator.rb | 17 ++++++++ spec/oga/xpath/evaluator/operators/or_spec.rb | 40 +++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 spec/oga/xpath/evaluator/operators/or_spec.rb diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index c5a9fe8..4832120 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -609,6 +609,23 @@ module Oga return on_call_boolean(context, left) && on_call_boolean(context, right) end + ## + # Processes the `or` operator. + # + # This operator returns `true` if one of the expressions evaluates to + # true, otherwise false is returned. If the first expression evaluates to + # `true` the second expression is ignored. + # + # @param [Oga::XPath::Node] ast_node + # @param [Oga::XML::NodeSet] context + # @return [TrueClass|FalseClass] + # + def on_or(ast_node, context) + left, right = *ast_node + + return on_call_boolean(context, left) || on_call_boolean(context, right) + end + ## # Delegates function calls to specific handlers. # diff --git a/spec/oga/xpath/evaluator/operators/or_spec.rb b/spec/oga/xpath/evaluator/operators/or_spec.rb new file mode 100644 index 0000000..28a2563 --- /dev/null +++ b/spec/oga/xpath/evaluator/operators/or_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'or operator' do + before do + @document = parse('11') + @evaluator = described_class.new(@document) + end + + example 'return true if both boolean literals are true' do + @evaluator.evaluate('true() or true()').should == true + end + + example 'return true if one of the boolean literals is false' do + @evaluator.evaluate('true() or false()').should == true + end + + example 'return true if the left node set is not empty' do + @evaluator.evaluate('root/a or root/x').should == true + end + + example 'return true if the right node set is not empty' do + @evaluator.evaluate('root/x or root/b').should == true + end + + example 'return true if both node sets are not empty' do + @evaluator.evaluate('root/a or root/b').should == true + end + + example 'return false if both node sets are empty' do + @evaluator.evaluate('root/x or root/y').should == false + end + + example 'skip the right expression if the left one evaluates to false' do + @evaluator.should_not receive(:on_call_false) + + @evaluator.evaluate('true() or false()').should == true + end + end +end