ducalis 0.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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +12 -0
- data/.ruby-version +1 -0
- data/.travis.yml +6 -0
- data/DOCUMENTATION.md +556 -0
- data/Dockerfile +33 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +112 -0
- data/LICENSE +21 -0
- data/README.md +15 -0
- data/Rakefile +17 -0
- data/bin/ducalis +38 -0
- data/bootstrap.sh +9 -0
- data/config.ru +18 -0
- data/config/.ducalis.yml +57 -0
- data/ducalis.gemspec +39 -0
- data/lib/ducalis.rb +47 -0
- data/lib/ducalis/adapters/base.rb +17 -0
- data/lib/ducalis/adapters/circle_ci.rb +21 -0
- data/lib/ducalis/adapters/custom.rb +21 -0
- data/lib/ducalis/adapters/pull_request.rb +26 -0
- data/lib/ducalis/cli.rb +35 -0
- data/lib/ducalis/commentators/console.rb +59 -0
- data/lib/ducalis/commentators/github.rb +50 -0
- data/lib/ducalis/cops/callbacks_activerecord.rb +47 -0
- data/lib/ducalis/cops/controllers_except.rb +38 -0
- data/lib/ducalis/cops/keyword_defaults.rb +23 -0
- data/lib/ducalis/cops/module_like_class.rb +68 -0
- data/lib/ducalis/cops/params_passing.rb +35 -0
- data/lib/ducalis/cops/private_instance_assign.rb +39 -0
- data/lib/ducalis/cops/protected_scope_cop.rb +38 -0
- data/lib/ducalis/cops/raise_withour_error_class.rb +20 -0
- data/lib/ducalis/cops/regex_cop.rb +52 -0
- data/lib/ducalis/cops/rest_only_cop.rb +33 -0
- data/lib/ducalis/cops/rubocop_disable.rb +19 -0
- data/lib/ducalis/cops/strings_in_activerecords.rb +39 -0
- data/lib/ducalis/cops/uncommented_gem.rb +33 -0
- data/lib/ducalis/cops/useless_only.rb +50 -0
- data/lib/ducalis/documentation.rb +101 -0
- data/lib/ducalis/passed_args.rb +22 -0
- data/lib/ducalis/patched_rubocop/diffs.rb +30 -0
- data/lib/ducalis/patched_rubocop/ducalis_config_loader.rb +14 -0
- data/lib/ducalis/patched_rubocop/git_files_access.rb +42 -0
- data/lib/ducalis/patched_rubocop/git_runner.rb +14 -0
- data/lib/ducalis/patched_rubocop/git_turget_finder.rb +11 -0
- data/lib/ducalis/patched_rubocop/rubo_cop.rb +32 -0
- data/lib/ducalis/runner.rb +48 -0
- data/lib/ducalis/utils.rb +27 -0
- data/lib/ducalis/version.rb +5 -0
- metadata +201 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0ab05ed0a584986aef9f907edf69722b74ff8ee6
|
4
|
+
data.tar.gz: 4d503a2e465a872c713b5a290872be2bfd24aecb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c664d527142a8799a0b2a052961e8b70e8fe90cc4bec1f9fc7d9fdaccf3f0d58b44901753078e52ce286b33a3d5cc0fefcbc2e7413c440fd84f290303f59b6d8
|
7
|
+
data.tar.gz: fddf53bf677b26fc4a1eeea987196bdcb6a29b9e794fa9aba1a86100f25caf921129f9f31d529c41781d9cb39c137a1e641b0697c69e3968284cf82b870d5215
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.4.2
|
data/.travis.yml
ADDED
data/DOCUMENTATION.md
ADDED
@@ -0,0 +1,556 @@
|
|
1
|
+
## Ducalis::CallbacksActiverecord
|
2
|
+
|
3
|
+
Please, avoid using of callbacks for models. It's better to keep models small ("dumb") and instead use "builder" classes/services: to construct new objects. You can read more [here](https://medium.com/planet-arkency/a61fd75ab2d3).
|
4
|
+
- rejects ActiveRecord classes which contains callbacks
|
5
|
+
```ruby
|
6
|
+
|
7
|
+
class A < ActiveRecord::Base
|
8
|
+
before_create :generate_code
|
9
|
+
end
|
10
|
+
|
11
|
+
```
|
12
|
+
- ignores non-ActiveRecord classes which contains callbacks
|
13
|
+
```ruby
|
14
|
+
|
15
|
+
class A < SomeBasicClass
|
16
|
+
before_create :generate_code
|
17
|
+
end
|
18
|
+
|
19
|
+
```
|
20
|
+
## Ducalis::ControllersExcept
|
21
|
+
|
22
|
+
Prefer to use `:only` over `:except` in controllers because it's more explicit and will be easier to maintain for new developers.
|
23
|
+
- raises for `before_filters` with `except` method as array
|
24
|
+
```ruby
|
25
|
+
|
26
|
+
class MyController < ApplicationController
|
27
|
+
before_filter :something, except: [:index]
|
28
|
+
def index; end
|
29
|
+
def edit; end
|
30
|
+
private
|
31
|
+
def something; end
|
32
|
+
end
|
33
|
+
|
34
|
+
```
|
35
|
+
- raises for filters with many actions and only one `except` method
|
36
|
+
```ruby
|
37
|
+
|
38
|
+
class MyController < ApplicationController
|
39
|
+
before_filter :something, :load_me, except: %i[edit]
|
40
|
+
def index; end
|
41
|
+
def edit; end
|
42
|
+
private
|
43
|
+
def something; end
|
44
|
+
def load_me; end
|
45
|
+
end
|
46
|
+
|
47
|
+
```
|
48
|
+
- ignores `before_filters` without arguments
|
49
|
+
```ruby
|
50
|
+
|
51
|
+
class MyController < ApplicationController
|
52
|
+
before_filter :something
|
53
|
+
def index; end
|
54
|
+
private
|
55
|
+
def something; end
|
56
|
+
end
|
57
|
+
|
58
|
+
```
|
59
|
+
## Ducalis::KeywordDefaults
|
60
|
+
|
61
|
+
Prefer to use keyword arguments for defaults. It increases readability and reduces ambiguities.
|
62
|
+
- rejects if method definition contains default values
|
63
|
+
```ruby
|
64
|
+
def some_method(a, b, c = 3); end
|
65
|
+
```
|
66
|
+
- rejects if class method definition contains default values
|
67
|
+
```ruby
|
68
|
+
def self.some_method(a, b, c = 3); end
|
69
|
+
```
|
70
|
+
- works if method definition contains default values through keywords
|
71
|
+
```ruby
|
72
|
+
def some_method(a, b, c: 3); end
|
73
|
+
```
|
74
|
+
- works for methods without arguments
|
75
|
+
```ruby
|
76
|
+
def some_method; end
|
77
|
+
```
|
78
|
+
- works for class methods without arguments
|
79
|
+
```ruby
|
80
|
+
def self.some_method; end
|
81
|
+
```
|
82
|
+
## Ducalis::ModuleLikeClass
|
83
|
+
|
84
|
+
Seems like it will be better to define initialize and pass %<args>s there instead of each method.
|
85
|
+
- raise if class doesn't contain constructor but accept the same args
|
86
|
+
```ruby
|
87
|
+
|
88
|
+
class MyClass
|
89
|
+
|
90
|
+
def initialize(customer)
|
91
|
+
# ...
|
92
|
+
end
|
93
|
+
|
94
|
+
def approve(task, estimate, some_args_1)
|
95
|
+
# ...
|
96
|
+
end
|
97
|
+
|
98
|
+
def decline(user, task, estimate, some_args_2)
|
99
|
+
# ...
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
|
104
|
+
def anything_you_want(args)
|
105
|
+
# ...
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
```
|
110
|
+
- raise for class with only one public method with args
|
111
|
+
```ruby
|
112
|
+
|
113
|
+
class MyClass
|
114
|
+
def approve(task)
|
115
|
+
# ...
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def anything_you_want(args)
|
121
|
+
# ...
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
```
|
126
|
+
- ignores classes with custom includes
|
127
|
+
```ruby
|
128
|
+
|
129
|
+
class MyClass
|
130
|
+
include Singleton
|
131
|
+
|
132
|
+
def approve(task)
|
133
|
+
# ...
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
```
|
138
|
+
- ignores classes with inheritance
|
139
|
+
```ruby
|
140
|
+
|
141
|
+
class MyClass < AnotherClass
|
142
|
+
def approve(task)
|
143
|
+
# ...
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
|
148
|
+
def anything_you_want(args)
|
149
|
+
# ...
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
```
|
154
|
+
- ignores classes with one method and initializer
|
155
|
+
```ruby
|
156
|
+
|
157
|
+
class MyClass
|
158
|
+
def initialize(task)
|
159
|
+
# ...
|
160
|
+
end
|
161
|
+
|
162
|
+
def call(args)
|
163
|
+
# ...
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
```
|
168
|
+
## Ducalis::ParamsPassing
|
169
|
+
|
170
|
+
It's better to pass already preprocessed params hash to services. Or you can use
|
171
|
+
`arcane` gem
|
172
|
+
- raise if user pass `params` as argument from controller
|
173
|
+
```ruby
|
174
|
+
|
175
|
+
class MyController < ApplicationController
|
176
|
+
def index
|
177
|
+
MyService.new(params).call
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
```
|
182
|
+
- raise if user pass `params` as any argument from controller
|
183
|
+
```ruby
|
184
|
+
|
185
|
+
class MyController < ApplicationController
|
186
|
+
def index
|
187
|
+
MyService.new(first_arg, params).call
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
```
|
192
|
+
- raise if user pass `params` as keyword argument from controller
|
193
|
+
```ruby
|
194
|
+
|
195
|
+
class MyController < ApplicationController
|
196
|
+
def index
|
197
|
+
MyService.new(first_arg, any_name: params).call
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
```
|
202
|
+
- ignores passing only one `params` field
|
203
|
+
```ruby
|
204
|
+
|
205
|
+
class MyController < ApplicationController
|
206
|
+
def index
|
207
|
+
MyService.new(first_arg, params[:id]).call
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
```
|
212
|
+
- ignores passing processed `params`
|
213
|
+
```ruby
|
214
|
+
|
215
|
+
class MyController < ApplicationController
|
216
|
+
def index
|
217
|
+
MyService.new(first_arg, params.slice(:name)).call
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
```
|
222
|
+
- ignores passing `params` from `arcane` gem
|
223
|
+
```ruby
|
224
|
+
|
225
|
+
class MyController < ApplicationController
|
226
|
+
def index
|
227
|
+
MyService.new(params.for(Log).as(user).refine).call
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
```
|
232
|
+
## Ducalis::PrivateInstanceAssign
|
233
|
+
|
234
|
+
Please, don't assign instance variables in controller's private methods. It's make hard to understand what variables are available in views.
|
235
|
+
- raises for assigning instance variables in controllers private methods
|
236
|
+
```ruby
|
237
|
+
|
238
|
+
class MyController < ApplicationController
|
239
|
+
private
|
240
|
+
|
241
|
+
def load_employee
|
242
|
+
@employee = Employee.find(params[:id])
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
```
|
247
|
+
- raises for memoization variables in controllers private methods
|
248
|
+
```ruby
|
249
|
+
|
250
|
+
class MyController < ApplicationController
|
251
|
+
private
|
252
|
+
|
253
|
+
def service
|
254
|
+
@service ||= Service.new
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
```
|
259
|
+
- ignores memoization variables in controllers private methods with _
|
260
|
+
```ruby
|
261
|
+
|
262
|
+
class MyController < ApplicationController
|
263
|
+
private
|
264
|
+
|
265
|
+
def service
|
266
|
+
@_service ||= Service.new
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
```
|
271
|
+
- ignores assigning instance variables in controllers public methods
|
272
|
+
```ruby
|
273
|
+
|
274
|
+
class MyController < ApplicationController
|
275
|
+
def index
|
276
|
+
@employee = load_employee
|
277
|
+
end
|
278
|
+
|
279
|
+
private
|
280
|
+
|
281
|
+
def load_employee
|
282
|
+
Employee.find(params[:id])
|
283
|
+
end
|
284
|
+
end
|
285
|
+
|
286
|
+
```
|
287
|
+
## Ducalis::ProtectedScopeCop
|
288
|
+
|
289
|
+
Seems like you are using `find` on non-protected scope. Potentially it could
|
290
|
+
lead to unauthorized access. It's better to call `find` on authorized resources
|
291
|
+
scopes. Example:
|
292
|
+
|
293
|
+
```ruby
|
294
|
+
current_group.employees.find(params[:id])
|
295
|
+
# better then
|
296
|
+
Employee.find(params[:id])
|
297
|
+
```
|
298
|
+
- raise if somewhere AR search was called on not protected scope
|
299
|
+
```ruby
|
300
|
+
Group.find(8)
|
301
|
+
```
|
302
|
+
- raise if AR search was called even for chain of calls
|
303
|
+
```ruby
|
304
|
+
Group.includes(:some_relation).find(8)
|
305
|
+
```
|
306
|
+
- works ignores where statements and still raises error
|
307
|
+
```ruby
|
308
|
+
Group.includes(:some_relation).where(name: "John").find(8)
|
309
|
+
```
|
310
|
+
## Ducalis::RaiseWithourErrorClass
|
311
|
+
|
312
|
+
It's better to add exception class as raise argument. It will make easier to catch and process it later.
|
313
|
+
- raise when `raise` called without exception class
|
314
|
+
```ruby
|
315
|
+
raise "Something went wrong"
|
316
|
+
```
|
317
|
+
- works when `raise` called with exception class
|
318
|
+
```ruby
|
319
|
+
raise StandardError, "Something went wrong"
|
320
|
+
```
|
321
|
+
- works when `raise` called with exception instance
|
322
|
+
```ruby
|
323
|
+
raise StandardError.new("Something went wrong")
|
324
|
+
```
|
325
|
+
## Ducalis::RegexCop
|
326
|
+
|
327
|
+
It's better to move regex to constants with example instead of direct using it.
|
328
|
+
It will allow you to reuse this regex and provide instructions for others.
|
329
|
+
|
330
|
+
```ruby
|
331
|
+
CONST_NAME = %<constant>s # "%<example>s"
|
332
|
+
%<fixed_string>s
|
333
|
+
```
|
334
|
+
- raise if somewhere in code used regex which is not moved to const
|
335
|
+
```ruby
|
336
|
+
|
337
|
+
name = "john"
|
338
|
+
puts "hi" if name =~ /john/
|
339
|
+
|
340
|
+
```
|
341
|
+
- accepts matching constants
|
342
|
+
```ruby
|
343
|
+
|
344
|
+
REGEX = /john/
|
345
|
+
name = "john"
|
346
|
+
puts "hi" if name =~ REGEX
|
347
|
+
|
348
|
+
```
|
349
|
+
- ignores named ruby constants
|
350
|
+
```ruby
|
351
|
+
|
352
|
+
name = "john"
|
353
|
+
puts "hi" if name =~ /[[:alpha:]]/
|
354
|
+
|
355
|
+
```
|
356
|
+
- ignores dynamic regexs
|
357
|
+
```ruby
|
358
|
+
|
359
|
+
name = "john"
|
360
|
+
puts "hi" if name =~ /.{#{name.length}}/
|
361
|
+
|
362
|
+
```
|
363
|
+
## Ducalis::RestOnlyCop
|
364
|
+
|
365
|
+
It's better for controllers to stay adherent to REST:
|
366
|
+
http://jeromedalbert.com/how-dhh-organizes-his-rails-controllers/
|
367
|
+
- raise for controllers with non-REST methods
|
368
|
+
```ruby
|
369
|
+
|
370
|
+
class MyController < ApplicationController
|
371
|
+
def index; end
|
372
|
+
def non_rest_method; end
|
373
|
+
end
|
374
|
+
|
375
|
+
```
|
376
|
+
- doesn't raise for controllers with private non-REST methods
|
377
|
+
```ruby
|
378
|
+
|
379
|
+
class MyController < ApplicationController
|
380
|
+
def index; end
|
381
|
+
private
|
382
|
+
def non_rest_method; end
|
383
|
+
end
|
384
|
+
|
385
|
+
```
|
386
|
+
- doesn't raise for controllers with only REST methods
|
387
|
+
```ruby
|
388
|
+
|
389
|
+
class MyController < ApplicationController
|
390
|
+
def index; end
|
391
|
+
def show; end
|
392
|
+
def new; end
|
393
|
+
def edit; end
|
394
|
+
def create; end
|
395
|
+
def update; end
|
396
|
+
def destroy; end
|
397
|
+
end
|
398
|
+
|
399
|
+
```
|
400
|
+
- doesn't raise for non-controllers with non-REST methods
|
401
|
+
```ruby
|
402
|
+
|
403
|
+
class MyClass
|
404
|
+
def index; end
|
405
|
+
def non_rest_method; end
|
406
|
+
end
|
407
|
+
|
408
|
+
```
|
409
|
+
## Ducalis::RubocopDisable
|
410
|
+
|
411
|
+
|
412
|
+
Please, do not suppress RuboCop metrics, may be you can introduce some refactoring or another concept.
|
413
|
+
|
414
|
+
- raises on RuboCop disable comments
|
415
|
+
```ruby
|
416
|
+
|
417
|
+
# rubocop:disable Metrics/ParameterLists
|
418
|
+
def some_method(a, b, c, d, e, f); end
|
419
|
+
|
420
|
+
```
|
421
|
+
- doesnt raise on comment without RuboCop disabling
|
422
|
+
```ruby
|
423
|
+
|
424
|
+
# some meaningful comment
|
425
|
+
def some_method(a, b, c, d, e, f); end
|
426
|
+
|
427
|
+
```
|
428
|
+
## Ducalis::StringsInActiverecords
|
429
|
+
|
430
|
+
Please, do not use strings as arguments for %<method_name>s argument.
|
431
|
+
It's hard to test, grep sources, code highlighting and so on.
|
432
|
+
Consider using of symbols or lambdas for complex expressions.
|
433
|
+
- raise for string if argument
|
434
|
+
```ruby
|
435
|
+
|
436
|
+
before_save :set_full_name,
|
437
|
+
if: 'name_changed? || postfix_name_changed?'
|
438
|
+
|
439
|
+
```
|
440
|
+
- doesnt raise for lambda if argument
|
441
|
+
```ruby
|
442
|
+
validates :file, if: -> { remote_url.blank? }
|
443
|
+
```
|
444
|
+
## Ducalis::UncommentedGem
|
445
|
+
|
446
|
+
Please, add comment why are you including non-realized gem version for %<gem>s.
|
447
|
+
It will increase [bus-factor](<https://en.wikipedia.org/wiki/Bus_factor>).
|
448
|
+
- raise for gem from github without comment
|
449
|
+
```ruby
|
450
|
+
|
451
|
+
gem 'a'
|
452
|
+
gem 'b', '~> 1.3.1'
|
453
|
+
gem 'c', git: 'https://github.com/c/c'
|
454
|
+
|
455
|
+
```
|
456
|
+
- doesn't raise for gem from github with comment
|
457
|
+
```ruby
|
458
|
+
|
459
|
+
gem 'a'
|
460
|
+
gem 'b', '~> 1.3.1'
|
461
|
+
gem 'c', git: 'https://github.com/c/c' # some description
|
462
|
+
|
463
|
+
```
|
464
|
+
## Ducalis::UselessOnly
|
465
|
+
|
466
|
+
Seems like there is no any reason to keep before filter only for one action. Maybe it will be better to inline it?
|
467
|
+
|
468
|
+
```ruby
|
469
|
+
before_filter :do_something, only: %i[index]
|
470
|
+
def index; end
|
471
|
+
|
472
|
+
# to
|
473
|
+
|
474
|
+
def index
|
475
|
+
do_something
|
476
|
+
end
|
477
|
+
```
|
478
|
+
- raises for `before_filters` with only one method as array
|
479
|
+
```ruby
|
480
|
+
|
481
|
+
class MyController < ApplicationController
|
482
|
+
before_filter :do_something, only: [:index]
|
483
|
+
def index; end
|
484
|
+
private
|
485
|
+
def do_something; end
|
486
|
+
end
|
487
|
+
|
488
|
+
```
|
489
|
+
- raises for `before_filters` with only one method as keyword array
|
490
|
+
```ruby
|
491
|
+
|
492
|
+
class MyController < ApplicationController
|
493
|
+
before_filter :do_something, only: %i[index]
|
494
|
+
def index; end
|
495
|
+
private
|
496
|
+
def do_something; end
|
497
|
+
end
|
498
|
+
|
499
|
+
```
|
500
|
+
- raises for `before_filters` with many actions and only one method
|
501
|
+
```ruby
|
502
|
+
|
503
|
+
class MyController < ApplicationController
|
504
|
+
before_filter :do_something, :load_me, only: %i[index]
|
505
|
+
def index; end
|
506
|
+
private
|
507
|
+
def do_something; end
|
508
|
+
def load_me; end
|
509
|
+
end
|
510
|
+
|
511
|
+
```
|
512
|
+
- raises for `before_filters` with only one method as argument
|
513
|
+
```ruby
|
514
|
+
|
515
|
+
class MyController < ApplicationController
|
516
|
+
before_filter :do_something, only: :index
|
517
|
+
def index; end
|
518
|
+
private
|
519
|
+
def do_something; end
|
520
|
+
end
|
521
|
+
|
522
|
+
```
|
523
|
+
- ignores `before_filters` without arguments
|
524
|
+
```ruby
|
525
|
+
|
526
|
+
class MyController < ApplicationController
|
527
|
+
before_filter :do_something
|
528
|
+
def index; end
|
529
|
+
private
|
530
|
+
def do_something; end
|
531
|
+
end
|
532
|
+
|
533
|
+
```
|
534
|
+
- ignores `before_filters` with `only` and many arguments
|
535
|
+
```ruby
|
536
|
+
|
537
|
+
class MyController < ApplicationController
|
538
|
+
before_filter :do_something, only: %i[index show]
|
539
|
+
def index; end
|
540
|
+
def show; end
|
541
|
+
private
|
542
|
+
def do_something; end
|
543
|
+
end
|
544
|
+
|
545
|
+
```
|
546
|
+
- ignores `before_filters` with `except` and one argument
|
547
|
+
```ruby
|
548
|
+
|
549
|
+
class MyController < ApplicationController
|
550
|
+
before_filter :do_something, except: %i[index]
|
551
|
+
def index; end
|
552
|
+
private
|
553
|
+
def do_something; end
|
554
|
+
end
|
555
|
+
|
556
|
+
```
|