brakeman 6.0.1 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +9 -0
  3. data/bundle/load.rb +1 -1
  4. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/NEWS.md +100 -2
  5. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/README.md +10 -1
  6. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/attribute.rb +14 -9
  7. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/document.rb +1 -1
  8. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/element.rb +3 -3
  9. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/entity.rb +25 -15
  10. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/formatters/pretty.rb +2 -2
  11. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/namespace.rb +8 -4
  12. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/xpathparser.rb +136 -86
  13. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/rexml.rb +3 -1
  14. data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/text.rb +6 -4
  15. data/lib/brakeman/checks/check_ransack.rb +53 -0
  16. data/lib/brakeman/checks/check_sql.rb +1 -1
  17. data/lib/brakeman/options.rb +4 -0
  18. data/lib/brakeman/processors/alias_processor.rb +1 -2
  19. data/lib/brakeman/processors/lib/module_helper.rb +31 -1
  20. data/lib/brakeman/processors/library_processor.rb +6 -0
  21. data/lib/brakeman/scanner.rb +104 -42
  22. data/lib/brakeman/tracker/controller.rb +14 -10
  23. data/lib/brakeman/tracker.rb +1 -1
  24. data/lib/brakeman/version.rb +1 -1
  25. data/lib/brakeman/warning_codes.rb +1 -0
  26. metadata +56 -55
  27. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/LICENSE.txt +0 -0
  28. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/attlistdecl.rb +0 -0
  29. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/cdata.rb +0 -0
  30. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/child.rb +0 -0
  31. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/comment.rb +0 -0
  32. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/doctype.rb +0 -0
  33. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/dtd/attlistdecl.rb +0 -0
  34. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/dtd/dtd.rb +0 -0
  35. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/dtd/elementdecl.rb +0 -0
  36. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/dtd/entitydecl.rb +0 -0
  37. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/dtd/notationdecl.rb +0 -0
  38. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/encoding.rb +0 -0
  39. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/formatters/default.rb +0 -0
  40. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/formatters/transitive.rb +0 -0
  41. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/functions.rb +0 -0
  42. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/instruction.rb +0 -0
  43. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/light/node.rb +0 -0
  44. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/node.rb +0 -0
  45. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/output.rb +0 -0
  46. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parent.rb +0 -0
  47. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parseexception.rb +0 -0
  48. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/baseparser.rb +0 -0
  49. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/lightparser.rb +0 -0
  50. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/pullparser.rb +0 -0
  51. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/sax2parser.rb +0 -0
  52. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/streamparser.rb +0 -0
  53. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/treeparser.rb +0 -0
  54. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/parsers/ultralightparser.rb +0 -0
  55. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/quickpath.rb +0 -0
  56. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/sax2listener.rb +0 -0
  57. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/security.rb +0 -0
  58. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/source.rb +0 -0
  59. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/streamlistener.rb +0 -0
  60. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/undefinednamespaceexception.rb +0 -0
  61. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/validation/relaxng.rb +0 -0
  62. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/validation/validation.rb +0 -0
  63. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/validation/validationexception.rb +0 -0
  64. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/xmldecl.rb +0 -0
  65. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/xmltokens.rb +0 -0
  66. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/xpath.rb +0 -0
  67. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml/xpath_parser.rb +0 -0
  68. /data/bundle/ruby/3.1.0/gems/{rexml-3.2.5 → rexml-3.2.6}/lib/rexml.rb +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3bfe97a2a21052a6b89113eba0488d389790be712085e953b0661bfdad31f5ea
4
- data.tar.gz: 9155ab4eb06b34c7e8294a63bc1878f4e754087f4c7eebc10ff0232f9b62ad14
3
+ metadata.gz: 52bfaf604bda47973161eb7bb9fd6d1dd2aa7e4d280561b282e68d41e738856d
4
+ data.tar.gz: 80718f17fda4fb4b405a238f54476e5d400aa8e8af15e4a4527860f3a4fb15dc
5
5
  SHA512:
6
- metadata.gz: 67f98784f2eff71cde186b940d6c7bae38495529d1f3882eee6f92103b9c44fb06caa62dd5e6ed2cfaab82b01e7a1c41b951b2529fd4b04e54e6c2ca89a65a91
7
- data.tar.gz: a35a4a539a877bdf2eb2150ef4556d31f995be90ce23a2b2d9697ffae41bb2ec2d7fefbfcb853c10897849f554d87b6c03e9a24265fd965158815df8f445a79b
6
+ metadata.gz: 619b6e399bc20989df267e7d3485ba785507aa3a7e459708abf0ba9922ef073ab056946e569228b30d6edba620231de3b337b414ca5102922d479a12c4bf93b8
7
+ data.tar.gz: ff2f0f6a6df45abe51acbb304c525276a285235054c498d06967331ffc586980f1ec2d98b00ffc5bbaaaf808d0dfb36fdc7ba90ed621c3088a6871f2195b120a
data/CHANGES.md CHANGED
@@ -1,3 +1,12 @@
1
+ # 6.1.0 - 2023-12-04
2
+
3
+ * Add `--timing` to add timing duration for scan steps
4
+ * Fix keyword splats in filter arguments
5
+ * Add check for unfiltered search with Ransack
6
+ * Fix class method lookup in parent classes
7
+ * Handle `class << self`
8
+ * Add `PG::Connection.escape_string` as a SQL sanitization method (Joévin Soulenq)
9
+
1
10
  # 6.0.1 - 2023-07-20
2
11
 
3
12
  * Accept strings for `load_defaults` version
data/bundle/load.rb CHANGED
@@ -3,7 +3,7 @@ $:.unshift "#{path}/bundle/ruby/3.1.0/gems/erubis-2.7.0/lib"
3
3
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/haml-5.2.2/lib"
4
4
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/highline-2.1.0/lib"
5
5
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/parallel-1.23.0/lib"
6
- $:.unshift "#{path}/bundle/ruby/3.1.0/gems/rexml-3.2.5/lib"
6
+ $:.unshift "#{path}/bundle/ruby/3.1.0/gems/rexml-3.2.6/lib"
7
7
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/ruby2ruby-2.4.4/lib"
8
8
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/ruby_parser-3.20.3/lib"
9
9
  $:.unshift "#{path}/bundle/ruby/3.1.0/gems/safe_yaml-1.0.5/lib"
@@ -1,15 +1,113 @@
1
1
  # News
2
2
 
3
+ ## 3.2.6 - 2023-07-27 {#version-3-2-6}
4
+
5
+ ### Improvements
6
+
7
+ * Required Ruby 2.5 or later explicitly.
8
+ [GH-69][gh-69]
9
+ [Patch by Ivo Anjo]
10
+
11
+ * Added documentation for maintenance cycle.
12
+ [GH-71][gh-71]
13
+ [Patch by Ivo Anjo]
14
+
15
+ * Added tutorial.
16
+ [GH-77][gh-77]
17
+ [GH-78][gh-78]
18
+ [Patch by Burdette Lamar]
19
+
20
+ * Improved performance and memory usage.
21
+ [GH-94][gh-94]
22
+ [Patch by fatkodima]
23
+
24
+ * `REXML::Parsers::XPathParser#abbreviate`: Added support for
25
+ function arguments.
26
+ [GH-95][gh-95]
27
+ [Reported by pulver]
28
+
29
+ * `REXML::Parsers::XPathParser#abbreviate`: Added support for string
30
+ literal that contains double-quote.
31
+ [GH-96][gh-96]
32
+ [Patch by pulver]
33
+
34
+ * `REXML::Parsers::XPathParser#abbreviate`: Added missing `/` to
35
+ `:descendant_or_self/:self/:parent`.
36
+ [GH-97][gh-97]
37
+ [Reported by pulver]
38
+
39
+ * `REXML::Parsers::XPathParser#abbreviate`: Added support for more patterns.
40
+ [GH-97][gh-97]
41
+ [Reported by pulver]
42
+
43
+ ### Fixes
44
+
45
+ * Fixed a typo in NEWS.
46
+ [GH-72][gh-72]
47
+ [Patch by Spencer Goodman]
48
+
49
+ * Fixed a typo in NEWS.
50
+ [GH-75][gh-75]
51
+ [Patch by Andrew Bromwich]
52
+
53
+ * Fixed documents.
54
+ [GH-87][gh-87]
55
+ [Patch by Alexander Ilyin]
56
+
57
+ * Fixed a bug that `Attriute` convert `'` and `&apos;` even when
58
+ `attribute_quote: :quote` is used.
59
+ [GH-92][gh-92]
60
+ [Reported by Edouard Brière]
61
+
62
+ * Fixed links in tutorial.
63
+ [GH-99][gh-99]
64
+ [Patch by gemmaro]
65
+
66
+
67
+ ### Thanks
68
+
69
+ * Ivo Anjo
70
+
71
+ * Spencer Goodman
72
+
73
+ * Andrew Bromwich
74
+
75
+ * Burdette Lamar
76
+
77
+ * Alexander Ilyin
78
+
79
+ * Edouard Brière
80
+
81
+ * fatkodima
82
+
83
+ * pulver
84
+
85
+ * gemmaro
86
+
87
+ [gh-69]:https://github.com/ruby/rexml/issues/69
88
+ [gh-71]:https://github.com/ruby/rexml/issues/71
89
+ [gh-72]:https://github.com/ruby/rexml/issues/72
90
+ [gh-75]:https://github.com/ruby/rexml/issues/75
91
+ [gh-77]:https://github.com/ruby/rexml/issues/77
92
+ [gh-87]:https://github.com/ruby/rexml/issues/87
93
+ [gh-92]:https://github.com/ruby/rexml/issues/92
94
+ [gh-94]:https://github.com/ruby/rexml/issues/94
95
+ [gh-95]:https://github.com/ruby/rexml/issues/95
96
+ [gh-96]:https://github.com/ruby/rexml/issues/96
97
+ [gh-97]:https://github.com/ruby/rexml/issues/97
98
+ [gh-98]:https://github.com/ruby/rexml/issues/98
99
+ [gh-99]:https://github.com/ruby/rexml/issues/99
100
+
3
101
  ## 3.2.5 - 2021-04-05 {#version-3-2-5}
4
102
 
5
103
  ### Improvements
6
104
 
7
105
  * Add more validations to XPath parser.
8
106
 
9
- * `require "rexml/docuemnt"` by default.
107
+ * `require "rexml/document"` by default.
10
108
  [GitHub#36][Patch by Koichi ITO]
11
109
 
12
- * Don't add `#dcloe` method to core classes globally.
110
+ * Don't add `#dclone` method to core classes globally.
13
111
  [GitHub#37][Patch by Akira Matsuda]
14
112
 
15
113
  * Add more documentations.
@@ -6,7 +6,7 @@ REXML supports both tree and stream document parsing. Stream parsing is faster (
6
6
 
7
7
  ## API
8
8
 
9
- See the {API documentation}[https://ruby.github.io/rexml/]
9
+ See the [API documentation](https://ruby.github.io/rexml/).
10
10
 
11
11
  ## Usage
12
12
 
@@ -33,6 +33,15 @@ doc = Document.new string
33
33
 
34
34
  So parsing a string is just as easy as parsing a file.
35
35
 
36
+ ## Support
37
+
38
+ REXML support follows the same maintenance cycle as Ruby releases, as shown on <https://www.ruby-lang.org/en/downloads/branches/>.
39
+
40
+ If you are running on an end-of-life Ruby, do not expect modern REXML releases to be compatible with it; in fact, it's recommended that you DO NOT use this gem, and instead use the REXML version that came bundled with your end-of-life Ruby version.
41
+
42
+ The `required_ruby_version` on the gemspec is kept updated on a [best-effort basis](https://github.com/ruby/rexml/pull/70) by the community.
43
+ Up to version 3.2.5, this information was not set. That version [is known broken with at least Ruby < 2.3](https://github.com/ruby/rexml/issues/69).
44
+
36
45
  ## Development
37
46
 
38
47
  After checking out the repo, run `rake test` to run the tests.
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  require_relative "namespace"
3
3
  require_relative 'text'
4
4
 
@@ -13,9 +13,6 @@ module REXML
13
13
 
14
14
  # The element to which this attribute belongs
15
15
  attr_reader :element
16
- # The normalized value of this attribute. That is, the attribute with
17
- # entities intact.
18
- attr_writer :normalized
19
16
  PATTERN = /\s*(#{NAME_STR})\s*=\s*(["'])(.*?)\2/um
20
17
 
21
18
  NEEDS_A_SECOND_CHECK = /(<|&((#{Entity::NAME});|(#0*((?:\d+)|(?:x[a-fA-F0-9]+)));)?)/um
@@ -122,10 +119,13 @@ module REXML
122
119
  # b = Attribute.new( "ns:x", "y" )
123
120
  # b.to_string # -> "ns:x='y'"
124
121
  def to_string
122
+ value = to_s
125
123
  if @element and @element.context and @element.context[:attribute_quote] == :quote
126
- %Q^#@expanded_name="#{to_s().gsub(/"/, '&quot;')}"^
124
+ value = value.gsub('"', '&quot;') if value.include?('"')
125
+ %Q^#@expanded_name="#{value}"^
127
126
  else
128
- "#@expanded_name='#{to_s().gsub(/'/, '&apos;')}'"
127
+ value = value.gsub("'", '&apos;') if value.include?("'")
128
+ "#@expanded_name='#{value}'"
129
129
  end
130
130
  end
131
131
 
@@ -141,7 +141,6 @@ module REXML
141
141
  return @normalized if @normalized
142
142
 
143
143
  @normalized = Text::normalize( @unnormalized, doctype )
144
- @unnormalized = nil
145
144
  @normalized
146
145
  end
147
146
 
@@ -150,10 +149,16 @@ module REXML
150
149
  def value
151
150
  return @unnormalized if @unnormalized
152
151
  @unnormalized = Text::unnormalize( @normalized, doctype )
153
- @normalized = nil
154
152
  @unnormalized
155
153
  end
156
154
 
155
+ # The normalized value of this attribute. That is, the attribute with
156
+ # entities intact.
157
+ def normalized=(new_normalized)
158
+ @normalized = new_normalized
159
+ @unnormalized = nil
160
+ end
161
+
157
162
  # Returns a copy of this attribute
158
163
  def clone
159
164
  Attribute.new self
@@ -190,7 +195,7 @@ module REXML
190
195
  end
191
196
 
192
197
  def inspect
193
- rv = ""
198
+ rv = +""
194
199
  write( rv )
195
200
  rv
196
201
  end
@@ -69,7 +69,7 @@ module REXML
69
69
  # d.to_s # => "<root><foo>Foo</foo><bar>Bar</bar></root>"
70
70
  #
71
71
  # When argument +document+ is given, it must be an existing
72
- # document object, whose context and attributes (but not chidren)
72
+ # document object, whose context and attributes (but not children)
73
73
  # are cloned into the new document:
74
74
  #
75
75
  # d = REXML::Document.new(xml_string)
@@ -989,7 +989,7 @@ module REXML
989
989
  # :call-seq:
990
990
  # has_text? -> true or false
991
991
  #
992
- # Returns +true if the element has one or more text noded,
992
+ # Returns +true+ if the element has one or more text noded,
993
993
  # +false+ otherwise:
994
994
  #
995
995
  # d = REXML::Document.new '<a><b/>text<c/></a>'
@@ -1006,7 +1006,7 @@ module REXML
1006
1006
  # text(xpath = nil) -> text_string or nil
1007
1007
  #
1008
1008
  # Returns the text string from the first text node child
1009
- # in a specified element, if it exists, # +nil+ otherwise.
1009
+ # in a specified element, if it exists, +nil+ otherwise.
1010
1010
  #
1011
1011
  # With no argument, returns the text from the first text node in +self+:
1012
1012
  #
@@ -1014,7 +1014,7 @@ module REXML
1014
1014
  # d.root.text.class # => String
1015
1015
  # d.root.text # => "some text "
1016
1016
  #
1017
- # With argument +xpath+, returns text from the the first text node
1017
+ # With argument +xpath+, returns text from the first text node
1018
1018
  # in the element that matches +xpath+:
1019
1019
  #
1020
1020
  # d.root.text(1) # => "this is bold!"
@@ -132,24 +132,34 @@ module REXML
132
132
  # then:
133
133
  # doctype.entity('yada').value #-> "nanoo bar nanoo"
134
134
  def value
135
- if @value
136
- matches = @value.scan(PEREFERENCE_RE)
137
- rv = @value.clone
138
- if @parent
139
- sum = 0
140
- matches.each do |entity_reference|
141
- entity_value = @parent.entity( entity_reference[0] )
142
- if sum + entity_value.bytesize > Security.entity_expansion_text_limit
143
- raise "entity expansion has grown too large"
144
- else
145
- sum += entity_value.bytesize
146
- end
147
- rv.gsub!( /%#{entity_reference.join};/um, entity_value )
135
+ @resolved_value ||= resolve_value
136
+ end
137
+
138
+ def parent=(other)
139
+ @resolved_value = nil
140
+ super
141
+ end
142
+
143
+ private
144
+ def resolve_value
145
+ return nil if @value.nil?
146
+ return @value unless @value.match?(PEREFERENCE_RE)
147
+
148
+ matches = @value.scan(PEREFERENCE_RE)
149
+ rv = @value.clone
150
+ if @parent
151
+ sum = 0
152
+ matches.each do |entity_reference|
153
+ entity_value = @parent.entity( entity_reference[0] )
154
+ if sum + entity_value.bytesize > Security.entity_expansion_text_limit
155
+ raise "entity expansion has grown too large"
156
+ else
157
+ sum += entity_value.bytesize
148
158
  end
159
+ rv.gsub!( /%#{entity_reference.join};/um, entity_value )
149
160
  end
150
- return rv
151
161
  end
152
- nil
162
+ rv
153
163
  end
154
164
  end
155
165
 
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
  require_relative 'default'
3
3
 
4
4
  module REXML
@@ -58,7 +58,7 @@ module REXML
58
58
  skip = false
59
59
  if compact
60
60
  if node.children.inject(true) {|s,c| s & c.kind_of?(Text)}
61
- string = ""
61
+ string = +""
62
62
  old_level = @level
63
63
  @level = 0
64
64
  node.children.each { |child| write( child, string ) }
@@ -1,4 +1,4 @@
1
- # frozen_string_literal: false
1
+ # frozen_string_literal: true
2
2
 
3
3
  require_relative 'xmltokens'
4
4
 
@@ -10,13 +10,17 @@ module REXML
10
10
  # The expanded name of the object, valid if name is set
11
11
  attr_accessor :prefix
12
12
  include XMLTokens
13
+ NAME_WITHOUT_NAMESPACE = /\A#{NCNAME_STR}\z/
13
14
  NAMESPLIT = /^(?:(#{NCNAME_STR}):)?(#{NCNAME_STR})/u
14
15
 
15
16
  # Sets the name and the expanded name
16
17
  def name=( name )
17
18
  @expanded_name = name
18
- case name
19
- when NAMESPLIT
19
+ if name.match?(NAME_WITHOUT_NAMESPACE)
20
+ @prefix = ""
21
+ @namespace = ""
22
+ @name = name
23
+ elsif name =~ NAMESPLIT
20
24
  if $1
21
25
  @prefix = $1
22
26
  else
@@ -24,7 +28,7 @@ module REXML
24
28
  @namespace = ""
25
29
  end
26
30
  @name = $2
27
- when ""
31
+ elsif name == ""
28
32
  @prefix = nil
29
33
  @namespace = nil
30
34
  @name = nil
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: false
2
+
2
3
  require_relative '../namespace'
3
4
  require_relative '../xmltokens'
4
5
 
@@ -38,108 +39,143 @@ module REXML
38
39
  parsed
39
40
  end
40
41
 
41
- def abbreviate( path )
42
- path = path.kind_of?(String) ? parse( path ) : path
43
- string = ""
44
- document = false
45
- while path.size > 0
46
- op = path.shift
42
+ def abbreviate(path_or_parsed)
43
+ if path_or_parsed.kind_of?(String)
44
+ parsed = parse(path_or_parsed)
45
+ else
46
+ parsed = path_or_parsed
47
+ end
48
+ components = []
49
+ component = nil
50
+ while parsed.size > 0
51
+ op = parsed.shift
47
52
  case op
48
53
  when :node
54
+ component << "node()"
49
55
  when :attribute
50
- string << "/" if string.size > 0
51
- string << "@"
56
+ component = "@"
57
+ components << component
52
58
  when :child
53
- string << "/" if string.size > 0
59
+ component = ""
60
+ components << component
54
61
  when :descendant_or_self
55
- string << "/"
62
+ next_op = parsed[0]
63
+ if next_op == :node
64
+ parsed.shift
65
+ component = ""
66
+ components << component
67
+ else
68
+ component = "descendant-or-self::"
69
+ components << component
70
+ end
56
71
  when :self
57
- string << "."
72
+ next_op = parsed[0]
73
+ if next_op == :node
74
+ parsed.shift
75
+ components << "."
76
+ else
77
+ component = "self::"
78
+ components << component
79
+ end
58
80
  when :parent
59
- string << ".."
81
+ next_op = parsed[0]
82
+ if next_op == :node
83
+ parsed.shift
84
+ components << ".."
85
+ else
86
+ component = "parent::"
87
+ components << component
88
+ end
60
89
  when :any
61
- string << "*"
90
+ component << "*"
62
91
  when :text
63
- string << "text()"
92
+ component << "text()"
64
93
  when :following, :following_sibling,
65
94
  :ancestor, :ancestor_or_self, :descendant,
66
95
  :namespace, :preceding, :preceding_sibling
67
- string << "/" unless string.size == 0
68
- string << op.to_s.tr("_", "-")
69
- string << "::"
96
+ component = op.to_s.tr("_", "-") << "::"
97
+ components << component
70
98
  when :qname
71
- prefix = path.shift
72
- name = path.shift
73
- string << prefix+":" if prefix.size > 0
74
- string << name
99
+ prefix = parsed.shift
100
+ name = parsed.shift
101
+ component << prefix+":" if prefix.size > 0
102
+ component << name
75
103
  when :predicate
76
- string << '['
77
- string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
78
- string << ']'
104
+ component << '['
105
+ component << predicate_to_path(parsed.shift) {|x| abbreviate(x)}
106
+ component << ']'
79
107
  when :document
80
- document = true
108
+ components << ""
81
109
  when :function
82
- string << path.shift
83
- string << "( "
84
- string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
85
- string << " )"
110
+ component << parsed.shift
111
+ component << "( "
112
+ component << predicate_to_path(parsed.shift[0]) {|x| abbreviate(x)}
113
+ component << " )"
86
114
  when :literal
87
- string << %Q{ "#{path.shift}" }
115
+ component << quote_literal(parsed.shift)
88
116
  else
89
- string << "/" unless string.size == 0
90
- string << "UNKNOWN("
91
- string << op.inspect
92
- string << ")"
117
+ component << "UNKNOWN("
118
+ component << op.inspect
119
+ component << ")"
93
120
  end
94
121
  end
95
- string = "/"+string if document
96
- return string
122
+ case components
123
+ when [""]
124
+ "/"
125
+ when ["", ""]
126
+ "//"
127
+ else
128
+ components.join("/")
129
+ end
97
130
  end
98
131
 
99
- def expand( path )
100
- path = path.kind_of?(String) ? parse( path ) : path
101
- string = ""
132
+ def expand(path_or_parsed)
133
+ if path_or_parsed.kind_of?(String)
134
+ parsed = parse(path_or_parsed)
135
+ else
136
+ parsed = path_or_parsed
137
+ end
138
+ path = ""
102
139
  document = false
103
- while path.size > 0
104
- op = path.shift
140
+ while parsed.size > 0
141
+ op = parsed.shift
105
142
  case op
106
143
  when :node
107
- string << "node()"
144
+ path << "node()"
108
145
  when :attribute, :child, :following, :following_sibling,
109
146
  :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
110
147
  :namespace, :preceding, :preceding_sibling, :self, :parent
111
- string << "/" unless string.size == 0
112
- string << op.to_s.tr("_", "-")
113
- string << "::"
148
+ path << "/" unless path.size == 0
149
+ path << op.to_s.tr("_", "-")
150
+ path << "::"
114
151
  when :any
115
- string << "*"
152
+ path << "*"
116
153
  when :qname
117
- prefix = path.shift
118
- name = path.shift
119
- string << prefix+":" if prefix.size > 0
120
- string << name
154
+ prefix = parsed.shift
155
+ name = parsed.shift
156
+ path << prefix+":" if prefix.size > 0
157
+ path << name
121
158
  when :predicate
122
- string << '['
123
- string << predicate_to_string( path.shift ) { |x| expand(x) }
124
- string << ']'
159
+ path << '['
160
+ path << predicate_to_path( parsed.shift ) { |x| expand(x) }
161
+ path << ']'
125
162
  when :document
126
163
  document = true
127
164
  else
128
- string << "/" unless string.size == 0
129
- string << "UNKNOWN("
130
- string << op.inspect
131
- string << ")"
165
+ path << "UNKNOWN("
166
+ path << op.inspect
167
+ path << ")"
132
168
  end
133
169
  end
134
- string = "/"+string if document
135
- return string
170
+ path = "/"+path if document
171
+ path
136
172
  end
137
173
 
138
- def predicate_to_string( path, &block )
139
- string = ""
140
- case path[0]
174
+ def predicate_to_path(parsed, &block)
175
+ path = ""
176
+ case parsed[0]
141
177
  when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
142
- op = path.shift
178
+ op = parsed.shift
143
179
  case op
144
180
  when :eq
145
181
  op = "="
@@ -156,36 +192,50 @@ module REXML
156
192
  when :union
157
193
  op = "|"
158
194
  end
159
- left = predicate_to_string( path.shift, &block )
160
- right = predicate_to_string( path.shift, &block )
161
- string << " "
162
- string << left
163
- string << " "
164
- string << op.to_s
165
- string << " "
166
- string << right
167
- string << " "
195
+ left = predicate_to_path( parsed.shift, &block )
196
+ right = predicate_to_path( parsed.shift, &block )
197
+ path << left
198
+ path << " "
199
+ path << op.to_s
200
+ path << " "
201
+ path << right
168
202
  when :function
169
- path.shift
170
- name = path.shift
171
- string << name
172
- string << "( "
173
- string << predicate_to_string( path.shift, &block )
174
- string << " )"
203
+ parsed.shift
204
+ name = parsed.shift
205
+ path << name
206
+ path << "("
207
+ parsed.shift.each_with_index do |argument, i|
208
+ path << ", " if i > 0
209
+ path << predicate_to_path(argument, &block)
210
+ end
211
+ path << ")"
175
212
  when :literal
176
- path.shift
177
- string << " "
178
- string << path.shift.inspect
179
- string << " "
213
+ parsed.shift
214
+ path << quote_literal(parsed.shift)
180
215
  else
181
- string << " "
182
- string << yield( path )
183
- string << " "
216
+ path << yield( parsed )
184
217
  end
185
- return string.squeeze(" ")
218
+ return path.squeeze(" ")
186
219
  end
220
+ # For backward compatibility
221
+ alias_method :preciate_to_string, :predicate_to_path
187
222
 
188
223
  private
224
+ def quote_literal( literal )
225
+ case literal
226
+ when String
227
+ # XPath 1.0 does not support escape characters.
228
+ # Assumes literal does not contain both single and double quotes.
229
+ if literal.include?("'")
230
+ "\"#{literal}\""
231
+ else
232
+ "'#{literal}'"
233
+ end
234
+ else
235
+ literal.inspect
236
+ end
237
+ end
238
+
189
239
  #LocationPath
190
240
  # | RelativeLocationPath
191
241
  # | '/' RelativeLocationPath?