diff --git a/lib/oga/xpath/evaluator.rb b/lib/oga/xpath/evaluator.rb index cd59eba..a71fba4 100644 --- a/lib/oga/xpath/evaluator.rb +++ b/lib/oga/xpath/evaluator.rb @@ -45,13 +45,29 @@ module Oga # For more information on the specification, see # . # + # ## 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) - @document = document - @nodes = [] + 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. diff --git a/spec/oga/xpath/evaluator/variables_spec.rb b/spec/oga/xpath/evaluator/variables_spec.rb new file mode 100644 index 0000000..d5cc80c --- /dev/null +++ b/spec/oga/xpath/evaluator/variables_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe Oga::XPath::Evaluator do + context 'variable bindings' do + before do + @document = parse('') + 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