From 2817784e6bed5f56504836db130ebb757b5e64de Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Sun, 17 Aug 2014 22:04:08 +0200 Subject: [PATCH] Support for the XPath pipe operator. --- lib/oga/xpath/evaluator.rb | 14 +++++ .../xpath/evaluator/operators/pipe_spec.rb | 62 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 spec/oga/xpath/evaluator/operators/pipe_spec.rb diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index ef5c17d..9892610 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -509,6 +509,20 @@ module Oga return nodes end + ## + # Processes the pipe (`|`) operator. This operator creates a union of two + # sets. + # + # @param [Oga::XPath::Node] ast_node + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_pipe(ast_node, context) + left, right = *ast_node + + return process(left, context) + process(right, context) + end + ## # Returns a node set containing all the child nodes of the given set of # nodes. diff --git a/spec/oga/xpath/evaluator/operators/pipe_spec.rb b/spec/oga/xpath/evaluator/operators/pipe_spec.rb new file mode 100644 index 0000000..1c886fd --- /dev/null +++ b/spec/oga/xpath/evaluator/operators/pipe_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'pipe operator' do + before do + @document = parse('') + @evaluator = described_class.new(@document) + end + + context 'merge two sets' do + before do + @set = @evaluator.evaluate('/root/a | /root/b') + end + + it_behaves_like :node_set, :length => 2 + + example 'include the node' do + @set[0].name.should == 'a' + end + + example 'include the node' do + @set[1].name.should == 'b' + end + end + + context 'merge two sets when the left hand side is empty' do + before do + @set = @evaluator.evaluate('foo | /root/b') + end + + it_behaves_like :node_set, :length => 1 + + example 'include the node' do + @set[0].name.should == 'b' + end + end + + context 'merge two sets when the right hand side is empty' do + before do + @set = @evaluator.evaluate('/root/a | foo') + end + + it_behaves_like :node_set, :length => 1 + + example 'include the node' do + @set[0].name.should == 'a' + end + end + + context 'merge two identical sets' do + before do + @set = @evaluator.evaluate('/root/a | /root/a') + end + + it_behaves_like :node_set, :length => 1 + + example 'include only a single node' do + @set[0].name.should == 'a' + end + end + end +end