XPath compiler support for sum()

This commit is contained in:
Yorick Peterse 2015-08-18 15:33:47 +02:00
parent e7e5b123cf
commit 106d83e780
2 changed files with 48 additions and 15 deletions

View File

@ -1103,6 +1103,28 @@ module Oga
end end
end end
# @param [Oga::Ruby::Node] input
# @param [AST::Node] arg
# @return [Oga::Ruby::Node]
def on_call_sum(input, arg)
unless return_nodeset?(arg)
raise TypeError, 'sum() can only operate on a path, axis or predicate'
end
sum_var = unique_literal(:sum)
conversion = literal(Conversion)
sum_var.assign(literal(0.0))
.followed_by do
process(arg, input) do |matched_node|
sum_var.assign(sum_var + conversion.to_float(matched_node.text))
end
end
.followed_by do
block_given? ? sum_var.zero?.not.if_true { yield } : sum_var
end
end
## ##
# Delegates type tests to specific handlers. # Delegates type tests to specific handlers.
# #

View File

@ -4,25 +4,36 @@ describe Oga::XPath::Compiler do
describe 'sum() spec' do describe 'sum() spec' do
before do before do
@document = parse('<root><a>1</a><b>2</b></root>') @document = parse('<root><a>1</a><b>2</b></root>')
@a1 = @document.children[0].children[0]
end end
it 'returns the sum of the <root> node' do describe 'at the top-level' do
# The test of <root> is "12", which is then converted to a number. it 'returns the sum of the <root> node' do
evaluate_xpath(@document, 'sum(root)').should == 12.0 # The test of <root> is "12", which is then converted to a number.
evaluate_xpath(@document, 'sum(root)').should == 12.0
end
it 'returns the sum of the child nodes of the <root> node' do
evaluate_xpath(@document, 'sum(root/*)').should == 3.0
end
it 'returns zero by default' do
evaluate_xpath(@document, 'sum(foo)').should be_zero
end
it 'raises a TypeError for non node set arguments' do
block = -> { evaluate_xpath(@document, 'sum("foo")') }
block.should raise_error(TypeError)
end
end end
it 'returns the sum of the child nodes of the <root> node' do describe 'in a predicate' do
evaluate_xpath(@document, 'sum(root/*)').should == 3.0 it 'returns a NodeSet containing all matching nodes' do
end evaluate_xpath(@document, 'root/a[sum(/root/*)]')
.should == node_set(@a1)
it 'returns zero by default' do end
evaluate_xpath(@document, 'sum(foo)').should be_zero
end
it 'raises a TypeError for non node set arguments' do
block = -> { evaluate_xpath(@document, 'sum("foo")') }
block.should raise_error(TypeError)
end end
end end
end end