brakeman 6.0.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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?