Support for binding/evaluating XPath variables.

This commit is contained in:
Yorick Peterse 2014-09-02 19:04:02 +02:00
parent 5a0e8c5480
commit ad34ab47a0
2 changed files with 60 additions and 3 deletions

View File

@ -45,13 +45,29 @@ module Oga
# For more information on the specification, see
# <http://www.w3.org/TR/xpath/#numbers>.
#
# ## Variables
#
# The evaluator supports the binding of custom variables in the
# {#initialize} method. Variables can be bound by passing in a Hash with the
# keys set to the variable names (minus the `$` sign) and their values to
# the variable values. The keys of the variables Hash *must* be Strings.
#
# A basic example:
#
# evaluator = Evaluator.new(document, 'number' => 10)
#
# evaluator.evaluate('$number') # => 10
#
class Evaluator
##
# @param [Oga::XML::Document|Oga::XML::Node] document
# @param [Hash] variables Hash containing variables to expose to the XPath
# expressions.
#
def initialize(document)
def initialize(document, variables = {})
@document = document
@nodes = []
@variables = variables
end
##
@ -1490,6 +1506,25 @@ module Oga
return ast_node.children[0]
end
##
# Processes a variable reference. If the variable is not defined an error
# is raised.
#
# @param [Oga::XPath::Node] ast_node
# @param [Oga::XML::NodeSet] context
# @return [Mixed]
# @raise [RuntimeError]
#
def on_var(ast_node, context)
name = ast_node.children[0]
if @variables.key?(name)
return @variables[name]
else
raise "Undefined XPath variable: #{name}"
end
end
##
# Returns the node for a function call. This node is either the first node
# in the supplied node set, or the first node in the current context.

View File

@ -0,0 +1,22 @@
require 'spec_helper'
describe Oga::XPath::Evaluator do
context 'variable bindings' do
before do
@document = parse('<a></a>')
end
example 'evaluate a variable' do
evaluator = described_class.new(@document, 'number' => 10.0)
evaluator.evaluate('$number').should == 10.0
end
example 'raise RuntimeError when evaluating an unbound variable' do
evaluator = described_class.new(@document)
block = lambda { evaluator.evaluate('$number') }
block.should raise_error 'Undefined XPath variable: number'
end
end
end