brakeman 4.10.0 → 4.10.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES.md +8 -0
  3. data/bundle/load.rb +2 -1
  4. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/CHANGELOG.md +16 -0
  5. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/FAQ.md +0 -0
  6. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/Gemfile +1 -4
  7. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/MIT-LICENSE +0 -0
  8. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/README.md +2 -3
  9. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/REFERENCE.md +29 -7
  10. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/TODO +0 -0
  11. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/haml.gemspec +2 -1
  12. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml.rb +0 -0
  13. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_builder.rb +3 -3
  14. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_compiler.rb +42 -31
  15. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/attribute_parser.rb +0 -0
  16. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/buffer.rb +0 -0
  17. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/compiler.rb +0 -0
  18. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/engine.rb +0 -0
  19. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/error.rb +0 -0
  20. data/bundle/ruby/2.7.0/gems/haml-5.2.1/lib/haml/escapable.rb +77 -0
  21. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/exec.rb +0 -0
  22. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/filters.rb +0 -0
  23. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/generator.rb +0 -0
  24. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers.rb +7 -1
  25. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_extensions.rb +0 -0
  26. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_mods.rb +0 -0
  27. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/action_view_xss_mods.rb +0 -0
  28. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/safe_erubi_template.rb +0 -0
  29. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/safe_erubis_template.rb +0 -0
  30. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/helpers/xss_mods.rb +6 -3
  31. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/options.rb +0 -0
  32. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/parser.rb +32 -4
  33. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/plugin.rb +0 -0
  34. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/railtie.rb +0 -0
  35. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/sass_rails_filter.rb +0 -0
  36. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/template.rb +0 -0
  37. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/template/options.rb +0 -0
  38. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/temple_engine.rb +0 -0
  39. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/temple_line_counter.rb +0 -0
  40. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/util.rb +1 -1
  41. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/lib/haml/version.rb +1 -1
  42. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/yard/default/fulldoc/html/css/common.sass +0 -0
  43. data/bundle/ruby/2.7.0/gems/{haml-5.1.2 → haml-5.2.1}/yard/default/layout/html/footer.erb +0 -0
  44. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/Gemfile +6 -0
  45. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/LICENSE.txt +22 -0
  46. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/NEWS.md +141 -0
  47. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/README.md +60 -0
  48. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attlistdecl.rb +63 -0
  49. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/attribute.rb +205 -0
  50. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/cdata.rb +68 -0
  51. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/child.rb +97 -0
  52. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/comment.rb +80 -0
  53. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/doctype.rb +287 -0
  54. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/document.rb +291 -0
  55. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/attlistdecl.rb +11 -0
  56. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/dtd.rb +47 -0
  57. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/elementdecl.rb +18 -0
  58. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/entitydecl.rb +57 -0
  59. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/dtd/notationdecl.rb +40 -0
  60. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/element.rb +1269 -0
  61. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/encoding.rb +51 -0
  62. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/entity.rb +171 -0
  63. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/default.rb +116 -0
  64. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/pretty.rb +142 -0
  65. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/formatters/transitive.rb +58 -0
  66. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/functions.rb +447 -0
  67. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/instruction.rb +79 -0
  68. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/light/node.rb +196 -0
  69. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/namespace.rb +59 -0
  70. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/node.rb +76 -0
  71. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/output.rb +30 -0
  72. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parent.rb +166 -0
  73. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parseexception.rb +52 -0
  74. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/baseparser.rb +594 -0
  75. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/lightparser.rb +59 -0
  76. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/pullparser.rb +197 -0
  77. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/sax2parser.rb +273 -0
  78. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/streamparser.rb +61 -0
  79. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/treeparser.rb +101 -0
  80. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/ultralightparser.rb +57 -0
  81. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/parsers/xpathparser.rb +675 -0
  82. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/quickpath.rb +266 -0
  83. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/rexml.rb +32 -0
  84. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/sax2listener.rb +98 -0
  85. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/security.rb +28 -0
  86. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/source.rb +298 -0
  87. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/streamlistener.rb +93 -0
  88. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/text.rb +424 -0
  89. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/undefinednamespaceexception.rb +9 -0
  90. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/relaxng.rb +539 -0
  91. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validation.rb +144 -0
  92. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/validation/validationexception.rb +10 -0
  93. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmldecl.rb +130 -0
  94. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xmltokens.rb +85 -0
  95. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath.rb +81 -0
  96. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/lib/rexml/xpath_parser.rb +968 -0
  97. data/bundle/ruby/2.7.0/gems/rexml-3.2.4/rexml.gemspec +84 -0
  98. data/lib/brakeman/checks/check_execute.rb +1 -1
  99. data/lib/brakeman/checks/check_regex_dos.rb +1 -1
  100. data/lib/brakeman/file_parser.rb +5 -0
  101. data/lib/brakeman/processors/alias_processor.rb +2 -2
  102. data/lib/brakeman/processors/controller_processor.rb +1 -1
  103. data/lib/brakeman/processors/haml_template_processor.rb +8 -1
  104. data/lib/brakeman/processors/output_processor.rb +1 -1
  105. data/lib/brakeman/processors/template_alias_processor.rb +5 -0
  106. data/lib/brakeman/tracker/controller.rb +1 -1
  107. data/lib/brakeman/util.rb +2 -2
  108. data/lib/brakeman/version.rb +1 -1
  109. data/lib/ruby_parser/bm_sexp.rb +9 -9
  110. metadata +96 -42
  111. data/bundle/ruby/2.7.0/gems/haml-5.1.2/lib/haml/escapable.rb +0 -50
@@ -0,0 +1,61 @@
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
@@ -0,0 +1,101 @@
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
@@ -0,0 +1,57 @@
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
@@ -0,0 +1,675 @@
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