nokogiri 1.12.5 → 1.13.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/README.md +9 -7
  4. data/bin/nokogiri +63 -50
  5. data/dependencies.yml +5 -6
  6. data/ext/nokogiri/extconf.rb +47 -35
  7. data/ext/nokogiri/xml_document.c +35 -35
  8. data/ext/nokogiri/xml_document_fragment.c +0 -2
  9. data/ext/nokogiri/xml_dtd.c +2 -2
  10. data/ext/nokogiri/xml_encoding_handler.c +25 -11
  11. data/ext/nokogiri/xml_node.c +638 -333
  12. data/ext/nokogiri/xml_reader.c +37 -11
  13. data/ext/nokogiri/xml_xpath_context.c +72 -49
  14. data/gumbo-parser/src/parser.c +0 -11
  15. data/lib/nokogiri/class_resolver.rb +67 -0
  16. data/lib/nokogiri/css/node.rb +9 -8
  17. data/lib/nokogiri/css/parser.rb +11 -3
  18. data/lib/nokogiri/css/parser.y +10 -2
  19. data/lib/nokogiri/css/parser_extras.rb +20 -20
  20. data/lib/nokogiri/css/syntax_error.rb +1 -0
  21. data/lib/nokogiri/css/tokenizer.rb +2 -1
  22. data/lib/nokogiri/css/tokenizer.rex +2 -1
  23. data/lib/nokogiri/css/xpath_visitor.rb +174 -75
  24. data/lib/nokogiri/css.rb +38 -6
  25. data/lib/nokogiri/decorators/slop.rb +8 -7
  26. data/lib/nokogiri/extension.rb +1 -1
  27. data/lib/nokogiri/gumbo.rb +1 -0
  28. data/lib/nokogiri/html.rb +16 -10
  29. data/lib/nokogiri/html4/builder.rb +1 -0
  30. data/lib/nokogiri/html4/document.rb +84 -75
  31. data/lib/nokogiri/html4/document_fragment.rb +11 -7
  32. data/lib/nokogiri/html4/element_description.rb +1 -0
  33. data/lib/nokogiri/html4/element_description_defaults.rb +426 -520
  34. data/lib/nokogiri/html4/entity_lookup.rb +2 -1
  35. data/lib/nokogiri/html4/sax/parser.rb +2 -1
  36. data/lib/nokogiri/html4/sax/parser_context.rb +1 -0
  37. data/lib/nokogiri/html4/sax/push_parser.rb +7 -7
  38. data/lib/nokogiri/html4.rb +11 -5
  39. data/lib/nokogiri/html5/document.rb +24 -10
  40. data/lib/nokogiri/html5/document_fragment.rb +5 -2
  41. data/lib/nokogiri/html5/node.rb +6 -3
  42. data/lib/nokogiri/html5.rb +68 -64
  43. data/lib/nokogiri/jruby/dependencies.rb +10 -9
  44. data/lib/nokogiri/syntax_error.rb +1 -0
  45. data/lib/nokogiri/version/constant.rb +2 -1
  46. data/lib/nokogiri/version/info.rb +19 -13
  47. data/lib/nokogiri/version.rb +1 -0
  48. data/lib/nokogiri/xml/attr.rb +5 -3
  49. data/lib/nokogiri/xml/attribute_decl.rb +2 -1
  50. data/lib/nokogiri/xml/builder.rb +32 -32
  51. data/lib/nokogiri/xml/cdata.rb +2 -1
  52. data/lib/nokogiri/xml/character_data.rb +1 -0
  53. data/lib/nokogiri/xml/document.rb +139 -103
  54. data/lib/nokogiri/xml/document_fragment.rb +41 -38
  55. data/lib/nokogiri/xml/dtd.rb +3 -2
  56. data/lib/nokogiri/xml/element_content.rb +1 -0
  57. data/lib/nokogiri/xml/element_decl.rb +2 -1
  58. data/lib/nokogiri/xml/entity_decl.rb +3 -2
  59. data/lib/nokogiri/xml/entity_reference.rb +1 -0
  60. data/lib/nokogiri/xml/namespace.rb +2 -0
  61. data/lib/nokogiri/xml/node/save_options.rb +6 -3
  62. data/lib/nokogiri/xml/node.rb +512 -348
  63. data/lib/nokogiri/xml/node_set.rb +46 -54
  64. data/lib/nokogiri/xml/notation.rb +12 -0
  65. data/lib/nokogiri/xml/parse_options.rb +11 -7
  66. data/lib/nokogiri/xml/pp/character_data.rb +8 -6
  67. data/lib/nokogiri/xml/pp/node.rb +24 -26
  68. data/lib/nokogiri/xml/pp.rb +1 -0
  69. data/lib/nokogiri/xml/processing_instruction.rb +2 -1
  70. data/lib/nokogiri/xml/reader.rb +17 -19
  71. data/lib/nokogiri/xml/relax_ng.rb +1 -0
  72. data/lib/nokogiri/xml/sax/document.rb +20 -19
  73. data/lib/nokogiri/xml/sax/parser.rb +36 -34
  74. data/lib/nokogiri/xml/sax/parser_context.rb +7 -3
  75. data/lib/nokogiri/xml/sax/push_parser.rb +5 -5
  76. data/lib/nokogiri/xml/sax.rb +1 -0
  77. data/lib/nokogiri/xml/schema.rb +7 -6
  78. data/lib/nokogiri/xml/searchable.rb +42 -22
  79. data/lib/nokogiri/xml/syntax_error.rb +4 -4
  80. data/lib/nokogiri/xml/text.rb +1 -0
  81. data/lib/nokogiri/xml/xpath/syntax_error.rb +2 -1
  82. data/lib/nokogiri/xml/xpath.rb +12 -0
  83. data/lib/nokogiri/xml/xpath_context.rb +2 -3
  84. data/lib/nokogiri/xml.rb +3 -3
  85. data/lib/nokogiri/xslt/stylesheet.rb +1 -0
  86. data/lib/nokogiri/xslt.rb +3 -2
  87. data/lib/nokogiri.rb +19 -16
  88. data/lib/xsd/xmlparser/nokogiri.rb +25 -24
  89. data/patches/libxml2/0008-htmlParseComment-handle-abruptly-closed-comments.patch +61 -0
  90. data/patches/libxml2/0009-allow-wildcard-namespaces.patch +77 -0
  91. metadata +101 -27
@@ -1,12 +1,14 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Nokogiri
3
4
  module XML
4
5
  class Attr < Node
5
- alias :value :content
6
- alias :to_s :content
7
- alias :content= :value=
6
+ alias_method :value, :content
7
+ alias_method :to_s, :content
8
+ alias_method :content=, :value=
8
9
 
9
10
  private
11
+
10
12
  def inspect_attributes
11
13
  [:name, :namespace, :value]
12
14
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Nokogiri
3
4
  module XML
4
5
  ###
@@ -12,7 +13,7 @@ module Nokogiri
12
13
  undef_method :line if method_defined?(:line)
13
14
 
14
15
  def inspect
15
- "#<#{self.class.name}:#{sprintf("0x%x", object_id)} #{to_s.inspect}>"
16
+ "#<#{self.class.name}:#{format("0x%x", object_id)} #{to_s.inspect}>"
16
17
  end
17
18
  end
18
19
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Nokogiri
3
4
  module XML
4
5
  ###
@@ -261,7 +262,9 @@ module Nokogiri
261
262
  # </root>
262
263
  #
263
264
  class Builder
264
- DEFAULT_DOCUMENT_OPTIONS = {namespace_inheritance: true}
265
+ include Nokogiri::ClassResolver
266
+
267
+ DEFAULT_DOCUMENT_OPTIONS = { namespace_inheritance: true }
265
268
 
266
269
  # The current Document object being built
267
270
  attr_accessor :doc
@@ -306,13 +309,7 @@ module Nokogiri
306
309
  @doc = root.document
307
310
  @parent = root
308
311
  else
309
- klassname = "::" + (self.class.name.split("::")[0..-2] + ["Document"]).join("::")
310
- klass = begin
311
- Object.const_get(klassname)
312
- rescue NameError
313
- Nokogiri::XML::Document
314
- end
315
- @parent = @doc = klass.new
312
+ @parent = @doc = related_class("Document").new
316
313
  end
317
314
 
318
315
  @context = nil
@@ -324,7 +321,7 @@ module Nokogiri
324
321
  @doc.send(:"#{k}=", v)
325
322
  end
326
323
 
327
- return unless block_given?
324
+ return unless block
328
325
 
329
326
  @arity = block.arity
330
327
  if @arity <= 0
@@ -340,19 +337,19 @@ module Nokogiri
340
337
  ###
341
338
  # Create a Text Node with content of +string+
342
339
  def text(string)
343
- insert @doc.create_text_node(string)
340
+ insert(@doc.create_text_node(string))
344
341
  end
345
342
 
346
343
  ###
347
344
  # Create a CDATA Node with content of +string+
348
345
  def cdata(string)
349
- insert doc.create_cdata(string)
346
+ insert(doc.create_cdata(string))
350
347
  end
351
348
 
352
349
  ###
353
350
  # Create a Comment Node with content of +string+
354
351
  def comment(string)
355
- insert doc.create_comment(string)
352
+ insert(doc.create_comment(string))
356
353
  end
357
354
 
358
355
  ###
@@ -370,8 +367,8 @@ module Nokogiri
370
367
  return self if @ns
371
368
  end
372
369
 
373
- @ns = { :pending => ns.to_s }
374
- return self
370
+ @ns = { pending: ns.to_s }
371
+ self
375
372
  end
376
373
 
377
374
  ###
@@ -379,7 +376,7 @@ module Nokogiri
379
376
  def to_xml(*args)
380
377
  if Nokogiri.jruby?
381
378
  options = args.first.is_a?(Hash) ? args.shift : {}
382
- if !options[:save_with]
379
+ unless options[:save_with]
383
380
  options[:save_with] = Node::SaveOptions::AS_BUILDER
384
381
  end
385
382
  args.insert(0, options)
@@ -394,18 +391,18 @@ module Nokogiri
394
391
  end
395
392
 
396
393
  def method_missing(method, *args, &block) # :nodoc:
397
- if @context && @context.respond_to?(method)
394
+ if @context&.respond_to?(method)
398
395
  @context.send(method, *args, &block)
399
396
  else
400
- node = @doc.create_element(method.to_s.sub(/[_!]$/, ""), *args) { |n|
397
+ node = @doc.create_element(method.to_s.sub(/[_!]$/, ""), *args) do |n|
401
398
  # Set up the namespace
402
- if @ns.is_a? Nokogiri::XML::Namespace
399
+ if @ns.is_a?(Nokogiri::XML::Namespace)
403
400
  n.namespace = @ns
404
401
  @ns = nil
405
402
  end
406
- }
403
+ end
407
404
 
408
- if @ns.is_a? Hash
405
+ if @ns.is_a?(Hash)
409
406
  node.namespace = node.namespace_definitions.find { |x| x.prefix == @ns[:pending] }
410
407
  if node.namespace.nil?
411
408
  raise ArgumentError, "Namespace #{@ns[:pending]} has not been defined"
@@ -423,16 +420,19 @@ module Nokogiri
423
420
  # Insert +node+ as a child of the current Node
424
421
  def insert(node, &block)
425
422
  node = @parent.add_child(node)
426
- if block_given?
427
- old_parent = @parent
428
- @parent = node
429
- @arity ||= block.arity
430
- if @arity <= 0
431
- instance_eval(&block)
432
- else
433
- block.call(self)
423
+ if block
424
+ begin
425
+ old_parent = @parent
426
+ @parent = node
427
+ @arity ||= block.arity
428
+ if @arity <= 0
429
+ instance_eval(&block)
430
+ else
431
+ yield(self)
432
+ end
433
+ ensure
434
+ @parent = old_parent
434
435
  end
435
- @parent = old_parent
436
436
  end
437
437
  NodeBuilder.new(node, self)
438
438
  end
@@ -455,10 +455,10 @@ module Nokogiri
455
455
  opts = args.last.is_a?(Hash) ? args.pop : {}
456
456
  case method.to_s
457
457
  when /^(.*)!$/
458
- @node["id"] = $1
458
+ @node["id"] = Regexp.last_match(1)
459
459
  @node.content = args.first if args.first
460
460
  when /^(.*)=/
461
- @node[$1] = args.first
461
+ @node[Regexp.last_match(1)] = args.first
462
462
  else
463
463
  @node["class"] =
464
464
  ((@node["class"] || "").split(/\s/) + [method.to_s]).join(" ")
@@ -470,7 +470,7 @@ module Nokogiri
470
470
  @node[k.to_s] = ((@node[k.to_s] || "").split(/\s/) + [v]).join(" ")
471
471
  end
472
472
 
473
- if block_given?
473
+ if block
474
474
  old_parent = @doc_builder.parent
475
475
  @doc_builder.parent = @node
476
476
  value = @doc_builder.instance_eval(&block)
@@ -1,11 +1,12 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Nokogiri
3
4
  module XML
4
5
  class CDATA < Nokogiri::XML::Text
5
6
  ###
6
7
  # Get the name of this CDATA node
7
8
  def name
8
- '#cdata-section'
9
+ "#cdata-section"
9
10
  end
10
11
  end
11
12
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Nokogiri
3
4
  module XML
4
5
  class CharacterData < Nokogiri::XML::Node
@@ -1,18 +1,16 @@
1
1
  # coding: utf-8
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'pathname'
4
+ require "pathname"
5
5
 
6
6
  module Nokogiri
7
7
  module XML
8
- ##
9
- # Nokogiri::XML::Document is the main entry point for dealing with
10
- # XML documents. The Document is created by parsing an XML document.
11
- # See Nokogiri::XML::Document.parse() for more information on parsing.
8
+ # Nokogiri::XML::Document is the main entry point for dealing with XML documents. The Document
9
+ # is created by parsing an XML document. See Nokogiri::XML::Document.parse for more information
10
+ # on parsing.
12
11
  #
13
12
  # For searching a Document, see Nokogiri::XML::Searchable#css and
14
13
  # Nokogiri::XML::Searchable#xpath
15
- #
16
14
  class Document < Nokogiri::XML::Node
17
15
  # See http://www.w3.org/TR/REC-xml-names/#ns-decl for more details. Note that we're not
18
16
  # attempting to handle unicode characters partly because libxml2 doesn't handle unicode
@@ -47,76 +45,86 @@ module Nokogiri
47
45
  #
48
46
  # Nokogiri.XML() is a convenience method which will call this method.
49
47
  #
50
- def self.parse string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML
48
+ def self.parse(string_or_io, url = nil, encoding = nil, options = ParseOptions::DEFAULT_XML)
51
49
  options = Nokogiri::XML::ParseOptions.new(options) if Integer === options
52
-
53
50
  yield options if block_given?
54
51
 
55
52
  url ||= string_or_io.respond_to?(:path) ? string_or_io.path : nil
56
53
 
57
54
  if empty_doc?(string_or_io)
58
55
  if options.strict?
59
- raise Nokogiri::XML::SyntaxError.new("Empty document")
56
+ raise Nokogiri::XML::SyntaxError, "Empty document"
60
57
  else
61
58
  return encoding ? new.tap { |i| i.encoding = encoding } : new
62
59
  end
63
60
  end
64
61
 
65
62
  doc = if string_or_io.respond_to?(:read)
66
- if string_or_io.is_a?(Pathname)
67
- # resolve the Pathname to the file and open it as an IO object, see #2110
68
- string_or_io = string_or_io.expand_path.open
69
- url ||= string_or_io.path
70
- end
63
+ if string_or_io.is_a?(Pathname)
64
+ # resolve the Pathname to the file and open it as an IO object, see #2110
65
+ string_or_io = string_or_io.expand_path.open
66
+ url ||= string_or_io.path
67
+ end
71
68
 
72
- read_io(string_or_io, url, encoding, options.to_i)
73
- else
74
- # read_memory pukes on empty docs
75
- read_memory(string_or_io, url, encoding, options.to_i)
76
- end
69
+ read_io(string_or_io, url, encoding, options.to_i)
70
+ else
71
+ # read_memory pukes on empty docs
72
+ read_memory(string_or_io, url, encoding, options.to_i)
73
+ end
77
74
 
78
75
  # do xinclude processing
79
76
  doc.do_xinclude(options) if options.xinclude?
80
77
 
81
- return doc
78
+ doc
82
79
  end
83
80
 
84
81
  ##
85
- # @!method wrap(java_document)
86
- # @!scope class
82
+ # :singleton-method: wrap
83
+ # :call-seq: wrap(java_document) → Nokogiri::XML::Document
84
+ #
85
+ # ⚠ This method is only available when running JRuby.
87
86
  #
88
- # Create a {Document} using an existing Java DOM document object.
87
+ # Create a Document using an existing Java DOM document object.
89
88
  #
90
- # The returned {Document} shares the same underlying data structure as the Java object, so
89
+ # The returned Document shares the same underlying data structure as the Java object, so
91
90
  # changes in one are reflected in the other.
92
91
  #
93
- # @param java_document [Java::OrgW3cDom::Document]
94
- # @return [Nokogiri::XML::Document]
95
- # @note This method is only available when running JRuby.
96
- # @note The class +Java::OrgW3cDom::Document+ is also accessible as +org.w3c.dom.Document+.
97
- # @see #to_java
92
+ # [Parameters]
93
+ # - `java_document` (Java::OrgW3cDom::Document)
94
+ # (The class `Java::OrgW3cDom::Document` is also accessible as `org.w3c.dom.Document`.)
95
+ #
96
+ # [Returns] Nokogiri::XML::Document
97
+ #
98
+ # See also \#to_java
98
99
 
99
- ##
100
- # @!method to_java()
100
+ # :method: to_java
101
+ # :call-seq: to_java() → Java::OrgW3cDom::Document
101
102
  #
102
- # Returns the underlying Java DOM document object for the {Document}.
103
+ # This method is only available when running JRuby.
103
104
  #
104
- # The returned Java object shares the same underlying data structure as the {Document}, so
105
+ # Returns the underlying Java DOM document object for this document.
106
+ #
107
+ # The returned Java object shares the same underlying data structure as this document, so
105
108
  # changes in one are reflected in the other.
106
109
  #
107
- # @return [Java::OrgW3cDom::Document]
108
- # @note This method is only available when running JRuby.
109
- # @note The class +Java::OrgW3cDom::Document+ is also accessible as +org.w3c.dom.Document+.
110
- # @see .wrap
111
-
110
+ # [Returns]
111
+ # Java::OrgW3cDom::Document
112
+ # (The class `Java::OrgW3cDom::Document` is also accessible as `org.w3c.dom.Document`.)
113
+ #
114
+ # See also Document.wrap
112
115
 
113
- # A list of Nokogiri::XML::SyntaxError found when parsing a document
116
+ # The errors found while parsing a document.
117
+ #
118
+ # [Returns] Array<Nokogiri::XML::SyntaxError>
114
119
  attr_accessor :errors
115
120
 
116
- # When true, reparented elements without a namespace will inherit their new parent's
117
- # namespace (if one exists). Defaults to +false+.
121
+ # When `true`, reparented elements without a namespace will inherit their new parent's
122
+ # namespace (if one exists). Defaults to `false`.
123
+ #
124
+ # [Returns] Boolean
125
+ #
126
+ # *Example:* Default behavior of namespace inheritance
118
127
  #
119
- # @example Default behavior of namespace inheritance
120
128
  # xml = <<~EOF
121
129
  # <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
122
130
  # <foo:parent>
@@ -134,7 +142,8 @@ module Nokogiri
134
142
  # # </foo:parent>
135
143
  # # </root>
136
144
  #
137
- # @example Setting namespace inheritance to +true+
145
+ # *Example:* Setting namespace inheritance to `true`
146
+ #
138
147
  # xml = <<~EOF
139
148
  # <root xmlns:foo="http://nokogiri.org/default_ns/test/foo">
140
149
  # <foo:parent>
@@ -153,49 +162,61 @@ module Nokogiri
153
162
  # # </foo:parent>
154
163
  # # </root>
155
164
  #
156
- # @return [Boolean]
157
- #
158
- # @since v1.12.4
165
+ # Since v1.12.4
159
166
  attr_accessor :namespace_inheritance
160
167
 
161
- def initialize *args # :nodoc:
168
+ def initialize(*args) # :nodoc:
162
169
  @errors = []
163
170
  @decorators = nil
164
171
  @namespace_inheritance = false
165
172
  end
166
173
 
167
- ##
168
- # Create a new +Element+ with +name+ sharing GC lifecycle with the document, optionally
169
- # setting contents or attributes.
174
+ # :call-seq:
175
+ # create_element(name, *contents_or_attrs, &block) Nokogiri::XML::Element
176
+ #
177
+ # Create a new Element with `name` belonging to this document, optionally setting contents or
178
+ # attributes.
179
+ #
180
+ # This method is _not_ the most user-friendly option if your intention is to add a node to the
181
+ # document tree. Prefer one of the Nokogiri::XML::Node methods like Node#add_child,
182
+ # Node#add_next_sibling, Node#replace, etc. which will both create an element (or subtree) and
183
+ # place it in the document tree.
170
184
  #
171
185
  # Arguments may be passed to initialize the element:
172
- # - a +Hash+ argument will be used to set attributes
173
- # - a non-Hash object that responds to +#to_s+ will be used to set the new node's contents
186
+ #
187
+ # - a Hash argument will be used to set attributes
188
+ # - a non-Hash object that responds to \#to_s will be used to set the new node's contents
174
189
  #
175
190
  # A block may be passed to mutate the node.
176
191
  #
177
- # @param name [String]
178
- # @param contents_or_attrs [#to_s,Hash]
179
- # @yieldparam node [Nokogiri::XML::Element]
180
- # @return [Nokogiri::XML::Element]
192
+ # [Parameters]
193
+ # - `name` (String)
194
+ # - `contents_or_attrs` (\#to_s, Hash)
195
+ # [Yields] `node` (Nokogiri::XML::Element)
196
+ # [Returns] Nokogiri::XML::Element
197
+ #
198
+ # *Example:* An empty element without attributes
181
199
  #
182
- # @example An empty element without attributes
183
200
  # doc.create_element("div")
184
201
  # # => <div></div>
185
202
  #
186
- # @example An element with contents
203
+ # *Example:* An element with contents
204
+ #
187
205
  # doc.create_element("div", "contents")
188
206
  # # => <div>contents</div>
189
207
  #
190
- # @example An element with attributes
208
+ # *Example:* An element with attributes
209
+ #
191
210
  # doc.create_element("div", {"class" => "container"})
192
211
  # # => <div class='container'></div>
193
212
  #
194
- # @example An element with contents and attributes
213
+ # *Example:* An element with contents and attributes
214
+ #
195
215
  # doc.create_element("div", "contents", {"class" => "container"})
196
216
  # # => <div class='container'>contents</div>
197
217
  #
198
- # @example Passing a block to mutate the element
218
+ # *Example:* Passing a block to mutate the element
219
+ #
199
220
  # doc.create_element("div") { |node| node["class"] = "blue" if before_noon? }
200
221
  #
201
222
  def create_element(name, *contents_or_attrs, &block)
@@ -216,30 +237,30 @@ module Nokogiri
216
237
  elm.content = arg
217
238
  end
218
239
  end
219
- if ns = elm.namespace_definitions.find { |n| n.prefix.nil? || (n.prefix == '') }
240
+ if (ns = elm.namespace_definitions.find { |n| n.prefix.nil? || (n.prefix == "") })
220
241
  elm.namespace = ns
221
242
  end
222
243
  elm
223
244
  end
224
245
 
225
246
  # Create a Text Node with +string+
226
- def create_text_node string, &block
227
- Nokogiri::XML::Text.new string.to_s, self, &block
247
+ def create_text_node(string, &block)
248
+ Nokogiri::XML::Text.new(string.to_s, self, &block)
228
249
  end
229
250
 
230
251
  # Create a CDATA Node containing +string+
231
- def create_cdata string, &block
232
- Nokogiri::XML::CDATA.new self, string.to_s, &block
252
+ def create_cdata(string, &block)
253
+ Nokogiri::XML::CDATA.new(self, string.to_s, &block)
233
254
  end
234
255
 
235
256
  # Create a Comment Node containing +string+
236
- def create_comment string, &block
237
- Nokogiri::XML::Comment.new self, string.to_s, &block
257
+ def create_comment(string, &block)
258
+ Nokogiri::XML::Comment.new(self, string.to_s, &block)
238
259
  end
239
260
 
240
261
  # The name of this document. Always returns "document"
241
262
  def name
242
- 'document'
263
+ "document"
243
264
  end
244
265
 
245
266
  # A reference to +self+
@@ -247,46 +268,51 @@ module Nokogiri
247
268
  self
248
269
  end
249
270
 
250
- ##
251
- # Recursively get all namespaces from this node and its subtree and
252
- # return them as a hash.
271
+ # :call-seq:
272
+ # collect_namespaces() Hash<String(Namespace#prefix) String(Namespace#href)>
253
273
  #
254
- # For example, given this document:
274
+ # Recursively get all namespaces from this node and its subtree and return them as a
275
+ # hash.
255
276
  #
256
- # <root xmlns:foo="bar">
277
+ # ⚠ This method will not handle duplicate namespace prefixes, since the return value is a hash.
278
+ #
279
+ # Note that this method does an xpath lookup for nodes with namespaces, and as a result the
280
+ # order (and which duplicate prefix "wins") may be dependent on the implementation of the
281
+ # underlying XML library.
282
+ #
283
+ # *Example:* Basic usage
284
+ #
285
+ # Given this document:
286
+ #
287
+ # <root xmlns="default" xmlns:foo="bar">
257
288
  # <bar xmlns:hello="world" />
258
289
  # </root>
259
290
  #
260
291
  # This method will return:
261
292
  #
262
- # { 'xmlns:foo' => 'bar', 'xmlns:hello' => 'world' }
293
+ # {"xmlns:foo"=>"bar", "xmlns"=>"default", "xmlns:hello"=>"world"}
263
294
  #
264
- # WARNING: this method will clobber duplicate names in the keys.
265
- # For example, given this document:
295
+ # *Example:* Duplicate prefixes
296
+ #
297
+ # Given this document:
266
298
  #
267
299
  # <root xmlns:foo="bar">
268
300
  # <bar xmlns:foo="baz" />
269
301
  # </root>
270
302
  #
271
- # The hash returned will look like this: { 'xmlns:foo' => 'bar' }
272
- #
273
- # Non-prefixed default namespaces (as in "xmlns=") are not included
274
- # in the hash.
303
+ # The hash returned will be something like:
275
304
  #
276
- # Note that this method does an xpath lookup for nodes with
277
- # namespaces, and as a result the order may be dependent on the
278
- # implementation of the underlying XML library.
305
+ # {"xmlns:foo" => "baz"}
279
306
  #
280
307
  def collect_namespaces
281
- xpath("//namespace::*").inject({}) do |hash, ns|
282
- hash[["xmlns",ns.prefix].compact.join(":")] = ns.href if ns.prefix != "xml"
283
- hash
308
+ xpath("//namespace::*").each_with_object({}) do |ns, hash|
309
+ hash[["xmlns", ns.prefix].compact.join(":")] = ns.href if ns.prefix != "xml"
284
310
  end
285
311
  end
286
312
 
287
313
  # Get the list of decorators given +key+
288
- def decorators key
289
- @decorators ||= Hash.new
314
+ def decorators(key)
315
+ @decorators ||= {}
290
316
  @decorators[key] ||= []
291
317
  end
292
318
 
@@ -295,7 +321,7 @@ module Nokogiri
295
321
  # the document or +nil+ when there is no DTD.
296
322
  def validate
297
323
  return nil unless internal_subset
298
- internal_subset.validate self
324
+ internal_subset.validate(self)
299
325
  end
300
326
 
301
327
  ##
@@ -315,7 +341,7 @@ module Nokogiri
315
341
  # ... which does absolutely nothing.
316
342
  #
317
343
  def slop!
318
- unless decorators(XML::Node).include? Nokogiri::Decorators::Slop
344
+ unless decorators(XML::Node).include?(Nokogiri::Decorators::Slop)
319
345
  decorators(XML::Node) << Nokogiri::Decorators::Slop
320
346
  decorate!
321
347
  end
@@ -325,16 +351,16 @@ module Nokogiri
325
351
 
326
352
  ##
327
353
  # Apply any decorators to +node+
328
- def decorate node
354
+ def decorate(node)
329
355
  return unless @decorators
330
- @decorators.each { |klass,list|
356
+ @decorators.each do |klass, list|
331
357
  next unless node.is_a?(klass)
332
358
  list.each { |moodule| node.extend(moodule) }
333
- }
359
+ end
334
360
  end
335
361
 
336
- alias :to_xml :serialize
337
- alias :clone :dup
362
+ alias_method :to_xml, :serialize
363
+ alias_method :clone, :dup
338
364
 
339
365
  # Get the hash of namespaces on the root Nokogiri::XML::Node
340
366
  def namespaces
@@ -344,16 +370,16 @@ module Nokogiri
344
370
  ##
345
371
  # Create a Nokogiri::XML::DocumentFragment from +tags+
346
372
  # Returns an empty fragment if +tags+ is nil.
347
- def fragment tags = nil
348
- DocumentFragment.new(self, tags, self.root)
373
+ def fragment(tags = nil)
374
+ DocumentFragment.new(self, tags, root)
349
375
  end
350
376
 
351
377
  undef_method :swap, :parent, :namespace, :default_namespace=
352
378
  undef_method :add_namespace_definition, :attributes
353
379
  undef_method :namespace_definitions, :line, :add_namespace
354
380
 
355
- def add_child node_or_tags
356
- raise "A document may not have multiple root nodes." if (root && root.name != 'nokogiri_text_wrapper') && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
381
+ def add_child(node_or_tags)
382
+ raise "A document may not have multiple root nodes." if (root && root.name != "nokogiri_text_wrapper") && !(node_or_tags.comment? || node_or_tags.processing_instruction?)
357
383
  node_or_tags = coerce(node_or_tags)
358
384
  if node_or_tags.is_a?(XML::NodeSet)
359
385
  raise "A document may not have multiple root nodes." if node_or_tags.size > 1
@@ -362,17 +388,27 @@ module Nokogiri
362
388
  super
363
389
  end
364
390
  end
365
- alias :<< :add_child
391
+ alias_method :<<, :add_child
392
+
393
+ # :call-seq:
394
+ # xpath_doctype() → Nokogiri::CSS::XPathVisitor::DoctypeConfig
395
+ #
396
+ # [Returns] The document type which determines CSS-to-XPath translation.
397
+ #
398
+ # See XPathVisitor for more information.
399
+ def xpath_doctype
400
+ Nokogiri::CSS::XPathVisitor::DoctypeConfig::XML
401
+ end
366
402
 
367
403
  private
368
404
 
369
- def self.empty_doc? string_or_io
405
+ def self.empty_doc?(string_or_io)
370
406
  string_or_io.nil? ||
371
407
  (string_or_io.respond_to?(:empty?) && string_or_io.empty?) ||
372
408
  (string_or_io.respond_to?(:eof?) && string_or_io.eof?)
373
409
  end
374
410
 
375
- IMPLIED_XPATH_CONTEXTS = [ '//'.freeze ].freeze # :nodoc:
411
+ IMPLIED_XPATH_CONTEXTS = ["//"].freeze # :nodoc:
376
412
 
377
413
  def inspect_attributes
378
414
  [:name, :children]