leftovers 0.2.3 → 0.3.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 +8 -0
- data/exe/leftovers +1 -1
- data/leftovers.gemspec +5 -2
- data/lib/config/rails.yml +1 -0
- data/lib/config/ruby.yml +8 -5
- data/lib/config/{selenium.yml → selenium-webdriver.yml} +0 -0
- data/lib/leftovers.rb +22 -17
- data/lib/leftovers/argument_rule.rb +29 -19
- data/lib/leftovers/ast/builder.rb +3 -0
- data/lib/leftovers/ast/node.rb +40 -54
- data/lib/leftovers/backports.rb +8 -28
- data/lib/leftovers/cli.rb +16 -10
- data/lib/leftovers/collector.rb +4 -4
- data/lib/leftovers/config.rb +38 -11
- data/lib/leftovers/core_ext.rb +7 -5
- data/lib/leftovers/definition.rb +7 -7
- data/lib/leftovers/definition_set.rb +0 -4
- data/lib/leftovers/file.rb +1 -1
- data/lib/leftovers/file_collector.rb +13 -16
- data/lib/leftovers/file_list.rb +9 -14
- data/lib/leftovers/haml.rb +9 -12
- data/lib/leftovers/hash_rule.rb +12 -10
- data/lib/leftovers/merged_config.rb +9 -8
- data/lib/leftovers/name_rule.rb +62 -17
- data/lib/leftovers/rake_task.rb +3 -3
- data/lib/leftovers/reporter.rb +1 -1
- data/lib/leftovers/rule.rb +22 -14
- data/lib/leftovers/transform_rule.rb +21 -23
- data/lib/leftovers/value_rule.rb +5 -4
- data/lib/leftovers/version.rb +1 -1
- metadata +49 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07755634c2f0119263912ecb6d90a64d37eea60aca5958f1c5f70555b5f63cb6
|
4
|
+
data.tar.gz: ac46e0dc82c7ed6aa10ca1775ecd1d080a4496fd6cbac942631e065892d8742c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb18eaa912ee5df99a96cb34eb9960e258aeec4e23fb00da879b7ea48cc8e42aaaa27d12dd21beb732e68257690ef2f1a8f71ab27f5402fd47c54768a4f895d4
|
7
|
+
data.tar.gz: d13c59bb909652a4bd0a1b4d46a66fc2faf40625e995dcfea43e60aed2a5fd617d2faf1b02408337837fed630474d0ec5c8c46113013d249648c7271783be74b
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
# v0.3.0
|
2
|
+
- Add simplecov, fix a handful of bugs it found
|
3
|
+
- update fast_ignore
|
4
|
+
|
5
|
+
# v0.2.4
|
6
|
+
- use the right name for selenium-webdriver gem, so the bundler magic can work
|
7
|
+
- handle yaml syntax errors.
|
8
|
+
|
1
9
|
# v0.2.3
|
2
10
|
- restore ability to handle syntax errors. I really need to add coverage to this project
|
3
11
|
- Fix bug with delete_after on an empty string
|
data/exe/leftovers
CHANGED
data/leftovers.gemspec
CHANGED
@@ -35,12 +35,15 @@ Gem::Specification.new do |spec|
|
|
35
35
|
spec.add_development_dependency 'pry', '~> 0.1'
|
36
36
|
spec.add_development_dependency 'rake', '>= 13'
|
37
37
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
38
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
38
|
+
spec.add_development_dependency 'rubocop', '~> 0.82'
|
39
39
|
spec.add_development_dependency 'rubocop-performance', '~> 1.4'
|
40
40
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.35'
|
41
|
+
spec.add_development_dependency 'simplecov', '>= 0.18.5'
|
42
|
+
spec.add_development_dependency 'simplecov-console'
|
43
|
+
spec.add_development_dependency 'tty_string', '>= 0.2.1'
|
41
44
|
|
42
45
|
spec.add_development_dependency 'spellr', '>= 0.8.1'
|
43
|
-
spec.add_dependency 'fast_ignore', '>= 0.
|
46
|
+
spec.add_dependency 'fast_ignore', '>= 0.11.0'
|
44
47
|
spec.add_dependency 'parallel'
|
45
48
|
spec.add_dependency 'parser'
|
46
49
|
end
|
data/lib/config/rails.yml
CHANGED
data/lib/config/ruby.yml
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
---
|
2
2
|
include_paths:
|
3
|
-
- '
|
4
|
-
- Gemfile
|
5
|
-
- '*.erb'
|
3
|
+
- '#!:ruby'
|
6
4
|
- '*.gemspec'
|
7
5
|
- .irbrc
|
8
6
|
- irb.rc
|
9
7
|
- _irbrc
|
10
8
|
- $irbrc
|
9
|
+
- Gemfile
|
10
|
+
- '*.erb'
|
11
|
+
- '*.rb'
|
11
12
|
|
12
13
|
test_paths:
|
13
14
|
- /tests/
|
@@ -61,7 +62,8 @@ rules:
|
|
61
62
|
- name: attr_writer
|
62
63
|
defines:
|
63
64
|
argument: '*'
|
64
|
-
|
65
|
+
transforms:
|
66
|
+
- add_suffix: '='
|
65
67
|
- name: attr_accessor
|
66
68
|
defines:
|
67
69
|
- argument: '*'
|
@@ -70,7 +72,8 @@ rules:
|
|
70
72
|
- add_suffix: '='
|
71
73
|
calls:
|
72
74
|
argument: '*'
|
73
|
-
|
75
|
+
transforms:
|
76
|
+
add_prefix: '@'
|
74
77
|
- name: define_method
|
75
78
|
defines:
|
76
79
|
argument: 1
|
File without changes
|
data/lib/leftovers.rb
CHANGED
@@ -7,15 +7,15 @@ require_relative './leftovers/merged_config'
|
|
7
7
|
require_relative './leftovers/reporter'
|
8
8
|
|
9
9
|
module Leftovers # rubocop:disable Metrics/ModuleLength
|
10
|
+
class Error < StandardError; end
|
11
|
+
class ConfigError < Error; end
|
12
|
+
|
10
13
|
module_function
|
11
14
|
|
12
15
|
class << self
|
13
16
|
attr_accessor :parallel
|
14
17
|
alias_method :parallel?, :parallel
|
15
18
|
|
16
|
-
attr_accessor :quiet
|
17
|
-
alias_method :quiet?, :quiet
|
18
|
-
|
19
19
|
attr_accessor :progress
|
20
20
|
alias_method :progress?, :progress
|
21
21
|
end
|
@@ -50,7 +50,6 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def run(stdout: StringIO.new, stderr: StringIO.new) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
53
|
-
reset
|
54
53
|
@stdout = stdout
|
55
54
|
@stderr = stderr
|
56
55
|
return 0 if leftovers.empty?
|
@@ -87,20 +86,19 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
87
86
|
remove_instance_variable(:@stdout) if defined?(@stdout)
|
88
87
|
remove_instance_variable(:@stderr) if defined?(@stderr)
|
89
88
|
remove_instance_variable(:@parallel) if defined?(@parallel)
|
90
|
-
remove_instance_variable(:@quiet) if defined?(@quiet)
|
91
89
|
remove_instance_variable(:@pwd) if defined?(@pwd)
|
92
90
|
end
|
93
91
|
|
94
92
|
def warn(message)
|
95
|
-
stderr.puts("\e[2K#{message}")
|
93
|
+
stderr.puts("\e[2K#{message}")
|
96
94
|
end
|
97
95
|
|
98
96
|
def puts(message)
|
99
|
-
stdout.puts("\e[2K#{message}")
|
97
|
+
stdout.puts("\e[2K#{message}")
|
100
98
|
end
|
101
99
|
|
102
100
|
def print(message)
|
103
|
-
stdout.print(message)
|
101
|
+
stdout.print(message)
|
104
102
|
end
|
105
103
|
|
106
104
|
def newline
|
@@ -111,18 +109,25 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
111
109
|
@pwd ||= Pathname.new(Dir.pwd + '/')
|
112
110
|
end
|
113
111
|
|
114
|
-
def
|
112
|
+
def exit(status = 0)
|
113
|
+
throw :leftovers_exit, status
|
114
|
+
end
|
115
|
+
|
116
|
+
def try_require(requirable, message: nil) # rubocop:disable Metrics/MethodLength
|
115
117
|
@try_require ||= {}
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
@try_require[requirable] = false
|
118
|
+
|
119
|
+
@try_require[requirable] = begin
|
120
|
+
if @try_require.key?(requirable)
|
121
|
+
@try_require[requirable]
|
122
|
+
else
|
123
|
+
require requirable
|
124
|
+
true
|
124
125
|
end
|
126
|
+
rescue LoadError
|
127
|
+
false
|
125
128
|
end
|
129
|
+
warn message if !@try_require[requirable] && message
|
130
|
+
@try_require[requirable]
|
126
131
|
end
|
127
132
|
|
128
133
|
def each_or_self(value, &block)
|
@@ -37,7 +37,7 @@ module Leftovers
|
|
37
37
|
@itself = itself
|
38
38
|
|
39
39
|
unless @positions || @keywords || @all_positions || @all_keywords || @key || @itself
|
40
|
-
raise
|
40
|
+
raise Leftovers::ConfigError, "require at least one of 'argument(s)', 'key(s)', itself"
|
41
41
|
end
|
42
42
|
|
43
43
|
@if = prepare_condition(options.delete(:if))
|
@@ -48,7 +48,7 @@ module Leftovers
|
|
48
48
|
|
49
49
|
def prepare_transform(options, transforms, linked_transforms) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
50
50
|
if linked_transforms && transforms
|
51
|
-
raise
|
51
|
+
raise Leftovers::ConfigError, 'Only use one of linked_transforms/transforms'
|
52
52
|
end
|
53
53
|
return if !linked_transforms && !transforms && options.empty?
|
54
54
|
|
@@ -57,7 +57,7 @@ module Leftovers
|
|
57
57
|
else
|
58
58
|
@linked = !!linked_transforms
|
59
59
|
|
60
|
-
transforms = (linked_transforms || transforms).map do |transform|
|
60
|
+
transforms = Leftovers.array_wrap(linked_transforms || transforms).map do |transform|
|
61
61
|
transform = { transform.to_sym => true } if transform.is_a?(String)
|
62
62
|
Leftovers::TransformRule.new(options.merge(transform))
|
63
63
|
end
|
@@ -70,20 +70,26 @@ module Leftovers
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def prepare_condition(conditions)
|
73
|
+
def prepare_condition(conditions) # rubocop:disable Metrics/MethodLength
|
74
74
|
Leftovers.array_wrap(conditions).each do |cond|
|
75
|
-
cond
|
75
|
+
unless cond.is_a?(Hash) && cond.keys == [:has_argument]
|
76
|
+
raise Leftovers::ConfigError, <<~MESSAGE
|
77
|
+
Invalid condition #{cond.inspect}. Valid condition keys are: has_argument
|
78
|
+
MESSAGE
|
79
|
+
end
|
80
|
+
|
81
|
+
cond[:has_argument] = HashRule.new(cond[:has_argument])
|
76
82
|
end
|
77
83
|
end
|
78
84
|
|
79
85
|
def prepare_key(key, keys)
|
80
|
-
raise
|
86
|
+
raise Leftovers::ConfigError, 'Only use one of key/keys' if key && keys
|
81
87
|
|
82
88
|
key || keys
|
83
89
|
end
|
84
90
|
|
85
91
|
def prepare_argument(argument, arguments) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
86
|
-
raise
|
92
|
+
raise Leftovers::ConfigError, 'Only use one of argument/arguments' if argument && arguments
|
87
93
|
|
88
94
|
positions = Set.new
|
89
95
|
keywords = []
|
@@ -98,11 +104,15 @@ module Leftovers
|
|
98
104
|
positions << arg - 1
|
99
105
|
when String, Symbol, Hash
|
100
106
|
keywords << arg
|
107
|
+
else
|
108
|
+
raise Leftovers::ConfigError, <<~MESSAGE
|
109
|
+
Invalid value for argument: #{arg.inspect}. Must by a string ('*', '**', or a keyword), or a hash with the name match rules, or an integer, or an array of these
|
110
|
+
MESSAGE
|
101
111
|
end
|
102
112
|
end
|
103
113
|
|
104
114
|
@positions = positions unless @all_positions || positions.empty? || @all_positions
|
105
|
-
@keywords = NameRule.
|
115
|
+
@keywords = NameRule.wrap(keywords) unless @all_keywords || keywords.empty?
|
106
116
|
end
|
107
117
|
|
108
118
|
def matches(method_node) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
|
@@ -135,13 +145,12 @@ module Leftovers
|
|
135
145
|
@unless.all? { |c| !condition_match?(c, method_node) }
|
136
146
|
end
|
137
147
|
|
138
|
-
def condition_match?(condition,
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
hash_node.each_pair.any? { |key, value| condition[:has_argument].match_pair?(key, value) }
|
148
|
+
def condition_match?(condition, method_node)
|
149
|
+
method_node.positional_arguments.each.with_index(1).any? do |value, index|
|
150
|
+
condition[:has_argument].match_pair?(index, value)
|
151
|
+
end || method_node.kwargs&.each_pair&.any? do |key, value|
|
152
|
+
condition[:has_argument].match_pair?(key.to_sym, value)
|
153
|
+
end
|
145
154
|
end
|
146
155
|
|
147
156
|
def hash_values(hash_node, method_node) # rubocop:disable Metrics/MethodLength
|
@@ -160,8 +169,6 @@ module Leftovers
|
|
160
169
|
end
|
161
170
|
|
162
171
|
def value(value_node, method_node) # rubocop:disable Metrics/MethodLength
|
163
|
-
return unless value_node
|
164
|
-
|
165
172
|
value_node = value_node.unwrap_freeze
|
166
173
|
|
167
174
|
case value_node.type
|
@@ -208,12 +215,15 @@ module Leftovers
|
|
208
215
|
end
|
209
216
|
end
|
210
217
|
|
211
|
-
def assert_valid_keys(options, keys)
|
218
|
+
def assert_valid_keys(options, keys) # rubocop:disable Metrics/MethodLength
|
212
219
|
invalid = options.keys - keys
|
213
220
|
|
214
221
|
return if invalid.empty?
|
215
222
|
|
216
|
-
raise
|
223
|
+
raise(
|
224
|
+
Leftovers::ConfigError,
|
225
|
+
"unknown keyword#{'s' if invalid.length > 1}: #{invalid.join(', ')}"
|
226
|
+
)
|
217
227
|
end
|
218
228
|
end
|
219
229
|
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'node'
|
4
|
+
|
3
5
|
module Leftovers
|
4
6
|
module AST
|
5
7
|
class Builder < ::Parser::Builders::Default
|
6
8
|
# Generates {Node} from the given information.
|
7
9
|
#
|
8
10
|
# @return [Node] the generated node
|
11
|
+
|
9
12
|
def n(type, children, source_map)
|
10
13
|
Leftovers::AST::Node.new(type, children, location: source_map)
|
11
14
|
end
|
data/lib/leftovers/ast/node.rb
CHANGED
@@ -5,6 +5,10 @@ require 'parser'
|
|
5
5
|
module Leftovers
|
6
6
|
module AST
|
7
7
|
class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength
|
8
|
+
# :nocov:
|
9
|
+
using ::Leftovers::SetCaseEq if defined?(::Leftovers::SetCaseEq)
|
10
|
+
# :nocov:
|
11
|
+
|
8
12
|
def initialize(type, children = [], properties = {})
|
9
13
|
# ::AST::Node#initialize freezes itself.
|
10
14
|
# so can't use normal memoizations
|
@@ -17,6 +21,7 @@ module Leftovers
|
|
17
21
|
children.first
|
18
22
|
end
|
19
23
|
|
24
|
+
# TODO: move file to loc.
|
20
25
|
def file
|
21
26
|
@memo[:file]
|
22
27
|
end
|
@@ -35,62 +40,51 @@ module Leftovers
|
|
35
40
|
end
|
36
41
|
|
37
42
|
def to_scalar_value # rubocop:disable Metrics/MethodLength
|
38
|
-
|
39
|
-
when :sym
|
43
|
+
case type
|
44
|
+
when :sym, :int, :float, :str
|
40
45
|
first
|
41
|
-
when :str
|
42
|
-
first.to_s.freeze
|
43
46
|
when :true
|
44
47
|
true
|
45
48
|
when :false
|
46
49
|
false
|
47
50
|
when :nil
|
48
51
|
nil
|
49
|
-
else
|
50
|
-
raise "Not scalar node, (#{type})"
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
54
|
-
def
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
def scalar?
|
56
|
+
case type
|
57
|
+
when :sym, :int, :float, :str, :true, :false, :nil
|
58
|
+
true
|
59
|
+
else false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def to_s
|
64
|
+
@memo[:to_s] ||= name&.to_s || to_scalar_value.to_s || ''
|
62
65
|
end
|
63
66
|
|
64
67
|
def to_sym
|
65
68
|
case type
|
66
|
-
when :
|
69
|
+
when :sym then first
|
67
70
|
when :nil, :true, :false then type
|
68
71
|
else to_s.to_sym
|
69
72
|
end
|
70
73
|
end
|
71
74
|
|
72
|
-
SCALAR_TYPES = %i{sym str true false nil}.freeze
|
73
|
-
def scalar?
|
74
|
-
SCALAR_TYPES.include?(type)
|
75
|
-
end
|
76
|
-
|
77
75
|
def string_or_symbol?
|
78
76
|
type == :str || type == :sym
|
79
77
|
end
|
80
78
|
|
81
|
-
def
|
82
|
-
type == :send || type == :csend
|
83
|
-
end
|
84
|
-
|
85
|
-
def named?
|
86
|
-
send? || type == :casgn
|
87
|
-
end
|
88
|
-
|
89
|
-
def arguments
|
79
|
+
def arguments # rubocop:disable Metrics/MethodLength
|
90
80
|
@memo[:arguments] ||= case type
|
91
81
|
when :send, :csend then children.drop(2)
|
92
82
|
when :casgn then [children[2]]
|
93
|
-
|
83
|
+
when :ivasgn, :cvasgn, :gvasgn then [children[1]]
|
84
|
+
else
|
85
|
+
# :nocov: # these are all the nodes with collect_rules
|
86
|
+
raise "Not argument node (#{type})"
|
87
|
+
# :nocov:
|
94
88
|
end
|
95
89
|
end
|
96
90
|
|
@@ -115,25 +109,18 @@ module Leftovers
|
|
115
109
|
each_pair.map { |k, _| k }
|
116
110
|
end
|
117
111
|
|
118
|
-
def key?(key)
|
119
|
-
each_pair.find do |k, _v|
|
120
|
-
next unless k.string_or_symbol?
|
121
|
-
|
122
|
-
k.to_sym == key
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
112
|
def values
|
113
|
+
# :nocov:
|
127
114
|
@memo[:kwargs] ||= case type
|
115
|
+
# :nocov:
|
128
116
|
when :hash then each_pair.map { |_, v| v }
|
129
117
|
when :array then children
|
130
|
-
else []
|
131
118
|
end
|
132
119
|
end
|
133
120
|
|
134
121
|
def values_at_match(matcher)
|
135
122
|
each_pair.with_object([]) do |(key, value), values|
|
136
|
-
values << value if matcher
|
123
|
+
values << value if matcher === key.to_sym
|
137
124
|
end
|
138
125
|
end
|
139
126
|
|
@@ -142,8 +129,6 @@ module Leftovers
|
|
142
129
|
end
|
143
130
|
|
144
131
|
def each_pair
|
145
|
-
raise "not hash node (#{type})" unless type == :hash
|
146
|
-
|
147
132
|
return enum_for(:each_pair) unless block_given?
|
148
133
|
|
149
134
|
children.each do |pair|
|
@@ -151,22 +136,23 @@ module Leftovers
|
|
151
136
|
end
|
152
137
|
end
|
153
138
|
|
154
|
-
def name
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
139
|
+
def name # rubocop:disable Metrics/MethodLength
|
140
|
+
@memo[:name] ||= case type
|
141
|
+
when :send, :csend, :casgn, :const
|
142
|
+
children[1]
|
143
|
+
when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn
|
144
|
+
first
|
145
|
+
when :module, :class
|
146
|
+
first.name
|
147
|
+
end
|
162
148
|
end
|
163
149
|
|
164
150
|
def [](index) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
151
|
+
# :nocov:
|
165
152
|
case type
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
children[index]
|
153
|
+
# :nocov:
|
154
|
+
when :send, :csend, :casgn, :cvasgn, :ivasgn, :gvasgn
|
155
|
+
index.is_a?(Integer) ? arguments[index - 1] : kwargs && kwargs[index]
|
170
156
|
when :hash
|
171
157
|
each_pair do |key, value|
|
172
158
|
next unless key.string_or_symbol?
|