Dutchie-Style 2.0.7 → 2.1.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: 65273e051cf2984400af56b705adb309d5d679664f0e4b0d2516223db16e0470
4
- data.tar.gz: '0208a19e313688ff46475083fce4b44d446eb30f3a4010bf6dd07931227d7bbe'
3
+ metadata.gz: 66d1a3b386238c749fe8a2a57e69ac726ab64167e54fbf18fb3242e8e9988d21
4
+ data.tar.gz: 5590171816b08b40de46bf110d7d5e59eae4a8289a2dbd71cec88be6e94a5da7
5
5
  SHA512:
6
- metadata.gz: b74f3ff0bc262f7f7c4312b4a390e84655925915b9eddfd9f95f7863e632e922643a3c791797b60c753f4a5aab60c98f63c7bb3556b2a4aebe17de31afd9d8e8
7
- data.tar.gz: 62fcfc8ffe8461d3eaabbc4d5579a4d18ca4c6eca8320b461d3280b16a7d4dac90203b74076bd00084b15128995e3a9fbf4340e75207e599c4b8d1ac09923261
6
+ metadata.gz: 95e9b22ce1d0f8016bb718f94145149f9f7f0daef5f8e431946559e3443e53e60935249884240dc8605293a64ee62156640bbc4923be535150213187bd6b516c
7
+ data.tar.gz: 906c6e5cb0961f91a2fae2b04628e42f73773f0e77e75e01cfc19a35fb4a52e6e7c403554e7abb4f1c2ae380b5c3e05d6e1af24cc1f2961e9e923d76d4114c9c
@@ -1,4 +1,6 @@
1
- require_relative 'lib/Dutchie/Style/version'
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/Dutchie/Style/version"
2
4
 
3
5
  Gem::Specification.new do |spec|
4
6
  spec.name = "Dutchie-Style"
@@ -6,12 +8,12 @@ Gem::Specification.new do |spec|
6
8
  spec.authors = ["Christopher Ostrowski"]
7
9
  spec.email = ["chris@dutchie.com"]
8
10
 
9
- spec.license = 'MIT'
11
+ spec.license = "MIT"
10
12
 
11
- spec.summary = %q{Rubocop Settings for all dutchie Ruby Apps}
12
- spec.description = %q{Rubocop Settings for all dutchie Ruby Apps}
13
+ spec.summary = "Rubocop Settings for all dutchie Ruby Apps"
14
+ spec.description = "Rubocop Settings for all dutchie Ruby Apps"
13
15
  spec.homepage = "https://github.com/GetDutchie/Dutchie-Style"
14
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
16
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.0.6")
15
17
 
16
18
  spec.metadata["homepage_uri"] = spec.homepage
17
19
  spec.metadata["source_code_uri"] = "https://github.com/GetDutchie/Dutchie-Style"
@@ -19,14 +21,20 @@ Gem::Specification.new do |spec|
19
21
 
20
22
  # Specify which files should be added to the gem when it is released.
21
23
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
- spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
23
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
- end
24
+ spec.files =
25
+ Dir.chdir(File.expand_path(__dir__)) do
26
+ `git ls-files -z`.split("\x0").reject {|f| f.match(%r{^(test|spec|features)/}) }
27
+ end
25
28
  spec.bindir = "exe"
26
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
29
+ spec.executables = spec.files.grep(%r{^exe/}) {|f| File.basename(f) }
27
30
  spec.require_paths = ["lib"]
28
31
 
29
- spec.add_dependency "rubocop", "~> 1.56"
30
- spec.add_dependency "rubocop-rspec"
31
- spec.add_dependency "rubocop-rails"
32
+ spec.add_dependency "rubocop", "~> 1.72"
33
+ spec.add_dependency "rubocop-capybara", "~> 2.18"
34
+ spec.add_dependency "rubocop-factory_bot", "~> 2.24"
35
+ spec.add_dependency "rubocop-rails", "~> 2.21"
36
+ spec.add_dependency "rubocop-rspec", "~> 2.24"
37
+ spec.add_dependency "rubocop-rspec_rails", "~> 2.25"
38
+
39
+ spec.metadata["rubygems_mfa_required"] = "true"
32
40
  end
data/Gemfile CHANGED
@@ -5,5 +5,5 @@ gemspec
5
5
 
6
6
  gem "rake", "~> 12.0"
7
7
  gem "rspec", "~> 3.0"
8
- gem "rubocop", "~> 1.56"
8
+ gem "rubocop", "~> 1.72"
9
9
  gem "rubocop-rails", "~> 2.14"
data/Gemfile.lock CHANGED
@@ -1,10 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- Dutchie-Style (2.0.7)
5
- rubocop (~> 1.56)
6
- rubocop-rails
7
- rubocop-rspec
4
+ Dutchie-Style (2.1.0)
5
+ rubocop (~> 1.72)
6
+ rubocop-capybara (~> 2.18)
7
+ rubocop-factory_bot (~> 2.24)
8
+ rubocop-rails (~> 2.21)
9
+ rubocop-rspec (~> 2.24)
10
+ rubocop-rspec_rails (~> 2.25)
8
11
 
9
12
  GEM
10
13
  remote: https://rubygems.org/
@@ -14,25 +17,25 @@ GEM
14
17
  i18n (>= 1.6, < 2)
15
18
  minitest (>= 5.1)
16
19
  tzinfo (~> 2.0)
17
- ast (2.4.2)
18
- base64 (0.1.1)
20
+ ast (2.4.3)
19
21
  concurrent-ruby (1.2.2)
20
22
  diff-lcs (1.4.2)
21
23
  i18n (1.14.1)
22
24
  concurrent-ruby (~> 1.0)
23
- json (2.6.3)
24
- language_server-protocol (3.17.0.3)
25
+ json (2.13.2)
26
+ language_server-protocol (3.17.0.5)
27
+ lint_roller (1.1.0)
25
28
  minitest (5.20.0)
26
- parallel (1.23.0)
27
- parser (3.2.2.3)
29
+ parallel (1.27.0)
30
+ parser (3.3.9.0)
28
31
  ast (~> 2.4.1)
29
32
  racc
30
- racc (1.7.1)
33
+ prism (1.4.0)
34
+ racc (1.8.1)
31
35
  rack (3.0.8)
32
36
  rainbow (3.1.1)
33
37
  rake (12.3.3)
34
- regexp_parser (2.8.1)
35
- rexml (3.2.6)
38
+ regexp_parser (2.10.0)
36
39
  rspec (3.9.0)
37
40
  rspec-core (~> 3.9.0)
38
41
  rspec-expectations (~> 3.9.0)
@@ -46,36 +49,44 @@ GEM
46
49
  diff-lcs (>= 1.2.0, < 2.0)
47
50
  rspec-support (~> 3.9.0)
48
51
  rspec-support (3.9.3)
49
- rubocop (1.56.2)
50
- base64 (~> 0.1.1)
52
+ rubocop (1.79.0)
51
53
  json (~> 2.3)
52
- language_server-protocol (>= 3.17.0)
54
+ language_server-protocol (~> 3.17.0.2)
55
+ lint_roller (~> 1.1.0)
53
56
  parallel (~> 1.10)
54
- parser (>= 3.2.2.3)
57
+ parser (>= 3.3.0.2)
55
58
  rainbow (>= 2.2.2, < 4.0)
56
- regexp_parser (>= 1.8, < 3.0)
57
- rexml (>= 3.2.5, < 4.0)
58
- rubocop-ast (>= 1.28.1, < 2.0)
59
+ regexp_parser (>= 2.9.3, < 3.0)
60
+ rubocop-ast (>= 1.46.0, < 2.0)
59
61
  ruby-progressbar (~> 1.7)
60
- unicode-display_width (>= 2.4.0, < 3.0)
61
- rubocop-ast (1.29.0)
62
- parser (>= 3.2.1.0)
62
+ tsort (>= 0.2.0)
63
+ unicode-display_width (>= 2.4.0, < 4.0)
64
+ rubocop-ast (1.46.0)
65
+ parser (>= 3.3.7.2)
66
+ prism (~> 1.4)
63
67
  rubocop-capybara (2.18.0)
64
68
  rubocop (~> 1.41)
65
- rubocop-factory_bot (2.23.1)
66
- rubocop (~> 1.33)
67
- rubocop-rails (2.14.2)
69
+ rubocop-factory_bot (2.27.1)
70
+ lint_roller (~> 1.1)
71
+ rubocop (~> 1.72, >= 1.72.1)
72
+ rubocop-rails (2.22.1)
68
73
  activesupport (>= 4.2.0)
69
74
  rack (>= 1.1)
70
- rubocop (>= 1.7.0, < 2.0)
71
- rubocop-rspec (2.23.2)
72
- rubocop (~> 1.33)
75
+ rubocop (>= 1.33.0, < 2.0)
76
+ rubocop-rspec (2.31.0)
77
+ rubocop (~> 1.40)
73
78
  rubocop-capybara (~> 2.17)
74
79
  rubocop-factory_bot (~> 2.22)
80
+ rubocop-rspec_rails (~> 2.28)
81
+ rubocop-rspec_rails (2.29.0)
82
+ rubocop (~> 1.40)
75
83
  ruby-progressbar (1.13.0)
84
+ tsort (0.2.0)
76
85
  tzinfo (2.0.6)
77
86
  concurrent-ruby (~> 1.0)
78
- unicode-display_width (2.4.2)
87
+ unicode-display_width (3.1.4)
88
+ unicode-emoji (~> 4.0, >= 4.0.4)
89
+ unicode-emoji (4.0.4)
79
90
 
80
91
  PLATFORMS
81
92
  ruby
@@ -84,7 +95,7 @@ DEPENDENCIES
84
95
  Dutchie-Style!
85
96
  rake (~> 12.0)
86
97
  rspec (~> 3.0)
87
- rubocop (~> 1.56)
98
+ rubocop (~> 1.72)
88
99
  rubocop-rails (~> 2.14)
89
100
 
90
101
  BUNDLED WITH
data/README.md CHANGED
@@ -8,6 +8,8 @@ This repo contains all shared linter configs and style guides used by dutchie en
8
8
 
9
9
  It is available as a rubygem as well as an NPM package.
10
10
 
11
+ To run rubocop on the project using the current style guide: `bundle exec rubocop -c config/default.yml`.
12
+
11
13
  [Join Us! We're Hiring!](https://dutchie.com/careers)
12
14
 
13
15
  Includes:
@@ -15,4 +17,4 @@ Includes:
15
17
  * RuboCop Config
16
18
  * RuboCop Rspec Config
17
19
  * Eslint Config
18
- * Prettier Config
20
+ * Prettier Config
@@ -0,0 +1,326 @@
1
+ require:
2
+ - rubocop-rspec
3
+ - rubocop-rspec_rails
4
+ - rubocop-rails
5
+ - rubocop-capybara
6
+
7
+ AllCops:
8
+ TargetRubyVersion: 3.1.4
9
+ EnabledByDefault: true
10
+ DisplayCopNames: true
11
+ Exclude:
12
+ - 'bin/**/*'
13
+ - 'db/**/*'
14
+ - 'vendor/**/*'
15
+ - 'config/**/*'
16
+ - 'docs/**/*'
17
+ - 'app/channels/**/*'
18
+ - 'script/**/*'
19
+ - 'lib/assets/**/*'
20
+ - 'Rakefile'
21
+ - 'Gemfile'
22
+ - 'Guardfile'
23
+ - '*.yml'
24
+ - '.pryrc'
25
+
26
+ # Capybara/RSpec cops
27
+
28
+ # Allows us to use scenario/feature instead of it/describes
29
+ RSpec/Dialect:
30
+ Enabled: true
31
+ PreferredMethods: ['feature', 'scenario']
32
+
33
+ # https://docs.rubocop.org/rubocop/1.10/cops_layout.html#layoutclassstructure
34
+ Layout/ClassStructure:
35
+ Enabled: true
36
+
37
+ # Commonly used screens these days easily fit more than 80 characters.
38
+ # Ignores long lines with Heredocs or URIs in them
39
+ Layout/LineLength:
40
+ Max: 120
41
+ AllowHeredoc: true
42
+ # - There's a bug which considers commas after a URI too long so we can't use built-in AllowURI setting.
43
+ # Pattern matches valid URI encapsulated within a string literal.
44
+ # - Ignore top level comments (sometimes autogenerated, e.g. annotate_models)
45
+ AllowedPatterns: ['["\u0027].*https?[\w\:\/\$\–\-\#\.\+\!\*\‘\(\)\,]*.*["\u0027]', '\A#']
46
+
47
+
48
+ # No space makes the method definition shorter and differentiates
49
+ # from a regular assignment.
50
+ Layout/SpaceAroundEqualsInParameterDefault:
51
+ EnforcedStyle: no_space
52
+
53
+ # Most readable form.
54
+ Layout/HashAlignment:
55
+ EnforcedHashRocketStyle: table
56
+ EnforcedColonStyle: table
57
+
58
+ # Indenting the chained dots beneath each other is not supported by this cop,
59
+ # see https://github.com/bbatsov/rubocop/issues/1633
60
+ Layout/MultilineOperationIndentation:
61
+ Enabled: false
62
+
63
+ # Suppressing exceptions can be perfectly fine, and be it to avoid to
64
+ # explicitly type nil into the rescue since that's what you want to return,
65
+ # or suppressing LoadError for optional dependencies
66
+ Lint/SuppressedException:
67
+ Enabled: false
68
+
69
+ Layout/SpaceInsideBlockBraces:
70
+ # The space here provides no real gain in readability while consuming
71
+ # horizontal space that could be used for a better parameter name.
72
+ # Also {| differentiates better from a hash than { | does.
73
+ SpaceBeforeBlockParameters: false
74
+
75
+ # No trailing space differentiates better from the block:
76
+ # foo} means hash, foo } means block.
77
+ Layout/SpaceInsideHashLiteralBraces:
78
+ EnforcedStyle: no_space
79
+
80
+ # Exclude RSpec
81
+ Metrics/BlockLength:
82
+ Exclude:
83
+ - "spec/factories/**/*.rb"
84
+ AllowedMethods: ['describe', 'context']
85
+
86
+ # Too short methods lead to extraction of single-use methods, which can make
87
+ # the code easier to read (by naming things), but can also clutter the class
88
+ Metrics/MethodLength:
89
+ Max: 20
90
+
91
+ # The guiding principle of classes is SRP, SRP can't be accurately measured by LoC
92
+ Metrics/ClassLength:
93
+ Max: 1500
94
+
95
+ # Check with yard instead.
96
+ Style/DocumentationMethod:
97
+ Enabled: false
98
+
99
+ Style/Copyright:
100
+ Enabled: false
101
+
102
+ Style/Documentation:
103
+ Enabled: false
104
+
105
+ # We are using DateTime extensively.
106
+ Style/DateTime:
107
+ Enabled: false
108
+
109
+ # We do not need to support Ruby 1.9, so this is good to use.
110
+ Style/SymbolArray:
111
+ Enabled: true
112
+
113
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/MissingElse
114
+ Style/MissingElse:
115
+ Enabled: false
116
+
117
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/StringHashKeys
118
+ Style/StringHashKeys:
119
+ Enabled: false
120
+
121
+ # Single quotes being faster is hardly measurable and only affects parse time.
122
+ # Enforcing double quotes reduces the times where you need to change them
123
+ # when introducing an interpolation. Use single quotes only if their semantics
124
+ # are needed.
125
+ Style/StringLiterals:
126
+ EnforcedStyle: double_quotes
127
+
128
+ Style/HashSyntax:
129
+ EnforcedStyle: ruby19_no_mixed_keys
130
+ EnforcedShorthandSyntax: either
131
+
132
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/HashEachMethods
133
+ Style/HashEachMethods:
134
+ Enabled: true
135
+
136
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/HashTransformKeys
137
+ Style/HashTransformKeys:
138
+ Enabled: false
139
+
140
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/HashTransformValues
141
+ Style/HashTransformValues:
142
+ Enabled: false
143
+
144
+ # has_key? and has_value? are far more readable than key? and value?
145
+ Style/PreferredHashMethods:
146
+ Enabled: false
147
+
148
+ # https://docs.rubocop.org/rubocop/cops_style.html#styledisablecopswithinsourcecodedirective
149
+ Style/DisableCopsWithinSourceCodeDirective:
150
+ Enabled: false
151
+
152
+ # String#% is by far the least verbose and only object oriented variant.
153
+ Style/FormatString:
154
+ EnforcedStyle: percent
155
+
156
+ Style/CollectionMethods:
157
+ Enabled: true
158
+ PreferredMethods:
159
+ # find is not equivalent on mongoid embeds or collections
160
+ find: "detect"
161
+ # inject seems more common in the community.
162
+ reduce: "inject"
163
+
164
+ # Either allow this style or don't. Marking it as safe with parenthesis
165
+ # is silly. Let's try to live without them for now.
166
+ Style/ParenthesesAroundCondition:
167
+ AllowSafeAssignment: false
168
+
169
+ # https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml#L3095
170
+ # https://getdutchie.slack.com/archives/CJQCWSWQ4/p1592860363429600
171
+ # Optional inline and required multi
172
+ Style/MethodCallWithArgsParentheses:
173
+ Description: 'Use parentheses for method calls with arguments.'
174
+ StyleGuide: '#method-invocation-parens'
175
+ Enabled: false
176
+ VersionAdded: '0.47'
177
+ VersionChanged: '0.61'
178
+ IgnoreMacros: true
179
+ AllowedMethods: []
180
+ AllowedPatterns: []
181
+ IncludedMacros: []
182
+ AllowParenthesesInMultilineCall: false
183
+ AllowParenthesesInChaining: false
184
+ AllowParenthesesInCamelCaseMethod: false
185
+ EnforcedStyle: require_parentheses
186
+ SupportedStyles:
187
+ - require_parentheses
188
+ - omit_parentheses
189
+
190
+ Style/MethodCallWithoutArgsParentheses:
191
+ Description: 'Do not use parentheses for method calls with no arguments.'
192
+ StyleGuide: '#method-invocation-parens'
193
+ Enabled: true
194
+ AllowedMethods: []
195
+ VersionAdded: '0.47'
196
+ VersionChanged: '0.55'
197
+
198
+ # A specialized exception class will take one or more arguments and construct the message from it.
199
+ # So both variants make sense.
200
+ Style/RaiseArgs:
201
+ Enabled: false
202
+
203
+ # Fail is an alias of raise. Avoid aliases, it's more cognitive load for no gain.
204
+ # The argument that fail should be used to abort the program is wrong too,
205
+ # there's Kernel#abort for that.
206
+ Style/SignalException:
207
+ EnforcedStyle: only_raise
208
+
209
+ # do / end blocks should be used for side effects,
210
+ # methods that run a block for side effects and have
211
+ # a useful return value are rare, assign the return
212
+ # value to a local variable for those cases.
213
+ Style/MethodCalledOnDoEndBlock:
214
+ Enabled: true
215
+
216
+
217
+ # OpenStruct shouldn't be used anymore due to performance
218
+ # degradation on ruby 3.2+
219
+ Style/OpenStructUse:
220
+ Enabled: true
221
+
222
+ # Enforcing the names of variables? To single letter ones? Just no.
223
+ Style/SingleLineBlockParams:
224
+ Enabled: false
225
+
226
+ # Style preference
227
+ Style/MethodDefParentheses:
228
+ Enabled: false
229
+
230
+ # Ignores requirement to add underscore to separate every 3 digits in a number
231
+ Style/NumericLiterals:
232
+ Enabled: false
233
+
234
+ # Shadowing outer local variables with block parameters is often useful
235
+ # to not reinvent a new name for the same thing, it highlights the relation
236
+ # between the outer variable and the parameter. The cases where it's actually
237
+ # confusing are rare, and usually bad for other reasons already, for example
238
+ # because the method is too long.
239
+ Lint/ShadowingOuterLocalVariable:
240
+ Enabled: false
241
+
242
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Lint/Debugger
243
+ # Show linting errors on debugger/binding.pry even in development
244
+ Lint/Debugger:
245
+ Enabled: true
246
+
247
+ Lint/AssignmentInCondition:
248
+ AllowSafeAssignment: false
249
+
250
+ # https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Lint/NumberConversion
251
+ Lint/NumberConversion:
252
+ Enabled: false
253
+
254
+ Naming/BinaryOperatorParameterName:
255
+ Enabled: false
256
+
257
+ Lint/ConstantResolution:
258
+ Enabled: false
259
+
260
+
261
+ # Rails
262
+ Rails/SaveBang:
263
+ Enabled: false
264
+
265
+ # Temporarily removing until Mongoid is no more...
266
+ # Mongoid #find_by raises an exception if it can't be found, unlike AR #find_by, so .where().first is preferred
267
+ # Rubocop can't tell the difference between the two
268
+ Rails/FindBy:
269
+ Enabled: false
270
+ Include:
271
+ - app/**/*.rb
272
+
273
+ # not a method in mongoid
274
+ Rails/FindEach:
275
+ Enabled: false
276
+
277
+ Rails/PluckId:
278
+ Enabled: false
279
+
280
+ Rails/PluckInWhere:
281
+ Enabled: false
282
+
283
+ # Disable I18n locale texts cop
284
+ Rails/I18nLocaleTexts:
285
+ Enabled: false
286
+
287
+ # RSpec
288
+
289
+ # Start context description without 'when', 'with', or 'without'.
290
+ RSpec/ContextWording:
291
+ Enabled: false
292
+
293
+ RSpec/AlignLeftLetBrace:
294
+ Enabled: true
295
+
296
+ RSpec/AlignRightLetBrace:
297
+ Enabled: false
298
+
299
+ RSpec/MultipleMemoizedHelpers:
300
+ Enabled: false
301
+
302
+ RSpec/NestedGroups:
303
+ Max: 5
304
+
305
+ # Allows us to mark specs as "skip"
306
+ RSpec/Pending:
307
+ Enabled: false
308
+
309
+ # Dutchie Custom Cops
310
+
311
+ # Ensures all LaunchDarkly feature flag calls have default values
312
+ # Supports both Armageddon (DutchieFeatureFlags) and MenuConnector (ld_client.variation) patterns
313
+ Dutchie/LaunchDarklyDefaults:
314
+ Enabled: true
315
+ Severity: warning
316
+ AutoCorrect: true
317
+
318
+ # Flags questionable usage of safety_assured in migrations
319
+ # The Include directive overrides the global Exclude: db/**/* for this cop only
320
+ Dutchie/MigrationSafetyAssured:
321
+ Enabled: true
322
+ Severity: warning
323
+ Include:
324
+ - 'db/migrate/**/*.rb'
325
+ - 'lib/migration_helpers.rb'
326
+ - 'lib/**/migration_helpers.rb'
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Dutchie
4
4
  module Style
5
- VERSION = '2.0.7'
5
+ VERSION = "2.1.0"
6
+ public_constant :VERSION
6
7
  end
7
8
  end
data/lib/Dutchie/Style.rb CHANGED
@@ -1,8 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "Dutchie/Style/version"
2
4
 
3
5
  module Dutchie
4
6
  module Style
5
7
  class Error < StandardError; end
6
- # Your code goes here...
8
+
9
+ # Returns the absolute path to the default configuration file
10
+ def self.config_path
11
+ File.expand_path("../../config/default.yml", __dir__)
12
+ end
13
+
14
+ # Returns the gem's root directory
15
+ def self.root
16
+ File.expand_path("../..", __dir__)
17
+ end
7
18
  end
8
19
  end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "Dutchie/Style"
4
+ require_relative "rubocop/cop/dutchie/launchdarkly_defaults"
5
+ require_relative "rubocop/cop/dutchie/migration_safety_assured"
@@ -0,0 +1,291 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Dutchie
8
+ # Ensures all LaunchDarkly feature flag calls have default values
9
+ # to prevent failures during LaunchDarkly service outages
10
+ #
11
+ # This cop supports two LaunchDarkly patterns:
12
+ # 1. Armageddon pattern: DutchieFeatureFlags.flag(), .context_flag(), etc.
13
+ # 2. MenuConnector pattern: ld_client.variation(), MenuConnector::App[:launchdarkly].variation()
14
+ #
15
+ # @example Armageddon pattern
16
+ # # bad
17
+ # DutchieFeatureFlags.flag("some.flag")
18
+ # DutchieFeatureFlags.context_flag("some.flag", dispensary_id: id)
19
+ # DutchieFeatureFlags.on?("some.flag")
20
+ #
21
+ # # good
22
+ # DutchieFeatureFlags.flag("some.flag", false)
23
+ # DutchieFeatureFlags.context_flag("some.flag", default: false, dispensary_id: id)
24
+ # DutchieFeatureFlags.on?("some.flag", default: false)
25
+ #
26
+ # @example MenuConnector pattern
27
+ # # bad
28
+ # ld_client.variation("flag", context)
29
+ # MenuConnector::App[:launchdarkly].variation("flag", context)
30
+ #
31
+ # # good
32
+ # ld_client.variation("flag", context, false)
33
+ # MenuConnector::App[:launchdarkly].variation("flag", context, false)
34
+ #
35
+ class LaunchDarklyDefaults < ::RuboCop::Cop::Base
36
+ extend AutoCorrector
37
+
38
+ MSG_FLAG = 'DutchieFeatureFlags.flag must have a default value as 2nd parameter'
39
+ MSG_CONTEXT_FLAG = 'DutchieFeatureFlags.context_flag must have a default: parameter'
40
+ MSG_DISPENSARY_FLAG = 'DutchieFeatureFlags.dispensary_flag must have a default: parameter'
41
+ MSG_ENTERPRISE_FLAG = 'DutchieFeatureFlags.enterprise_flag must have a default: parameter'
42
+ MSG_ON = 'DutchieFeatureFlags.on? should have a default: parameter'
43
+ MSG_OFF = 'DutchieFeatureFlags.off? should have a default: parameter'
44
+ MSG_VARIATION = 'LaunchDarkly variation must have a default value as 3rd parameter'
45
+
46
+ # DutchieFeatureFlags.flag("key", default, ...)
47
+ def_node_matcher :dutchie_flag_call?, <<~PATTERN
48
+ (send
49
+ (const nil? :DutchieFeatureFlags) :flag
50
+ $_
51
+ $...
52
+ )
53
+ PATTERN
54
+
55
+ # DutchieFeatureFlags.context_flag("key", ...)
56
+ def_node_matcher :context_flag_call?, <<~PATTERN
57
+ (send
58
+ (const nil? :DutchieFeatureFlags) :context_flag
59
+ $_
60
+ $...
61
+ )
62
+ PATTERN
63
+
64
+ # DutchieFeatureFlags.dispensary_flag("key", ...)
65
+ def_node_matcher :dispensary_flag_call?, <<~PATTERN
66
+ (send
67
+ (const nil? :DutchieFeatureFlags) :dispensary_flag
68
+ $_
69
+ $...
70
+ )
71
+ PATTERN
72
+
73
+ # DutchieFeatureFlags.enterprise_flag("key", ...)
74
+ def_node_matcher :enterprise_flag_call?, <<~PATTERN
75
+ (send
76
+ (const nil? :DutchieFeatureFlags) :enterprise_flag
77
+ $_
78
+ $...
79
+ )
80
+ PATTERN
81
+
82
+ # DutchieFeatureFlags.on?("key", ...)
83
+ def_node_matcher :on_call?, <<~PATTERN
84
+ (send
85
+ (const nil? :DutchieFeatureFlags) :on?
86
+ $_
87
+ $...
88
+ )
89
+ PATTERN
90
+
91
+ # DutchieFeatureFlags.off?("key", ...)
92
+ def_node_matcher :off_call?, <<~PATTERN
93
+ (send
94
+ (const nil? :DutchieFeatureFlags) :off?
95
+ $_
96
+ $...
97
+ )
98
+ PATTERN
99
+
100
+ # Direct variation calls on ld_client or MenuConnector::App[:launchdarkly]
101
+ def_node_matcher :variation_call?, <<~PATTERN
102
+ (send
103
+ {
104
+ (send nil? :ld_client)
105
+ (send
106
+ (const (const nil? :MenuConnector) :App)
107
+ :[]
108
+ (sym :launchdarkly)
109
+ )
110
+ (send _ :ld_client)
111
+ }
112
+ :variation
113
+ $_
114
+ $...
115
+ )
116
+ PATTERN
117
+
118
+ # MockLaunchDarkly variation calls (for test environments)
119
+ def_node_matcher :mock_variation_call?, <<~PATTERN
120
+ (send
121
+ (const (const nil? :MenuConnector) :MockLaunchDarkly)
122
+ :variation
123
+ $_
124
+ $...
125
+ )
126
+ PATTERN
127
+
128
+ def on_send(node)
129
+ # Check Armageddon patterns
130
+ check_flag_method(node)
131
+ check_context_flag_method(node)
132
+ check_dispensary_flag_method(node)
133
+ check_enterprise_flag_method(node)
134
+ check_on_method(node)
135
+ check_off_method(node)
136
+
137
+ # Check MenuConnector patterns
138
+ check_variation_method(node)
139
+ check_mock_variation_method(node)
140
+ end
141
+
142
+ private
143
+
144
+ # Armageddon pattern checks
145
+
146
+ def check_flag_method(node)
147
+ flag_key, *args = dutchie_flag_call?(node)
148
+ return unless flag_key
149
+
150
+ # Need at least one more argument after the key (the default value)
151
+ return if args.any?
152
+
153
+ add_offense(node, message: MSG_FLAG) do |corrector|
154
+ corrector.insert_after(flag_key, ', false')
155
+ end
156
+ end
157
+
158
+ def check_context_flag_method(node)
159
+ flag_key, *args = context_flag_call?(node)
160
+ return unless flag_key
161
+
162
+ return if has_default_kwarg?(args)
163
+
164
+ add_offense(node, message: MSG_CONTEXT_FLAG) do |corrector|
165
+ insert_default_kwarg(corrector, flag_key, args)
166
+ end
167
+ end
168
+
169
+ def check_dispensary_flag_method(node)
170
+ flag_key, *args = dispensary_flag_call?(node)
171
+ return unless flag_key
172
+
173
+ return if has_default_kwarg?(args)
174
+
175
+ add_offense(node, message: MSG_DISPENSARY_FLAG) do |corrector|
176
+ insert_default_kwarg(corrector, flag_key, args)
177
+ end
178
+ end
179
+
180
+ def check_enterprise_flag_method(node)
181
+ flag_key, *args = enterprise_flag_call?(node)
182
+ return unless flag_key
183
+
184
+ return if has_default_kwarg?(args)
185
+
186
+ add_offense(node, message: MSG_ENTERPRISE_FLAG) do |corrector|
187
+ insert_default_kwarg(corrector, flag_key, args)
188
+ end
189
+ end
190
+
191
+ def check_on_method(node)
192
+ flag_key, *args = on_call?(node)
193
+ return unless flag_key
194
+
195
+ # on? accepts default: as keyword or as second positional argument
196
+ # Return if there's a positional default (non-hash arg) or default: kwarg
197
+ return if has_positional_default?(args) || has_default_kwarg?(args)
198
+
199
+ add_offense(node, message: MSG_ON) do |corrector|
200
+ insert_default_kwarg(corrector, flag_key, args)
201
+ end
202
+ end
203
+
204
+ def check_off_method(node)
205
+ flag_key, *args = off_call?(node)
206
+ return unless flag_key
207
+
208
+ # off? accepts default: as keyword or as second positional argument
209
+ # Return if there's a positional default (non-hash arg) or default: kwarg
210
+ return if has_positional_default?(args) || has_default_kwarg?(args)
211
+
212
+ add_offense(node, message: MSG_OFF) do |corrector|
213
+ insert_default_kwarg(corrector, flag_key, args)
214
+ end
215
+ end
216
+
217
+ # MenuConnector pattern checks
218
+
219
+ def check_variation_method(node)
220
+ flag_key, *args = variation_call?(node)
221
+ return unless flag_key
222
+
223
+ # variation(flag, context, default) - need at least 2 args after flag
224
+ return if args.size >= 2
225
+
226
+ add_offense(node, message: MSG_VARIATION) do |corrector|
227
+ if args.empty?
228
+ # No context provided, add both context and default
229
+ corrector.insert_after(flag_key, ', nil, false')
230
+ elsif args.size == 1
231
+ # Context provided but no default
232
+ corrector.insert_after(args.last, ', false')
233
+ end
234
+ end
235
+ end
236
+
237
+ def check_mock_variation_method(node)
238
+ # Don't check mock variation calls in test code
239
+ return if in_test_file?(node)
240
+
241
+ flag_key, *args = mock_variation_call?(node)
242
+ return unless flag_key
243
+
244
+ # Same logic as regular variation
245
+ return if args.size >= 2
246
+
247
+ add_offense(node, message: MSG_VARIATION) do |corrector|
248
+ if args.empty?
249
+ corrector.insert_after(flag_key, ', nil, false')
250
+ elsif args.size == 1
251
+ corrector.insert_after(args.last, ', false')
252
+ end
253
+ end
254
+ end
255
+
256
+ # Helper methods
257
+
258
+ def has_default_kwarg?(args)
259
+ args.any? do |arg|
260
+ next false unless arg.hash_type?
261
+
262
+ arg.pairs.any? do |pair|
263
+ pair.key.sym_type? && pair.key.value == :default
264
+ end
265
+ end
266
+ end
267
+
268
+ def has_positional_default?(args)
269
+ args.any? { |arg| !arg.hash_type? }
270
+ end
271
+
272
+ def insert_default_kwarg(corrector, flag_key, args)
273
+ if args.any? && args.last.hash_type?
274
+ # Add to existing hash
275
+ corrector.insert_after(args.last.source_range.end.adjust(begin_pos: -1), ', default: false')
276
+ elsif args.any?
277
+ # Add as new keyword argument after existing args
278
+ corrector.insert_after(args.last, ', default: false')
279
+ else
280
+ # Add as first argument after flag key
281
+ corrector.insert_after(flag_key, ', default: false')
282
+ end
283
+ end
284
+
285
+ def in_test_file?(node)
286
+ processed_source.file_path.include?('spec/')
287
+ end
288
+ end
289
+ end
290
+ end
291
+ end
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module RuboCop
6
+ module Cop
7
+ module Dutchie
8
+ # Flags usage of safety_assured in migrations
9
+ #
10
+ # The safety_assured block bypasses strong_migrations safety checks,
11
+ # which should only be used when you're certain the operation is safe
12
+ # and have documented why it's necessary.
13
+ #
14
+ # @example
15
+ # # bad
16
+ # def change
17
+ # safety_assured do
18
+ # remove_column :users, :email
19
+ # end
20
+ # end
21
+ #
22
+ # # good - avoid safety_assured when possible
23
+ # def change
24
+ # # Use strong_migrations approved patterns instead
25
+ # remove_column :users, :email, type: :string
26
+ # end
27
+ #
28
+ # # acceptable - with clear documentation
29
+ # def change
30
+ # # This operation is safe because:
31
+ # # 1. The column was already removed from the model
32
+ # # 2. No code references this column anymore
33
+ # # 3. We've verified in production logs that no queries use this column
34
+ # safety_assured do
35
+ # remove_column :users, :deprecated_field
36
+ # end
37
+ # end
38
+ #
39
+ class MigrationSafetyAssured < ::RuboCop::Cop::Base
40
+ MSG = 'Avoid `safety_assured` in migrations. It bypasses strong_migrations safety checks. ' \
41
+ 'Ensure this operation is truly safe, consider safer alternatives, and document why ' \
42
+ 'safety_assured is necessary.'
43
+
44
+ # Matches: safety_assured do...end or safety_assured {...}
45
+ def_node_matcher :safety_assured_block?, <<~PATTERN
46
+ (block
47
+ (send nil? :safety_assured)
48
+ ...
49
+ )
50
+ PATTERN
51
+
52
+ def on_block(node)
53
+ return unless safety_assured_block?(node)
54
+
55
+ add_offense(node)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -3,7 +3,7 @@ require:
3
3
  - rubocop-rails
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 2.6
6
+ TargetRubyVersion: 2.7.4
7
7
  EnabledByDefault: true
8
8
  DisplayCopNames: true
9
9
  Exclude:
@@ -21,7 +21,6 @@ AllCops:
21
21
  - '*.yml'
22
22
  - '.pryrc'
23
23
 
24
-
25
24
  # Capybara cops
26
25
 
27
26
  # Allows us to use scenario/feature instead of it/describes
@@ -80,7 +79,7 @@ Layout/SpaceInsideHashLiteralBraces:
80
79
  Metrics/BlockLength:
81
80
  Exclude:
82
81
  - "spec/factories/**/*.rb"
83
- IgnoredMethods: ['describe', 'context']
82
+ AllowedMethods: ['describe', 'context']
84
83
 
85
84
  # Too short methods lead to extraction of single-use methods, which can make
86
85
  # the code easier to read (by naming things), but can also clutter the class
@@ -175,7 +174,7 @@ Style/MethodCallWithArgsParentheses:
175
174
  VersionAdded: '0.47'
176
175
  VersionChanged: '0.61'
177
176
  IgnoreMacros: true
178
- IgnoredMethods: []
177
+ AllowedMethods: []
179
178
  AllowedPatterns: []
180
179
  IncludedMacros: []
181
180
  AllowParenthesesInMultilineCall: false
@@ -190,7 +189,7 @@ Style/MethodCallWithoutArgsParentheses:
190
189
  Description: 'Do not use parentheses for method calls with no arguments.'
191
190
  StyleGuide: '#method-invocation-parens'
192
191
  Enabled: true
193
- IgnoredMethods: []
192
+ AllowedMethods: []
194
193
  VersionAdded: '0.47'
195
194
  VersionChanged: '0.55'
196
195
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: Dutchie-Style
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.7
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Ostrowski
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-09-11 00:00:00.000000000 Z
11
+ date: 2026-02-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubocop
@@ -16,42 +16,84 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '1.56'
19
+ version: '1.72'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '1.56'
26
+ version: '1.72'
27
27
  - !ruby/object:Gem::Dependency
28
- name: rubocop-rspec
28
+ name: rubocop-capybara
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.18'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.18'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rubocop-factory_bot
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - ">="
45
+ - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: '0'
47
+ version: '2.24'
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - ">="
52
+ - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: '0'
54
+ version: '2.24'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rubocop-rails
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - ">="
59
+ - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '0'
61
+ version: '2.21'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - ">="
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.21'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop-rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2.24'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2.24'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec_rails
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.25'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
53
95
  - !ruby/object:Gem::Version
54
- version: '0'
96
+ version: '2.25'
55
97
  description: Rubocop Settings for all dutchie Ruby Apps
56
98
  email:
57
99
  - chris@dutchie.com
@@ -65,9 +107,13 @@ files:
65
107
  - Gemfile
66
108
  - Gemfile.lock
67
109
  - README.md
68
- - default.yml
110
+ - config/default.yml
69
111
  - lib/Dutchie/Style.rb
70
112
  - lib/Dutchie/Style/version.rb
113
+ - lib/dutchie-style.rb
114
+ - lib/rubocop/cop/dutchie/launchdarkly_defaults.rb
115
+ - lib/rubocop/cop/dutchie/migration_safety_assured.rb
116
+ - old-default.yml
71
117
  homepage: https://github.com/GetDutchie/Dutchie-Style
72
118
  licenses:
73
119
  - MIT
@@ -75,6 +121,7 @@ metadata:
75
121
  homepage_uri: https://github.com/GetDutchie/Dutchie-Style
76
122
  source_code_uri: https://github.com/GetDutchie/Dutchie-Style
77
123
  changelog_uri: https://github.com/GetDutchie/Dutchie-Style/releases
124
+ rubygems_mfa_required: 'true'
78
125
  post_install_message:
79
126
  rdoc_options: []
80
127
  require_paths:
@@ -83,7 +130,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
83
130
  requirements:
84
131
  - - ">="
85
132
  - !ruby/object:Gem::Version
86
- version: 2.3.0
133
+ version: 3.0.6
87
134
  required_rubygems_version: !ruby/object:Gem::Requirement
88
135
  requirements:
89
136
  - - ">="