cql_ruby 0.0.10 → 0.0.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e75a456d8dff7bb1b1affde452bfc7df1e01508a2514ca1729cf996e28c3bff6
4
- data.tar.gz: 57d5bdbfe2991ba0ed0c529373405885cc4382c8cf2f6cec3c86117b65fc31bf
3
+ metadata.gz: f10c73e5413cfa12307f6343a47469c7b4836e682d31847f5786539a2edff359
4
+ data.tar.gz: 4c54670fbfea11478aefd78b266448f9776988ce2089df53ceae001ae35b57eb
5
5
  SHA512:
6
- metadata.gz: b56ead4780a2823d1e327c7ab24e5d73923d21096a5b95832cdfbe7bc499a335bdc2ea5d252efaff96e2ba4fd6471b4ca6e12c9c18f90249116bff509217b66d
7
- data.tar.gz: 1b30aedc86c325e1cc6fdd8813abe2d46f5d76d34f542e0d9f0446b0a7fa42721c4f76dfec376c477287eff46d71311f2b86b20c1dea6c9658cfe8b04207b775
6
+ metadata.gz: f7b22f9f736297227407e8abfaddc33329d3564174dce7072330149d84d15a160df6ce18b34bf3237977af5cf467370d983536bd7c453d3d8d398950644562f0
7
+ data.tar.gz: a3e8fcf9c81fff91cf9f807ba5ce8185b97e354842e1f95e694528badd93cdde19dbbccd22d2ede34d8309df268b1fbebd162cf14df03e35f4b950d72e24a05e
@@ -2,12 +2,14 @@
2
2
 
3
3
  require 'parser'
4
4
  require 'cql_ruby'
5
+ require 'pry-byebug'
5
6
 
6
7
  def show_help
7
8
  puts <<~HELP
8
9
 
9
10
  \tSYNOPSIS
10
- \t\tcql_ruby options pattern path filters ...
11
+ \t\tcql_ruby [--token] pattern path options filters ...
12
+ \t\tcql_ruby --node type path options filters ...
11
13
 
12
14
  \tDESCRIPTION
13
15
  \t\tCQL (Code Query Language) is a semantic search tool for your Ruby source code.
@@ -16,6 +18,8 @@ def show_help
16
18
  \t\tParent node type: type:T(,T)* Example: type:def,send,arg
17
19
  \t\tNesting under: nest:T(=NAME) Example: nest:def=save_user nest:class=UserManager
18
20
  \t\tHas child: has:T(=NAME) Example: has:const has:def=valid?
21
+ \t\tPattern: pattern:(T-)*X(-T)* Example: pattern:class-def-X-block
22
+ \t\tAssignment left side: assigned Example: assigned
19
23
 
20
24
  \tOPTIONS
21
25
  \t\t--include=PATTERN Parses only files whose name matches the pattern.
@@ -49,6 +53,7 @@ def extract_options
49
53
  surrounding_lines: 0,
50
54
  include_pattern: nil,
51
55
  exclude_pattern: nil,
56
+ search_type: :token,
52
57
  }
53
58
 
54
59
  ARGV.delete_if do |arg|
@@ -72,6 +77,10 @@ def extract_options
72
77
  options[:include_pattern] = arg.split('=')[1]
73
78
  elsif arg.start_with?('--exclude=')
74
79
  options[:exclude_pattern] = arg.split('=')[1]
80
+ elsif arg == '--node'
81
+ options[:search_type] = :node
82
+ elsif arg == '--token'
83
+ options[:search_type] = :token
75
84
  else
76
85
  raise "Unknown arg #{arg}"
77
86
  end
@@ -124,6 +133,7 @@ begin
124
133
  recursive: options[:recursive_search],
125
134
  include: options[:include_pattern],
126
135
  exclude: options[:exclude_pattern],
136
+ search_type: options[:search_type],
127
137
  ).search_all
128
138
  rescue
129
139
  puts "Error: #{$!}"
@@ -6,10 +6,12 @@ module CqlRuby;
6
6
  end
7
7
  end
8
8
 
9
+ require 'cql_ruby/defs'
9
10
  require 'cql_ruby/executor'
10
11
  require 'cql_ruby/crumb_collector'
11
12
  require 'cql_ruby/abstract_printer'
12
13
  require 'cql_ruby/console_printer'
13
14
  require 'cql_ruby/filter_reader'
15
+ require 'cql_ruby/filters/assignments'
14
16
  require 'cql_ruby/filter_evaluator'
15
17
  require 'cql_ruby/pattern_matcher'
@@ -2,7 +2,7 @@
2
2
 
3
3
  module CqlRuby
4
4
  #
5
- # Printing Cqlruby::Crumb-s.
5
+ # Printing CqlRuby::Crumb-s.
6
6
  #
7
7
  class AbstractPrinter
8
8
  def print(_crumb)
@@ -21,7 +21,7 @@ module CqlRuby
21
21
  end
22
22
 
23
23
  #
24
- # @param crumb [Cqlruby::Crumb]
24
+ # @param crumb [CqlRuby::Crumb]
25
25
  #
26
26
  def print(crumb)
27
27
  parts = "##{color(97)}#{@counter}#{decor_reset}"
@@ -71,14 +71,18 @@ module CqlRuby
71
71
  end
72
72
  end
73
73
 
74
- # @param [Cqlruby::Crumb] crumb
74
+ # @param [CqlRuby::Crumb] crumb
75
75
  # @return [String]
76
76
  def decorate_source_line(crumb)
77
77
  source = crumb.source
78
78
  from = crumb.line_col_no
79
79
  to = from + crumb.expression_size
80
80
 
81
- prefix = source[0..from - 1] || ''
81
+ prefix = if from > 0
82
+ source[0..from - 1] || ''
83
+ else
84
+ ''
85
+ end
82
86
  subject = source[from..to - 1] || ''
83
87
  suffix = source[to..] || ''
84
88
 
@@ -3,7 +3,7 @@
3
3
  module CqlRuby
4
4
  class CrumbCollector
5
5
  #
6
- # @param printer [Cqlruby::AbstractPrinter]
6
+ # @param printer [CqlRuby::AbstractPrinter]
7
7
  #
8
8
  def initialize(printer)
9
9
  super()
@@ -0,0 +1,3 @@
1
+ module CqlRuby
2
+ MATCH_ANYTHING = '*'
3
+ end
@@ -20,7 +20,7 @@ end
20
20
  #
21
21
  # Executes search and dumps results into the collector.
22
22
  #
23
- # @param collector [Cqlruby::CrumbCollector]
23
+ # @param collector [CqlRuby::CrumbCollector]
24
24
  # @param pattern [String]
25
25
  # @param path [String]
26
26
  # @param filters [Array<String>]
@@ -35,7 +35,8 @@ module CqlRuby
35
35
  filters: [],
36
36
  recursive: true,
37
37
  include: nil,
38
- exclude: nil
38
+ exclude: nil,
39
+ search_type: :token
39
40
  )
40
41
  @collector = collector
41
42
  @filter_reader = filter_reader
@@ -45,6 +46,7 @@ module CqlRuby
45
46
  @recursive = recursive
46
47
  @include = include
47
48
  @exclude = exclude
49
+ @search_type = search_type
48
50
  end
49
51
 
50
52
  def search_all
@@ -72,11 +74,17 @@ module CqlRuby
72
74
 
73
75
  def walk(node, ancestors, source_reader)
74
76
  if node.is_a?(Parser::AST::Node)
77
+ if search_for_node?
78
+ if match?(node.type) && CqlRuby::FilterEvaluator.pass?(filter_reader, ancestors, node)
79
+ collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
80
+ end
81
+ end
82
+
75
83
  node.children.flat_map do |child|
76
84
  walk(child, ancestors.dup + [node], source_reader)
77
85
  end
78
86
  else
79
- if match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, node, ancestors)
87
+ if search_for_token? && match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, ancestors, node)
80
88
  collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
81
89
  end
82
90
  end
@@ -98,6 +106,14 @@ module CqlRuby
98
106
  Dir.glob(clean_path)
99
107
  end
100
108
 
109
+ def search_for_token?
110
+ @search_type == :token
111
+ end
112
+
113
+ def search_for_node?
114
+ @search_type == :node
115
+ end
116
+
101
117
  attr_reader :collector
102
118
  attr_reader :filter_reader
103
119
  attr_reader :pattern
@@ -107,33 +123,55 @@ module CqlRuby
107
123
  end
108
124
  end
109
125
 
110
- CqlRuby::Crumb = Struct.new(:full_name, :ancestors, :source_reader) do
111
- def line_no
112
- ancestors.last.location.expression.line
113
- end
126
+ module CqlRuby
127
+ class Crumb
128
+ def initialize(node, ancestors, source_reader)
129
+ @node = node
130
+ @ancestors = ancestors
131
+ @source_reader = source_reader
132
+ end
114
133
 
115
- def line_col_no
116
- ancestors.last.location.expression.column
117
- end
134
+ def line_no
135
+ anchor.location.expression.line
136
+ end
118
137
 
119
- def source
120
- source_reader.source_line(line_no)
121
- end
138
+ def line_col_no
139
+ anchor.location.expression.column
140
+ end
122
141
 
123
- def surrounding_line(offset)
124
- source_reader.source_line(line_no + offset)
125
- end
142
+ def source
143
+ source_reader.source_line(line_no)
144
+ end
126
145
 
127
- def file_name
128
- source_reader.file
129
- end
146
+ def surrounding_line(offset)
147
+ source_reader.source_line(line_no + offset)
148
+ end
130
149
 
131
- def expression_size
132
- ancestors.last.location.expression.size
133
- end
150
+ def file_name
151
+ source_reader.file
152
+ end
153
+
154
+ def expression_size
155
+ anchor.location.expression.size
156
+ end
157
+
158
+ def type
159
+ anchor.type
160
+ end
161
+
162
+ private
163
+
164
+ def anchor
165
+ if node.is_a?(Parser::AST::Node)
166
+ node
167
+ else
168
+ ancestors.last
169
+ end
170
+ end
134
171
 
135
- def type
136
- ancestors.last.type
172
+ attr_reader :node
173
+ attr_reader :ancestors
174
+ attr_reader :source_reader
137
175
  end
138
176
  end
139
177
 
@@ -3,18 +3,20 @@
3
3
  module CqlRuby
4
4
  class FilterEvaluator
5
5
  class << self
6
- def pass?(filter_reader, node, ancestors)
6
+ def pass?(filter_reader, ancestors, node)
7
7
  [
8
8
  pass_type?(filter_reader, ancestors),
9
9
  pass_nesting?(filter_reader, ancestors),
10
- pass_has?(filter_reader, node, ancestors),
10
+ pass_has?(filter_reader, ancestors, node),
11
+ pass_pattern?(filter_reader, ancestors, node),
12
+ pass_assignment?(filter_reader, ancestors, node),
11
13
  ].all?
12
14
  end
13
15
 
14
16
  private
15
17
 
16
18
  #
17
- # @param [Cqlruby::FilterReader] filter_reader
19
+ # @param [CqlRuby::FilterReader] filter_reader
18
20
  # @param [Array<Parser::AST::Node>] ancestors
19
21
  #
20
22
  # @return [Boolean]
@@ -39,7 +41,6 @@ module CqlRuby
39
41
  next false unless ancestor.type.to_s == nest_rule.type
40
42
  next true unless nest_rule.restrict_name?
41
43
 
42
- # TODO Make a proper matcher class.
43
44
  if %w[class module].include?(nest_rule.type)
44
45
  CqlRuby::PatternMatcher.match?(nest_rule.name, ancestor.children[0].children[1])
45
46
  elsif %[def].include?(nest_rule.type)
@@ -53,20 +54,86 @@ module CqlRuby
53
54
 
54
55
  #
55
56
  # @param [CqlRuby::FilterReader] filter_reader
56
- # @param [Parser::AST::Node] node
57
57
  # @param [Array<Parser::AST::Node>] ancestors
58
+ # @param [Any<Parser::AST::Node, Symbol>] node
59
+ #
60
+ # @return [Boolean]
58
61
  #
59
- def pass_has?(filter_reader, node, ancestors)
62
+ def pass_has?(filter_reader, ancestors, node)
60
63
  return true unless filter_reader.restrict_children?
61
64
 
62
65
  filter_reader.has_leaves.all? do |has_rule|
63
- anchor_node = try_get_class(ancestors) || try_get_module(ancestors) || try_get_def(ancestors)
66
+ anchor_node = if node.is_a?(Symbol)
67
+ try_get_class(ancestors) || try_get_module(ancestors) || try_get_def(ancestors)
68
+ else
69
+ node
70
+ end
64
71
  next false unless anchor_node
65
72
 
66
73
  has_node_with_name?(anchor_node, has_rule)
67
74
  end
68
75
  end
69
76
 
77
+ #
78
+ # @param [CqlRuby::FilterReader] filter_reader
79
+ # @param [Array<Parser::AST::Node>] ancestors
80
+ # @param [Any<Parser::AST::Node, Symbol>] node
81
+ #
82
+ # @return [Boolean]
83
+ #
84
+ def pass_pattern?(filter_reader, ancestors, node)
85
+ return true unless filter_reader.restrict_pattern?
86
+
87
+ filter_reader.patterns.all? do |pattern|
88
+ pattern_ancestors = pattern.ancestors.dup
89
+ ancestor_idx = ancestors.size - 1
90
+
91
+ while !pattern_ancestors.empty? && ancestor_idx >= 0
92
+ if CqlRuby::PatternMatcher.match?(pattern_ancestors.last, ancestors[ancestor_idx].type)
93
+ pattern_ancestors.pop
94
+ end
95
+
96
+ ancestor_idx -= 1
97
+ end
98
+ return false unless pattern_ancestors.empty?
99
+
100
+ pattern_descendants = pattern.descendants.dup
101
+ match_descendant_pattern?(pattern_descendants, node)
102
+ end
103
+ end
104
+
105
+ #
106
+ # @param [CqlRuby::FilterReader] filter_reader
107
+ # @param [Array<Parser::AST::Node>] ancestors
108
+ # @param [Parser::AST::Node] node
109
+ #
110
+ # @return [Boolean]
111
+ #
112
+ def pass_assignment?(filter_reader, ancestors, node)
113
+ CqlRuby::Filters::Assignments.pass?(filter_reader, ancestors, node)
114
+ end
115
+
116
+ #
117
+ # @param [Array<String>] pattern_descendants
118
+ # @param [Parser::AST::Node] node
119
+ #
120
+ # @return [Boolean]
121
+ #
122
+ def match_descendant_pattern?(pattern_descendants, node)
123
+ return true if pattern_descendants.empty?
124
+ # If we're at the end and we're still expecting a type - no match.
125
+ return false unless node.is_a?(Parser::AST::Node)
126
+
127
+ node.children.any? do |child|
128
+ next false unless child.is_a?(Parser::AST::Node)
129
+ if CqlRuby::PatternMatcher.match?(pattern_descendants.first, child.type)
130
+ match_descendant_pattern?(pattern_descendants[1..], child)
131
+ else
132
+ match_descendant_pattern?(pattern_descendants.dup, child)
133
+ end
134
+ end
135
+ end
136
+
70
137
  #
71
138
  # @param [Array<Parser::AST::Node>] ancestors
72
139
  #
@@ -101,7 +168,7 @@ module CqlRuby
101
168
 
102
169
  #
103
170
  # @param [Parser::AST::Node] anchor_node
104
- # @param [CqlRuby::NodeSpec]
171
+ # @param [CqlRuby::FilterReader::NodeSpec]
105
172
  #
106
173
  def has_node_with_name?(anchor_node, has_rule)
107
174
  return false unless anchor_node.is_a?(Parser::AST::Node)
@@ -1,33 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: Have convenience filters for type:_ such as: isclass, ismodule, isdef ...
4
-
5
3
  module CqlRuby
6
- class NodeSpec < Struct.new(:type, :name)
7
- # Make this non duplicated.
8
- NAME_ANY = '*'
9
-
10
- class << self
11
- #
12
- # @param [String] raw_value
13
- # Format: TYPE(=NAME|=*)
14
- # Accepted types: class, module, def, block
15
- #
16
- def from(raw_value)
17
- type, name = raw_value.split('=')
18
- name ||= NAME_ANY
19
-
20
- raise "Type '#{type}' is not recognized. See 'cql_ruby --help' for allowed types." unless Parser::Meta::NODE_TYPES.member?(type.to_sym)
21
-
22
- new(type, name)
23
- end
24
- end
25
-
26
- def restrict_name?
27
- name != NAME_ANY
28
- end
29
- end
30
-
31
4
  #
32
5
  # Reads and provides filters.
33
6
  #
@@ -39,21 +12,72 @@ module CqlRuby
39
12
  # example: type:def,send
40
13
  #
41
14
  class FilterReader
15
+ class HierarchyPattern
16
+ SELF_MARKER = 'X'
17
+
18
+ def self.from(raw_value)
19
+ parts = raw_value.split('-')
20
+ self_marker_idx = parts.index(SELF_MARKER)
21
+ raise "Missing self marker '#{SELF_MARKER}' in hierarchy pattern." if self_marker_idx.nil?
22
+
23
+ ancestors = parts[0...self_marker_idx]
24
+ descendants = parts[self_marker_idx + 1..]
25
+
26
+ new(ancestors, descendants)
27
+ end
28
+
29
+ attr_reader :ancestors
30
+ attr_reader :descendants
31
+
32
+ def initialize(ancestors, descendants)
33
+ @ancestors = ancestors
34
+ @descendants = descendants
35
+ end
36
+ end
37
+
38
+ class NodeSpec < Struct.new(:type, :name)
39
+ class << self
40
+ #
41
+ # @param [String] raw_value
42
+ # Format: TYPE(=NAME|=*)
43
+ # Accepted types: class, module, def, block
44
+ #
45
+ def from(raw_value)
46
+ type, name = raw_value.split('=')
47
+ name ||= CqlRuby::MATCH_ANYTHING
48
+
49
+ raise "Type '#{type}' is not recognized. See 'cql_ruby --help' for allowed types." unless Parser::Meta::NODE_TYPES.member?(type.to_sym)
50
+
51
+ new(type, name)
52
+ end
53
+ end
54
+
55
+ def restrict_name?
56
+ name != CqlRuby::MATCH_ANYTHING
57
+ end
58
+ end
59
+
42
60
  NESTING_ALLOWED_TYPES = %w[class module def block].freeze
43
61
 
44
62
  # @attribute [Array<Symbol>] allowed_types
45
63
  attr_reader :allowed_types
46
- # @attribute [Array<CqlRuby::NodeSpec>] nest_under
64
+ # @attribute [Array<CqlRuby::FilterReader::NodeSpec>] nest_under
47
65
  attr_reader :nest_under
48
- # @attribute [Array<CqlRuby::NodeSpec>] has_leaves
66
+ # @attribute [Array<CqlRuby::FilterReader::NodeSpec>] has_leaves
49
67
  attr_reader :has_leaves
68
+ # @attribute [Array<CqlRuby::FilterReader::HierarchyPattern>] patterns
69
+ attr_reader :patterns
70
+ # @attribute [Boolean] is_assigned
71
+ attr_reader :is_assigned
50
72
 
51
- def initialize(raw_filters)
73
+ def initialize(raw_filters = [])
52
74
  super()
53
75
 
54
76
  @allowed_types = []
55
77
  @nest_under = []
56
78
  @has_leaves = []
79
+ @patterns = []
80
+ @is_assigned = false
57
81
 
58
82
  parse_raw_filters(raw_filters)
59
83
  end
@@ -70,13 +94,21 @@ module CqlRuby
70
94
  !@has_leaves.empty?
71
95
  end
72
96
 
97
+ def restrict_pattern?
98
+ !@patterns.empty?
99
+ end
100
+
101
+ def restrict_assignment?
102
+ @is_assigned
103
+ end
104
+
73
105
  private
74
106
 
75
107
  # @param [Array<String>] raw_filters
76
108
  def parse_raw_filters(raw_filters)
77
109
  raw_filters.each do |raw_filter|
78
110
  name, value = raw_filter.split(':')
79
- raise "Unrecognized filter: #{raw_filter}" if name.nil? || value.nil?
111
+ raise "Unrecognized filter: #{raw_filter}" if name.nil?
80
112
 
81
113
  if %w[type t].include?(name)
82
114
  @allowed_types += value.split(',').map(&:to_sym)
@@ -88,6 +120,10 @@ module CqlRuby
88
120
  @nest_under << spec
89
121
  elsif %w[has h].include?(name)
90
122
  @has_leaves << NodeSpec.from(value)
123
+ elsif %w[pattern p].include?(name)
124
+ @patterns << HierarchyPattern.from(value)
125
+ elsif name == 'assigned'
126
+ @is_assigned = true
91
127
  end
92
128
  end
93
129
 
@@ -0,0 +1,151 @@
1
+ module CqlRuby
2
+ module Filters
3
+ class Assignments
4
+ class << self
5
+ #
6
+ # @param [CqlRuby::FilterReader] filter_reader
7
+ # @param [Array<Parser::AST::Node>] ancestors
8
+ # @param [Parser::AST::Node] node
9
+ #
10
+ # @return [Boolean]
11
+ #
12
+ def pass?(filter_reader, ancestors, node)
13
+ return true unless filter_reader.restrict_assignment?
14
+ return true if lvar_assign?(ancestors, node)
15
+ return true if instance_attr_assign?(ancestors, node)
16
+ return true if array_sym_key_assign?(ancestors, node)
17
+ return true if array_string_key_assign?(ancestors, node)
18
+ return true if hash_sym_key_assign?(ancestors, node)
19
+ return true if hash_string_key_assign?(ancestors, node)
20
+ false
21
+ end
22
+
23
+ private
24
+
25
+ #
26
+ # @param [Array<Parser::AST::Node>] ancestors
27
+ # @param [Parser::AST::Node] node
28
+ #
29
+ # @return [Boolean]
30
+ #
31
+ def lvar_assign?(ancestors, node)
32
+ pattern_pass?({
33
+ nth_child: 0,
34
+ parent: {
35
+ type: :lvasgn
36
+ }
37
+ }, ancestors, node)
38
+ end
39
+
40
+ # TODO This does not work as symbol token is suffixed with =, eg foo= for bar.foo = x.
41
+ # Workaround for now is to use a =-alloed pattern, such as 'r/^token(|=)$/'
42
+ def instance_attr_assign?(ancestors, node)
43
+ pattern_pass?({
44
+ nth_child: 1,
45
+ parent: {
46
+ type: :send
47
+ }
48
+ }, ancestors, node)
49
+ end
50
+
51
+ def array_sym_key_assign?(ancestors, node)
52
+ pattern_pass?({
53
+ nth_child: 0,
54
+ parent: {
55
+ type: :sym,
56
+ nth_child: 2,
57
+ parent: {
58
+ type: :send,
59
+ child: {
60
+ nth: 1,
61
+ token: :[]=
62
+ }
63
+ }
64
+ }
65
+ }, ancestors, node)
66
+ end
67
+
68
+ def array_string_key_assign?(ancestors, node)
69
+ pattern_pass?({
70
+ nth_child: 0,
71
+ parent: {
72
+ type: :str,
73
+ nth_child: 2,
74
+ parent: {
75
+ type: :send,
76
+ child: {
77
+ nth: 1,
78
+ token: :[]=
79
+ }
80
+ }
81
+ }
82
+ }, ancestors, node)
83
+ end
84
+
85
+ def hash_sym_key_assign?(ancestors, node)
86
+ pattern_pass?({
87
+ nth_child: 0,
88
+ parent: {
89
+ type: :sym,
90
+ nth_child: 0,
91
+ parent: {
92
+ type: :pair,
93
+ parent: {
94
+ type: :hash
95
+ }
96
+ }
97
+ }
98
+ }, ancestors, node)
99
+ end
100
+
101
+ def hash_string_key_assign?(ancestors, node)
102
+ pattern_pass?({
103
+ nth_child: 0,
104
+ parent: {
105
+ type: :str,
106
+ nth_child: 0,
107
+ parent: {
108
+ type: :pair,
109
+ parent: {
110
+ type: :hash
111
+ }
112
+ }
113
+ }
114
+ }, ancestors, node)
115
+ end
116
+
117
+ def pattern_pass?(pattern, ancestors, node)
118
+ ancestor_idx = ancestors.size
119
+ current_node = node
120
+ current_pattern = pattern
121
+
122
+ loop do
123
+ if current_pattern.key?(:nth_child)
124
+ return false unless ancestor_idx - 1 >= 0
125
+ return false unless ancestors[ancestor_idx - 1].is_a?(Parser::AST::Node)
126
+ return false unless ancestors[ancestor_idx - 1].children[current_pattern[:nth_child]] == current_node
127
+ end
128
+
129
+ if current_pattern.key?(:type)
130
+ return false unless current_node.type == current_pattern[:type]
131
+ end
132
+
133
+ if current_pattern.key?(:child)
134
+ return false if current_node.children.size <= current_pattern[:child][:nth]
135
+ return false unless current_node.children[current_pattern[:child][:nth]] == current_pattern[:child][:token]
136
+ end
137
+
138
+ break unless current_pattern.key?(:parent)
139
+
140
+ ancestor_idx -= 1
141
+ return false unless ancestor_idx >= 0
142
+ current_node = ancestors[ancestor_idx]
143
+ current_pattern = current_pattern[:parent]
144
+ end
145
+
146
+ true
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -1,11 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
  module CqlRuby
3
3
  module PatternMatcher
4
- MATCH_ANY = '*'
5
-
6
4
  def self.match?(pattern, subject)
7
5
  pattern = pattern.to_s
8
- return true if pattern == MATCH_ANY
6
+ return true if pattern == CqlRuby::MATCH_ANYTHING
9
7
 
10
8
  subject = subject.to_s
11
9
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cql_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.10
4
+ version: 0.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - itarato
@@ -30,6 +30,20 @@ dependencies:
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
32
  version: 2.7.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: rspec
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
40
+ type: :development
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
33
47
  description:
34
48
  email: it.arato@gmail.com
35
49
  executables:
@@ -42,9 +56,11 @@ files:
42
56
  - lib/cql_ruby/abstract_printer.rb
43
57
  - lib/cql_ruby/console_printer.rb
44
58
  - lib/cql_ruby/crumb_collector.rb
59
+ - lib/cql_ruby/defs.rb
45
60
  - lib/cql_ruby/executor.rb
46
61
  - lib/cql_ruby/filter_evaluator.rb
47
62
  - lib/cql_ruby/filter_reader.rb
63
+ - lib/cql_ruby/filters/assignments.rb
48
64
  - lib/cql_ruby/pattern_matcher.rb
49
65
  homepage: https://github.com/itarato/cql
50
66
  licenses: