cql_ruby 0.0.10 → 0.0.15

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.
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: