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 +4 -4
- data/bin/cql_ruby +11 -1
- data/lib/cql_ruby.rb +2 -0
- data/lib/cql_ruby/abstract_printer.rb +1 -1
- data/lib/cql_ruby/console_printer.rb +7 -3
- data/lib/cql_ruby/crumb_collector.rb +1 -1
- data/lib/cql_ruby/defs.rb +3 -0
- data/lib/cql_ruby/executor.rb +62 -24
- data/lib/cql_ruby/filter_evaluator.rb +75 -8
- data/lib/cql_ruby/filter_reader.rb +67 -31
- data/lib/cql_ruby/filters/assignments.rb +151 -0
- data/lib/cql_ruby/pattern_matcher.rb +1 -3
- metadata +17 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f10c73e5413cfa12307f6343a47469c7b4836e682d31847f5786539a2edff359
|
4
|
+
data.tar.gz: 4c54670fbfea11478aefd78b266448f9776988ce2089df53ceae001ae35b57eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7b22f9f736297227407e8abfaddc33329d3564174dce7072330149d84d15a160df6ce18b34bf3237977af5cf467370d983536bd7c453d3d8d398950644562f0
|
7
|
+
data.tar.gz: a3e8fcf9c81fff91cf9f807ba5ce8185b97e354842e1f95e694528badd93cdde19dbbccd22d2ede34d8309df268b1fbebd162cf14df03e35f4b950d72e24a05e
|
data/bin/cql_ruby
CHANGED
@@ -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
|
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: #{$!}"
|
data/lib/cql_ruby.rb
CHANGED
@@ -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'
|
@@ -21,7 +21,7 @@ module CqlRuby
|
|
21
21
|
end
|
22
22
|
|
23
23
|
#
|
24
|
-
# @param 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 [
|
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 =
|
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
|
|
data/lib/cql_ruby/executor.rb
CHANGED
@@ -20,7 +20,7 @@ end
|
|
20
20
|
#
|
21
21
|
# Executes search and dumps results into the collector.
|
22
22
|
#
|
23
|
-
# @param collector [
|
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,
|
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
|
111
|
-
|
112
|
-
ancestors
|
113
|
-
|
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
|
-
|
116
|
-
|
117
|
-
|
134
|
+
def line_no
|
135
|
+
anchor.location.expression.line
|
136
|
+
end
|
118
137
|
|
119
|
-
|
120
|
-
|
121
|
-
|
138
|
+
def line_col_no
|
139
|
+
anchor.location.expression.column
|
140
|
+
end
|
122
141
|
|
123
|
-
|
124
|
-
|
125
|
-
|
142
|
+
def source
|
143
|
+
source_reader.source_line(line_no)
|
144
|
+
end
|
126
145
|
|
127
|
-
|
128
|
-
|
129
|
-
|
146
|
+
def surrounding_line(offset)
|
147
|
+
source_reader.source_line(line_no + offset)
|
148
|
+
end
|
130
149
|
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
-
|
136
|
-
ancestors
|
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,
|
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,
|
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 [
|
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,
|
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 =
|
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?
|
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 ==
|
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.
|
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:
|