leftovers 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 392cec9799ddf44fd1b532c714e70bdeb5bcd56d68843015fd45ab12aa747813
4
- data.tar.gz: 2b34e3689fa2a376e83372234b936f0f9d0a4f0db1bd01f3cd4f48191f8d4f49
3
+ metadata.gz: b87286f8934cc673a0c9ccea260ac5bee0117230cf21917d244eb6988b70aede
4
+ data.tar.gz: c2daf36aaec3ffe393e4adab37bc80ba8bb5a5ffed2f1c94977a3138bbecde05
5
5
  SHA512:
6
- metadata.gz: a8a681a625180b33210f36f74f2d5a2da5ade1955adbf357f9feefdd03fb32ea7088a57392056d4c31d6e937f4dbde79e54547ee80323ae8dd5d16997accea49
7
- data.tar.gz: 1679d83c75a635bf12b2978bb415ae2d5f7280b5a162df16529058af2d3b0b814762e8710704cca3f84aa75e7d4809d396ee1baaa094a618544365fe47e21f77
6
+ metadata.gz: aca4a439cdbf92fbf6589bf2b9459d209e8ea3affd75bf432648110b58845870f06f80b9815bd1a5404e995a1f4a576885291cffbd1390d45c38f3ff658b9185
7
+ data.tar.gz: 464a65edd31f10324be77be82b5d28c3632b7b0f691e6268903d9b00190bed3e7c553f6301760c9222dceda12d62e4dba7e927d7dd717300b6effac3e57c790c
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # v0.2.0
2
+
3
+ Play nice with rubocop
4
+
5
+ # v0.1.0
6
+
7
+ Initial release
data/leftovers.gemspec CHANGED
@@ -16,13 +16,15 @@ Gem::Specification.new do |spec|
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = 'http://github.com/robotdana/leftovers'
19
- spec.metadata['changelog_uri'] = 'http://github.com/robotdana/leftovers/blob/master/CHANGELOG'
19
+ spec.metadata['changelog_uri'] = 'http://github.com/robotdana/leftovers/blob/master/CHANGELOG.md'
20
20
 
21
- # Specify which files should be added to the gem when it is released.
22
- # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
- spec.files = Dir.chdir(::File.expand_path(__dir__)) do
24
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
- end
21
+ spec.files = Dir.glob('{lib,exe}/**/{*,.*}') + %w{
22
+ CHANGELOG.md
23
+ Gemfile
24
+ LICENSE.txt
25
+ README.md
26
+ leftovers.gemspec
27
+ }
26
28
  spec.bindir = 'exe'
27
29
  spec.executables = spec.files.grep(%r{^exe/}) { |f| ::File.basename(f) }
28
30
  spec.require_paths = ['lib']
@@ -33,10 +35,12 @@ Gem::Specification.new do |spec|
33
35
  spec.add_development_dependency 'pry', '~> 0.1'
34
36
  spec.add_development_dependency 'rake', '~> 10.0'
35
37
  spec.add_development_dependency 'rspec', '~> 3.0'
36
- spec.add_development_dependency 'rubocop'
37
- spec.add_development_dependency 'rubocop-rspec'
38
+ spec.add_development_dependency 'rubocop', '~> 0.74'
39
+ spec.add_development_dependency 'rubocop-performance', '~> 1.4'
40
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.35'
41
+
38
42
  spec.add_development_dependency 'spellr', '>= 0.8.1'
39
- spec.add_dependency 'fast_ignore', '>= 0.8.3'
43
+ spec.add_dependency 'fast_ignore', '>= 0.9.0'
40
44
  spec.add_dependency 'parallel'
41
45
  spec.add_dependency 'parser'
42
46
  end
data/lib/config/ruby.yml CHANGED
@@ -29,6 +29,10 @@ rules:
29
29
  - marshal_load # called by Marshal.load
30
30
  - _dump # called by Marshal.dump
31
31
  - _load # called by Marshal.load
32
+ - inherited # called by Subclass < Klass or Class.new(Klass)
33
+ - extended # called by extend Module
34
+ - included # called by include Module
35
+ - $VERBOSE # called by whatever is outputting warnings i guess
32
36
  - name:
33
37
  - send
34
38
  - public_send
@@ -71,7 +71,7 @@ module Leftovers
71
71
  end
72
72
 
73
73
  def prepare_condition(conditions)
74
- Array.wrap(conditions).each do |cond|
74
+ Leftovers.array_wrap(conditions).each do |cond|
75
75
  cond[:has_argument] = HashRule.new(cond[:has_argument]) if cond[:has_argument]
76
76
  end
77
77
  end
@@ -88,7 +88,7 @@ module Leftovers
88
88
  positions = Set.new
89
89
  keywords = []
90
90
 
91
- Array.each_or_self(argument || arguments) do |arg|
91
+ Leftovers.each_or_self(argument || arguments) do |arg|
92
92
  case arg
93
93
  when '*'
94
94
  @all_positions = true
@@ -105,19 +105,21 @@ module Leftovers
105
105
  @keywords = NameRule.new(keywords) unless @all_keywords || keywords.empty?
106
106
  end
107
107
 
108
- def matches(method_node) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
109
- return Array::EMPTY unless all_conditions_match?(method_node)
108
+ def matches(method_node) # rubocop:disable Metrics/MethodLength, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/AbcSize
109
+ return [].freeze unless all_conditions_match?(method_node)
110
110
 
111
111
  result = []
112
112
 
113
113
  if @all_positions
114
- result.gather values(method_node.positional_arguments, method_node)
114
+ result.leftovers_append values(method_node.positional_arguments, method_node)
115
115
  elsif @positions
116
- result.gather values(method_node.positional_arguments_at(@positions).compact, method_node)
116
+ result.leftovers_append(
117
+ values(method_node.positional_arguments_at(@positions).compact, method_node)
118
+ )
117
119
  end
118
120
 
119
121
  if @keywords || @all_keywords || @key
120
- result.gather hash_values(method_node.kwargs, method_node)
122
+ result.leftovers_append hash_values(method_node.kwargs, method_node)
121
123
  end
122
124
  result << method_value(method_node) if @itself
123
125
 
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module AST
5
+ class Builder < ::Parser::Builders::Default
6
+ # Generates {Node} from the given information.
7
+ #
8
+ # @return [Node] the generated node
9
+ def n(type, children, source_map)
10
+ Leftovers::AST::Node.new(type, children, location: source_map)
11
+ end
12
+
13
+ # Don't complain about invalid strings
14
+ def string_value(token)
15
+ value(token)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'parser'
4
4
 
5
- module Parser
5
+ module Leftovers
6
6
  module AST
7
- class Node # rubocop:disable Metrics/ClassLength
7
+ class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength
8
8
  def initialize(type, children = [], properties = {})
9
9
  # ::AST::Node#initialize freezes itself.
10
10
  # so can't use normal memoizations
@@ -3,30 +3,11 @@
3
3
  require 'set'
4
4
 
5
5
  class Array
6
- # concat, # push, # add, #
7
- EMPTY = [].freeze
8
-
9
- def gather(other)
6
+ def leftovers_append(other)
10
7
  case other
11
8
  when Array, Set then concat(other)
12
9
  when nil then self
13
10
  else self.<< other
14
11
  end
15
12
  end
16
-
17
- def self.wrap(value)
18
- case value
19
- when nil then EMPTY
20
- when Array then value
21
- else [value]
22
- end
23
- end
24
-
25
- def self.each_or_self(value, &block)
26
- case value
27
- when nil then nil
28
- when Array then value.each(&block)
29
- else block.call(value)
30
- end
31
- end
32
13
  end
@@ -4,7 +4,8 @@ require 'fast_ignore'
4
4
  require 'set'
5
5
  require 'parser'
6
6
  require 'parser/current'
7
- require_relative 'node'
7
+ require_relative 'ast/builder'
8
+ require_relative 'ast/node'
8
9
  require_relative 'definition'
9
10
 
10
11
  module Leftovers
@@ -33,8 +34,33 @@ module Leftovers
33
34
  }
34
35
  end
35
36
 
37
+ # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
38
+ # but with our builder
39
+ def self.parser # rubocop:disable Metrics/MethodLength
40
+ p = ::Parser::CurrentRuby.new(Leftovers::AST::Builder.new)
41
+ p.diagnostics.all_errors_are_fatal = true
42
+ p.diagnostics.ignore_warnings = true
43
+
44
+ p.diagnostics.consumer = lambda do |diagnostic|
45
+ warn(diagnostic.render)
46
+ end
47
+
48
+ p
49
+ end
50
+ PARSER = parser
51
+
52
+ # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
53
+ # but with our parser
54
+ def parse_with_comments(string, file = '(string)', line = 1)
55
+ PARSER.reset
56
+ source_buffer = ::Parser::CurrentRuby.send(
57
+ :setup_source_buffer, file, line, string, PARSER.default_encoding
58
+ )
59
+ PARSER.parse_with_comments(source_buffer)
60
+ end
61
+
36
62
  def collect
37
- ast, comments = Parser::CurrentRuby.parse_with_comments(@ruby)
63
+ ast, comments = parse_with_comments(@ruby, @file)
38
64
  process_comments(comments)
39
65
  process(ast)
40
66
  rescue Parser::SyntaxError => e
@@ -9,7 +9,7 @@ module Leftovers
9
9
  def initialize(patterns) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/PerceivedComplexity
10
10
  keys = []
11
11
  pairs = []
12
- Array.each_or_self(patterns) do |pat|
12
+ Leftovers.each_or_self(patterns) do |pat|
13
13
  if pat.is_a?(Hash) && pat[:value]
14
14
  pairs << [
15
15
  (NameRule.new(pat[:keyword]) if pat[:keyword]),
@@ -8,7 +8,7 @@ module Leftovers
8
8
  def initialize(patterns) # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
9
9
  regexps = []
10
10
  syms = Set.new
11
- Array.each_or_self(patterns) do |pat|
11
+ Leftovers.each_or_self(patterns) do |pat|
12
12
  case pat
13
13
  when Leftovers::NameRule
14
14
  syms.merge(pat.sym) if pat.sym
@@ -6,7 +6,7 @@ module Leftovers
6
6
  literal_values = Set.new
7
7
  value_types = Set.new
8
8
 
9
- Array.each_or_self(values) do |value|
9
+ Leftovers.each_or_self(values) do |value|
10
10
  case value
11
11
  when Hash
12
12
  raise ArgumentError, "invalid value #{value.inspect}" unless value[:type]
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
- VERSION = '0.1.0'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/leftovers.rb CHANGED
@@ -6,7 +6,7 @@ require_relative './leftovers/collector'
6
6
  require_relative './leftovers/merged_config'
7
7
  require_relative './leftovers/reporter'
8
8
 
9
- module Leftovers
9
+ module Leftovers # rubocop:disable Metrics/ModuleLength
10
10
  module_function
11
11
 
12
12
  class << self
@@ -124,4 +124,20 @@ module Leftovers
124
124
  end
125
125
  end
126
126
  end
127
+
128
+ def each_or_self(value, &block)
129
+ case value
130
+ when nil then nil
131
+ when Array then value.each(&block)
132
+ else yield(value)
133
+ end
134
+ end
135
+
136
+ def array_wrap(value)
137
+ case value
138
+ when nil then [].freeze
139
+ when Array then value
140
+ else [value]
141
+ end
142
+ end
127
143
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leftovers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Sherson
@@ -98,30 +98,44 @@ dependencies:
98
98
  name: rubocop
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ">="
101
+ - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: '0'
103
+ version: '0.74'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ">="
108
+ - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: '0'
110
+ version: '0.74'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop-performance
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.4'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rubocop-rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - ">="
129
+ - - "~>"
116
130
  - !ruby/object:Gem::Version
117
- version: '0'
131
+ version: '1.35'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - ">="
136
+ - - "~>"
123
137
  - !ruby/object:Gem::Version
124
- version: '0'
138
+ version: '1.35'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: spellr
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +156,14 @@ dependencies:
142
156
  requirements:
143
157
  - - ">="
144
158
  - !ruby/object:Gem::Version
145
- version: 0.8.3
159
+ version: 0.9.0
146
160
  type: :runtime
147
161
  prerelease: false
148
162
  version_requirements: !ruby/object:Gem::Requirement
149
163
  requirements:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
- version: 0.8.3
166
+ version: 0.9.0
153
167
  - !ruby/object:Gem::Dependency
154
168
  name: parallel
155
169
  requirement: !ruby/object:Gem::Requirement
@@ -186,24 +200,10 @@ executables:
186
200
  extensions: []
187
201
  extra_rdoc_files: []
188
202
  files:
189
- - ".gitignore"
190
- - ".leftovers.yml"
191
- - ".rspec"
192
- - ".rubocop.yml"
193
- - ".ruby-version"
194
- - ".spellr.yml"
195
- - ".spellr_wordlists/english.txt"
196
- - ".spellr_wordlists/lorem.txt"
197
- - ".spellr_wordlists/ruby.txt"
198
- - ".spellr_wordlists/shell.txt"
199
- - ".travis.yml"
200
- - Configuration.md
203
+ - CHANGELOG.md
201
204
  - Gemfile
202
205
  - LICENSE.txt
203
206
  - README.md
204
- - Rakefile
205
- - bin/console
206
- - bin/setup
207
207
  - exe/leftovers
208
208
  - leftovers.gemspec
209
209
  - lib/config/attr_encrypted.yml
@@ -230,6 +230,8 @@ files:
230
230
  - lib/config/will_paginate.yml
231
231
  - lib/leftovers.rb
232
232
  - lib/leftovers/argument_rule.rb
233
+ - lib/leftovers/ast/builder.rb
234
+ - lib/leftovers/ast/node.rb
233
235
  - lib/leftovers/backports.rb
234
236
  - lib/leftovers/cli.rb
235
237
  - lib/leftovers/collector.rb
@@ -245,7 +247,6 @@ files:
245
247
  - lib/leftovers/hash_rule.rb
246
248
  - lib/leftovers/merged_config.rb
247
249
  - lib/leftovers/name_rule.rb
248
- - lib/leftovers/node.rb
249
250
  - lib/leftovers/rake_task.rb
250
251
  - lib/leftovers/reporter.rb
251
252
  - lib/leftovers/rule.rb
@@ -258,7 +259,7 @@ licenses:
258
259
  metadata:
259
260
  homepage_uri: http://github.com/robotdana/leftovers
260
261
  source_code_uri: http://github.com/robotdana/leftovers
261
- changelog_uri: http://github.com/robotdana/leftovers/blob/master/CHANGELOG
262
+ changelog_uri: http://github.com/robotdana/leftovers/blob/master/CHANGELOG.md
262
263
  post_install_message:
263
264
  rdoc_options: []
264
265
  require_paths:
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- .rspec_status
2
- Gemfile.lock
3
- /pkg/
4
-
data/.leftovers.yml DELETED
@@ -1,19 +0,0 @@
1
- exclude_paths:
2
- - /vendor
3
-
4
- rules:
5
- - skip: true
6
- name:
7
- - add_insert_cmd # called by ::ERB::Compiler
8
- - add_put_cmd # called by ::ERB::Compiler
9
- - Node
10
- - name:
11
- - RUBY_STRING_METHODS
12
- - ACTIVESUPPORT_STRING_METHODS
13
- - CUSTOM_TRANSFORMS
14
- calls:
15
- argument: 1
16
- - name: HASH_VALUE_TRANSFORMS
17
- calls:
18
- argument: 1
19
- add_suffix: _dynamic
data/.rspec DELETED
@@ -1,3 +0,0 @@
1
- --format documentation
2
- --color
3
- --require spec_helper
data/.rubocop.yml DELETED
@@ -1,216 +0,0 @@
1
- require: rubocop-rspec
2
-
3
- # Reference:
4
- # https://rubocop.readthedocs.io/en/latest/
5
-
6
- # Keep this in alphabetical order.
7
- # Each override should have a comment (even if it's just "default is bad")
8
-
9
- AllCops:
10
- NewCops: enable
11
- Exclude:
12
- - db/schema*
13
- - .bundle/**/*
14
- - tmp/**/*
15
- - vendor/**/*
16
- DisplayCopNames: true
17
- DisplayStyleGuide: true
18
- TargetRubyVersion: 2.4
19
-
20
- # all of our layout customisations are because we prefer indentation to be
21
- # always consistently 2 spaces, for blocks, scopes, multiline expressions, etc
22
- # e.g.
23
- # class Klass
24
- # def method(arg1,
25
- # arg2)
26
- # value = if arg1 == 'value' && arg2 == 'value'
27
- # method2
28
- # .method(arg_a, arg_b,
29
- # arg_c, arg_d, keyword1: true,
30
- # keyword2: true) do
31
- # @last = [
32
- # arg_a, arg_b,
33
- # arg_c, arg_d
34
- # ]
35
- # end
36
- # end
37
- # value
38
- # end
39
- # end
40
-
41
- # to match our preference for consistent indentation
42
- Layout/HashAlignment:
43
- EnforcedLastArgumentHashStyle: always_ignore
44
-
45
- # to match our preference for consistent indentation
46
- Layout/ParameterAlignment:
47
- EnforcedStyle: with_fixed_indentation
48
-
49
- # to match our preference for consistent indentation
50
- Layout/BlockAlignment:
51
- EnforcedStyleAlignWith: start_of_block
52
-
53
- # to match our preference for consistent indentation
54
- Layout/CaseIndentation:
55
- EnforcedStyle: end
56
-
57
- # to match our preference for consistent indentation
58
- Layout/EndAlignment:
59
- EnforcedStyleAlignWith: start_of_line
60
-
61
- # Aligning Assignments, etc makes diffs noisy
62
- Layout/ExtraSpacing:
63
- AllowForAlignment: false
64
-
65
- # to match our preference for consistent indentation
66
- Layout/FirstArrayElementLineBreak:
67
- Enabled: true
68
-
69
- # to match our preference for consistent indentation
70
- Layout/FirstHashElementLineBreak:
71
- Enabled: true
72
-
73
- # to match our preference for consistent indentation
74
- Layout/FirstArgumentIndentation:
75
- EnforcedStyle: consistent
76
-
77
- # to match our preference for consistent indentation
78
- Layout/FirstArrayElementIndentation:
79
- EnforcedStyle: consistent
80
-
81
- # to match our preference for consistent indentation
82
- Layout/FirstHashElementIndentation:
83
- EnforcedStyle: consistent
84
-
85
- # to match our preference for consistent indentation
86
- # and hanging assignment looks lost
87
- Layout/MultilineAssignmentLayout:
88
- EnforcedStyle: same_line
89
-
90
- # this changes our preferred:
91
- # value = if thing1 &&
92
- # thing2
93
- # to:
94
- # value = if thing1 &&
95
- # thing2
96
- # even though the IndentationWidth is 2
97
- # but it's right most of the time so I put up with it
98
- Layout/MultilineOperationIndentation:
99
- EnforcedStyle: indented
100
-
101
- Layout/MultilineMethodCallIndentation:
102
- EnforcedStyle: indented
103
-
104
- # Temporarily disable this spec as a recent change has broken it for us:
105
- # https://github.com/rubocop-hq/rubocop/issues/6254
106
- Layout/RescueEnsureAlignment:
107
- Enabled: false
108
-
109
- Metrics:
110
- CountComments: false
111
-
112
- Metrics/BlockLength:
113
- ExcludedMethods:
114
- - configure
115
- - describe
116
- - context
117
- - it
118
-
119
- Layout/LineLength:
120
- Max: 100
121
- IgnoreCopDirectives: true
122
-
123
- Metrics/MethodLength:
124
- Max: 5
125
-
126
- Naming/MethodParameterName:
127
- AllowedNames: [_, io, id, to, by, 'on', in, at, ip, db]
128
-
129
- RSpec:
130
- Enabled: true
131
- Include:
132
- - spec/**/*.rb
133
-
134
- RSpec/DescribeClass:
135
- Enabled: false
136
-
137
- RSpec/ExampleLength:
138
- Enabled: false
139
-
140
- # I misuse matchers often
141
- RSpec/ExpectActual:
142
- Enabled: false
143
-
144
- RSpec/FilePath:
145
- Enabled: false
146
-
147
- # Multiple expectations are useful
148
- # checking you've partially achieved something on the way to completely achieving it is useful for debugging failures
149
- RSpec/MultipleExpectations:
150
- Enabled: false
151
-
152
- # It should be obvious from context. Chill out rubocop
153
- RSpec/NamedSubject:
154
- Enabled: false
155
-
156
-
157
- # This matches the style we've been using all along (ever so slightly more frequently)
158
- Style/Alias:
159
- EnforcedStyle: prefer_alias_method
160
-
161
- Style/CollectionMethods:
162
- Enabled: true
163
-
164
- # we don't rdoc
165
- Style/Documentation:
166
- Enabled: false
167
-
168
- # [a, b].include?(x) is more unclear than a == x || b == x
169
- Style/MultipleComparison:
170
- Enabled: false
171
-
172
- Style/NumericPredicate:
173
- Enabled: false
174
-
175
- # we use %w{} pretty frequently
176
- Style/PercentLiteralDelimiters:
177
- PreferredDelimiters:
178
- default: '{}'
179
- '%w': '{}'
180
- '%W': '{}'
181
- '%i': '{}'
182
- '%I': '{}'
183
- '%r': '{}'
184
-
185
- # We want this to warn to force consistency within the codebase.
186
- Style/SafeNavigation:
187
- Enabled: true
188
-
189
- # different methods calls that do exactly the same thing are a smell, regardless of semantics
190
- Style/SignalException:
191
- EnforcedStyle: only_raise
192
-
193
- # this wants less descriptive names
194
- Style/SingleLineBlockParams:
195
- Enabled: false
196
-
197
- Style/HashEachMethods:
198
- Enabled: true
199
- Style/HashTransformKeys:
200
- Enabled: true
201
- Style/HashTransformValues:
202
- Enabled: true
203
- Lint/RaiseException:
204
- Enabled: true
205
- Lint/StructNewOverride:
206
- Enabled: true
207
-
208
- # hey rubocop you even use parser which uses :true and :false types. no
209
- Lint/BooleanSymbol:
210
- Enabled: false
211
-
212
- Style/DoubleNegation:
213
- Enabled: false
214
-
215
- RSpec/InstanceVariable:
216
- Enabled: false # I'll figure it out soon
data/.ruby-version DELETED
@@ -1 +0,0 @@
1
- 2.5.1
data/.spellr.yml DELETED
@@ -1,13 +0,0 @@
1
- excludes:
2
- - vendor
3
- languages:
4
- english:
5
- locale: [US, AU]
6
- lorem:
7
- includes:
8
- - /spec/
9
- ruby:
10
- includes:
11
- - README.md
12
- - Configuration.md
13
- - '*.yml'
@@ -1,21 +0,0 @@
1
- affixxed
2
- backports
3
- classnames
4
- codebase
5
- esque
6
- gemfile
7
- hashbang
8
- lorem
9
- nocov
10
- noninfringement
11
- precompiled
12
- readme
13
- requirables
14
- rspec
15
- rubo
16
- rvm
17
- sherson
18
- todo
19
- unmemoize
20
- wtf
21
- yml
@@ -1 +0,0 @@
1
- baz
@@ -1,67 +0,0 @@
1
- activesupport
2
- asgn
3
- ast
4
- autolink
5
- bigint
6
- camelcase
7
- camelize
8
- capfile
9
- casgn
10
- cattr
11
- changelog
12
- codespan
13
- configs
14
- coverband
15
- csend
16
- cvasgn
17
- cyclomatic
18
- deconstantize
19
- demodulize
20
- diffable
21
- dstr
22
- dsym
23
- eflipflop
24
- encryptor
25
- gitignore
26
- guardfile
27
- gvasgn
28
- haml
29
- hrule
30
- iflipflop
31
- irange
32
- ivasgn
33
- jbuilder
34
- kwbegin
35
- kwoptarg
36
- kwrestarg
37
- linebreak
38
- lvars
39
- lvasgn
40
- masgn
41
- mattr
42
- memoizations
43
- optarg
44
- postexe
45
- postprocess
46
- precompile
47
- preexe
48
- preload
49
- procarg
50
- pryrc
51
- regexps
52
- resbody
53
- restarg
54
- rhtml
55
- rjs
56
- rspec
57
- rubocop
58
- shadowarg
59
- simplecov
60
- strikethrough
61
- subnodes
62
- syms
63
- titlecase
64
- titleize
65
- usr
66
- vasgn
67
- xstr
@@ -1,3 +0,0 @@
1
- env
2
- euo
3
- usr
data/.travis.yml DELETED
@@ -1,10 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.4
6
- - 2.5
7
- - 2.6
8
- - 2.7
9
- before_install: gem install bundler
10
-
data/Configuration.md DELETED
@@ -1,427 +0,0 @@
1
- # Configuration
2
-
3
- The configuration is read from `.leftovers.yml` in your project root.
4
- Its presence is optional and all of these settings are optional:
5
-
6
- see the [built in config files](https://github.com/robotdana/leftovers/tree/master/lib/config) for examples.
7
-
8
- - [`include_paths:`](#include_paths)
9
- - [`exclude_paths:`](#exclude_paths)
10
- - [`test_paths:`](#test_paths)
11
- - [`gems:`](#gems)
12
- - [`rules:`](#rules)
13
- - [`names:`](#names)
14
- - [`has_prefix](#has_prefix-has_suffix)
15
- - [`has_suffix](#has_prefix-has_suffix)
16
- - [`matches](#matches)
17
- - [`paths:`](#paths)
18
- - [`skip:`](#skip)
19
- - [`calls:`](#calls-defines), [`defines:`](#calls-defines)
20
- - [`arguments:`](#arguments), [`keys:`](#keys-), [`itself:`](#itself-true)
21
- - [`transforms:`](#transforms), [`linked_transforms:`](#linked_transforms)
22
- - `original:`, `add_prefix:`, `add_suffix:`, `delete_prefix:`, `delete_suffix:`, `replace_with:`
23
- - `delete_before:`, `delete_after:`, `downcase:`, `upcase:`, `capitalize:`, `swapcase:`
24
- - `pluralize`, `singularize`, `camelize`, `underscore`, `demodulize`, `deconstantize`
25
- - [`if:`](#if-unless), [`unless:`](#if-unless)
26
- - [`has_argument:`](#has_argument)
27
- - `keyword:`
28
- - [`has_prefix:`](#has_prefix-has_suffix)
29
- - [`has_suffix:`](#has_prefix-has_suffix)
30
- - [`matches:`](#matches)
31
- - `value:`
32
- - [`has_prefix:`](#has_prefix-has_suffix)
33
- - [`has_suffix:`](#has_prefix-has_suffix)
34
- - [`matches:`](#matches)
35
- - `type:`
36
-
37
-
38
- ## `include_paths:`
39
-
40
- List filenames/paths in the gitignore format of files to be checked using a [gitignore-esque format](https://github.com/robotdana/fast_ignore#using-an-includes-list).
41
-
42
- ```yml
43
- include_paths:
44
- - '*.rb'
45
- - '*.rake'
46
- - Gemfile
47
- ```
48
-
49
- Also it will check files with no extension that have `ruby` in the shebang/hashbang, e.g. `#!/usr/bin/env ruby` or `#!/usr/bin/ruby` etc
50
-
51
- ## `exclude_paths:`
52
-
53
- List filenames/paths that match the above that you might want to exclude, using the gitignore format.
54
- By default it will also read your project's .gitignore file and ignore anything there.
55
-
56
- ```yml
57
- exclude_paths:
58
- - /some/long/irrelevant/generated/file
59
- ```
60
-
61
- ## `test_paths:`
62
-
63
- list filenames/paths of test directories that will be used to determine if a method/etc is only tested but not otherwise used.
64
- Also in the gitignore format
65
-
66
- ```yml
67
- test_paths:
68
- - /test/
69
- - /spec/
70
- ```
71
-
72
- ## `gems:`
73
-
74
- By default Leftovers will look at your Gemfile.lock file to find all gem dependencies
75
-
76
- If you don't use bundler, or don't have a Gemfile.lock for some reason, you can still take advantage of the built in handling for certain gems
77
- ```yml
78
- gems:
79
- - rspec
80
- - rails
81
- ```
82
-
83
- ## `rules:`
84
-
85
- This is the most complex part of configuration, and is a list of methods that define/call other methods/classes/etc.
86
- Each must have a list of `names:`. and can optionally be limited to a list of `paths:`.
87
-
88
- This rule can either `skip:` these names, or describe method/class `calls:` and definitions (`defines:`).
89
-
90
- ### `names:`
91
- **required**
92
-
93
- _alias `name:`_
94
-
95
- list methods/classnames/etc that this rule applies to.
96
-
97
- ```yml
98
- rules:
99
- - names:
100
- - initialize
101
- - ClassName
102
- skip: true
103
- - name: respond_to_missing?
104
- skip: true
105
- ```
106
-
107
- #### `has_prefix:`, `has_suffix:`
108
-
109
- To match names other than exact strings, you can use has_suffix or has_prefix or both if you're feeling fancy.
110
-
111
- ```yml
112
- rules:
113
- - names:
114
- - has_suffix: Helper # will match Helper, LinkHelper FormHelper, etc
115
- - has_prefix: be_ # will match be_equal, be_invalid, etc
116
- - { has_prefix: is_, has_suffix: '?' } # will match is_invalid?, is_equal? etc
117
- skip: true
118
- ```
119
-
120
-
121
- #### `matches:`
122
-
123
- if `has_suffix:` and `has_prefix:` isn't enough, you can use `matches:` to supply a regexp.
124
- This string is automatically converted into a ruby regexp and must match the whole method/constant name.
125
- ```yml
126
- rules:
127
- - names:
128
- - matches: 'column_\d+' # will match column_1, column_2, column_99, but not column_left etc
129
- skip: true
130
- ```
131
-
132
- ### `paths:`
133
- _alias `path:`_
134
-
135
- An optional list of paths that limits what paths this method rule can apply to, defined using a .gitignore-esque format
136
-
137
- ```yml
138
- rules:
139
- - name:
140
- - has_suffix: Helper
141
- path: /app/helpers
142
- skip: true
143
- ```
144
-
145
- ### `skip:`
146
-
147
- Skip methods that are called on your behalf by code outside your project, or called dynamically using send with variables.
148
-
149
- You can also skip method calls and definitions in place using [magic comments](https://github.com/robotdana/leftovers/tree/master/README.md#magic-comments).
150
-
151
- ```yml
152
- rules:
153
- - name: initialize
154
- skip: true
155
- ```
156
- ```ruby
157
- def initialize
158
- end
159
- ```
160
-
161
- will not report that you didn't directly use the initialize method
162
-
163
- ### `calls:`, `defines:`
164
- _aliases `call:`, `define:`_
165
- Describe implicitly called and defined methods using these keys. they're structured the same way:
166
-
167
- It must have at least one of `argument:`, `itself: true`, or `keys: '*'` which points to the implied method definition/call.
168
- This value must be a literal string, symbol, or array of strings or symbols.
169
-
170
- #### `arguments:`
171
- _alias `argument:`_
172
-
173
- the position or keyword of the value or values being implicitly called/defined.
174
- it can be a single argument or a list.
175
-
176
- This value must be itself a literal String, Symbol, or Array or Hash whose values are Strings and Symbols or more nested Arrays and Hashes.
177
- Variables and other method calls returning values will be ignored.
178
-
179
- `*` means all positional arguments values. `**` means all keyword arguments values.
180
- Positional arguments start at 1.
181
-
182
- ```yml
183
- rules:
184
- # `send(:my_method, arg)` is equivalent to `my_method(arg)`
185
- - name: send
186
- calls:
187
- argument: 1
188
- ```
189
- ```ruby
190
- user.send(:my_private_method, true)
191
- ```
192
- will count as a call to `my_private_method`.
193
-
194
- ```yml
195
- - name: attr_reader
196
- defines:
197
- arguments: '*'
198
- ```
199
- ```ruby
200
- attr_reader :my_attr, :my_other_attr
201
- ```
202
- will count as a definition of `my_attr` and `my_other_attr` and will need to be used elsewhere or they'll be reported as leftovers.
203
-
204
- ```yml
205
- rules:
206
- - name: validate
207
- calls:
208
- - arguments: ['*', if, unless]
209
- ```
210
- ```ruby
211
- validate :does_not_match_existing_record, if: :new_record?
212
- ```
213
- will count as a call to `does_not_match_existing_record`, and `new_record?`
214
-
215
- ##### Constant assignment.
216
-
217
- In addition to method call arguments, this can be used for constant assignment, as often constant assignment plus class_eval/instance_eval/define_method is used to dry up similar methods.
218
- ```yml
219
- rules:
220
- - name: METHOD_NAMES
221
- defines:
222
- - arguments: 1
223
- add_suffix: _attributes
224
- calls:
225
- - arguments: 1
226
- ```
227
- ```ruby
228
- METHOD_NAMES = %w{user account}.freeze
229
- METHOD_NAMES.each do |method_name|
230
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
231
- def #{method}_attributes
232
- self.#{method}
233
- end
234
- end
235
- end
236
- ```
237
- counts as a definition of `user_attributes` and `account_attributes` and calls to `user` and `account`
238
-
239
- use `arguments: '**'`, and or `keys: true` for assigning hashes
240
- ```yml
241
- rules:
242
- - name: METHOD_NAMES
243
- defines:
244
- - keys: '*'
245
- add_prefix: setup_
246
- calls:
247
- - arguments: '**'
248
- add_prefix: build_
249
- ```
250
- ```ruby
251
- METHOD_NAMES = { user: :login, account: :profile }
252
- METHOD_NAMES.each do |method_name|
253
- class_eval <<~RUBY, __FILE__, __LINE__ + 1
254
- def setup_#{method}
255
- build_#{method}
256
- end
257
- end
258
- end
259
- ```
260
- Would count as defining `setup_user`, and `setup_account` and calling `build_login` and `build_profile`
261
-
262
- #### `itself: true`
263
-
264
- Will supply the method/constant name itself as the thing to be transformed.
265
- The original method/constant name will continue to be defined as normal
266
- ```yml
267
- - name:
268
- has_prefix: be_
269
- calls:
270
- itself: true
271
- delete_prefix: be_
272
- add_suffix: '?'
273
- ```
274
- ```ruby
275
- expect(value).to be_empty
276
- ```
277
- will count `be_empty` as a call to `empty?`
278
-
279
- #### `keys: '*'`
280
- When the keyword argument **keywords** are the thing being called.
281
-
282
- ```yml
283
- rules:
284
- - name: validates
285
- calls:
286
- - arguments: '*'
287
- - keys: '*'
288
- add_suffix: Validator
289
- activesupport: camelize
290
- ```
291
- ```ruby
292
- validates :first_name, :surname, presence: true
293
- ```
294
- will count calls for `validates`, `first_name`, `surname`, and `PresenceValidator`
295
-
296
- #### `transforms:`
297
-
298
- Sometimes the method being called is modified from the literal argument, sometimes that's just appending an `=` and sometimes it's more complex:
299
-
300
- ```yml
301
- - name: attribute
302
- defines:
303
- - argument: 1
304
- transforms:
305
- - original # no transformation
306
- - add_suffix: '?'
307
- - add_suffix: '='
308
- ```
309
- ```ruby
310
- attribute :first_name
311
- ```
312
- will count as a definition of `first_name`, `first_name=` and `first_name?`
313
-
314
- If there is just one transform for the arguments you can remove the `transforms:` keyword and move everything up a level.
315
-
316
- ```yml
317
- - name: attr_writer
318
- defines:
319
- - argument: '*'
320
- add_suffix: '='
321
- ```
322
- ```ruby
323
- attr_writer :first_name, :surname
324
- ```
325
- will count as the definition of `first_name=`, and `surname=`
326
-
327
- | transform | examples | effect |
328
- | --- | --- | --- |
329
- |original| `original`, `original: true` | no change. useful when grouped with other transforms |
330
- |add_prefix| `add_prefix: be_`, `add_prefix: { from_argument: 'to', joiner: '_' }` | adds the prefix string. possibly from another attribute (used for rails' delegate). |
331
- |add_suffix| `add_suffix: '?'`, `add_suffix: Validator` | adds the suffix string. possibly from another attribute. |
332
- |delete_prefix| `delete_prefix: be_` | removes the prefix string. |
333
- |delete_suffix| `delete_suffix: _html` | removes the suffix string. |
334
- |delete_before| `delete_before: '#'` | removes everything up to and including the string. used for rails' routes. |
335
- |delete_after| `delete_after: '#'` | removes everything after to and including the string. used for rails' routes. |
336
- |replace_with| `replace_with: html` | replaces the original string, perhaps because it dynamically calls it |
337
- |downcase| `downcase`, `downcase: true` | calls ruby's `String#downcase` |
338
- |upcase| `upcase`, `upcase: true` | calls ruby's `String#upcase` |
339
- |capitalize| `capitalize`, `capitalize: true` | calls ruby's `String#capitalize` |
340
- |swapcase| `swapcase`, `swapcase: true` | calls ruby's `String#swapcase` |
341
- |pluralize| `pluralize`, `pluralize: true` | calls activesupport's `String#pluralize` extension. Will try to load config/initializers/inflections.rb |
342
- |singularize| `singularize`, `singularize: true` | calls activesupport's `String#singularize` extension. Will try to load config/initializers/inflections.rb |
343
- |camelize| `camelize`, `camelize: true`, `camelcase`, `camelcase: true` | calls activesupport's `String#camelize` extension. Will try to load config/initializers/inflections.rb |
344
- |underscore| `underscore`, `underscore: true` | calls activesupport's `String#underscore` extension. |
345
- |demodulize| `demodulize`, `demodulize: true` | calls activesupport's `String#demodulize` extension. |
346
- |deconstantize| `deconstantize`, `deconstantize: true` | calls activesupport's `String#deconstantize` extension. |
347
- |titleize| `titleize`, `titleize: true`, `titlecase`, `titlecase: true` | calls activesupport's `String#titleize` extension. |
348
- |parameterize| `parameterize`, `parameterize: true` | calls activesupport's `String#parameterize` extension. |
349
-
350
- #### `linked_transforms:`
351
-
352
- This is identical to `transforms:` except that a call to one of the defined methods counts as a call to them all.
353
-
354
- ```yml
355
- - name: attribute
356
- defines:
357
- - argument: 1
358
- linked_transforms:
359
- - original # no transformation
360
- - add_suffix: '?'
361
- - add_suffix: '='
362
- ```
363
- ```ruby
364
- attribute :first_name
365
-
366
- def initialize
367
- self.first_name = 'dana'
368
- end
369
- ```
370
- will count as a definition of `first_name`, `first_name=` and `first_name?`, and because of `linked_transforms` the call to `first_name=` also counts as a call to `first_name?` and `first_name`
371
-
372
- #### `if:`, `unless:`
373
-
374
- Sometimes what to do depends on other arguments than the ones looked at:
375
- e.g. rails' `delegate` method has a `prefix:` argument of its own that is used when defining methods:
376
-
377
- `if:` and `unless:` work the same way and can be given a list or single value of conditions. For a list, all conditions must be met.
378
-
379
- ```yml
380
- rules:
381
- - name: field
382
- calls:
383
- - argument: 1
384
- unless:
385
- has_argument: method
386
- - argument: method
387
- ```
388
- ```ruby
389
- field :first_name
390
- field :family_name, method: :surname
391
- ```
392
- would count calls to `first_name`, and `surname`, but not `family_name`
393
-
394
- ##### `has_argument:`
395
-
396
- has_argument can be given a keyword or list of keywords. or a list of patterns like name.
397
- or to check either the exact value or type of value it can be given `keyword:` and `value:` which also match the patterns like `name:`.
398
- instead of an exact value `value:` can be given a type or list of type.
399
-
400
- This all comes together to give the most complex rule, rails delegate method.
401
- ```yml
402
- rules:
403
- - name: delegate
404
- defines:
405
- - argument: '*'
406
- if:
407
- has_argument:
408
- keyword: prefix
409
- value: true # if the value of the prefix keyword argument is literal true value
410
- add_prefix:
411
- from_argument: to # use the value of the "to" keyword as the prefix
412
- joiner: '_' # joining with _ to the original string
413
- - argument: '*'
414
- if: # if the method call has a prefix keyword argument that is not a literal true value
415
- has_argument:
416
- keyword: prefix
417
- value:
418
- type: [String, Symbol]
419
- add_prefix:
420
- from_argument: prefix # use the value of the "prefix" keyword as the prefix
421
- joiner: '_' # joining with _ to the original string
422
- calls:
423
- - argument: to # consider the to argument called.
424
- - argument: '*'
425
- if:
426
- has_argument: prefix # if there is a prefix, consider the original method called.
427
- ```
data/Rakefile DELETED
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'bundler/setup'
4
- require 'bundler/gem_tasks'
5
- require 'rspec/core/rake_task'
6
- require 'rubocop/rake_task'
7
- require 'spellr/rake_task'
8
- require_relative 'lib/leftovers/rake_task'
9
-
10
- # RuboCop::RakeTask.new
11
- RSpec::Core::RakeTask.new(:spec)
12
- Spellr::RakeTask.generate_task
13
- Leftovers::RakeTask.generate_task(:leftovers, '--no-progress')
14
-
15
- # rubocop is misbehaving currently
16
- task default: %i{spec spellr leftovers}
data/bin/console DELETED
@@ -1,15 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # frozen_string_literal: true
3
-
4
- require 'bundler/setup'
5
- require 'leftovers'
6
-
7
- # You can add fixtures and/or initialization code here to make experimenting
8
- # with your gem easier. You can also use a different console, if you like.
9
-
10
- # (If you use this, don't forget to add pry to your Gemfile!)
11
- # require "pry"
12
- # Pry.start
13
-
14
- require 'irb'
15
- IRB.start(__FILE__)
data/bin/setup DELETED
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here