betterlint 1.24.0 → 1.26.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dedcf1bca77813b532e0523d2c85776697e0a0602faaa7a6939f77d0c1af5d9c
4
- data.tar.gz: 68097f9df8adb9f37db3ecafa2fbec26d1445418bc080f8d879a845557b25f4a
3
+ metadata.gz: 521829c1a24b2013526ec739c7767473854130c2e57f7c29b184011f059264a4
4
+ data.tar.gz: a7cb5622266cc225688096b99811eae23fec5a1af226e410f205986c3d7414ac
5
5
  SHA512:
6
- metadata.gz: '07922a227dc628c4c3fd9389dee5ffbacb56db56cc4e15160db8849a69a21e8102e1b46c9f80bbe1062073e6886832b4ef1978ed4506aa7912edfc9a6948d9e8'
7
- data.tar.gz: 38d4bfc4ea265f2242cbb45b67f9d872dfb4ea7c168b3f729ce121a7f848f2c9b1c7ca2b3df89a2b65969eb9b5994f3f012ab575b3899b9b8e1c2d060a7c76fd
6
+ metadata.gz: cc3c3e063757b97e37257303a939e2d6d13bd8534646c5b0047f2fd58a229979bf2687702025a6d24971dac784b987c2393d67df79bc58875842500d67f55cb0
7
+ data.tar.gz: 0e1171c10b8c6b26f71cc13ddd77694487fce3749e40d84931ad82d90d0f57bf9eaea48bd16504c64695cdc95686932625de0dd4c56853c6bb2bf2807539a6ce
data/README.md CHANGED
@@ -15,9 +15,8 @@ gem 'betterlint'
15
15
  .rubocop.yml:
16
16
 
17
17
  ```yml
18
- inherit_gem:
19
- betterlint:
20
- - config/default.yml
18
+ plugins:
19
+ - betterlint
21
20
  ```
22
21
 
23
22
  ## Dependencies
data/config/default.yml CHANGED
@@ -2,11 +2,16 @@
2
2
 
3
3
  require:
4
4
  - rubocop/cop/betterment.rb
5
+
6
+ plugins:
7
+ - rubocop-capybara
8
+ - rubocop-factory_bot
5
9
  - rubocop-graphql
6
10
  - rubocop-performance
7
11
  - rubocop-rails
8
12
  - rubocop-rake
9
13
  - rubocop-rspec
14
+ - rubocop-rspec_rails
10
15
 
11
16
  AllCops:
12
17
  DisplayCopNames: true
@@ -42,10 +47,9 @@ Betterment/DynamicParams:
42
47
 
43
48
  Betterment/EnvironmentConfiguration:
44
49
  StyleGuide: '#bettermentenvironmentconfiguration'
45
- Exclude:
46
- - config/**/*.rb
47
- - spec/**/*.rb
48
- - test/**/*.rb
50
+ Include:
51
+ - app/**/*.rb
52
+ - lib/**/*.rb
49
53
 
50
54
  Betterment/HardcodedID:
51
55
  AutoCorrect: false
@@ -254,7 +258,7 @@ Metrics/PerceivedComplexity:
254
258
  Naming/HeredocDelimiterNaming:
255
259
  Enabled: false
256
260
 
257
- Naming/PredicateName:
261
+ Naming/PredicatePrefix:
258
262
  ForbiddenPrefixes:
259
263
  - is_
260
264
  NamePrefix:
@@ -269,9 +273,6 @@ Performance/RedundantMatch:
269
273
  RSpec/BeEq:
270
274
  Enabled: false
271
275
 
272
- RSpec/Capybara/FeatureMethods:
273
- Enabled: false
274
-
275
276
  RSpec/ContextWording:
276
277
  Enabled: false
277
278
 
@@ -303,7 +304,7 @@ RSpec/ExpectChange:
303
304
  EnforcedStyle: block
304
305
 
305
306
  RSpec/SpecFilePathSuffix:
306
- Enabled: false
307
+ Enabled: true
307
308
 
308
309
  RSpec/SpecFilePathFormat:
309
310
  Enabled: false
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Betterlint
4
+ VERSION = '1.26.0'
5
+ end
data/lib/betterlint.rb ADDED
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'lint_roller'
4
+ require_relative 'betterlint/version'
5
+
6
+ module Betterlint
7
+ class Plugin < LintRoller::Plugin
8
+ def about
9
+ LintRoller::About.new(
10
+ name: 'betterlint',
11
+ version: VERSION,
12
+ homepage: 'https://github.com/Betterment/betterlint',
13
+ description: 'Shared rubocop configuration for Betterment Rails apps/engines.',
14
+ )
15
+ end
16
+
17
+ def supported?(context)
18
+ context.engine == :rubocop
19
+ end
20
+
21
+ def rules(_context)
22
+ LintRoller::Rules.new(
23
+ type: :path,
24
+ config_format: :rubocop,
25
+ value: File.expand_path('../config/default.yml', __dir__),
26
+ )
27
+ end
28
+ end
29
+ end
@@ -37,17 +37,17 @@ module RuboCop
37
37
  super
38
38
  @unsafe_parameters = cop_config.fetch("unsafe_parameters").map(&:to_sym)
39
39
  @unsafe_regex = Regexp.new cop_config.fetch("unsafe_regex")
40
- @param_wrappers = []
40
+ end
41
+
42
+ def on_new_investigation
43
+ super
44
+ @class_methods = {}.freeze
45
+ @param_wrappers = [].freeze
41
46
  end
42
47
 
43
48
  def on_class(node)
44
- Utils::MethodReturnTable.populate_index node
45
- Utils::MethodReturnTable.indexed_methods.each do |method_name, method_returns|
46
- method_returns.each do |x|
47
- name = Utils::Parser.get_root_token(x)
48
- @param_wrappers << method_name if name == :params || @param_wrappers.include?(name)
49
- end
50
- end
49
+ @class_methods = Utils::Parser.get_instance_methods(node).freeze
50
+ @param_wrappers = find_param_wrappers(@class_methods).freeze
51
51
  end
52
52
 
53
53
  def on_send(node) # rubocop:disable Metrics/PerceivedComplexity
@@ -88,7 +88,7 @@ module RuboCop
88
88
 
89
89
  # Flags objects being created/updated with unsafe
90
90
  # params indirectly from params or through params.permit
91
- def flag_indirect_param_use(node) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
91
+ def flag_indirect_param_use(node) # rubocop:disable Metrics/PerceivedComplexity
92
92
  name = Utils::Parser.get_root_token(node)
93
93
  # extracted_params contains parameters used like:
94
94
  # def create
@@ -99,7 +99,7 @@ module RuboCop
99
99
  # end
100
100
  extracted_params = Utils::Parser.get_extracted_parameters(node, param_aliases: @param_wrappers)
101
101
 
102
- returns = Utils::MethodReturnTable.get_method(name) || []
102
+ returns = get_method_returns(name)
103
103
  returns.each do |ret|
104
104
  # # propagated_params contains parameters used like:
105
105
  # def create
@@ -118,9 +118,9 @@ module RuboCop
118
118
  # params[:user_id]
119
119
  # end
120
120
  if ret.send_type? && ret.method?(:[])
121
- internal_params = ret.arguments.select { |x| x.sym_type? || x.str_type? }.map(&:value)
121
+ internal_params = ret.arguments.select { |x| x.type?(:sym, :str) }.map(&:value)
122
122
  else
123
- internal_returns = Utils::MethodReturnTable.get_method(Utils::Parser.get_root_token(ret)) || []
123
+ internal_returns = get_method_returns(Utils::Parser.get_root_token(ret))
124
124
  internal_params = internal_returns.flat_map { |x| Utils::Parser.get_extracted_parameters(x, param_aliases: @param_wrappers) }
125
125
  end
126
126
 
@@ -144,6 +144,19 @@ module RuboCop
144
144
  def suspicious_id?(symbol_name)
145
145
  @unsafe_parameters.include?(symbol_name.to_sym) || @unsafe_regex.match(symbol_name) # symbol_name.to_s.end_with?("_id")
146
146
  end
147
+
148
+ def find_param_wrappers(class_methods)
149
+ class_methods.each_with_object([]) do |(method_name, method_returns), param_wrappers|
150
+ param_wrappers << method_name if method_returns.any? do |return_value|
151
+ name = Utils::Parser.get_root_token(return_value)
152
+ name.equal?(:params) || param_wrappers.include?(name)
153
+ end
154
+ end
155
+ end
156
+
157
+ def get_method_returns(method_name)
158
+ @class_methods.fetch(method_name, [])
159
+ end
147
160
  end
148
161
  end
149
162
  end
@@ -52,6 +52,10 @@ module RuboCop
52
52
  route = route_to(node)
53
53
  if route
54
54
  (path, param, value) = route
55
+
56
+ # Newer Rubocop versions return param as an array
57
+ param = param.first if param.is_a?(Array)
58
+
55
59
  action = case param
56
60
  when :to then value.first.split('#').last
57
61
  when :action then value.first
@@ -40,8 +40,13 @@ module RuboCop
40
40
  @unauthenticated_models = cop_config.fetch("unauthenticated_models").map(&:to_sym)
41
41
  end
42
42
 
43
+ def on_new_investigation
44
+ super
45
+ @class_methods = {}.freeze
46
+ end
47
+
43
48
  def on_class(node)
44
- Utils::MethodReturnTable.populate_index(node)
49
+ @class_methods = Utils::Parser.get_instance_methods(node).freeze
45
50
  end
46
51
 
47
52
  def on_send(node)
@@ -86,9 +91,7 @@ module RuboCop
86
91
 
87
92
  def uses_params?(node)
88
93
  root = Utils::Parser.get_root_token(node)
89
- root == :params || Array(Utils::MethodReturnTable.get_method(root)).find do |x|
90
- Utils::Parser.get_root_token(x) == :params
91
- end
94
+ root.equal?(:params) || method_returns_params?(root)
92
95
  end
93
96
 
94
97
  # yoinked from Rails/DynamicFindBy
@@ -98,6 +101,12 @@ module RuboCop
98
101
 
99
102
  match[2] ? 'find_by!' : 'find_by'
100
103
  end
104
+
105
+ def method_returns_params?(method_name)
106
+ @class_methods.fetch(method_name, []).any? do |return_value|
107
+ Utils::Parser.get_root_token(return_value).equal?(:params)
108
+ end
109
+ end
101
110
  end
102
111
  end
103
112
  end
@@ -67,16 +67,16 @@ module RuboCop
67
67
  end
68
68
  end
69
69
 
70
- def self.params_from_arguments(arguments) # rubocop:disable Metrics/PerceivedComplexity
70
+ def self.params_from_arguments(arguments)
71
71
  parameter_names = []
72
72
 
73
73
  arguments.each do |arg|
74
74
  if arg.hash_type?
75
75
  arg.children.each do |pair|
76
76
  value = pair.value
77
- parameter_names << value.value if value.sym_type? || value.str_type?
77
+ parameter_names << value.value if value.type?(:sym, :str)
78
78
  end
79
- elsif arg.sym_type? || arg.str_type?
79
+ elsif arg.type?(:sym, :str)
80
80
  parameter_names << arg.value
81
81
  end
82
82
  end
@@ -88,16 +88,16 @@ module RuboCop
88
88
  return [] unless node.send_type?
89
89
 
90
90
  parameter_names = []
91
- param_aliases << :params
91
+ aliases = param_aliases | %i(params)
92
92
 
93
- if node.method?(:[]) && param_aliases.include?(get_root_token(node))
93
+ if node.method?(:[]) && aliases.include?(get_root_token(node))
94
94
  return node.arguments.select { |x|
95
- x.sym_type? || x.str_type?
95
+ x.type?(:sym, :str)
96
96
  }.map(&:value)
97
97
  end
98
98
 
99
99
  children = node.descendants.select do |child|
100
- child.send_type? && param_aliases.include?(child.method_name)
100
+ child.send_type? && aliases.include?(child.method_name)
101
101
  end
102
102
 
103
103
  children.each do |child|
@@ -112,6 +112,23 @@ module RuboCop
112
112
 
113
113
  parameter_names.map(&:to_sym)
114
114
  end
115
+
116
+ def self.get_instance_methods(node) # rubocop:disable Metrics/PerceivedComplexity
117
+ raise ArgumentError, 'must be a class node' unless node&.class_type?
118
+
119
+ methods = node.descendants.select(&:def_type?).to_h do |method|
120
+ [method.method_name, get_return_values(method)]
121
+ end
122
+
123
+ node.descendants.each do |descendant|
124
+ lhs, rhs = *descendant
125
+ if descendant.equals_asgn? && !descendant.type.equal?(:casgn) && rhs&.send_type?
126
+ methods[lhs] = [rhs]
127
+ end
128
+ end
129
+
130
+ methods
131
+ end
115
132
  end
116
133
  end
117
134
  end
@@ -26,6 +26,5 @@ require 'rubocop/cop/betterment/unsafe_job'
26
26
  require 'rubocop/cop/betterment/unscoped_find'
27
27
  require 'rubocop/cop/betterment/use_global_strict_loading'
28
28
  require 'rubocop/cop/betterment/utils/hardcoded_attribute'
29
- require 'rubocop/cop/betterment/utils/method_return_table'
30
29
  require 'rubocop/cop/betterment/utils/parser'
31
30
  require 'rubocop/cop/betterment/vague_serialize'
metadata CHANGED
@@ -1,28 +1,71 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: betterlint
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.24.0
4
+ version: 1.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Development
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2025-12-17 00:00:00.000000000 Z
11
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: lint_roller
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
12
27
  - !ruby/object:Gem::Dependency
13
28
  name: rubocop
14
29
  requirement: !ruby/object:Gem::Requirement
15
30
  requirements:
16
31
  - - "~>"
17
32
  - !ruby/object:Gem::Version
18
- version: '1.71'
33
+ version: '1.82'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.82'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-capybara
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.22'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.22'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop-factory_bot
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.28'
19
62
  type: :runtime
20
63
  prerelease: false
21
64
  version_requirements: !ruby/object:Gem::Requirement
22
65
  requirements:
23
66
  - - "~>"
24
67
  - !ruby/object:Gem::Version
25
- version: '1.71'
68
+ version: '2.28'
26
69
  - !ruby/object:Gem::Dependency
27
70
  name: rubocop-graphql
28
71
  requirement: !ruby/object:Gem::Requirement
@@ -30,6 +73,9 @@ dependencies:
30
73
  - - "~>"
31
74
  - !ruby/object:Gem::Version
32
75
  version: '1.5'
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 1.5.6
33
79
  type: :runtime
34
80
  prerelease: false
35
81
  version_requirements: !ruby/object:Gem::Requirement
@@ -37,62 +83,79 @@ dependencies:
37
83
  - - "~>"
38
84
  - !ruby/object:Gem::Version
39
85
  version: '1.5'
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.5.6
40
89
  - !ruby/object:Gem::Dependency
41
90
  name: rubocop-performance
42
91
  requirement: !ruby/object:Gem::Requirement
43
92
  requirements:
44
93
  - - "~>"
45
94
  - !ruby/object:Gem::Version
46
- version: '1.23'
95
+ version: '1.26'
47
96
  type: :runtime
48
97
  prerelease: false
49
98
  version_requirements: !ruby/object:Gem::Requirement
50
99
  requirements:
51
100
  - - "~>"
52
101
  - !ruby/object:Gem::Version
53
- version: '1.23'
102
+ version: '1.26'
54
103
  - !ruby/object:Gem::Dependency
55
104
  name: rubocop-rails
56
105
  requirement: !ruby/object:Gem::Requirement
57
106
  requirements:
58
107
  - - "~>"
59
108
  - !ruby/object:Gem::Version
60
- version: '2.29'
109
+ version: '2.34'
61
110
  type: :runtime
62
111
  prerelease: false
63
112
  version_requirements: !ruby/object:Gem::Requirement
64
113
  requirements:
65
114
  - - "~>"
66
115
  - !ruby/object:Gem::Version
67
- version: '2.29'
116
+ version: '2.34'
68
117
  - !ruby/object:Gem::Dependency
69
118
  name: rubocop-rake
70
119
  requirement: !ruby/object:Gem::Requirement
71
120
  requirements:
72
121
  - - "~>"
73
122
  - !ruby/object:Gem::Version
74
- version: '0.6'
123
+ version: '0.7'
75
124
  type: :runtime
76
125
  prerelease: false
77
126
  version_requirements: !ruby/object:Gem::Requirement
78
127
  requirements:
79
128
  - - "~>"
80
129
  - !ruby/object:Gem::Version
81
- version: '0.6'
130
+ version: '0.7'
82
131
  - !ruby/object:Gem::Dependency
83
132
  name: rubocop-rspec
84
133
  requirement: !ruby/object:Gem::Requirement
85
134
  requirements:
86
135
  - - "~>"
87
136
  - !ruby/object:Gem::Version
88
- version: '2.29'
137
+ version: '3.8'
138
+ type: :runtime
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - "~>"
143
+ - !ruby/object:Gem::Version
144
+ version: '3.8'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rubocop-rspec_rails
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - "~>"
150
+ - !ruby/object:Gem::Version
151
+ version: '2.32'
89
152
  type: :runtime
90
153
  prerelease: false
91
154
  version_requirements: !ruby/object:Gem::Requirement
92
155
  requirements:
93
156
  - - "~>"
94
157
  - !ruby/object:Gem::Version
95
- version: '2.29'
158
+ version: '2.32'
96
159
  description: Betterment rubocop configuration
97
160
  email:
98
161
  - development@betterment.com
@@ -103,6 +166,8 @@ files:
103
166
  - README.md
104
167
  - STYLEGUIDE.md
105
168
  - config/default.yml
169
+ - lib/betterlint.rb
170
+ - lib/betterlint/version.rb
106
171
  - lib/rubocop/cop/betterment.rb
107
172
  - lib/rubocop/cop/betterment/active_job_performable.rb
108
173
  - lib/rubocop/cop/betterment/allowlist_blocklist.rb
@@ -129,7 +194,6 @@ files:
129
194
  - lib/rubocop/cop/betterment/unscoped_find.rb
130
195
  - lib/rubocop/cop/betterment/use_global_strict_loading.rb
131
196
  - lib/rubocop/cop/betterment/utils/hardcoded_attribute.rb
132
- - lib/rubocop/cop/betterment/utils/method_return_table.rb
133
197
  - lib/rubocop/cop/betterment/utils/parser.rb
134
198
  - lib/rubocop/cop/betterment/utils/response_status.rb
135
199
  - lib/rubocop/cop/betterment/vague_serialize.rb
@@ -138,11 +202,13 @@ licenses:
138
202
  - MIT
139
203
  metadata:
140
204
  homepage_uri: https://github.com/Betterment/betterlint
141
- source_code_uri: https://github.com/Betterment/betterlint/tree/v1.24.0
142
- changelog_uri: https://github.com/Betterment/betterlint/blob/v1.24.0/CHANGELOG.md
205
+ source_code_uri: https://github.com/Betterment/betterlint/tree/v1.26.0
206
+ changelog_uri: https://github.com/Betterment/betterlint/blob/v1.26.0/CHANGELOG.md
143
207
  bug_tracker_uri: https://github.com/Betterment/betterlint/issues
144
- documentation_uri: https://www.rubydoc.info/gems/betterlint/1.24.0
208
+ documentation_uri: https://www.rubydoc.info/gems/betterlint/1.26.0
145
209
  rubygems_mfa_required: 'true'
210
+ default_lint_roller_plugin: Betterlint::Plugin
211
+ post_install_message:
146
212
  rdoc_options: []
147
213
  require_paths:
148
214
  - lib
@@ -157,7 +223,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
223
  - !ruby/object:Gem::Version
158
224
  version: '0'
159
225
  requirements: []
160
- rubygems_version: 3.6.8
226
+ rubygems_version: 3.4.10
227
+ signing_key:
161
228
  specification_version: 4
162
229
  summary: Betterment rubocop configuration
163
230
  test_files: []
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Betterment
6
- module Utils
7
- module MethodReturnTable
8
- class << self
9
- def populate_index(node)
10
- raise "not a class" unless node.class_type?
11
-
12
- get_methods_for_class(node).each do |method|
13
- track_method(method.method_name, Utils::Parser.get_return_values(method))
14
- end
15
-
16
- node.descendants.each do |descendant|
17
- lhs, rhs = *descendant
18
- next unless descendant.equals_asgn? && (descendant.type != :casgn) && rhs&.send_type?
19
-
20
- track_method(lhs, [rhs])
21
- end
22
- end
23
-
24
- def indexed_methods
25
- @indexed_methods ||= {}
26
- end
27
-
28
- def get_method(method_name)
29
- indexed_methods[method_name]
30
- end
31
-
32
- def has_method?(method_name)
33
- indexed_methods.include?(method_name)
34
- end
35
-
36
- private
37
-
38
- def track_method(method_name, returns)
39
- indexed_methods[method_name] = returns
40
- end
41
-
42
- def get_methods_for_class(node)
43
- return [] unless node.children && node.class_type?
44
-
45
- node.descendants.select(&:def_type?)
46
- end
47
- end
48
- end
49
- end
50
- end
51
- end
52
- end