synvert-core 1.4.0 → 1.5.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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +0 -3
  5. data/Guardfile +0 -9
  6. data/README.md +30 -12
  7. data/Rakefile +1 -15
  8. data/lib/synvert/core/engine/erb.rb +1 -1
  9. data/lib/synvert/core/engine.rb +1 -1
  10. data/lib/synvert/core/node_ext.rb +0 -466
  11. data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
  12. data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -1
  13. data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -1
  14. data/lib/synvert/core/rewriter/instance.rb +83 -133
  15. data/lib/synvert/core/rewriter/scope/query_scope.rb +2 -2
  16. data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -4
  17. data/lib/synvert/core/rewriter.rb +0 -10
  18. data/lib/synvert/core/version.rb +1 -1
  19. data/lib/synvert/core.rb +4 -6
  20. data/spec/synvert/core/engine/erb_spec.rb +3 -3
  21. data/spec/synvert/core/node_ext_spec.rb +0 -795
  22. data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
  23. data/spec/synvert/core/rewriter/instance_spec.rb +47 -115
  24. data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
  25. data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -4
  26. data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +1 -4
  27. data/synvert-core-ruby.gemspec +4 -2
  28. metadata +44 -61
  29. data/lib/synvert/core/array_ext.rb +0 -48
  30. data/lib/synvert/core/node_query/compiler/array.rb +0 -34
  31. data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
  32. data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
  33. data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
  34. data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
  35. data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
  36. data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
  37. data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
  38. data/lib/synvert/core/node_query/compiler/float.rb +0 -23
  39. data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
  40. data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
  41. data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
  42. data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
  43. data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
  44. data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
  45. data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
  46. data/lib/synvert/core/node_query/compiler/string.rb +0 -23
  47. data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
  48. data/lib/synvert/core/node_query/compiler.rb +0 -25
  49. data/lib/synvert/core/node_query/lexer.rex +0 -99
  50. data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
  51. data/lib/synvert/core/node_query/parser.racc.rb +0 -306
  52. data/lib/synvert/core/node_query/parser.y +0 -60
  53. data/lib/synvert/core/node_query.rb +0 -36
  54. data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
  55. data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
  56. data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
  57. data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
  58. data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
  59. data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
  60. data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
  61. data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
  62. data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
  63. data/lib/synvert/core/rewriter/action.rb +0 -102
  64. data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
  65. data/spec/synvert/core/node_query/parser_spec.rb +0 -337
  66. data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
  67. data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
  68. data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
  69. data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
  70. data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
  71. data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
  72. data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
  73. data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
  74. data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
  75. data/spec/synvert/core/rewriter/action_spec.rb +0 -14
@@ -1,86 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Compare acutal value with expected value.
5
- module Comparable
6
- SIMPLE_VALID_OPERATORS = ['==', '!=', 'includes']
7
- STRING_VALID_OPERATORS = ['==', '!=', '^=', '$=', '*=', 'includes']
8
- NUMBER_VALID_OPERATORS = ['==', '!=', '>', '>=', '<', '<=', 'includes']
9
- ARRAY_VALID_OPERATORS = ['==', '!=', 'in', 'not_in']
10
- REGEXP_VALID_OPERATORS = ['=~', '!~']
11
-
12
- # Check if the actual value matches the expected value.
13
- #
14
- # @param node [Parser::AST::Node] node to calculate actual value
15
- # @param operator [Symbol] operator to compare with expected value, operator can be <code>'=='</code>, <code>'!='</code>, <code>'>'</code>, <code>'>='</code>, <code>'<'</code>, <code>'<='</code>, <code>'includes'</code>, <code>'in'</code>, <code>'not_in'</code>, <code>'=~'</code>, <code>'!~'</code>
16
- # @return [Boolean] true if actual value matches the expected value
17
- # @raise [Synvert::Core::NodeQuery::Compiler::InvalidOperatorError] if operator is invalid
18
- def match?(node, operator)
19
- raise InvalidOperatorError, "invalid operator #{operator}" unless valid_operator?(operator)
20
-
21
- case operator
22
- when '!='
23
- if expected_value.is_a?(::Array)
24
- actual = actual_value(node)
25
- !actual.is_a?(::Array) || actual.size != expected_value.size ||
26
- actual.zip(expected_value).any? { |actual_node, expected_node| expected_node.match?(actual_node, '!=') }
27
- else
28
- actual_value(node) != expected_value
29
- end
30
- when '=~'
31
- actual_value(node) =~ expected_value
32
- when '!~'
33
- actual_value(node) !~ expected_value
34
- when '^='
35
- actual_value(node).start_with?(expected_value)
36
- when '$='
37
- actual_value(node).end_with?(expected_value)
38
- when '*='
39
- actual_value(node).include?(expected_value)
40
- when '>'
41
- actual_value(node) > expected_value
42
- when '>='
43
- actual_value(node) >= expected_value
44
- when '<'
45
- actual_value(node) < expected_value
46
- when '<='
47
- actual_value(node) <= expected_value
48
- when 'in'
49
- expected_value.any? { |expected| expected.match?(node, '==') }
50
- when 'not_in'
51
- expected_value.all? { |expected| expected.match?(node, '!=') }
52
- when 'includes'
53
- actual_value(node).any? { |actual| actual == expected_value }
54
- else
55
- if expected_value.is_a?(::Array)
56
- actual = actual_value(node)
57
- actual.is_a?(::Array) && actual.size == expected_value.size &&
58
- actual.zip(expected_value).all? { |actual_node, expected_node| expected_node.match?(actual_node, '==') }
59
- else
60
- actual_value(node) == expected_value
61
- end
62
- end
63
- end
64
-
65
- # Get the actual value from ast node.
66
- # @return if node is a {Parser::AST::Node}, return the node value, otherwise, return the node itself.
67
- def actual_value(node)
68
- if node.is_a?(::Parser::AST::Node)
69
- node.to_value
70
- else
71
- node
72
- end
73
- end
74
-
75
- # Get the expected value
76
- def expected_value
77
- @value
78
- end
79
-
80
- # Check if the operator is valid.
81
- # @return [Boolean] true if the operator is valid
82
- def valid_operator?(operator)
83
- valid_operators.include?(operator)
84
- end
85
- end
86
- end
@@ -1,51 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # DynamicAttribute represents a ruby dynamic attribute.
5
- # e.g. code is <code>{ a: a }</code>, query is <code>'.hash > .pair[key={{value}}]'</code>,
6
- # <code>{{value}}</code> is the dynamic attribute.
7
- class DynamicAttribute
8
- include Comparable
9
-
10
- attr_accessor :base_node
11
-
12
- # Initialize a DynamicAttribute.
13
- # @param value [String] the dynamic attribute value
14
- def initialize(value:)
15
- @value = value
16
- end
17
-
18
- # Get the actual value of a node.
19
- #
20
- # @param node the node
21
- # @return [String] if node is a {Parser::AST::Node}, return the node source code, otherwise return the node itself.
22
- def actual_value(node)
23
- if node.is_a?(::Parser::AST::Node)
24
- node.to_source
25
- else
26
- node
27
- end
28
- end
29
-
30
- # Get the expected value.
31
- #
32
- # @return [String] Query the node by @valud from base_node, if the node is a {Parser::AST::Node}, return the node source code, otherwise return the node itself.
33
- def expected_value
34
- node = base_node.child_node_by_name(@value)
35
- if node.is_a?(::Parser::AST::Node)
36
- node.to_source
37
- else
38
- node
39
- end
40
- end
41
-
42
- # Get valid operators.
43
- def valid_operators
44
- SIMPLE_VALID_OPERATORS
45
- end
46
-
47
- def to_s
48
- "{{#{@value}}}"
49
- end
50
- end
51
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Expression represents a node query expression.
5
- class Expression
6
- # Initialize a Expression.
7
- # @param selector [Synvert::Core::NodeQuery::Compiler::Selector] the selector
8
- # @param rest [Synvert::Core::NodeQuery::Compiler::Expression] the rest expression
9
- def initialize(selector: nil, rest: nil)
10
- @selector = selector
11
- @rest = rest
12
- end
13
-
14
- # Check if the node matches the expression.
15
- # @param node [Parser::AST::Node] the node
16
- # @return [Boolean]
17
- def match?(node)
18
- !query_nodes(node).empty?
19
- end
20
-
21
- # Query nodes by the selector and the rest expression.
22
- #
23
- # @param node [Parser::AST::Node] node to match
24
- # @return [Array<Parser::AST::Node>] matching nodes.
25
- def query_nodes(node)
26
- matching_nodes = @selector.query_nodes(node)
27
- return matching_nodes if @rest.nil?
28
-
29
- matching_nodes.flat_map do |matching_node|
30
- @rest.query_nodes(matching_node)
31
- end
32
- end
33
-
34
- def to_s
35
- result = []
36
- result << @selector.to_s if @selector
37
- result << @rest.to_s if @rest
38
- result.join(' ')
39
- end
40
- end
41
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Float represents a ruby float value.
5
- class Float
6
- include Comparable
7
-
8
- # Initialize a Float.
9
- # @param value [Float] the float value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Get valid operators.
15
- def valid_operators
16
- NUMBER_VALID_OPERATORS
17
- end
18
-
19
- def to_s
20
- @value.to_s
21
- end
22
- end
23
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Identifier represents a ruby identifier value.
5
- # e.g. code is `class Synvert; end`, `Synvert` is an identifier.
6
- class Identifier
7
- include Comparable
8
-
9
- # Initialize an Identifier.
10
- # @param value [String] the identifier value
11
- def initialize(value:)
12
- @value = value
13
- end
14
-
15
- # Get the actual value.
16
- #
17
- # @param node the node
18
- # @return [String|Array]
19
- # If the node is a {Parser::AST::Node}, return the node source code,
20
- # if the node is an Array, return the array of each element's actual value,
21
- # otherwise, return the String value.
22
- def actual_value(node)
23
- if node.is_a?(::Parser::AST::Node)
24
- node.to_source
25
- elsif node.is_a?(::Array)
26
- node.map { |n| actual_value(n) }
27
- else
28
- node.to_s
29
- end
30
- end
31
-
32
- # Get valid operators.
33
- def valid_operators
34
- STRING_VALID_OPERATORS
35
- end
36
-
37
- def to_s
38
- @value
39
- end
40
- end
41
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Integer represents a ruby integer value.
5
- class Integer
6
- include Comparable
7
-
8
- # Initialize a Integer.
9
- # @param value [Integer] the integer value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Get valid operators.
15
- def valid_operators
16
- NUMBER_VALID_OPERATORS
17
- end
18
-
19
- def to_s
20
- @value.to_s
21
- end
22
- end
23
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Operator is invalid error.
5
- class InvalidOperatorError < StandardError
6
- end
7
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Nil represents a ruby nil value.
5
- class Nil
6
- include Comparable
7
-
8
- # Initialize a Nil.
9
- # @param value [nil] the nil value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Get valid operators.
15
- def valid_operators
16
- SIMPLE_VALID_OPERATORS
17
- end
18
-
19
- def to_s
20
- 'nil'
21
- end
22
- end
23
- end
@@ -1,7 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # The parser error.
5
- class ParseError < StandardError
6
- end
7
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Regexp represents a ruby regexp value.
5
- class Regexp
6
- include Comparable
7
-
8
- # Initialize a Regexp.
9
- # @param value [Regexp] the regexp value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Check if the regexp value matches the node value.
15
- # @param node [Parser::AST::Node] the node
16
- # @param operator [Symbol] the operator
17
- # @return [Boolean] true if the regexp value matches the node value, otherwise, false.
18
- def match?(node, operator = '=~')
19
- match =
20
- if node.is_a?(::Parser::AST::Node)
21
- @value.match(node.to_source)
22
- else
23
- @value.match(node.to_s)
24
- end
25
- operator == '=~' ? match : !match
26
- end
27
-
28
- # Get valid operators.
29
- def valid_operators
30
- REGEXP_VALID_OPERATORS
31
- end
32
-
33
- def to_s
34
- @value.to_s
35
- end
36
- end
37
- end
@@ -1,113 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Selector used to match nodes, it combines by node type and/or attribute list, plus index or has expression.
5
- class Selector
6
- # Initialize a Selector.
7
- # @param goto_scope [String] goto scope
8
- # @param relationship [Symbol] the relationship between the selectors, it can be descendant <code>nil</code>, child <code>></code>, next sibling <code>+</code> or subsequent sibing <code>~</code>.
9
- # @param rest [Synvert::Core::NodeQuery::Compiler::Selector] the rest selector
10
- # @param basic_selector [Synvert::Core::NodeQuery::Compiler::BasicSelector] the simple selector
11
- # @param attribute_list [Synvert::Core::NodeQuery::Compiler::AttributeList] the attribute list
12
- # @param pseudo_class [String] the pseudo class, can be <code>has</code> or <code>not_has</code>
13
- # @param pseudo_selector [Synvert::Core::NodeQuery::Compiler::Expression] the pseudo selector
14
- def initialize(goto_scope: nil, relationship: nil, rest: nil, basic_selector: nil, pseudo_class: nil, pseudo_selector: nil)
15
- @goto_scope = goto_scope
16
- @relationship = relationship
17
- @rest = rest
18
- @basic_selector = basic_selector
19
- @pseudo_class = pseudo_class
20
- @pseudo_selector = pseudo_selector
21
- end
22
-
23
- # Check if node matches the selector.
24
- # @param node [Parser::AST::Node] the node
25
- def match?(node)
26
- node.is_a?(::Parser::AST::Node) && (!@basic_selector || @basic_selector.match?(node)) && match_pseudo_class?(node)
27
- end
28
-
29
- # Query nodes by the selector.
30
- #
31
- # * If relationship is nil, it will match in all recursive child nodes and return matching nodes.
32
- # * If relationship is decendant, it will match in all recursive child nodes.
33
- # * If relationship is child, it will match in direct child nodes.
34
- # * If relationship is next sibling, it try to match next sibling node.
35
- # * If relationship is subsequent sibling, it will match in all sibling nodes.
36
- # @param node [Parser::AST::Node] node to match
37
- # @return [Array<Parser::AST::Node>] matching nodes.
38
- def query_nodes(node)
39
- return find_nodes_by_relationship(node) if @relationship
40
-
41
- if node.is_a?(::Array)
42
- return node.flat_map { |child_node| query_nodes(child_node) }
43
- end
44
-
45
- return find_nodes_by_goto_scope(node) if @goto_scope
46
-
47
- nodes = []
48
- nodes << node if match?(node)
49
- if @basic_selector
50
- node.recursive_children do |child_node|
51
- nodes << child_node if match?(child_node)
52
- end
53
- end
54
- nodes
55
- end
56
-
57
- def to_s
58
- result = []
59
- result << "#{@goto_scope} " if @goto_scope
60
- result << "#{@relationship} " if @relationship
61
- result << @rest.to_s if @rest
62
- result << @basic_selector.to_s if @basic_selector
63
- result << ":#{@pseudo_class}(#{@pseudo_selector})" if @pseudo_class
64
- result.join('')
65
- end
66
-
67
- private
68
-
69
- # Find nodes by @goto_scope
70
- # @param node [Parser::AST::Node] node to match
71
- def find_nodes_by_goto_scope(node)
72
- @goto_scope.split('.').each { |scope| node = node.send(scope) }
73
- @rest.query_nodes(node)
74
- end
75
-
76
- # Find ndoes by @relationship
77
- # @param node [Parser::AST::Node] node to match
78
- def find_nodes_by_relationship(node)
79
- nodes = []
80
- case @relationship
81
- when '>'
82
- if node.is_a?(::Array)
83
- node.each do |child_node|
84
- nodes << child_node if @rest.match?(child_node)
85
- end
86
- else
87
- node.children.each do |child_node|
88
- nodes << child_node if @rest.match?(child_node)
89
- end
90
- end
91
- when '+'
92
- next_sibling = node.siblings.first
93
- nodes << next_sibling if @rest.match?(next_sibling)
94
- when '~'
95
- node.siblings.each do |sibling_node|
96
- nodes << sibling_node if @rest.match?(sibling_node)
97
- end
98
- end
99
- nodes
100
- end
101
-
102
- def match_pseudo_class?(node)
103
- case @pseudo_class
104
- when 'has'
105
- !@pseudo_selector.query_nodes(node).empty?
106
- when 'not_has'
107
- @pseudo_selector.query_nodes(node).empty?
108
- else
109
- true
110
- end
111
- end
112
- end
113
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # String represents a ruby string value.
5
- class String
6
- include Comparable
7
-
8
- # Initialize a String.
9
- # @param value [String] the string value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Get valid operators.
15
- def valid_operators
16
- STRING_VALID_OPERATORS
17
- end
18
-
19
- def to_s
20
- "\"#{@value}\""
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- # Symbol represents a ruby symbol value.
5
- class Symbol
6
- include Comparable
7
-
8
- # Initliaze a Symobol.
9
- # @param value [Symbol] the symbol value
10
- def initialize(value:)
11
- @value = value
12
- end
13
-
14
- # Get valid operators.
15
- def valid_operators
16
- SIMPLE_VALID_OPERATORS
17
- end
18
-
19
- def to_s
20
- ":#{@value}"
21
- end
22
- end
23
- end
@@ -1,25 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core::NodeQuery::Compiler
4
- autoload :InvalidOperatorError, 'synvert/core/node_query/compiler/invalid_operator_error'
5
- autoload :ParseError, 'synvert/core/node_query/compiler/parse_error'
6
-
7
- autoload :Comparable, 'synvert/core/node_query/compiler/comparable'
8
-
9
- autoload :Expression, 'synvert/core/node_query/compiler/expression'
10
- autoload :Selector, 'synvert/core/node_query/compiler/selector'
11
- autoload :BasicSelector, 'synvert/core/node_query/compiler/basic_selector'
12
- autoload :AttributeList, 'synvert/core/node_query/compiler/attribute_list'
13
- autoload :Attribute, 'synvert/core/node_query/compiler/attribute'
14
-
15
- autoload :Array, 'synvert/core/node_query/compiler/array'
16
- autoload :Boolean, 'synvert/core/node_query/compiler/boolean'
17
- autoload :DynamicAttribute, 'synvert/core/node_query/compiler/dynamic_attribute'
18
- autoload :Float, 'synvert/core/node_query/compiler/float'
19
- autoload :Identifier, 'synvert/core/node_query/compiler/identifier'
20
- autoload :Integer, 'synvert/core/node_query/compiler/integer'
21
- autoload :Nil, 'synvert/core/node_query/compiler/nil'
22
- autoload :Regexp, 'synvert/core/node_query/compiler/regexp'
23
- autoload :String, 'synvert/core/node_query/compiler/string'
24
- autoload :Symbol, 'synvert/core/node_query/compiler/symbol'
25
- end
@@ -1,99 +0,0 @@
1
- class Synvert::Core::NodeQuery::Lexer
2
-
3
- macros
4
- OPEN_ATTRIBUTE /\[/
5
- CLOSE_ATTRIBUTE /\]/
6
- OPEN_ARRAY /\(/
7
- CLOSE_ARRAY /\)/
8
- OPEN_SELECTOR /\(/
9
- CLOSE_SELECTOR /\)/
10
- OPEN_DYNAMIC_ATTRIBUTE /{{/
11
- CLOSE_DYNAMIC_ATTRIBUTE /}}/
12
- NODE_TYPE /\.[a-z]+/
13
- IDENTIFIER /[\.\w]+/
14
- IDENTIFIER_VALUE /[\.\w!&:\?<>=]+/
15
- FALSE /false/
16
- FLOAT /\d+\.\d+/
17
- INTEGER /\d+/
18
- NIL /nil/
19
- REGEXP_BODY /(?:[^\/]|\\\/)*/
20
- REGEXP /\/(#{REGEXP_BODY})(?<!\\)\/([imxo]*)/
21
- SYMBOL /:[\w!\?<>=]+/
22
- TRUE /true/
23
- SINGLE_QUOTE_STRING /'.*?'/
24
- DOUBLE_QUOTE_STRING /".*?"/
25
-
26
- rules
27
-
28
- # [:state] pattern [actions]
29
- /\s+/
30
- /:has/ { [:tPSEUDO_CLASS, text[1..-1]] }
31
- /:not_has/ { [:tPSEUDO_CLASS, text[1..-1]] }
32
- /#{NODE_TYPE}/ { [:tNODE_TYPE, text[1..]] }
33
- /#{IDENTIFIER}/ { [:tGOTO_SCOPE, text] }
34
- />/ { [:tRELATIONSHIP, text] }
35
- /~/ { [:tRELATIONSHIP, text] }
36
- /\+/ { [:tRELATIONSHIP, text] }
37
- /#{OPEN_SELECTOR}/ { [:tOPEN_SELECTOR, text] }
38
- /#{CLOSE_SELECTOR}/ { [:tCLOSE_SELECTOR, text] }
39
- /#{OPEN_ATTRIBUTE}/ { @nested_count += 1; @state = :KEY; [:tOPEN_ATTRIBUTE, text] }
40
- :KEY /\s+/
41
- :KEY /\^=/ { @state = :VALUE; [:tOPERATOR, '^='] }
42
- :KEY /\$=/ { @state = :VALUE; [:tOPERATOR, '$='] }
43
- :KEY /\*=/ { @state = :VALUE; [:tOPERATOR, '*='] }
44
- :KEY /!=/ { @state = :VALUE; [:tOPERATOR, '!='] }
45
- :KEY /=~/ { @state = :VALUE; [:tOPERATOR, '=~'] }
46
- :KEY /!~/ { @state = :VALUE; [:tOPERATOR, '!~'] }
47
- :KEY />=/ { @state = :VALUE; [:tOPERATOR, '>='] }
48
- :KEY /<=/ { @state = :VALUE; [:tOPERATOR, '<='] }
49
- :KEY />/ { @state = :VALUE; [:tOPERATOR, '>'] }
50
- :KEY /</ { @state = :VALUE; [:tOPERATOR, '<'] }
51
- :KEY /=/ { @state = :VALUE; [:tOPERATOR, '=='] }
52
- :KEY /includes/i { @state = :VALUE; [:tOPERATOR, 'includes'] }
53
- :KEY /not in/i { @state = :VALUE; [:tOPERATOR, 'not_in'] }
54
- :KEY /in/i { @state = :VALUE; [:tOPERATOR, 'in'] }
55
- :KEY /#{IDENTIFIER}/ { [:tKEY, text] }
56
- :VALUE /\s+/
57
- :VALUE /\[\]=/ { [:tIDENTIFIER_VALUE, text] }
58
- :VALUE /\[\]/ { [:tIDENTIFIER_VALUE, text] }
59
- :VALUE /:\[\]=/ { [:tSYMBOL, text[1..-1].to_sym] }
60
- :VALUE /:\[\]/ { [:tSYMBOL, text[1..-1].to_sym] }
61
- :VALUE /#{OPEN_DYNAMIC_ATTRIBUTE}/ { @state = :DYNAMIC_ATTRIBUTE; [:tOPEN_DYNAMIC_ATTRIBUTE, text] }
62
- :VALUE /#{OPEN_ARRAY}/ { @state = :ARRAY_VALUE; [:tOPEN_ARRAY, text] }
63
- :VALUE /#{CLOSE_ATTRIBUTE}/ { @nested_count -= 1; @state = @nested_count == 0 ? nil : :VALUE; [:tCLOSE_ATTRIBUTE, text] }
64
- :VALUE /#{NIL}\?/ { [:tIDENTIFIER_VALUE, text] }
65
- :VALUE /#{NIL}/ { [:tNIL, nil] }
66
- :VALUE /#{TRUE}/ { [:tBOOLEAN, true] }
67
- :VALUE /#{FALSE}/ { [:tBOOLEAN, false] }
68
- :VALUE /#{SYMBOL}/ { [:tSYMBOL, text[1..-1].to_sym] }
69
- :VALUE /#{FLOAT}/ { [:tFLOAT, text.to_f] }
70
- :VALUE /#{INTEGER}/ { [:tINTEGER, text.to_i] }
71
- :VALUE /#{REGEXP}/ { [:tREGEXP, eval(text)] }
72
- :VALUE /#{DOUBLE_QUOTE_STRING}/ { [:tSTRING, text[1...-1]] }
73
- :VALUE /#{SINGLE_QUOTE_STRING}/ { [:tSTRING, text[1...-1]] }
74
- :VALUE /#{NODE_TYPE}/ { [:tNODE_TYPE, text[1..]] }
75
- :VALUE /#{OPEN_ATTRIBUTE}/ { @nested_count += 1; @state = :KEY; [:tOPEN_ATTRIBUTE, text] }
76
- :VALUE /#{IDENTIFIER_VALUE}/ { [:tIDENTIFIER_VALUE, text] }
77
- :DYNAMIC_ATTRIBUTE /#{CLOSE_DYNAMIC_ATTRIBUTE}/ { @state = :VALUE; [:tCLOSE_DYNAMIC_ATTRIBUTE, text] }
78
- :DYNAMIC_ATTRIBUTE /#{IDENTIFIER}/ { [:tDYNAMIC_ATTRIBUTE, text] }
79
- :ARRAY_VALUE /\s+/
80
- :ARRAY_VALUE /#{CLOSE_ARRAY}/ { @state = :VALUE; [:tCLOSE_ARRAY, text] }
81
- :ARRAY_VALUE /#{NIL}\?/ { [:tIDENTIFIER_VALUE, text] }
82
- :ARRAY_VALUE /#{NIL}/ { [:tNIL, nil] }
83
- :ARRAY_VALUE /#{TRUE}/ { [:tBOOLEAN, true] }
84
- :ARRAY_VALUE /#{FALSE}/ { [:tBOOLEAN, false] }
85
- :ARRAY_VALUE /#{SYMBOL}/ { [:tSYMBOL, text[1..-1].to_sym] }
86
- :ARRAY_VALUE /#{FLOAT}/ { [:tFLOAT, text.to_f] }
87
- :ARRAY_VALUE /#{INTEGER}/ { [:tINTEGER, text.to_i] }
88
- :ARRAY_VALUE /#{REGEXP}/ { [:tREGEXP, eval(text)] }
89
- :ARRAY_VALUE /#{DOUBLE_QUOTE_STRING}/ { [:tSTRING, text[1...-1]] }
90
- :ARRAY_VALUE /#{SINGLE_QUOTE_STRING}/ { [:tSTRING, text[1...-1]] }
91
- :ARRAY_VALUE /#{IDENTIFIER_VALUE}/ { [:tIDENTIFIER_VALUE, text] }
92
-
93
- inner
94
- def initialize
95
- @nested_count = 0
96
- end
97
-
98
- def do_parse; end
99
- end