Skip to content

Commit b95f586

Browse files
committed
wip
1 parent 9e3a236 commit b95f586

File tree

5 files changed

+77
-140
lines changed

5 files changed

+77
-140
lines changed

ext/nokogiri/xml_node_set.c

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -471,21 +471,4 @@ void
471471
noko_init_xml_node_set(void)
472472
{
473473
cNokogiriXmlNodeSet = rb_define_class_under(mNokogiriXml, "NodeSet", rb_cArray);
474-
475-
/* rb_define_alloc_func(cNokogiriXmlNodeSet, allocate); */
476-
477-
/* rb_define_method(cNokogiriXmlNodeSet, "length", length, 0); */
478-
/* rb_define_method(cNokogiriXmlNodeSet, "[]", slice, -1); */
479-
/* rb_define_method(cNokogiriXmlNodeSet, "slice", slice, -1); */
480-
/* rb_define_method(cNokogiriXmlNodeSet, "push", push, 1); */
481-
/* rb_define_method(cNokogiriXmlNodeSet, "|", rb_xml_node_set_union, 1); */
482-
/* rb_define_method(cNokogiriXmlNodeSet, "-", minus, 1); */
483-
/* rb_define_method(cNokogiriXmlNodeSet, "unlink", unlink_nodeset, 0); */
484-
/* rb_define_method(cNokogiriXmlNodeSet, "to_a", to_array, 0); */
485-
/* rb_define_method(cNokogiriXmlNodeSet, "dup", duplicate, 0); */
486-
/* rb_define_method(cNokogiriXmlNodeSet, "delete", delete, 1); */
487-
/* rb_define_method(cNokogiriXmlNodeSet, "&", intersection, 1); */
488-
/* rb_define_method(cNokogiriXmlNodeSet, "include?", include_eh, 1); */
489-
490-
/* decorate = rb_intern("decorate"); */
491474
}

ext/nokogiri/xml_xpath_context.c

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,16 @@ xpath2ruby(xmlXPathObjectPtr xpath_object, xmlXPathContextPtr xpath_context)
182182
}
183183

184184

185+
static VALUE
186+
ruby2xpath_node_set_append(RB_BLOCK_CALL_FUNC_ARGLIST(rb_node, wrapped_c_node_set))
187+
{
188+
xmlNodeSetPtr c_node_set = (xmlNodeSetPtr)wrapped_c_node_set;
189+
xmlNodePtr c_node;
190+
Data_Get_Struct(rb_node, xmlNode, c_node);
191+
xmlXPathNodeSetAddUnique(c_node_set, c_node);
192+
return Qnil;
193+
}
194+
185195
/*
186196
* convert a Ruby object into an XPath object of the appropriate type.
187197
* raises an exception if no conversion was possible.
@@ -209,28 +219,11 @@ ruby2xpath(VALUE rb_object, xmlXPathContextPtr xpath_context)
209219
break;
210220
case T_ARRAY:
211221
{
212-
xmlNodeSetPtr c_node_set = NULL;
213-
VALUE rb_node_set;
214-
VALUE args[2];
215-
216-
assert(xpath_context->doc);
217-
assert(DOC_RUBY_OBJECT_TEST(xpath_context->doc));
218-
219-
args[0] = DOC_RUBY_OBJECT(xpath_context->doc);
220-
args[1] = rb_object;
221-
rb_node_set = rb_class_new_instance(2, args, cNokogiriXmlNodeSet);
222-
Data_Get_Struct(rb_node_set, xmlNodeSet, c_node_set);
222+
xmlNodeSetPtr c_node_set = xmlXPathNodeSetCreate(NULL);
223+
rb_block_call(rb_object, rb_intern("each"), 0, NULL, ruby2xpath_node_set_append, (VALUE)c_node_set);
223224
result = xmlXPathWrapNodeSet(xmlXPathNodeSetMerge(NULL, c_node_set));
224225
}
225226
break;
226-
case T_DATA:
227-
if (rb_obj_is_kind_of(rb_object, cNokogiriXmlNodeSet)) {
228-
xmlNodeSetPtr c_node_set = NULL;
229-
Data_Get_Struct(rb_object, xmlNodeSet, c_node_set);
230-
/* Copy the node set, otherwise it will get GC'd. */
231-
result = xmlXPathWrapNodeSet(xmlXPathNodeSetMerge(NULL, c_node_set));
232-
break;
233-
}
234227
default:
235228
rb_raise(rb_eRuntimeError, "Invalid return type");
236229
}

lib/nokogiri/xml/namespace.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ class Namespace
66
include Nokogiri::XML::PP::Node
77
attr_reader :document
88

9+
# Returns true if this is a Namespace
10+
def namespace?
11+
true
12+
end
13+
914
private
1015

1116
def inspect_attributes

lib/nokogiri/xml/node_set.rb

Lines changed: 34 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class NodeSet < ::Array
1313
attr_accessor :document
1414

1515
# Create a NodeSet with +document+ defaulting to +list+
16+
# TODO: test that it can only contain Node and Namespace objects
1617
def initialize(document, list = [])
1718
super()
1819
@document = document
@@ -21,40 +22,6 @@ def initialize(document, list = [])
2122
yield self if block_given?
2223
end
2324

24-
# ###
25-
# # Get the first element of the NodeSet.
26-
# def first(n = nil)
27-
# return self[0] unless n
28-
29-
# list = []
30-
# [n, length].min.times { |i| list << self[i] }
31-
# list
32-
# end
33-
34-
# ###
35-
# # Get the last element of the NodeSet.
36-
# def last
37-
# self[-1]
38-
# end
39-
40-
# ###
41-
# # Is this NodeSet empty?
42-
# def empty?
43-
# length == 0
44-
# end
45-
46-
# ###
47-
# # Returns the index of the first node in self that is == to +node+ or meets the given block. Returns nil if no match is found.
48-
# def index(node = nil)
49-
# if node
50-
# warn("given block not used") if block_given?
51-
# each_with_index { |member, j| return j if member == node }
52-
# elsif block_given?
53-
# each_with_index { |member, j| return j if yield(member) }
54-
# end
55-
# nil
56-
# end
57-
5825
###
5926
# Insert +datum+ before the first Node in this NodeSet
6027
# TODO: this method only makes sense in the context of siblings
@@ -69,8 +36,6 @@ def after(datum)
6936
last.after(datum)
7037
end
7138

72-
# alias_method :<<, :push
73-
7439
# call-seq:
7540
# unlink
7641
#
@@ -235,17 +200,6 @@ def remove_attr(name)
235200
end
236201
alias_method :remove_attribute, :remove_attr
237202

238-
# ###
239-
# # Iterate over each node, yielding to +block+
240-
# def each
241-
# return to_enum unless block_given?
242-
243-
# 0.upto(length - 1) do |x|
244-
# yield self[x]
245-
# end
246-
# self
247-
# end
248-
249203
###
250204
# Get the inner text of all contained Node objects
251205
#
@@ -305,41 +259,6 @@ def to_xml(*args)
305259
map { |x| x.to_xml(*args) }.join
306260
end
307261

308-
# alias_method :size, :length
309-
# alias_method :to_ary, :to_a
310-
311-
# ###
312-
# # Removes the last element from set and returns it, or +nil+ if
313-
# # the set is empty
314-
# def pop
315-
# return nil if length == 0
316-
317-
# delete(last)
318-
# end
319-
320-
# ###
321-
# # Returns the first element of the NodeSet and removes it. Returns
322-
# # +nil+ if the set is empty.
323-
# def shift
324-
# return nil if length == 0
325-
326-
# delete(first)
327-
# end
328-
329-
# ###
330-
# # Equality -- Two NodeSets are equal if the contain the same number
331-
# # of elements and if each element is equal to the corresponding
332-
# # element in the other NodeSet
333-
# def ==(other)
334-
# return false unless other.is_a?(Nokogiri::XML::NodeSet)
335-
# return false unless length == other.length
336-
337-
# each_with_index do |node, i|
338-
# return false unless node == other[i]
339-
# end
340-
# true
341-
# end
342-
343262
###
344263
# Returns a new NodeSet containing all the children of all the nodes in
345264
# the NodeSet
@@ -351,28 +270,45 @@ def children
351270
node_set
352271
end
353272

354-
# ###
355-
# # Returns a new NodeSet containing all the nodes in the NodeSet
356-
# # in reverse order
357-
# def reverse
358-
# node_set = NodeSet.new(document)
359-
# (length - 1).downto(0) do |x|
360-
# node_set.push(self[x])
361-
# end
362-
# node_set
363-
# end
364-
365-
# ###
366-
# # Return a nicely formated string representation
367-
# def inspect
368-
# "[#{map(&:inspect).join(", ")}]"
369-
# end
273+
###
274+
# Returns a new NodeSet containing all the nodes in the NodeSet
275+
# in reverse order
276+
def reverse
277+
NodeSet.new(document, super)
278+
end
279+
280+
# TODO: document
281+
def difference(*args)
282+
NodeSet.new(document, super)
283+
end
284+
alias_method :-, :difference
370285

371286
# TODO: document
372287
# TODO: can raise TypeError (was formerly ArgumentError)
288+
def union(other)
289+
NodeSet.new(document, super)
290+
end
373291
alias_method :+, :union
374292
alias_method :|, :union
375293

294+
# TODO: document
295+
def intersection(*args)
296+
NodeSet.new(document, super)
297+
end
298+
alias_method :&, :intersection
299+
300+
# TODO: document
301+
def slice(*args)
302+
result = super
303+
Array === result ? NodeSet.new(document, result) : result
304+
end
305+
alias_method :[], :slice
306+
307+
# TODO: document
308+
def dup
309+
NodeSet.new(document, super)
310+
end
311+
376312
IMPLIED_XPATH_CONTEXTS = [".//", "self::"].freeze # :nodoc:
377313
end
378314
end

test/xml/test_node_set.rb

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -306,8 +306,11 @@ def awesome(ns)
306306
describe "#pop" do
307307
it "returns the last element and mutates the set" do
308308
set = xml.xpath("//employee")
309-
last = set.last
310-
assert_equal(last, set.pop)
309+
length = set.length
310+
expected = set.last
311+
actual = set.pop
312+
assert_equal(expected, actual)
313+
assert_equal(length - 1, set.length)
311314
end
312315

313316
it "returns nil for an empty set" do
@@ -319,8 +322,11 @@ def awesome(ns)
319322
describe "#shift" do
320323
it "returns the first element and mutates the set" do
321324
set = xml.xpath("//employee")
322-
first = set.first
323-
assert_equal(first, set.shift)
325+
length = set.length
326+
expected = set.first
327+
actual = set.shift
328+
assert_equal(expected, actual)
329+
assert_equal(length - 1, set.length)
324330
end
325331

326332
it "returns nil for an empty set" do
@@ -470,6 +476,7 @@ def awesome(ns)
470476

471477
describe "#delete" do
472478
it "raises ArgumentError when given an invalid argument" do
479+
skip "TODO: arrays just do the right thing here"
473480
employees = xml.search("//employee")
474481
positions = xml.search("//position")
475482

@@ -483,6 +490,7 @@ def awesome(ns)
483490
length = employees.length
484491

485492
result = employees.delete(wally)
493+
assert_instance_of(Nokogiri::XML::NodeSet, result)
486494
assert_equal(result, wally)
487495
refute_includes(employees, wally)
488496
assert_equal(length - 1, employees.length)
@@ -623,7 +631,7 @@ def awesome(ns)
623631
employees_len = employees.length
624632
women_len = women.length
625633

626-
assert_raises(ArgumentError) { employees - women.first }
634+
assert_raises(TypeError) { employees - women.first }
627635

628636
result = employees - women
629637
assert_equal(employees_len, employees.length)
@@ -830,6 +838,7 @@ def awesome(ns)
830838
assert_instance_of(Nokogiri::XML::NodeSet, children)
831839

832840
reversed = children.reverse
841+
assert_instance_of(Nokogiri::XML::NodeSet, reversed)
833842
assert_equal(reversed[0], children[4])
834843
assert_equal(reversed[1], children[3])
835844
assert_equal(reversed[2], children[2])
@@ -850,6 +859,17 @@ def awesome!; end
850859
assert_respond_to(new_set, :awesome!)
851860
end
852861

862+
it "node_set_clone_result_has_document_and_is_decorated" do
863+
x = Module.new do
864+
def awesome!; end
865+
end
866+
util_decorate(xml, x)
867+
node_set = xml.css("address")
868+
new_set = node_set.clone
869+
assert_equal(node_set.document, new_set.document)
870+
assert_respond_to(new_set, :awesome!)
871+
end
872+
853873
it "node_set_union_result_has_document_and_is_decorated" do
854874
x = Module.new do
855875
def awesome!; end
@@ -858,7 +878,7 @@ def awesome!; end
858878
node_set1 = xml.css("address")
859879
node_set2 = xml.css("address")
860880
new_set = node_set1 | node_set2
861-
assert_equal(node_set1.document, new_set.document)
881+
# assert_equal(node_set1.document, new_set.document) # TODO: drop NodeSet#document ?
862882
assert_respond_to(new_set, :awesome!)
863883
end
864884

0 commit comments

Comments
 (0)