leftovers 0.4.0 → 0.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +37 -4
- data/docs/Configuration.md +75 -11
- data/leftovers.gemspec +1 -0
- data/lib/config/actioncable.yml +4 -0
- data/lib/config/actionmailer.yml +22 -0
- data/lib/config/actionpack.yml +190 -0
- data/lib/config/actionview.yml +64 -0
- data/lib/config/activejob.yml +29 -0
- data/lib/config/activemodel.yml +74 -0
- data/lib/config/activerecord.yml +179 -0
- data/lib/config/activesupport.yml +98 -0
- data/lib/config/haml.yml +2 -0
- data/lib/config/rails.yml +11 -450
- data/lib/config/ruby.yml +6 -0
- data/lib/leftovers/ast/node.rb +18 -4
- data/lib/leftovers/cli.rb +13 -4
- data/lib/leftovers/collector.rb +2 -1
- data/lib/leftovers/config.rb +12 -0
- data/lib/leftovers/config_validator/schema_hash.rb +57 -11
- data/lib/leftovers/definition.rb +6 -6
- data/lib/leftovers/definition_node.rb +36 -0
- data/lib/leftovers/definition_set.rb +15 -8
- data/lib/leftovers/file.rb +2 -3
- data/lib/leftovers/file_collector.rb +10 -5
- data/lib/leftovers/matcher_builders/node.rb +2 -0
- data/lib/leftovers/matcher_builders/node_has_argument.rb +11 -7
- data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +14 -10
- data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +17 -13
- data/lib/leftovers/matcher_builders/node_has_receiver.rb +15 -0
- data/lib/leftovers/matcher_builders/node_type.rb +7 -6
- data/lib/leftovers/matcher_builders/node_value.rb +42 -0
- data/lib/leftovers/matcher_builders.rb +3 -2
- data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +4 -1
- data/lib/leftovers/matchers/node_has_positional_argument.rb +0 -4
- data/lib/leftovers/matchers/node_has_receiver.rb +20 -0
- data/lib/leftovers/matchers/predicate.rb +19 -0
- data/lib/leftovers/matchers.rb +2 -0
- data/lib/leftovers/merged_config.rb +28 -1
- data/lib/leftovers/reporter.rb +56 -4
- data/lib/leftovers/todo_reporter.rb +127 -0
- data/lib/leftovers/value_processors/each_for_definition_set.rb +2 -6
- data/lib/leftovers/value_processors/return_definition.rb +5 -3
- data/lib/leftovers/version.rb +1 -1
- data/lib/leftovers.rb +94 -96
- metadata +31 -5
- data/lib/leftovers/matcher_builders/argument_node_value.rb +0 -21
@@ -91,7 +91,7 @@ module Leftovers
|
|
91
91
|
},
|
92
92
|
'valueType' => {
|
93
93
|
'type' => 'string',
|
94
|
-
'enum' => %w{String Symbol Integer Float}
|
94
|
+
'enum' => %w{String Symbol Integer Float Array Hash Proc}
|
95
95
|
},
|
96
96
|
'valueTypeList' => {
|
97
97
|
'anyOf' => [
|
@@ -110,7 +110,41 @@ module Leftovers
|
|
110
110
|
{ 'type' => 'integer' },
|
111
111
|
{ 'type' => 'number' },
|
112
112
|
{ 'type' => 'boolean' },
|
113
|
-
{ 'type' => 'null' }
|
113
|
+
{ 'type' => 'null' },
|
114
|
+
{ 'allOf' => [
|
115
|
+
{ '$ref' => '#/definitions/stringPattern' },
|
116
|
+
{
|
117
|
+
'type' => 'object',
|
118
|
+
'properties' => {
|
119
|
+
'match' => true, 'matches' => true,
|
120
|
+
'has_prefix' => true, 'has_suffix' => true,
|
121
|
+
'at' => { '$ref' => '#/definitions/argumentPositionList' },
|
122
|
+
'has_value' => { '$ref' => '#/definitions/hasValueList' },
|
123
|
+
'has_receiver' => { '$ref' => '#/definitions/hasValueList' },
|
124
|
+
'type' => { '$ref' => '#/definitions/valueTypeList' },
|
125
|
+
'unless' => { '$ref' => '#/definitions/hasValueList' }
|
126
|
+
},
|
127
|
+
'minProperties' => 1,
|
128
|
+
'additionalProperties' => false,
|
129
|
+
'allOf' => [
|
130
|
+
# incompatible groups
|
131
|
+
{ 'not' => { 'required' => %w{match at} } },
|
132
|
+
{ 'not' => { 'required' => %w{match has_value} } },
|
133
|
+
{ 'not' => { 'required' => %w{match type} } },
|
134
|
+
{ 'not' => { 'required' => %w{matches at} } },
|
135
|
+
{ 'not' => { 'required' => %w{matches has_value} } },
|
136
|
+
{ 'not' => { 'required' => %w{matches type} } },
|
137
|
+
{ 'not' => { 'required' => %w{has_prefix at} } },
|
138
|
+
{ 'not' => { 'required' => %w{has_prefix has_value} } },
|
139
|
+
{ 'not' => { 'required' => %w{has_prefix type} } },
|
140
|
+
{ 'not' => { 'required' => %w{has_suffix at} } },
|
141
|
+
{ 'not' => { 'required' => %w{has_suffix has_value} } },
|
142
|
+
{ 'not' => { 'required' => %w{has_suffix type} } },
|
143
|
+
{ 'not' => { 'required' => %w{at type} } },
|
144
|
+
{ 'not' => { 'required' => %w{has_value type} } }
|
145
|
+
]
|
146
|
+
}
|
147
|
+
] }
|
114
148
|
]
|
115
149
|
},
|
116
150
|
'hasValueList' => {
|
@@ -133,11 +167,14 @@ module Leftovers
|
|
133
167
|
'properties' => {
|
134
168
|
'at' => { '$ref' => '#/definitions/argumentPositionList' },
|
135
169
|
'has_value' => { '$ref' => '#/definitions/hasValueList' },
|
136
|
-
'has_value_type' => { '$ref' => '#/definitions/valueTypeList' },
|
137
170
|
'unless' => { '$ref' => '#/definitions/hasArgumentList' }
|
138
171
|
},
|
139
172
|
'minProperties' => 1,
|
140
|
-
'additionalProperties' => false
|
173
|
+
'additionalProperties' => false,
|
174
|
+
'allOf' => [
|
175
|
+
# synonyms
|
176
|
+
{ 'not' => { 'required' => %w{has_argument has_arguments} } }
|
177
|
+
]
|
141
178
|
}
|
142
179
|
]
|
143
180
|
},
|
@@ -160,7 +197,8 @@ module Leftovers
|
|
160
197
|
'path' => { '$ref' => '#/definitions/stringList' },
|
161
198
|
'paths' => { '$ref' => '#/definitions/stringList' },
|
162
199
|
'has_argument' => { '$ref' => '#/definitions/hasArgumentList' },
|
163
|
-
'has_arguments' => { '$ref' => '#/definitions/hasArgumentList' }
|
200
|
+
'has_arguments' => { '$ref' => '#/definitions/hasArgumentList' },
|
201
|
+
'has_receiver' => { '$ref' => '#/definitions/hasValueList' }
|
164
202
|
},
|
165
203
|
'minProperties' => 1,
|
166
204
|
'allOf' => [
|
@@ -390,6 +428,7 @@ module Leftovers
|
|
390
428
|
{ 'required' => ['name'] }, { 'required' => ['names'] },
|
391
429
|
{ 'required' => ['path'] }, { 'required' => ['paths'] },
|
392
430
|
{ 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
|
431
|
+
{ 'required' => ['has_receiver'] },
|
393
432
|
{ 'required' => ['unless'] }
|
394
433
|
] },
|
395
434
|
{
|
@@ -399,6 +438,7 @@ module Leftovers
|
|
399
438
|
'name' => true, 'names' => true,
|
400
439
|
'path' => true, 'paths' => true,
|
401
440
|
'has_argument' => true, 'has_arguments' => true,
|
441
|
+
'has_receiver' => true,
|
402
442
|
'unless' => { '$ref' => '#/definitions/ruleMatcherList' }
|
403
443
|
|
404
444
|
},
|
@@ -415,6 +455,7 @@ module Leftovers
|
|
415
455
|
{ 'required' => ['name'] }, { 'required' => ['names'] },
|
416
456
|
{ 'required' => ['path'] }, { 'required' => ['paths'] },
|
417
457
|
{ 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
|
458
|
+
{ 'required' => ['has_receiver'] },
|
418
459
|
{ 'required' => ['unless'] }
|
419
460
|
] },
|
420
461
|
{
|
@@ -424,6 +465,7 @@ module Leftovers
|
|
424
465
|
'name' => true, 'names' => true,
|
425
466
|
'path' => true, 'paths' => true,
|
426
467
|
'has_argument' => true, 'has_arguments' => true,
|
468
|
+
'has_receiver' => true,
|
427
469
|
'unless' => { '$ref' => '#/definitions/ruleMatcherList' },
|
428
470
|
|
429
471
|
'call' => true, 'calls' => true,
|
@@ -445,7 +487,7 @@ module Leftovers
|
|
445
487
|
{ '$ref' => '#/definitions/dynamic' }
|
446
488
|
]
|
447
489
|
},
|
448
|
-
'
|
490
|
+
'keepTestOnly' => {
|
449
491
|
'anyOf' => [
|
450
492
|
{ '$ref' => '#/definitions/string' },
|
451
493
|
{
|
@@ -460,7 +502,8 @@ module Leftovers
|
|
460
502
|
'has_prefix' => true, 'has_suffix' => true, 'matches' => true,
|
461
503
|
'path' => true, 'paths' => true,
|
462
504
|
'has_argument' => true, 'has_arguments' => true,
|
463
|
-
'
|
505
|
+
'has_receiver' => true,
|
506
|
+
'unless' => { '$ref' => '#/definitions/keepTestOnlyList' }
|
464
507
|
},
|
465
508
|
'additionalProperties' => false,
|
466
509
|
'minProperties' => 1
|
@@ -469,15 +512,15 @@ module Leftovers
|
|
469
512
|
}
|
470
513
|
]
|
471
514
|
},
|
472
|
-
'
|
515
|
+
'keepTestOnlyList' => {
|
473
516
|
'anyOf' => [
|
474
517
|
{
|
475
518
|
'type' => 'array',
|
476
|
-
'items' => { '$ref' => '#/definitions/
|
519
|
+
'items' => { '$ref' => '#/definitions/keepTestOnly' },
|
477
520
|
'minItems' => 1,
|
478
521
|
'uniqueItems' => true
|
479
522
|
},
|
480
|
-
{ '$ref' => '#/definitions/
|
523
|
+
{ '$ref' => '#/definitions/keepTestOnly' }
|
481
524
|
]
|
482
525
|
}
|
483
526
|
},
|
@@ -485,9 +528,12 @@ module Leftovers
|
|
485
528
|
'include_paths' => { '$ref' => '#/definitions/stringList' },
|
486
529
|
'exclude_paths' => { '$ref' => '#/definitions/stringList' },
|
487
530
|
'test_paths' => { '$ref' => '#/definitions/stringList' },
|
531
|
+
'haml_paths' => { '$ref' => '#/definitions/stringList' },
|
532
|
+
'erb_paths' => { '$ref' => '#/definitions/stringList' },
|
488
533
|
'requires' => { '$ref' => '#/definitions/stringList' },
|
489
534
|
'gems' => { '$ref' => '#/definitions/stringList' },
|
490
|
-
'keep' => { '$ref' => '#/definitions/
|
535
|
+
'keep' => { '$ref' => '#/definitions/keepTestOnlyList' },
|
536
|
+
'test_only' => { '$ref' => '#/definitions/keepTestOnlyList' },
|
491
537
|
'dynamic' => { '$ref' => '#/definitions/dynamicList' }
|
492
538
|
}
|
493
539
|
}.freeze
|
data/lib/leftovers/definition.rb
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
module Leftovers
|
4
4
|
class Definition
|
5
|
-
attr_reader :name, :test, :location_s
|
5
|
+
attr_reader :name, :test, :location_s, :source_line
|
6
6
|
alias_method :names, :name
|
7
7
|
|
8
8
|
alias_method :test?, :test
|
9
9
|
|
10
10
|
def initialize(
|
11
11
|
name,
|
12
|
-
method_node: nil,
|
13
12
|
location: method_node.loc.expression,
|
14
|
-
test: method_node.
|
13
|
+
test: method_node.test_line?
|
15
14
|
)
|
16
15
|
@name = name
|
17
|
-
@
|
16
|
+
@path = location.source_buffer.name.to_s
|
17
|
+
@source_line = location.source_line.to_s
|
18
18
|
@location_column_range_begin = location.column_range.begin.to_i
|
19
19
|
@location_column_range_end = location.column_range.end.to_i
|
20
20
|
@location_source = location.source.to_s
|
@@ -29,9 +29,9 @@ module Leftovers
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def highlighted_source(highlight = "\e[31m", normal = "\e[0m")
|
32
|
-
@
|
32
|
+
@source_line[0...@location_column_range_begin].lstrip +
|
33
33
|
highlight + @location_source + normal +
|
34
|
-
@
|
34
|
+
@source_line[@location_column_range_end..-1].rstrip
|
35
35
|
end
|
36
36
|
|
37
37
|
def in_collection?
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
# To give to matchers before creating a Definition
|
4
|
+
|
5
|
+
module Leftovers
|
6
|
+
class DefinitionNode
|
7
|
+
attr_reader :path, :name
|
8
|
+
|
9
|
+
def initialize(name, path)
|
10
|
+
@name = name
|
11
|
+
@path = path
|
12
|
+
|
13
|
+
freeze
|
14
|
+
end
|
15
|
+
|
16
|
+
# these are the methods checked by things in lib/leftovers/matchers
|
17
|
+
def kwargs
|
18
|
+
nil
|
19
|
+
end
|
20
|
+
|
21
|
+
def positional_arguments
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
# these two i'm not sure are possible with the current config flags
|
26
|
+
# :nocov:
|
27
|
+
def scalar?
|
28
|
+
false
|
29
|
+
end
|
30
|
+
|
31
|
+
def type
|
32
|
+
:leftovers_definition
|
33
|
+
end
|
34
|
+
# :nocov:
|
35
|
+
end
|
36
|
+
end
|
@@ -1,18 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Leftovers
|
4
|
-
class DefinitionSet
|
4
|
+
class DefinitionSet
|
5
5
|
attr_reader :definitions
|
6
6
|
|
7
|
-
def initialize(
|
8
|
-
definitions,
|
9
|
-
method_node: nil,
|
10
|
-
location: method_node.loc.expression,
|
11
|
-
test: method_node.test?
|
12
|
-
)
|
7
|
+
def initialize(definitions)
|
13
8
|
@definitions = definitions
|
14
9
|
|
15
|
-
|
10
|
+
freeze
|
16
11
|
end
|
17
12
|
|
18
13
|
def names
|
@@ -23,10 +18,22 @@ module Leftovers
|
|
23
18
|
@definitions.map(&:to_s).join(', ')
|
24
19
|
end
|
25
20
|
|
21
|
+
def location_s
|
22
|
+
@definitions.first.location_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def highlighted_source(*args)
|
26
|
+
@definitions.first.highlighted_source(*args)
|
27
|
+
end
|
28
|
+
|
26
29
|
def in_collection?
|
27
30
|
@definitions.any?(&:in_collection?)
|
28
31
|
end
|
29
32
|
|
33
|
+
def test?
|
34
|
+
@definitions.any?(&:test?)
|
35
|
+
end
|
36
|
+
|
30
37
|
def in_test_collection?
|
31
38
|
@definitions.any?(&:in_test_collection?)
|
32
39
|
end
|
data/lib/leftovers/file.rb
CHANGED
@@ -15,10 +15,9 @@ module Leftovers
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def ruby
|
18
|
-
|
19
|
-
when '.haml'
|
18
|
+
if Leftovers.config.haml_paths.allowed?(relative_path)
|
20
19
|
::Leftovers::Haml.precompile(read, self)
|
21
|
-
|
20
|
+
elsif Leftovers.config.erb_paths.allowed?(relative_path)
|
22
21
|
::Leftovers::ERB.precompile(read)
|
23
22
|
else
|
24
23
|
read
|
@@ -57,7 +57,7 @@ module Leftovers
|
|
57
57
|
NAME_RE = Regexp.union(METHOD_NAME_RE, NON_ALNUM_METHOD_NAME_RE, CONSTANT_NAME_RE)
|
58
58
|
LEFTOVERS_CALL_RE = /\bleftovers:call(?:s|ed|er|ers|) (#{NAME_RE}(?:[, :]+#{NAME_RE})*)/.freeze
|
59
59
|
LEFTOVERS_ALLOW_RE = /\bleftovers:(?:keeps?|skip(?:s|ped|)|allow(?:s|ed|))\b/.freeze
|
60
|
-
LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing)\b/.freeze
|
60
|
+
LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing|test_only)\b/.freeze
|
61
61
|
def process_comments(comments) # rubocop:disable Metrics/AbcSize
|
62
62
|
comments.each do |comment|
|
63
63
|
@allow_lines << comment.loc.line if comment.text.match?(LEFTOVERS_ALLOW_RE)
|
@@ -171,15 +171,20 @@ module Leftovers
|
|
171
171
|
|
172
172
|
private
|
173
173
|
|
174
|
-
def
|
175
|
-
@file.test? ||
|
174
|
+
def test_line?(loc)
|
175
|
+
@file.test? ||
|
176
|
+
@test_lines.include?(loc.line)
|
177
|
+
end
|
178
|
+
|
179
|
+
def test_node?(node, loc)
|
180
|
+
test_line?(loc) || ::Leftovers.config.test_only === node
|
176
181
|
end
|
177
182
|
|
178
183
|
def add_definition(node, name: node.name, loc: node.loc.name)
|
179
184
|
return if @allow_lines.include?(loc.line)
|
180
185
|
return if Leftovers.config.keep === node
|
181
186
|
|
182
|
-
definitions << Leftovers::Definition.new(name, location: loc, test:
|
187
|
+
definitions << Leftovers::Definition.new(name, location: loc, test: test_node?(node, loc))
|
183
188
|
end
|
184
189
|
|
185
190
|
def add_call(name)
|
@@ -222,7 +227,7 @@ module Leftovers
|
|
222
227
|
|
223
228
|
def collect_dynamic(node) # rubocop:disable Metrics/AbcSize
|
224
229
|
node.keep_line = @allow_lines.include?(node.loc.line)
|
225
|
-
node.
|
230
|
+
node.test_line = test_line?(node.loc) unless node.keep_line?
|
226
231
|
|
227
232
|
Leftovers.config.dynamic.process(node, self)
|
228
233
|
rescue StandardError => e
|
@@ -21,6 +21,7 @@ module Leftovers
|
|
21
21
|
names: nil, match: nil, has_prefix: nil, has_suffix: nil,
|
22
22
|
paths: nil,
|
23
23
|
has_arguments: nil,
|
24
|
+
has_receiver: nil,
|
24
25
|
unless_arg: nil
|
25
26
|
)
|
26
27
|
::Leftovers::MatcherBuilders::And.build([
|
@@ -30,6 +31,7 @@ module Leftovers
|
|
30
31
|
]),
|
31
32
|
::Leftovers::MatcherBuilders::NodePath.build(paths),
|
32
33
|
::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
|
34
|
+
::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
|
33
35
|
::Leftovers::MatcherBuilders::Unless.build(
|
34
36
|
(::Leftovers::MatcherBuilders::Node.build(unless_arg) if unless_arg)
|
35
37
|
)
|
@@ -26,6 +26,8 @@ module Leftovers
|
|
26
26
|
|
27
27
|
::Leftovers.each_or_self(at) do |k|
|
28
28
|
case k
|
29
|
+
when '*'
|
30
|
+
positions << k
|
29
31
|
when ::String, ::Hash
|
30
32
|
keys << k
|
31
33
|
when ::Integer
|
@@ -35,23 +37,25 @@ module Leftovers
|
|
35
37
|
# :nocov:
|
36
38
|
end
|
37
39
|
end
|
40
|
+
|
38
41
|
keys = nil if keys.empty?
|
39
42
|
positions = nil if positions.empty?
|
40
43
|
|
41
44
|
[keys, positions]
|
42
45
|
end
|
43
46
|
|
44
|
-
def self.build_from_hash(
|
47
|
+
def self.build_from_hash( # rubocop:disable Metrics/MethodLength
|
48
|
+
at: nil,
|
49
|
+
has_value: nil,
|
50
|
+
unless_arg: nil
|
51
|
+
)
|
45
52
|
keys, positions = separate_argument_types(at)
|
46
53
|
|
47
|
-
value_matcher = ::Leftovers::MatcherBuilders::
|
48
|
-
::Leftovers::MatcherBuilders::ArgumentNodeValue.build(has_value),
|
49
|
-
::Leftovers::MatcherBuilders::NodeType.build(has_value_type)
|
50
|
-
])
|
54
|
+
value_matcher = ::Leftovers::MatcherBuilders::NodeValue.build(has_value)
|
51
55
|
matcher = if (keys && positions) || (!keys && !positions)
|
52
56
|
::Leftovers::MatcherBuilders::Or.build([
|
53
|
-
::Leftovers::MatcherBuilders::
|
54
|
-
::Leftovers::MatcherBuilders::
|
57
|
+
::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher),
|
58
|
+
::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
|
55
59
|
])
|
56
60
|
elsif keys
|
57
61
|
::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
|
@@ -3,19 +3,23 @@
|
|
3
3
|
module Leftovers
|
4
4
|
module MatcherBuilders
|
5
5
|
module NodeHasKeywordArgument
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
class << self
|
7
|
+
def build(keywords, value_matcher) # rubocop:disable Metrics/MethodLength
|
8
|
+
value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
|
9
|
+
keyword_matcher = if ::Leftovers.each_or_self(keywords).any? { |x| x == '**' }
|
10
|
+
::Leftovers::Matchers::NodeType.new(:pair)
|
11
|
+
else
|
12
|
+
::Leftovers::MatcherBuilders::NodePairName.build(keywords)
|
13
|
+
end
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# :nocov:
|
14
|
-
raise unless pair_matcher
|
15
|
+
pair_matcher = ::Leftovers::MatcherBuilders::And.build([
|
16
|
+
keyword_matcher, value_matcher
|
17
|
+
])
|
15
18
|
|
16
|
-
|
19
|
+
return nil unless pair_matcher
|
17
20
|
|
18
|
-
|
21
|
+
::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -3,20 +3,24 @@
|
|
3
3
|
module Leftovers
|
4
4
|
module MatcherBuilders
|
5
5
|
module NodeHasPositionalArgument
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
::Leftovers::
|
10
|
-
|
11
|
-
|
12
|
-
|
6
|
+
class << self
|
7
|
+
def build(positions, value_matcher) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
8
|
+
if positions && value_matcher
|
9
|
+
::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |pos|
|
10
|
+
if pos == '*'
|
11
|
+
::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
|
12
|
+
else
|
13
|
+
::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(pos, value_matcher)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
elsif positions
|
17
|
+
pos = 0 if ::Leftovers.each_or_self(positions).any? { |x| x == '*' }
|
18
|
+
pos ||= ::Leftovers.each_or_self(positions).min
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
else raise
|
19
|
-
# :nocov:
|
20
|
+
::Leftovers::Matchers::NodeHasPositionalArgument.new(pos)
|
21
|
+
elsif value_matcher
|
22
|
+
::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module MatcherBuilders
|
5
|
+
module NodeHasReceiver
|
6
|
+
class << self
|
7
|
+
def build(pattern)
|
8
|
+
matcher = ::Leftovers::MatcherBuilders::NodeValue.build(pattern)
|
9
|
+
|
10
|
+
::Leftovers::Matchers::NodeHasReceiver.new(matcher) if matcher
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,18 +5,19 @@ require 'set'
|
|
5
5
|
module Leftovers
|
6
6
|
module MatcherBuilders
|
7
7
|
module NodeType
|
8
|
-
def self.build(types_pattern)
|
8
|
+
def self.build(types_pattern) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
9
9
|
::Leftovers::MatcherBuilders::Or.each_or_self(types_pattern) do |type|
|
10
10
|
case type
|
11
11
|
when 'Symbol' then ::Leftovers::Matchers::NodeType.new(:sym)
|
12
12
|
when 'String' then ::Leftovers::Matchers::NodeType.new(:str)
|
13
13
|
when 'Integer' then ::Leftovers::Matchers::NodeType.new(:int)
|
14
14
|
when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# when '
|
15
|
+
when 'Array' then ::Leftovers::Matchers::NodeType.new(:array)
|
16
|
+
when 'Hash' then ::Leftovers::Matchers::NodeType.new(:hash)
|
17
|
+
|
18
|
+
when 'Proc' then ::Leftovers::Matchers::Predicate.new(:proc?)
|
19
|
+
# when 'Method' then ::Leftovers::Matchers::NodeType.new(Set[:send, :csend, :def])
|
20
|
+
# when 'Constant' then ::Leftovers::Matchers::NodeType.new(Set[:const, :class, :module])
|
20
21
|
# :nocov:
|
21
22
|
else raise
|
22
23
|
# :nocov:
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module MatcherBuilders
|
5
|
+
module NodeValue
|
6
|
+
class << self
|
7
|
+
def build(pattern) # rubocop:disable Metrics/MethodLength
|
8
|
+
::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
|
9
|
+
case pat
|
10
|
+
when ::Integer, true, false, nil
|
11
|
+
::Leftovers::Matchers::NodeScalarValue.new(pat)
|
12
|
+
when ::String
|
13
|
+
::Leftovers::MatcherBuilders::NodeName.build(pat)
|
14
|
+
when ::Hash
|
15
|
+
build_from_hash(pat)
|
16
|
+
# :nocov:
|
17
|
+
else raise
|
18
|
+
# :nocov:
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def build_from_hash(pat) # rubocop:disable Metrics/MethodLength
|
26
|
+
matcher = ::Leftovers::MatcherBuilders::And.build([
|
27
|
+
::Leftovers::MatcherBuilders::NodeHasArgument.build(pat.slice(:at, :has_value)),
|
28
|
+
::Leftovers::MatcherBuilders::NodeName.build(
|
29
|
+
pat.slice(:match, :has_prefix, :has_suffix)
|
30
|
+
),
|
31
|
+
::Leftovers::MatcherBuilders::NodeType.build(pat[:type]),
|
32
|
+
::Leftovers::MatcherBuilders::NodeHasReceiver.build(pat[:has_receiver])
|
33
|
+
])
|
34
|
+
|
35
|
+
::Leftovers::MatcherBuilders::AndNot.build(
|
36
|
+
matcher, ::Leftovers::MatcherBuilders::NodeValue.build(pat[:unless_arg])
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,17 +4,18 @@ module Leftovers
|
|
4
4
|
module MatcherBuilders
|
5
5
|
autoload(:AndNot, "#{__dir__}/matcher_builders/and_not")
|
6
6
|
autoload(:And, "#{__dir__}/matcher_builders/and")
|
7
|
-
autoload(:ArgumentNodeValue, "#{__dir__}/matcher_builders/argument_node_value")
|
8
7
|
autoload(:Name, "#{__dir__}/matcher_builders/name")
|
8
|
+
autoload(:Node, "#{__dir__}/matcher_builders/node")
|
9
9
|
autoload(:NodeHasArgument, "#{__dir__}/matcher_builders/node_has_argument")
|
10
10
|
autoload(:NodeHasKeywordArgument, "#{__dir__}/matcher_builders/node_has_keyword_argument")
|
11
11
|
autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
|
12
|
+
autoload(:NodeHasReceiver, "#{__dir__}/matcher_builders/node_has_receiver")
|
12
13
|
autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
|
13
14
|
autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
|
14
15
|
autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
|
15
16
|
autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
|
16
17
|
autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
|
17
|
-
autoload(:
|
18
|
+
autoload(:NodeValue, "#{__dir__}/matcher_builders/node_value")
|
18
19
|
autoload(:Or, "#{__dir__}/matcher_builders/or")
|
19
20
|
autoload(:Path, "#{__dir__}/matcher_builders/path")
|
20
21
|
autoload(:StringPattern, "#{__dir__}/matcher_builders/string_pattern")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module Matchers
|
5
|
+
class NodeHasReceiver
|
6
|
+
def initialize(matcher)
|
7
|
+
@matcher = matcher
|
8
|
+
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def ===(node)
|
13
|
+
receiver = node.receiver
|
14
|
+
@matcher === receiver if receiver
|
15
|
+
end
|
16
|
+
|
17
|
+
freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module Matchers
|
5
|
+
class Predicate
|
6
|
+
def initialize(predicate)
|
7
|
+
@predicate = predicate
|
8
|
+
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def ===(node)
|
13
|
+
node.send(@predicate)
|
14
|
+
end
|
15
|
+
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/leftovers/matchers.rb
CHANGED
@@ -15,6 +15,7 @@ module Leftovers
|
|
15
15
|
"#{__dir__}/matchers/node_has_positional_argument_with_value"
|
16
16
|
)
|
17
17
|
autoload(:NodeHasPositionalArgument, "#{__dir__}/matchers/node_has_positional_argument")
|
18
|
+
autoload(:NodeHasReceiver, "#{__dir__}/matchers/node_has_receiver")
|
18
19
|
autoload(:NodeName, "#{__dir__}/matchers/node_name")
|
19
20
|
autoload(:NodePairValue, "#{__dir__}/matchers/node_pair_value")
|
20
21
|
autoload(:NodePath, "#{__dir__}/matchers/node_path")
|
@@ -22,5 +23,6 @@ module Leftovers
|
|
22
23
|
autoload(:NodeType, "#{__dir__}/matchers/node_type")
|
23
24
|
autoload(:Not, "#{__dir__}/matchers/not")
|
24
25
|
autoload(:Or, "#{__dir__}/matchers/or")
|
26
|
+
autoload(:Predicate, "#{__dir__}/matchers/predicate")
|
25
27
|
end
|
26
28
|
end
|