From 423af37422f5f53109a591607ce7369494c061ee Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Mon, 18 Aug 2014 19:00:32 +0200 Subject: [PATCH] Basic support for the XPath last() function. --- lib/oga/xpath/evaluator.rb | 42 ++++++++++++++++++++- spec/oga/xpath/evaluator/calls/last_spec.rb | 17 +++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 spec/oga/xpath/evaluator/calls/last_spec.rb diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index 9892610..73d234c 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -98,12 +98,16 @@ module Oga # @return [Oga::XML::NodeSet] # def on_test(ast_node, context) - nodes = XML::NodeSet.new + nodes = XML::NodeSet.new + predicate = ast_node.children[2] context.each do |xml_node| nodes << xml_node if node_matches?(xml_node, ast_node) end + # Filter the nodes based on the predicate. + nodes = process(predicate, nodes) if predicate + return nodes end @@ -523,6 +527,42 @@ module Oga return process(left, context) + process(right, context) end + ## + # Delegates function calls to specific handlers. + # + # Handler functions take two arguments: + # + # 1. The context node set + # 2. A variable list of XPath function arguments, passed as individual + # Ruby method arguments. + # + # @param [Oga::XPath::Node] ast_node + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_call(ast_node, context) + name, args = *ast_node + + handler = name.gsub('-', '_') + + return send("on_call_#{handler}", context, *args) + end + + ## + # Processes the `last()` function call. This function call returns a node + # set containing the last node of the context set. + # + # @param [Oga::XML::NodeSet] context + # @return [Oga::XML::NodeSet] + # + def on_call_last(context) + if context.empty? + return context + else + return XML::NodeSet.new([context.last]) + end + end + ## # Returns a node set containing all the child nodes of the given set of # nodes. diff --git a/spec/oga/xpath/evaluator/calls/last_spec.rb b/spec/oga/xpath/evaluator/calls/last_spec.rb new file mode 100644 index 0000000..7714ff3 --- /dev/null +++ b/spec/oga/xpath/evaluator/calls/last_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'last() function' do + before do + @document = parse('foobar') + @second_a = @document.children[0].children[1] + @set = described_class.new(@document).evaluate('root/a[last()]') + end + + it_behaves_like :node_set, :length => 1 + + example 'return the second node' do + @set[0].should == @second_a + end + end +end