brakeman 4.10.1 → 5.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +9 -7
  3. data/README.md +1 -1
  4. data/bundle/load.rb +8 -9
  5. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/CHANGELOG.md +1 -8
  6. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/FAQ.md +0 -0
  7. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/Gemfile +0 -0
  8. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/MIT-LICENSE +0 -0
  9. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/README.md +0 -0
  10. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/REFERENCE.md +5 -9
  11. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/TODO +0 -0
  12. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/haml.gemspec +1 -1
  13. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml.rb +0 -0
  14. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_builder.rb +0 -0
  15. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_compiler.rb +0 -0
  16. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/attribute_parser.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/buffer.rb +0 -0
  18. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/compiler.rb +0 -0
  19. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/engine.rb +0 -0
  20. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/error.rb +0 -0
  21. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/escapable.rb +0 -0
  22. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/exec.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/filters.rb +0 -0
  24. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/generator.rb +0 -0
  25. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers.rb +0 -0
  26. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_extensions.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_mods.rb +0 -0
  28. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/action_view_xss_mods.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/safe_erubi_template.rb +0 -0
  30. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/safe_erubis_template.rb +0 -0
  31. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/helpers/xss_mods.rb +0 -0
  32. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/options.rb +0 -0
  33. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/parser.rb +3 -31
  34. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/plugin.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/railtie.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/sass_rails_filter.rb +0 -0
  37. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/template.rb +0 -0
  38. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/template/options.rb +0 -0
  39. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/temple_engine.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/temple_line_counter.rb +0 -0
  41. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/util.rb +1 -1
  42. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/lib/haml/version.rb +1 -1
  43. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/yard/default/fulldoc/html/css/common.sass +0 -0
  44. data/bundle/ruby/2.7.0/gems/{haml-5.2.1 → haml-5.2.0}/yard/default/layout/html/footer.erb +0 -0
  45. data/lib/brakeman.rb +6 -0
  46. data/lib/brakeman/app_tree.rb +36 -3
  47. data/lib/brakeman/checks/check_execute.rb +1 -1
  48. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  49. data/lib/brakeman/checks/check_unsafe_reflection_methods.rb +68 -0
  50. data/lib/brakeman/checks/check_verb_confusion.rb +75 -0
  51. data/lib/brakeman/file_parser.rb +19 -23
  52. data/lib/brakeman/options.rb +5 -1
  53. data/lib/brakeman/parsers/template_parser.rb +2 -3
  54. data/lib/brakeman/processors/alias_processor.rb +2 -2
  55. data/lib/brakeman/processors/controller_processor.rb +1 -1
  56. data/lib/brakeman/processors/lib/file_type_detector.rb +64 -0
  57. data/lib/brakeman/processors/output_processor.rb +1 -1
  58. data/lib/brakeman/processors/template_alias_processor.rb +0 -5
  59. data/lib/brakeman/report.rb +8 -0
  60. data/lib/brakeman/report/report_sonar.rb +38 -0
  61. data/lib/brakeman/rescanner.rb +7 -5
  62. data/lib/brakeman/scanner.rb +42 -18
  63. data/lib/brakeman/tracker.rb +6 -0
  64. data/lib/brakeman/tracker/controller.rb +1 -1
  65. data/lib/brakeman/util.rb +9 -4
  66. data/lib/brakeman/version.rb +1 -1
  67. data/lib/brakeman/warning_codes.rb +2 -0
  68. data/lib/ruby_parser/bm_sexp.rb +9 -9
  69. metadata +49 -99
  70. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/Gemfile +0 -6
  71. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/LICENSE.txt +0 -22
  72. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/NEWS.md +0 -141
  73. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/README.md +0 -60
  74. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attlistdecl.rb +0 -63
  75. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attribute.rb +0 -205
  76. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/cdata.rb +0 -68
  77. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/child.rb +0 -97
  78. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/comment.rb +0 -80
  79. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/doctype.rb +0 -287
  80. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/document.rb +0 -291
  81. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/attlistdecl.rb +0 -11
  82. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/dtd.rb +0 -47
  83. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/elementdecl.rb +0 -18
  84. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/entitydecl.rb +0 -57
  85. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/notationdecl.rb +0 -40
  86. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +0 -1269
  87. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/encoding.rb +0 -51
  88. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/entity.rb +0 -171
  89. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/default.rb +0 -116
  90. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/pretty.rb +0 -142
  91. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/transitive.rb +0 -58
  92. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/functions.rb +0 -447
  93. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/instruction.rb +0 -79
  94. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/light/node.rb +0 -196
  95. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/namespace.rb +0 -59
  96. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/node.rb +0 -76
  97. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/output.rb +0 -30
  98. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parent.rb +0 -166
  99. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parseexception.rb +0 -52
  100. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/baseparser.rb +0 -594
  101. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/lightparser.rb +0 -59
  102. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/pullparser.rb +0 -197
  103. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/sax2parser.rb +0 -273
  104. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/streamparser.rb +0 -61
  105. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/treeparser.rb +0 -101
  106. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/ultralightparser.rb +0 -57
  107. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/xpathparser.rb +0 -675
  108. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/quickpath.rb +0 -266
  109. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +0 -32
  110. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/sax2listener.rb +0 -98
  111. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/security.rb +0 -28
  112. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/source.rb +0 -298
  113. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/streamlistener.rb +0 -93
  114. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/text.rb +0 -424
  115. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/undefinednamespaceexception.rb +0 -9
  116. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/relaxng.rb +0 -539
  117. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validation.rb +0 -144
  118. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validationexception.rb +0 -10
  119. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmldecl.rb +0 -130
  120. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmltokens.rb +0 -85
  121. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath.rb +0 -81
  122. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath_parser.rb +0 -968
  123. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +0 -84
@@ -1,61 +0,0 @@
1
- # frozen_string_literal: false
2
- require_relative "baseparser"
3
-
4
- module REXML
5
- module Parsers
6
- class StreamParser
7
- def initialize source, listener
8
- @listener = listener
9
- @parser = BaseParser.new( source )
10
- @tag_stack = []
11
- end
12
-
13
- def add_listener( listener )
14
- @parser.add_listener( listener )
15
- end
16
-
17
- def parse
18
- # entity string
19
- while true
20
- event = @parser.pull
21
- case event[0]
22
- when :end_document
23
- unless @tag_stack.empty?
24
- tag_path = "/" + @tag_stack.join("/")
25
- raise ParseException.new("Missing end tag for '#{tag_path}'",
26
- @parser.source)
27
- end
28
- return
29
- when :start_element
30
- @tag_stack << event[1]
31
- attrs = event[2].each do |n, v|
32
- event[2][n] = @parser.unnormalize( v )
33
- end
34
- @listener.tag_start( event[1], attrs )
35
- when :end_element
36
- @listener.tag_end( event[1] )
37
- @tag_stack.pop
38
- when :text
39
- normalized = @parser.unnormalize( event[1] )
40
- @listener.text( normalized )
41
- when :processing_instruction
42
- @listener.instruction( *event[1,2] )
43
- when :start_doctype
44
- @listener.doctype( *event[1..-1] )
45
- when :end_doctype
46
- # FIXME: remove this condition for milestone:3.2
47
- @listener.doctype_end if @listener.respond_to? :doctype_end
48
- when :comment, :attlistdecl, :cdata, :xmldecl, :elementdecl
49
- @listener.send( event[0].to_s, *event[1..-1] )
50
- when :entitydecl, :notationdecl
51
- @listener.send( event[0].to_s, event[1..-1] )
52
- when :externalentity
53
- entity_reference = event[1]
54
- content = entity_reference.gsub(/\A%|;\z/, "")
55
- @listener.entity(content)
56
- end
57
- end
58
- end
59
- end
60
- end
61
- end
@@ -1,101 +0,0 @@
1
- # frozen_string_literal: false
2
- require_relative '../validation/validationexception'
3
- require_relative '../undefinednamespaceexception'
4
-
5
- module REXML
6
- module Parsers
7
- class TreeParser
8
- def initialize( source, build_context = Document.new )
9
- @build_context = build_context
10
- @parser = Parsers::BaseParser.new( source )
11
- end
12
-
13
- def add_listener( listener )
14
- @parser.add_listener( listener )
15
- end
16
-
17
- def parse
18
- tag_stack = []
19
- in_doctype = false
20
- entities = nil
21
- begin
22
- while true
23
- event = @parser.pull
24
- #STDERR.puts "TREEPARSER GOT #{event.inspect}"
25
- case event[0]
26
- when :end_document
27
- unless tag_stack.empty?
28
- raise ParseException.new("No close tag for #{@build_context.xpath}",
29
- @parser.source, @parser)
30
- end
31
- return
32
- when :start_element
33
- tag_stack.push(event[1])
34
- el = @build_context = @build_context.add_element( event[1] )
35
- event[2].each do |key, value|
36
- el.attributes[key]=Attribute.new(key,value,self)
37
- end
38
- when :end_element
39
- tag_stack.pop
40
- @build_context = @build_context.parent
41
- when :text
42
- if not in_doctype
43
- if @build_context[-1].instance_of? Text
44
- @build_context[-1] << event[1]
45
- else
46
- @build_context.add(
47
- Text.new(event[1], @build_context.whitespace, nil, true)
48
- ) unless (
49
- @build_context.ignore_whitespace_nodes and
50
- event[1].strip.size==0
51
- )
52
- end
53
- end
54
- when :comment
55
- c = Comment.new( event[1] )
56
- @build_context.add( c )
57
- when :cdata
58
- c = CData.new( event[1] )
59
- @build_context.add( c )
60
- when :processing_instruction
61
- @build_context.add( Instruction.new( event[1], event[2] ) )
62
- when :end_doctype
63
- in_doctype = false
64
- entities.each { |k,v| entities[k] = @build_context.entities[k].value }
65
- @build_context = @build_context.parent
66
- when :start_doctype
67
- doctype = DocType.new( event[1..-1], @build_context )
68
- @build_context = doctype
69
- entities = {}
70
- in_doctype = true
71
- when :attlistdecl
72
- n = AttlistDecl.new( event[1..-1] )
73
- @build_context.add( n )
74
- when :externalentity
75
- n = ExternalEntity.new( event[1] )
76
- @build_context.add( n )
77
- when :elementdecl
78
- n = ElementDecl.new( event[1] )
79
- @build_context.add(n)
80
- when :entitydecl
81
- entities[ event[1] ] = event[2] unless event[2] =~ /PUBLIC|SYSTEM/
82
- @build_context.add(Entity.new(event))
83
- when :notationdecl
84
- n = NotationDecl.new( *event[1..-1] )
85
- @build_context.add( n )
86
- when :xmldecl
87
- x = XMLDecl.new( event[1], event[2], event[3] )
88
- @build_context.add( x )
89
- end
90
- end
91
- rescue REXML::Validation::ValidationException
92
- raise
93
- rescue REXML::ParseException
94
- raise
95
- rescue
96
- raise ParseException.new( $!.message, @parser.source, @parser, $! )
97
- end
98
- end
99
- end
100
- end
101
- end
@@ -1,57 +0,0 @@
1
- # frozen_string_literal: false
2
- require_relative 'streamparser'
3
- require_relative 'baseparser'
4
-
5
- module REXML
6
- module Parsers
7
- class UltraLightParser
8
- def initialize stream
9
- @stream = stream
10
- @parser = REXML::Parsers::BaseParser.new( stream )
11
- end
12
-
13
- def add_listener( listener )
14
- @parser.add_listener( listener )
15
- end
16
-
17
- def rewind
18
- @stream.rewind
19
- @parser.stream = @stream
20
- end
21
-
22
- def parse
23
- root = context = []
24
- while true
25
- event = @parser.pull
26
- case event[0]
27
- when :end_document
28
- break
29
- when :end_doctype
30
- context = context[1]
31
- when :start_element, :start_doctype
32
- context << event
33
- event[1,0] = [context]
34
- context = event
35
- when :end_element
36
- context = context[1]
37
- else
38
- context << event
39
- end
40
- end
41
- root
42
- end
43
- end
44
-
45
- # An element is an array. The array contains:
46
- # 0 The parent element
47
- # 1 The tag name
48
- # 2 A hash of attributes
49
- # 3..-1 The child elements
50
- # An element is an array of size > 3
51
- # Text is a String
52
- # PIs are [ :processing_instruction, target, data ]
53
- # Comments are [ :comment, data ]
54
- # DocTypes are DocType structs
55
- # The root is an array with XMLDecls, Text, DocType, Array, Text
56
- end
57
- end
@@ -1,675 +0,0 @@
1
- # frozen_string_literal: false
2
- require_relative '../namespace'
3
- require_relative '../xmltokens'
4
-
5
- module REXML
6
- module Parsers
7
- # You don't want to use this class. Really. Use XPath, which is a wrapper
8
- # for this class. Believe me. You don't want to poke around in here.
9
- # There is strange, dark magic at work in this code. Beware. Go back! Go
10
- # back while you still can!
11
- class XPathParser
12
- include XMLTokens
13
- LITERAL = /^'([^']*)'|^"([^"]*)"/u
14
-
15
- def namespaces=( namespaces )
16
- Functions::namespace_context = namespaces
17
- @namespaces = namespaces
18
- end
19
-
20
- def parse path
21
- path = path.dup
22
- path.gsub!(/([\(\[])\s+/, '\1') # Strip ignorable spaces
23
- path.gsub!( /\s+([\]\)])/, '\1')
24
- parsed = []
25
- OrExpr(path, parsed)
26
- parsed
27
- end
28
-
29
- def predicate path
30
- parsed = []
31
- Predicate( "[#{path}]", parsed )
32
- parsed
33
- end
34
-
35
- def abbreviate( path )
36
- path = path.kind_of?(String) ? parse( path ) : path
37
- string = ""
38
- document = false
39
- while path.size > 0
40
- op = path.shift
41
- case op
42
- when :node
43
- when :attribute
44
- string << "/" if string.size > 0
45
- string << "@"
46
- when :child
47
- string << "/" if string.size > 0
48
- when :descendant_or_self
49
- string << "/"
50
- when :self
51
- string << "."
52
- when :parent
53
- string << ".."
54
- when :any
55
- string << "*"
56
- when :text
57
- string << "text()"
58
- when :following, :following_sibling,
59
- :ancestor, :ancestor_or_self, :descendant,
60
- :namespace, :preceding, :preceding_sibling
61
- string << "/" unless string.size == 0
62
- string << op.to_s.tr("_", "-")
63
- string << "::"
64
- when :qname
65
- prefix = path.shift
66
- name = path.shift
67
- string << prefix+":" if prefix.size > 0
68
- string << name
69
- when :predicate
70
- string << '['
71
- string << predicate_to_string( path.shift ) {|x| abbreviate( x ) }
72
- string << ']'
73
- when :document
74
- document = true
75
- when :function
76
- string << path.shift
77
- string << "( "
78
- string << predicate_to_string( path.shift[0] ) {|x| abbreviate( x )}
79
- string << " )"
80
- when :literal
81
- string << %Q{ "#{path.shift}" }
82
- else
83
- string << "/" unless string.size == 0
84
- string << "UNKNOWN("
85
- string << op.inspect
86
- string << ")"
87
- end
88
- end
89
- string = "/"+string if document
90
- return string
91
- end
92
-
93
- def expand( path )
94
- path = path.kind_of?(String) ? parse( path ) : path
95
- string = ""
96
- document = false
97
- while path.size > 0
98
- op = path.shift
99
- case op
100
- when :node
101
- string << "node()"
102
- when :attribute, :child, :following, :following_sibling,
103
- :ancestor, :ancestor_or_self, :descendant, :descendant_or_self,
104
- :namespace, :preceding, :preceding_sibling, :self, :parent
105
- string << "/" unless string.size == 0
106
- string << op.to_s.tr("_", "-")
107
- string << "::"
108
- when :any
109
- string << "*"
110
- when :qname
111
- prefix = path.shift
112
- name = path.shift
113
- string << prefix+":" if prefix.size > 0
114
- string << name
115
- when :predicate
116
- string << '['
117
- string << predicate_to_string( path.shift ) { |x| expand(x) }
118
- string << ']'
119
- when :document
120
- document = true
121
- else
122
- string << "/" unless string.size == 0
123
- string << "UNKNOWN("
124
- string << op.inspect
125
- string << ")"
126
- end
127
- end
128
- string = "/"+string if document
129
- return string
130
- end
131
-
132
- def predicate_to_string( path, &block )
133
- string = ""
134
- case path[0]
135
- when :and, :or, :mult, :plus, :minus, :neq, :eq, :lt, :gt, :lteq, :gteq, :div, :mod, :union
136
- op = path.shift
137
- case op
138
- when :eq
139
- op = "="
140
- when :lt
141
- op = "<"
142
- when :gt
143
- op = ">"
144
- when :lteq
145
- op = "<="
146
- when :gteq
147
- op = ">="
148
- when :neq
149
- op = "!="
150
- when :union
151
- op = "|"
152
- end
153
- left = predicate_to_string( path.shift, &block )
154
- right = predicate_to_string( path.shift, &block )
155
- string << " "
156
- string << left
157
- string << " "
158
- string << op.to_s
159
- string << " "
160
- string << right
161
- string << " "
162
- when :function
163
- path.shift
164
- name = path.shift
165
- string << name
166
- string << "( "
167
- string << predicate_to_string( path.shift, &block )
168
- string << " )"
169
- when :literal
170
- path.shift
171
- string << " "
172
- string << path.shift.inspect
173
- string << " "
174
- else
175
- string << " "
176
- string << yield( path )
177
- string << " "
178
- end
179
- return string.squeeze(" ")
180
- end
181
-
182
- private
183
- #LocationPath
184
- # | RelativeLocationPath
185
- # | '/' RelativeLocationPath?
186
- # | '//' RelativeLocationPath
187
- def LocationPath path, parsed
188
- path = path.lstrip
189
- if path[0] == ?/
190
- parsed << :document
191
- if path[1] == ?/
192
- parsed << :descendant_or_self
193
- parsed << :node
194
- path = path[2..-1]
195
- else
196
- path = path[1..-1]
197
- end
198
- end
199
- return RelativeLocationPath( path, parsed ) if path.size > 0
200
- end
201
-
202
- #RelativeLocationPath
203
- # | Step
204
- # | (AXIS_NAME '::' | '@' | '') AxisSpecifier
205
- # NodeTest
206
- # Predicate
207
- # | '.' | '..' AbbreviatedStep
208
- # | RelativeLocationPath '/' Step
209
- # | RelativeLocationPath '//' Step
210
- AXIS = /^(ancestor|ancestor-or-self|attribute|child|descendant|descendant-or-self|following|following-sibling|namespace|parent|preceding|preceding-sibling|self)::/
211
- def RelativeLocationPath path, parsed
212
- loop do
213
- original_path = path
214
- path = path.lstrip
215
-
216
- return original_path if path.empty?
217
-
218
- # (axis or @ or <child::>) nodetest predicate >
219
- # OR > / Step
220
- # (. or ..) >
221
- if path[0] == ?.
222
- if path[1] == ?.
223
- parsed << :parent
224
- parsed << :node
225
- path = path[2..-1]
226
- else
227
- parsed << :self
228
- parsed << :node
229
- path = path[1..-1]
230
- end
231
- else
232
- if path[0] == ?@
233
- parsed << :attribute
234
- path = path[1..-1]
235
- # Goto Nodetest
236
- elsif path =~ AXIS
237
- parsed << $1.tr('-','_').intern
238
- path = $'
239
- # Goto Nodetest
240
- else
241
- parsed << :child
242
- end
243
-
244
- n = []
245
- path = NodeTest( path, n)
246
-
247
- path = Predicate( path, n )
248
-
249
- parsed.concat(n)
250
- end
251
-
252
- original_path = path
253
- path = path.lstrip
254
- return original_path if path.empty?
255
-
256
- return original_path if path[0] != ?/
257
-
258
- if path[1] == ?/
259
- parsed << :descendant_or_self
260
- parsed << :node
261
- path = path[2..-1]
262
- else
263
- path = path[1..-1]
264
- end
265
- end
266
- end
267
-
268
- # Returns a 1-1 map of the nodeset
269
- # The contents of the resulting array are either:
270
- # true/false, if a positive match
271
- # String, if a name match
272
- #NodeTest
273
- # | ('*' | NCNAME ':' '*' | QNAME) NameTest
274
- # | '*' ':' NCNAME NameTest since XPath 2.0
275
- # | NODE_TYPE '(' ')' NodeType
276
- # | PI '(' LITERAL ')' PI
277
- # | '[' expr ']' Predicate
278
- PREFIX_WILDCARD = /^\*:(#{NCNAME_STR})/u
279
- LOCAL_NAME_WILDCARD = /^(#{NCNAME_STR}):\*/u
280
- QNAME = Namespace::NAMESPLIT
281
- NODE_TYPE = /^(comment|text|node)\(\s*\)/m
282
- PI = /^processing-instruction\(/
283
- def NodeTest path, parsed
284
- original_path = path
285
- path = path.lstrip
286
- case path
287
- when PREFIX_WILDCARD
288
- prefix = nil
289
- name = $1
290
- path = $'
291
- parsed << :qname
292
- parsed << prefix
293
- parsed << name
294
- when /^\*/
295
- path = $'
296
- parsed << :any
297
- when NODE_TYPE
298
- type = $1
299
- path = $'
300
- parsed << type.tr('-', '_').intern
301
- when PI
302
- path = $'
303
- literal = nil
304
- if path !~ /^\s*\)/
305
- path =~ LITERAL
306
- literal = $1
307
- path = $'
308
- raise ParseException.new("Missing ')' after processing instruction") if path[0] != ?)
309
- path = path[1..-1]
310
- end
311
- parsed << :processing_instruction
312
- parsed << (literal || '')
313
- when LOCAL_NAME_WILDCARD
314
- prefix = $1
315
- path = $'
316
- parsed << :namespace
317
- parsed << prefix
318
- when QNAME
319
- prefix = $1
320
- name = $2
321
- path = $'
322
- prefix = "" unless prefix
323
- parsed << :qname
324
- parsed << prefix
325
- parsed << name
326
- else
327
- path = original_path
328
- end
329
- return path
330
- end
331
-
332
- # Filters the supplied nodeset on the predicate(s)
333
- def Predicate path, parsed
334
- original_path = path
335
- path = path.lstrip
336
- return original_path unless path[0] == ?[
337
- predicates = []
338
- while path[0] == ?[
339
- path, expr = get_group(path)
340
- predicates << expr[1..-2] if expr
341
- end
342
- predicates.each{ |pred|
343
- preds = []
344
- parsed << :predicate
345
- parsed << preds
346
- OrExpr(pred, preds)
347
- }
348
- path
349
- end
350
-
351
- # The following return arrays of true/false, a 1-1 mapping of the
352
- # supplied nodeset, except for axe(), which returns a filtered
353
- # nodeset
354
-
355
- #| OrExpr S 'or' S AndExpr
356
- #| AndExpr
357
- def OrExpr path, parsed
358
- n = []
359
- rest = AndExpr( path, n )
360
- if rest != path
361
- while rest =~ /^\s*( or )/
362
- n = [ :or, n, [] ]
363
- rest = AndExpr( $', n[-1] )
364
- end
365
- end
366
- if parsed.size == 0 and n.size != 0
367
- parsed.replace(n)
368
- elsif n.size > 0
369
- parsed << n
370
- end
371
- rest
372
- end
373
-
374
- #| AndExpr S 'and' S EqualityExpr
375
- #| EqualityExpr
376
- def AndExpr path, parsed
377
- n = []
378
- rest = EqualityExpr( path, n )
379
- if rest != path
380
- while rest =~ /^\s*( and )/
381
- n = [ :and, n, [] ]
382
- rest = EqualityExpr( $', n[-1] )
383
- end
384
- end
385
- if parsed.size == 0 and n.size != 0
386
- parsed.replace(n)
387
- elsif n.size > 0
388
- parsed << n
389
- end
390
- rest
391
- end
392
-
393
- #| EqualityExpr ('=' | '!=') RelationalExpr
394
- #| RelationalExpr
395
- def EqualityExpr path, parsed
396
- n = []
397
- rest = RelationalExpr( path, n )
398
- if rest != path
399
- while rest =~ /^\s*(!?=)\s*/
400
- if $1[0] == ?!
401
- n = [ :neq, n, [] ]
402
- else
403
- n = [ :eq, n, [] ]
404
- end
405
- rest = RelationalExpr( $', n[-1] )
406
- end
407
- end
408
- if parsed.size == 0 and n.size != 0
409
- parsed.replace(n)
410
- elsif n.size > 0
411
- parsed << n
412
- end
413
- rest
414
- end
415
-
416
- #| RelationalExpr ('<' | '>' | '<=' | '>=') AdditiveExpr
417
- #| AdditiveExpr
418
- def RelationalExpr path, parsed
419
- n = []
420
- rest = AdditiveExpr( path, n )
421
- if rest != path
422
- while rest =~ /^\s*([<>]=?)\s*/
423
- if $1[0] == ?<
424
- sym = "lt"
425
- else
426
- sym = "gt"
427
- end
428
- sym << "eq" if $1[-1] == ?=
429
- n = [ sym.intern, n, [] ]
430
- rest = AdditiveExpr( $', n[-1] )
431
- end
432
- end
433
- if parsed.size == 0 and n.size != 0
434
- parsed.replace(n)
435
- elsif n.size > 0
436
- parsed << n
437
- end
438
- rest
439
- end
440
-
441
- #| AdditiveExpr ('+' | '-') MultiplicativeExpr
442
- #| MultiplicativeExpr
443
- def AdditiveExpr path, parsed
444
- n = []
445
- rest = MultiplicativeExpr( path, n )
446
- if rest != path
447
- while rest =~ /^\s*(\+|-)\s*/
448
- if $1[0] == ?+
449
- n = [ :plus, n, [] ]
450
- else
451
- n = [ :minus, n, [] ]
452
- end
453
- rest = MultiplicativeExpr( $', n[-1] )
454
- end
455
- end
456
- if parsed.size == 0 and n.size != 0
457
- parsed.replace(n)
458
- elsif n.size > 0
459
- parsed << n
460
- end
461
- rest
462
- end
463
-
464
- #| MultiplicativeExpr ('*' | S ('div' | 'mod') S) UnaryExpr
465
- #| UnaryExpr
466
- def MultiplicativeExpr path, parsed
467
- n = []
468
- rest = UnaryExpr( path, n )
469
- if rest != path
470
- while rest =~ /^\s*(\*| div | mod )\s*/
471
- if $1[0] == ?*
472
- n = [ :mult, n, [] ]
473
- elsif $1.include?( "div" )
474
- n = [ :div, n, [] ]
475
- else
476
- n = [ :mod, n, [] ]
477
- end
478
- rest = UnaryExpr( $', n[-1] )
479
- end
480
- end
481
- if parsed.size == 0 and n.size != 0
482
- parsed.replace(n)
483
- elsif n.size > 0
484
- parsed << n
485
- end
486
- rest
487
- end
488
-
489
- #| '-' UnaryExpr
490
- #| UnionExpr
491
- def UnaryExpr path, parsed
492
- path =~ /^(\-*)/
493
- path = $'
494
- if $1 and (($1.size % 2) != 0)
495
- mult = -1
496
- else
497
- mult = 1
498
- end
499
- parsed << :neg if mult < 0
500
-
501
- n = []
502
- path = UnionExpr( path, n )
503
- parsed.concat( n )
504
- path
505
- end
506
-
507
- #| UnionExpr '|' PathExpr
508
- #| PathExpr
509
- def UnionExpr path, parsed
510
- n = []
511
- rest = PathExpr( path, n )
512
- if rest != path
513
- while rest =~ /^\s*(\|)\s*/
514
- n = [ :union, n, [] ]
515
- rest = PathExpr( $', n[-1] )
516
- end
517
- end
518
- if parsed.size == 0 and n.size != 0
519
- parsed.replace( n )
520
- elsif n.size > 0
521
- parsed << n
522
- end
523
- rest
524
- end
525
-
526
- #| LocationPath
527
- #| FilterExpr ('/' | '//') RelativeLocationPath
528
- def PathExpr path, parsed
529
- path = path.lstrip
530
- n = []
531
- rest = FilterExpr( path, n )
532
- if rest != path
533
- if rest and rest[0] == ?/
534
- rest = RelativeLocationPath(rest, n)
535
- parsed.concat(n)
536
- return rest
537
- end
538
- end
539
- rest = LocationPath(rest, n) if rest =~ /\A[\/\.\@\[\w*]/
540
- parsed.concat(n)
541
- return rest
542
- end
543
-
544
- #| FilterExpr Predicate
545
- #| PrimaryExpr
546
- def FilterExpr path, parsed
547
- n = []
548
- path = PrimaryExpr( path, n )
549
- path = Predicate(path, n)
550
- parsed.concat(n)
551
- path
552
- end
553
-
554
- #| VARIABLE_REFERENCE
555
- #| '(' expr ')'
556
- #| LITERAL
557
- #| NUMBER
558
- #| FunctionCall
559
- VARIABLE_REFERENCE = /^\$(#{NAME_STR})/u
560
- NUMBER = /^(\d*\.?\d+)/
561
- NT = /^comment|text|processing-instruction|node$/
562
- def PrimaryExpr path, parsed
563
- case path
564
- when VARIABLE_REFERENCE
565
- varname = $1
566
- path = $'
567
- parsed << :variable
568
- parsed << varname
569
- #arry << @variables[ varname ]
570
- when /^(\w[-\w]*)(?:\()/
571
- fname = $1
572
- tmp = $'
573
- return path if fname =~ NT
574
- path = tmp
575
- parsed << :function
576
- parsed << fname
577
- path = FunctionCall(path, parsed)
578
- when NUMBER
579
- varname = $1.nil? ? $2 : $1
580
- path = $'
581
- parsed << :literal
582
- parsed << (varname.include?('.') ? varname.to_f : varname.to_i)
583
- when LITERAL
584
- varname = $1.nil? ? $2 : $1
585
- path = $'
586
- parsed << :literal
587
- parsed << varname
588
- when /^\(/ #/
589
- path, contents = get_group(path)
590
- contents = contents[1..-2]
591
- n = []
592
- OrExpr( contents, n )
593
- parsed.concat(n)
594
- end
595
- path
596
- end
597
-
598
- #| FUNCTION_NAME '(' ( expr ( ',' expr )* )? ')'
599
- def FunctionCall rest, parsed
600
- path, arguments = parse_args(rest)
601
- argset = []
602
- for argument in arguments
603
- args = []
604
- OrExpr( argument, args )
605
- argset << args
606
- end
607
- parsed << argset
608
- path
609
- end
610
-
611
- # get_group( '[foo]bar' ) -> ['bar', '[foo]']
612
- def get_group string
613
- ind = 0
614
- depth = 0
615
- st = string[0,1]
616
- en = (st == "(" ? ")" : "]")
617
- begin
618
- case string[ind,1]
619
- when st
620
- depth += 1
621
- when en
622
- depth -= 1
623
- end
624
- ind += 1
625
- end while depth > 0 and ind < string.length
626
- return nil unless depth==0
627
- [string[ind..-1], string[0..ind-1]]
628
- end
629
-
630
- def parse_args( string )
631
- arguments = []
632
- ind = 0
633
- inquot = false
634
- inapos = false
635
- depth = 1
636
- begin
637
- case string[ind]
638
- when ?"
639
- inquot = !inquot unless inapos
640
- when ?'
641
- inapos = !inapos unless inquot
642
- else
643
- unless inquot or inapos
644
- case string[ind]
645
- when ?(
646
- depth += 1
647
- if depth == 1
648
- string = string[1..-1]
649
- ind -= 1
650
- end
651
- when ?)
652
- depth -= 1
653
- if depth == 0
654
- s = string[0,ind].strip
655
- arguments << s unless s == ""
656
- string = string[ind+1..-1]
657
- end
658
- when ?,
659
- if depth == 1
660
- s = string[0,ind].strip
661
- arguments << s unless s == ""
662
- string = string[ind+1..-1]
663
- ind = -1
664
- end
665
- end
666
- end
667
- end
668
- ind += 1
669
- end while depth > 0 and ind < string.length
670
- return nil unless depth==0
671
- [string,arguments]
672
- end
673
- end
674
- end
675
- end