cql_ruby 0.0.12 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,18 +1,18 @@
1
- # frozen_string_literal: true
2
-
3
- module CqlRuby
4
- class CrumbCollector
5
- #
6
- # @param printer [CqlRuby::AbstractPrinter]
7
- #
8
- def initialize(printer)
9
- super()
10
-
11
- @printer = printer
12
- end
13
-
14
- def add(crumb)
15
- @printer.print(crumb)
16
- end
17
- end
18
- end
1
+ # frozen_string_literal: true
2
+
3
+ module CqlRuby
4
+ class CrumbCollector
5
+ #
6
+ # @param printer [CqlRuby::AbstractPrinter]
7
+ #
8
+ def initialize(printer)
9
+ super()
10
+
11
+ @printer = printer
12
+ end
13
+
14
+ def add(crumb)
15
+ @printer.print(crumb)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,3 @@
1
+ module CqlRuby
2
+ MATCH_ANYTHING = '*'
3
+ end
@@ -1,194 +1,194 @@
1
- # frozen_string_literal: true
2
-
3
- require 'parser/current'
4
- require 'pathname'
5
-
6
- module CqlRuby
7
- class Config
8
- @@debug_level = 0
9
-
10
- class << self
11
- def debug_level=(lvl); @@debug_level = lvl; end
12
- def debug_level; @@debug_level; end
13
- def debug_level_1?; @@debug_level >= 1; end
14
- def debug_level_2?; @@debug_level >= 2; end
15
- def debug_level_3?; @@debug_level >= 3; end
16
- end
17
- end
18
- end
19
-
20
- #
21
- # Executes search and dumps results into the collector.
22
- #
23
- # @param collector [CqlRuby::CrumbCollector]
24
- # @param pattern [String]
25
- # @param path [String]
26
- # @param filters [Array<String>]
27
- #
28
- module CqlRuby
29
- class Executor
30
- def initialize(
31
- collector:,
32
- filter_reader:,
33
- pattern:,
34
- path:,
35
- filters: [],
36
- recursive: true,
37
- include: nil,
38
- exclude: nil,
39
- search_type: :token
40
- )
41
- @collector = collector
42
- @filter_reader = filter_reader
43
- @pattern = pattern
44
- @path = path
45
- @filters = filters
46
- @recursive = recursive
47
- @include = include
48
- @exclude = exclude
49
- @search_type = search_type
50
- end
51
-
52
- def search_all
53
- files.flat_map do |file|
54
- next if !@exclude.nil? && CqlRuby::PatternMatcher.match?(@exclude, file)
55
- next unless @include.nil? || CqlRuby::PatternMatcher.match?(@include, file)
56
-
57
- CqlRuby.log "File check: #{file}" if CqlRuby::Config.debug_level_3?
58
- search(file)
59
- end
60
- end
61
-
62
- private
63
-
64
- def search(file)
65
- ast = Parser::CurrentRuby.parse(File.read(file))
66
- source_reader = CqlRuby::SourceReader.new(file)
67
- walk(ast, [], source_reader)
68
-
69
- nil
70
- rescue
71
- CqlRuby.log "File #{file} cannot be parsed"
72
- CqlRuby.log "Reason: #{$!}" if CqlRuby::Config.debug_level_1?
73
- end
74
-
75
- def walk(node, ancestors, source_reader)
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
-
83
- node.children.flat_map do |child|
84
- walk(child, ancestors.dup + [node], source_reader)
85
- end
86
- else
87
- if search_for_token? && match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, ancestors, node)
88
- collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
89
- end
90
- end
91
-
92
- nil
93
- end
94
-
95
- def match?(target)
96
- CqlRuby::PatternMatcher.match?(pattern, target)
97
- end
98
-
99
- def files
100
- return [path] if File.file?(path)
101
-
102
- clean_path = Pathname(path).cleanpath.to_s
103
- clean_path += '/**' if recursive
104
- clean_path += '/*.rb'
105
-
106
- Dir.glob(clean_path)
107
- end
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
-
117
- attr_reader :collector
118
- attr_reader :filter_reader
119
- attr_reader :pattern
120
- attr_reader :path
121
- attr_reader :filters
122
- attr_reader :recursive
123
- end
124
- end
125
-
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
133
-
134
- def line_no
135
- anchor.location.expression.line
136
- end
137
-
138
- def line_col_no
139
- anchor.location.expression.column
140
- end
141
-
142
- def source
143
- source_reader.source_line(line_no)
144
- end
145
-
146
- def surrounding_line(offset)
147
- source_reader.source_line(line_no + offset)
148
- end
149
-
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
171
-
172
- attr_reader :node
173
- attr_reader :ancestors
174
- attr_reader :source_reader
175
- end
176
- end
177
-
178
- CqlRuby::SourceReader = Struct.new(:file) do
179
- def initialize(*args)
180
- super
181
- end
182
-
183
- def source_line(n)
184
- return nil unless lines.size >= n
185
-
186
- lines[n - 1].chop
187
- end
188
-
189
- private
190
-
191
- def lines
192
- @lines ||= IO.readlines(file)
193
- end
194
- end
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser/current'
4
+ require 'pathname'
5
+
6
+ module CqlRuby
7
+ class Config
8
+ @@debug_level = 0
9
+
10
+ class << self
11
+ def debug_level=(lvl); @@debug_level = lvl; end
12
+ def debug_level; @@debug_level; end
13
+ def debug_level_1?; @@debug_level >= 1; end
14
+ def debug_level_2?; @@debug_level >= 2; end
15
+ def debug_level_3?; @@debug_level >= 3; end
16
+ end
17
+ end
18
+ end
19
+
20
+ #
21
+ # Executes search and dumps results into the collector.
22
+ #
23
+ # @param collector [CqlRuby::CrumbCollector]
24
+ # @param pattern [String]
25
+ # @param path [String]
26
+ # @param filters [Array<String>]
27
+ #
28
+ module CqlRuby
29
+ class Executor
30
+ def initialize(
31
+ collector:,
32
+ filter_reader:,
33
+ pattern:,
34
+ path:,
35
+ filters: [],
36
+ recursive: true,
37
+ include: nil,
38
+ exclude: nil,
39
+ search_type: :token
40
+ )
41
+ @collector = collector
42
+ @filter_reader = filter_reader
43
+ @pattern = pattern
44
+ @path = path
45
+ @filters = filters
46
+ @recursive = recursive
47
+ @include = include
48
+ @exclude = exclude
49
+ @search_type = search_type
50
+ end
51
+
52
+ def search_all
53
+ files.flat_map do |file|
54
+ next if !@exclude.nil? && CqlRuby::PatternMatcher.match?(@exclude, file)
55
+ next unless @include.nil? || CqlRuby::PatternMatcher.match?(@include, file)
56
+
57
+ CqlRuby.log "File check: #{file}" if CqlRuby::Config.debug_level_3?
58
+ search(file)
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def search(file)
65
+ ast = Parser::CurrentRuby.parse(File.read(file))
66
+ source_reader = CqlRuby::SourceReader.new(file)
67
+ walk(ast, [], source_reader)
68
+
69
+ nil
70
+ rescue
71
+ CqlRuby.log "File #{file} cannot be parsed"
72
+ CqlRuby.log "Reason: #{$!}" if CqlRuby::Config.debug_level_1?
73
+ end
74
+
75
+ def walk(node, ancestors, source_reader)
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
+
83
+ node.children.flat_map do |child|
84
+ walk(child, ancestors.dup + [node], source_reader)
85
+ end
86
+ else
87
+ if search_for_token? && match?(node) && CqlRuby::FilterEvaluator.pass?(filter_reader, ancestors, node)
88
+ collector.add(CqlRuby::Crumb.new(node, ancestors, source_reader))
89
+ end
90
+ end
91
+
92
+ nil
93
+ end
94
+
95
+ def match?(target)
96
+ CqlRuby::PatternMatcher.match?(pattern, target)
97
+ end
98
+
99
+ def files
100
+ return [path] if File.file?(path)
101
+
102
+ clean_path = Pathname(path).cleanpath.to_s
103
+ clean_path += '/**' if recursive
104
+ clean_path += '/*.rb'
105
+
106
+ Dir.glob(clean_path)
107
+ end
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
+
117
+ attr_reader :collector
118
+ attr_reader :filter_reader
119
+ attr_reader :pattern
120
+ attr_reader :path
121
+ attr_reader :filters
122
+ attr_reader :recursive
123
+ end
124
+ end
125
+
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
133
+
134
+ def line_no
135
+ anchor.location.expression.line
136
+ end
137
+
138
+ def line_col_no
139
+ anchor.location.expression.column
140
+ end
141
+
142
+ def source
143
+ source_reader.source_line(line_no)
144
+ end
145
+
146
+ def surrounding_line(offset)
147
+ source_reader.source_line(line_no + offset)
148
+ end
149
+
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
171
+
172
+ attr_reader :node
173
+ attr_reader :ancestors
174
+ attr_reader :source_reader
175
+ end
176
+ end
177
+
178
+ CqlRuby::SourceReader = Struct.new(:file) do
179
+ def initialize(*args)
180
+ super
181
+ end
182
+
183
+ def source_line(n)
184
+ return nil unless lines.size >= n
185
+
186
+ lines[n - 1].chop
187
+ end
188
+
189
+ private
190
+
191
+ def lines
192
+ @lines ||= IO.readlines(file)
193
+ end
194
+ end
@@ -1,178 +1,177 @@
1
- # frozen_string_literal: true
2
-
3
- module CqlRuby
4
- class FilterEvaluator
5
- class << self
6
- def pass?(filter_reader, ancestors, node)
7
- [
8
- pass_type?(filter_reader, ancestors),
9
- pass_nesting?(filter_reader, ancestors),
10
- pass_has?(filter_reader, ancestors, node),
11
- pass_pattern?(filter_reader, ancestors, node),
12
- ].all?
13
- end
14
-
15
- private
16
-
17
- #
18
- # @param [CqlRuby::FilterReader] filter_reader
19
- # @param [Array<Parser::AST::Node>] ancestors
20
- #
21
- # @return [Boolean]
22
- #
23
- def pass_type?(filter_reader, ancestors)
24
- return true unless filter_reader.restrict_types?
25
-
26
- filter_reader.allowed_types.include?(ancestors.last.type)
27
- end
28
-
29
- #
30
- # @param [CqlRuby::FilterReader] filter_reader
31
- # @param [Array<Parser::AST::Node>] ancestors
32
- #
33
- # @return [Boolean]
34
- #
35
- def pass_nesting?(filter_reader, ancestors)
36
- return true unless filter_reader.restrict_nesting?
37
-
38
- filter_reader.nest_under.all? do |nest_rule|
39
- ancestors.reverse.any? do |ancestor|
40
- next false unless ancestor.type.to_s == nest_rule.type
41
- next true unless nest_rule.restrict_name?
42
-
43
- if %w[class module].include?(nest_rule.type)
44
- CqlRuby::PatternMatcher.match?(nest_rule.name, ancestor.children[0].children[1])
45
- elsif %[def].include?(nest_rule.type)
46
- CqlRuby::PatternMatcher.match?(nest_rule.name, ancestor.children[0])
47
- else
48
- raise 'Unknown type.'
49
- end
50
- end
51
- end
52
- end
53
-
54
- #
55
- # @param [CqlRuby::FilterReader] filter_reader
56
- # @param [Array<Parser::AST::Node>] ancestors
57
- # @param [Any<Parser::AST::Node, Symbol>] node
58
- #
59
- def pass_has?(filter_reader, ancestors, node)
60
- return true unless filter_reader.restrict_children?
61
-
62
- filter_reader.has_leaves.all? do |has_rule|
63
- anchor_node = if node.is_a?(Symbol)
64
- # TODO: Expand this to other wrappers (loops, conditions, etc).
65
- try_get_class(ancestors) || try_get_module(ancestors) || try_get_def(ancestors)
66
- else
67
- node
68
- end
69
- next false unless anchor_node
70
-
71
- has_node_with_name?(anchor_node, has_rule)
72
- end
73
- end
74
-
75
- #
76
- # @param [CqlRuby::FilterReader] filter_reader
77
- # @param [Array<Parser::AST::Node>] ancestors
78
- # @param [Any<Parser::AST::Node, Symbol>] node
79
- #
80
- def pass_pattern?(filter_reader, ancestors, node)
81
- return true unless filter_reader.restrict_pattern?
82
-
83
- filter_reader.patterns.all? do |pattern|
84
- pattern_ancestors = pattern.ancestors.dup
85
- ancestor_idx = ancestors.size - 1
86
-
87
- while !pattern_ancestors.empty? && ancestor_idx >= 0
88
- if CqlRuby::PatternMatcher.match?(pattern_ancestors.last, ancestors[ancestor_idx].type)
89
- pattern_ancestors.pop
90
- end
91
-
92
- ancestor_idx -= 1
93
- end
94
- return false unless pattern_ancestors.empty?
95
-
96
- pattern_descendants = pattern.descendants.dup
97
- match_descendant_pattern?(pattern_descendants, node)
98
- end
99
- end
100
-
101
- #
102
- # @param [Array<String>] pattern_descendants
103
- # @param [Parser::AST::Node] node
104
- #
105
- def match_descendant_pattern?(pattern_descendants, node)
106
- return true if pattern_descendants.empty?
107
- # If we're at the end and we're still expecting a type - no match.
108
- return false unless node.is_a?(Parser::AST::Node)
109
-
110
- node.children.any? do |child|
111
- next false unless child.is_a?(Parser::AST::Node)
112
- if CqlRuby::PatternMatcher.match?(pattern_descendants.first, child.type)
113
- match_descendant_pattern?(pattern_descendants[1..], child)
114
- else
115
- match_descendant_pattern?(pattern_descendants.dup, child)
116
- end
117
- end
118
- end
119
-
120
- #
121
- # @param [Array<Parser::AST::Node>] ancestors
122
- #
123
- def try_get_class(ancestors)
124
- return nil unless ancestors.size >= 2
125
- return nil unless ancestors[-1].type == :const
126
- return nil unless ancestors[-2].type == :class
127
-
128
- ancestors[-2].children[2]
129
- end
130
-
131
- #
132
- # @param [Array<Parser::AST::Node>] ancestors
133
- #
134
- def try_get_module(ancestors)
135
- return nil unless ancestors.size >= 2
136
- return nil unless ancestors[-1].type == :const
137
- return nil unless ancestors[-2].type == :module
138
-
139
- ancestors[-2].children[1]
140
- end
141
-
142
- #
143
- # @param [Array<Parser::AST::Node>] ancestors
144
- #
145
- def try_get_def(ancestors)
146
- return nil unless ancestors.size >= 1
147
- return nil unless ancestors[-1].type == :def
148
-
149
- ancestors[-1].children[2]
150
- end
151
-
152
- #
153
- # @param [Parser::AST::Node] anchor_node
154
- # @param [CqlRuby::NodeSpec]
155
- #
156
- def has_node_with_name?(anchor_node, has_rule)
157
- return false unless anchor_node.is_a?(Parser::AST::Node)
158
-
159
- fn_children_with_type = ->(node) { node.children.map { |child| [child, node.type] } }
160
- to_visit = fn_children_with_type.call(anchor_node)
161
-
162
- until to_visit.empty?
163
- current_node, current_type = to_visit.shift
164
-
165
- if current_node.is_a?(Parser::AST::Node)
166
- to_visit += fn_children_with_type.call(current_node)
167
- else
168
- if current_type == has_rule.type.to_sym && CqlRuby::PatternMatcher.match?(has_rule.name, current_node)
169
- return true
170
- end
171
- end
172
- end
173
-
174
- false
175
- end
176
- end
177
- end
178
- end
1
+ # frozen_string_literal: true
2
+
3
+ module CqlRuby
4
+ class FilterEvaluator
5
+ class << self
6
+ def pass?(filter_reader, ancestors, node)
7
+ [
8
+ pass_type?(filter_reader, ancestors),
9
+ pass_nesting?(filter_reader, ancestors),
10
+ pass_has?(filter_reader, ancestors, node),
11
+ pass_pattern?(filter_reader, ancestors, node),
12
+ ].all?
13
+ end
14
+
15
+ private
16
+
17
+ #
18
+ # @param [CqlRuby::FilterReader] filter_reader
19
+ # @param [Array<Parser::AST::Node>] ancestors
20
+ #
21
+ # @return [Boolean]
22
+ #
23
+ def pass_type?(filter_reader, ancestors)
24
+ return true unless filter_reader.restrict_types?
25
+
26
+ filter_reader.allowed_types.include?(ancestors.last.type)
27
+ end
28
+
29
+ #
30
+ # @param [CqlRuby::FilterReader] filter_reader
31
+ # @param [Array<Parser::AST::Node>] ancestors
32
+ #
33
+ # @return [Boolean]
34
+ #
35
+ def pass_nesting?(filter_reader, ancestors)
36
+ return true unless filter_reader.restrict_nesting?
37
+
38
+ filter_reader.nest_under.all? do |nest_rule|
39
+ ancestors.reverse.any? do |ancestor|
40
+ next false unless ancestor.type.to_s == nest_rule.type
41
+ next true unless nest_rule.restrict_name?
42
+
43
+ if %w[class module].include?(nest_rule.type)
44
+ CqlRuby::PatternMatcher.match?(nest_rule.name, ancestor.children[0].children[1])
45
+ elsif %[def].include?(nest_rule.type)
46
+ CqlRuby::PatternMatcher.match?(nest_rule.name, ancestor.children[0])
47
+ else
48
+ raise 'Unknown type.'
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ #
55
+ # @param [CqlRuby::FilterReader] filter_reader
56
+ # @param [Array<Parser::AST::Node>] ancestors
57
+ # @param [Any<Parser::AST::Node, Symbol>] node
58
+ #
59
+ def pass_has?(filter_reader, ancestors, node)
60
+ return true unless filter_reader.restrict_children?
61
+
62
+ filter_reader.has_leaves.all? do |has_rule|
63
+ anchor_node = if node.is_a?(Symbol)
64
+ try_get_class(ancestors) || try_get_module(ancestors) || try_get_def(ancestors)
65
+ else
66
+ node
67
+ end
68
+ next false unless anchor_node
69
+
70
+ has_node_with_name?(anchor_node, has_rule)
71
+ end
72
+ end
73
+
74
+ #
75
+ # @param [CqlRuby::FilterReader] filter_reader
76
+ # @param [Array<Parser::AST::Node>] ancestors
77
+ # @param [Any<Parser::AST::Node, Symbol>] node
78
+ #
79
+ def pass_pattern?(filter_reader, ancestors, node)
80
+ return true unless filter_reader.restrict_pattern?
81
+
82
+ filter_reader.patterns.all? do |pattern|
83
+ pattern_ancestors = pattern.ancestors.dup
84
+ ancestor_idx = ancestors.size - 1
85
+
86
+ while !pattern_ancestors.empty? && ancestor_idx >= 0
87
+ if CqlRuby::PatternMatcher.match?(pattern_ancestors.last, ancestors[ancestor_idx].type)
88
+ pattern_ancestors.pop
89
+ end
90
+
91
+ ancestor_idx -= 1
92
+ end
93
+ return false unless pattern_ancestors.empty?
94
+
95
+ pattern_descendants = pattern.descendants.dup
96
+ match_descendant_pattern?(pattern_descendants, node)
97
+ end
98
+ end
99
+
100
+ #
101
+ # @param [Array<String>] pattern_descendants
102
+ # @param [Parser::AST::Node] node
103
+ #
104
+ def match_descendant_pattern?(pattern_descendants, node)
105
+ return true if pattern_descendants.empty?
106
+ # If we're at the end and we're still expecting a type - no match.
107
+ return false unless node.is_a?(Parser::AST::Node)
108
+
109
+ node.children.any? do |child|
110
+ next false unless child.is_a?(Parser::AST::Node)
111
+ if CqlRuby::PatternMatcher.match?(pattern_descendants.first, child.type)
112
+ match_descendant_pattern?(pattern_descendants[1..], child)
113
+ else
114
+ match_descendant_pattern?(pattern_descendants.dup, child)
115
+ end
116
+ end
117
+ end
118
+
119
+ #
120
+ # @param [Array<Parser::AST::Node>] ancestors
121
+ #
122
+ def try_get_class(ancestors)
123
+ return nil unless ancestors.size >= 2
124
+ return nil unless ancestors[-1].type == :const
125
+ return nil unless ancestors[-2].type == :class
126
+
127
+ ancestors[-2].children[2]
128
+ end
129
+
130
+ #
131
+ # @param [Array<Parser::AST::Node>] ancestors
132
+ #
133
+ def try_get_module(ancestors)
134
+ return nil unless ancestors.size >= 2
135
+ return nil unless ancestors[-1].type == :const
136
+ return nil unless ancestors[-2].type == :module
137
+
138
+ ancestors[-2].children[1]
139
+ end
140
+
141
+ #
142
+ # @param [Array<Parser::AST::Node>] ancestors
143
+ #
144
+ def try_get_def(ancestors)
145
+ return nil unless ancestors.size >= 1
146
+ return nil unless ancestors[-1].type == :def
147
+
148
+ ancestors[-1].children[2]
149
+ end
150
+
151
+ #
152
+ # @param [Parser::AST::Node] anchor_node
153
+ # @param [CqlRuby::FilterReader::NodeSpec]
154
+ #
155
+ def has_node_with_name?(anchor_node, has_rule)
156
+ return false unless anchor_node.is_a?(Parser::AST::Node)
157
+
158
+ fn_children_with_type = ->(node) { node.children.map { |child| [child, node.type] } }
159
+ to_visit = fn_children_with_type.call(anchor_node)
160
+
161
+ until to_visit.empty?
162
+ current_node, current_type = to_visit.shift
163
+
164
+ if current_node.is_a?(Parser::AST::Node)
165
+ to_visit += fn_children_with_type.call(current_node)
166
+ else
167
+ if current_type == has_rule.type.to_sym && CqlRuby::PatternMatcher.match?(has_rule.name, current_node)
168
+ return true
169
+ end
170
+ end
171
+ end
172
+
173
+ false
174
+ end
175
+ end
176
+ end
177
+ end