Dutchie-Style 2.0.11 → 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 +4 -4
- data/Dutchie-Style.gemspec +1 -1
- data/Gemfile.lock +1 -1
- data/config/default.yml +23 -0
- data/lib/Dutchie/Style/version.rb +1 -1
- data/lib/dutchie-style.rb +2 -0
- data/lib/rubocop/cop/dutchie/launchdarkly_defaults.rb +291 -0
- data/lib/rubocop/cop/dutchie/migration_safety_assured.rb +60 -0
- metadata +9 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 66d1a3b386238c749fe8a2a57e69ac726ab64167e54fbf18fb3242e8e9988d21
|
|
4
|
+
data.tar.gz: 5590171816b08b40de46bf110d7d5e59eae4a8289a2dbd71cec88be6e94a5da7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 95e9b22ce1d0f8016bb718f94145149f9f7f0daef5f8e431946559e3443e53e60935249884240dc8605293a64ee62156640bbc4923be535150213187bd6b516c
|
|
7
|
+
data.tar.gz: 906c6e5cb0961f91a2fae2b04628e42f73773f0e77e75e01cfc19a35fb4a52e6e7c403554e7abb4f1c2ae380b5c3e05d6e1af24cc1f2961e9e923d76d4114c9c
|
data/Dutchie-Style.gemspec
CHANGED
|
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.summary = "Rubocop Settings for all dutchie Ruby Apps"
|
|
14
14
|
spec.description = "Rubocop Settings for all dutchie Ruby Apps"
|
|
15
15
|
spec.homepage = "https://github.com/GetDutchie/Dutchie-Style"
|
|
16
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 3.
|
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 3.0.6")
|
|
17
17
|
|
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
|
19
19
|
spec.metadata["source_code_uri"] = "https://github.com/GetDutchie/Dutchie-Style"
|
data/Gemfile.lock
CHANGED
data/config/default.yml
CHANGED
|
@@ -280,6 +280,10 @@ Rails/PluckId:
|
|
|
280
280
|
Rails/PluckInWhere:
|
|
281
281
|
Enabled: false
|
|
282
282
|
|
|
283
|
+
# Disable I18n locale texts cop
|
|
284
|
+
Rails/I18nLocaleTexts:
|
|
285
|
+
Enabled: false
|
|
286
|
+
|
|
283
287
|
# RSpec
|
|
284
288
|
|
|
285
289
|
# Start context description without 'when', 'with', or 'without'.
|
|
@@ -301,3 +305,22 @@ RSpec/NestedGroups:
|
|
|
301
305
|
# Allows us to mark specs as "skip"
|
|
302
306
|
RSpec/Pending:
|
|
303
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'
|
data/lib/dutchie-style.rb
CHANGED
|
@@ -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
|
metadata
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: Dutchie-Style
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.0
|
|
4
|
+
version: 2.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christopher Ostrowski
|
|
8
|
+
autorequire:
|
|
8
9
|
bindir: exe
|
|
9
10
|
cert_chain: []
|
|
10
|
-
date:
|
|
11
|
+
date: 2026-02-07 00:00:00.000000000 Z
|
|
11
12
|
dependencies:
|
|
12
13
|
- !ruby/object:Gem::Dependency
|
|
13
14
|
name: rubocop
|
|
@@ -110,6 +111,8 @@ files:
|
|
|
110
111
|
- lib/Dutchie/Style.rb
|
|
111
112
|
- lib/Dutchie/Style/version.rb
|
|
112
113
|
- lib/dutchie-style.rb
|
|
114
|
+
- lib/rubocop/cop/dutchie/launchdarkly_defaults.rb
|
|
115
|
+
- lib/rubocop/cop/dutchie/migration_safety_assured.rb
|
|
113
116
|
- old-default.yml
|
|
114
117
|
homepage: https://github.com/GetDutchie/Dutchie-Style
|
|
115
118
|
licenses:
|
|
@@ -119,6 +122,7 @@ metadata:
|
|
|
119
122
|
source_code_uri: https://github.com/GetDutchie/Dutchie-Style
|
|
120
123
|
changelog_uri: https://github.com/GetDutchie/Dutchie-Style/releases
|
|
121
124
|
rubygems_mfa_required: 'true'
|
|
125
|
+
post_install_message:
|
|
122
126
|
rdoc_options: []
|
|
123
127
|
require_paths:
|
|
124
128
|
- lib
|
|
@@ -126,14 +130,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
126
130
|
requirements:
|
|
127
131
|
- - ">="
|
|
128
132
|
- !ruby/object:Gem::Version
|
|
129
|
-
version: 3.
|
|
133
|
+
version: 3.0.6
|
|
130
134
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
135
|
requirements:
|
|
132
136
|
- - ">="
|
|
133
137
|
- !ruby/object:Gem::Version
|
|
134
138
|
version: '0'
|
|
135
139
|
requirements: []
|
|
136
|
-
rubygems_version: 3.
|
|
140
|
+
rubygems_version: 3.0.3.1
|
|
141
|
+
signing_key:
|
|
137
142
|
specification_version: 4
|
|
138
143
|
summary: Rubocop Settings for all dutchie Ruby Apps
|
|
139
144
|
test_files: []
|