ducalis 0.5.11 → 0.5.12

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
  SHA1:
3
- metadata.gz: 0e9545be92ee4417db0ef82c0becd1ccb5c7a8cd
4
- data.tar.gz: a11c6683e3364627615fcaec02444e21100aadb8
3
+ metadata.gz: cc58534f3d61b3f00faf32d15c18fd4ade02b01d
4
+ data.tar.gz: e2e5523eab7bd5dfe942f0e09722e718148ff6c4
5
5
  SHA512:
6
- metadata.gz: 21529fb2e38466c9c011bf2310811db2bc35b197d178e8c87ab2067a67a35ef2987a1920dcc6f54bc41945c774c84d90fdbf4ca1561defc1d3f55dc1fe089356
7
- data.tar.gz: 6d8d1be1aeda6b342d594f87bb9a68037712aea33b13802b7637d8c5055c608a9686e5d44647e41f3595ece8f9d6e2a2387307b21f9975c175657cd2bd7dbf84
6
+ metadata.gz: d84c6cbef793f301ce284c6325f992ea20672f6f01938f9a0feeef6cc76b8b564992aa552d1433a6960e893c08d3aada0682ec6a1eb3f28a8c0d942797f4c6e5
7
+ data.tar.gz: cbf69b4a43714b164e21ea3f19b08634504c563ca7f008b030fa625bed221bea0efba9f14bb917e96af25d4c1e180c53634bd9fb0f01f0fd73c443bd26bfdffb
data/DOCUMENTATION.md CHANGED
@@ -294,10 +294,60 @@ class TaskJournal
294
294
  end
295
295
  end
296
296
 
297
+ ```
298
+ ## Ducalis::OnlyDefsCope
299
+
300
+ Prefer object instances to class methods because class methods resist refactoring. Begin with an object instance, even if it doesn’t have state or multiple methods right away. If you come back to change it later, you will be more likely to refactor. If it never changes, the difference between the class method approach and the instance is negligible, and you certainly won’t be any worse off.
301
+ Related article: https://codeclimate.com/blog/why-ruby-class-methods-resist-refactoring/
302
+
303
+ ![](https://placehold.it/10/2cbe4e/000000?text=+) ignores classes with one instance method
304
+ ```ruby
305
+
306
+ class TaskJournal
307
+ def initialize(task)
308
+ # ...
309
+ end
310
+
311
+ def call(args)
312
+ # ...
313
+ end
314
+ end
315
+
316
+ ```
317
+
318
+ ![](https://placehold.it/10/2cbe4e/000000?text=+) ignores classes with mixed methods
319
+ ```ruby
320
+
321
+ class TaskJournal
322
+ def self.find(task)
323
+ # ...
324
+ end
325
+
326
+ def call(args)
327
+ # ...
328
+ end
329
+ end
330
+
331
+ ```
332
+
333
+ ![](https://placehold.it/10/f03c15/000000?text=+) raises error for class with ONLY class methods
334
+ ```ruby
335
+
336
+ class TaskJournal
337
+
338
+ def self.call(task)
339
+ # ...
340
+ end
341
+
342
+ def self.find(args)
343
+ # ...
344
+ end
345
+ end
346
+
297
347
  ```
298
348
  ## Ducalis::OptionsArgument
299
349
 
300
- Default options argument isn't good idea. It's better to explicitly pass which keys are you interested in as keyword arguments. You can use split operator to support hash arguments.
350
+ Default `options` (or `args`) argument isn't good idea. It's better to explicitly pass which keys are you interested in as keyword arguments. You can use split operator to support hash arguments.
301
351
 
302
352
  Compare:
303
353
 
@@ -308,7 +358,10 @@ def generate_1(document, options = {})
308
358
  # ...
309
359
  [format, limit, options]
310
360
  end
311
- generate_1(1, format: 'csv', limit: 5, useless_arg: :value)
361
+
362
+ options = { format: 'csv', limit: 5, useless_arg: :value }
363
+ generate_1(1, options) #=> ["csv", 5, {:useless_arg=>:value}]
364
+ generate_1(1, format: 'csv', limit: 5, useless_arg: :value) #=> ["csv", 5, {:useless_arg=>:value}]
312
365
 
313
366
  # vs
314
367
 
@@ -316,7 +369,11 @@ def generate_2(document, format:, limit: 20, **options)
316
369
  # ...
317
370
  [format, limit, options]
318
371
  end
319
- generate_2(1, format: 'csv', limit: 5, useless_arg: :value)
372
+
373
+ options = { format: 'csv', limit: 5, useless_arg: :value }
374
+ generate_2(1, **options) #=> ["csv", 5, {:useless_arg=>:value}]
375
+ generate_2(1, format: 'csv', limit: 5, useless_arg: :value) #=> ["csv", 5, {:useless_arg=>:value}]
376
+
320
377
  ```
321
378
 
322
379
  ![](https://placehold.it/10/f03c15/000000?text=+) raises if method accepts default options argument
@@ -339,6 +396,15 @@ end
339
396
 
340
397
  ```
341
398
 
399
+ ![](https://placehold.it/10/f03c15/000000?text=+) raises if method accepts args argument
400
+ ```ruby
401
+
402
+ def log(record, args)
403
+ # ...
404
+ end
405
+
406
+ ```
407
+
342
408
  ![](https://placehold.it/10/2cbe4e/000000?text=+) ignores passing options with split operator
343
409
  ```ruby
344
410
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ducalis (0.5.11)
4
+ ducalis (0.5.12)
5
5
  git (~> 1.3, >= 1.3.0)
6
6
  policial (= 0.0.4)
7
7
  regexp-examples (~> 1.3, >= 1.3.2)
data/config/.ducalis.yml CHANGED
@@ -51,6 +51,9 @@ Ducalis/TooLongWorkers:
51
51
  Enabled: true
52
52
  Max: 25
53
53
 
54
+ Ducalis/OnlyDefsCope:
55
+ Enabled: true
56
+
54
57
  Ducalis/UselessOnly:
55
58
  Enabled: true
56
59
 
@@ -18,8 +18,11 @@ module Ducalis
18
18
  after_commit
19
19
  after_create
20
20
  after_destroy
21
+ after_find
22
+ after_initialize
21
23
  after_rollback
22
24
  after_save
25
+ after_touch
23
26
  after_update
24
27
  after_validation
25
28
  around_create
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rubocop'
4
+
5
+ module Ducalis
6
+ class OnlyDefsCope < RuboCop::Cop::Cop
7
+ include RuboCop::Cop::DefNode
8
+
9
+ OFFENSE = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
10
+ | Prefer object instances to class methods because class methods resist refactoring. Begin with an object instance, even if it doesn’t have state or multiple methods right away. If you come back to change it later, you will be more likely to refactor. If it never changes, the difference between the class method approach and the instance is negligible, and you certainly won’t be any worse off.
11
+ MESSAGE
12
+
13
+ DETAILS = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
14
+ | Related article: https://codeclimate.com/blog/why-ruby-class-methods-resist-refactoring/
15
+ MESSAGE
16
+
17
+ def on_class(node)
18
+ _name, inheritance, body = *node
19
+ return if !inheritance.nil? || body.nil?
20
+ instance_methods = children(body).select(&public_method_definition?)
21
+ class_methods = children(body).select(&class_method_definition?)
22
+
23
+ return unless instance_methods.empty? && class_methods.any?
24
+ add_offense(node, :expression, OFFENSE)
25
+ end
26
+
27
+ private
28
+
29
+ def public_method_definition?
30
+ lambda do |node|
31
+ node.type == :def && !non_public?(node) && !initialize?(node)
32
+ end
33
+ end
34
+
35
+ def class_method_definition?
36
+ lambda do |node|
37
+ node.type == :defs && !non_public?(node) && !initialize?(node)
38
+ end
39
+ end
40
+
41
+ def children(body)
42
+ (body.type != :begin ? s(:begin, body) : body).children
43
+ end
44
+
45
+ def_node_search :initialize?, '(def :initialize ...)'
46
+ end
47
+ end
@@ -5,7 +5,7 @@ require 'rubocop'
5
5
  module Ducalis
6
6
  class OptionsArgument < RuboCop::Cop::Cop
7
7
  OFFENSE = <<-MESSAGE.gsub(/^ +\|\s/, '').strip
8
- | Default options argument isn't good idea. It's better to explicitly pass which keys are you interested in as keyword arguments. You can use split operator to support hash arguments.
8
+ | Default `options` (or `args`) argument isn't good idea. It's better to explicitly pass which keys are you interested in as keyword arguments. You can use split operator to support hash arguments.
9
9
 
10
10
  | Compare:
11
11
 
@@ -16,7 +16,10 @@ module Ducalis
16
16
  | # ...
17
17
  | [format, limit, options]
18
18
  | end
19
- | generate_1(1, format: 'csv', limit: 5, useless_arg: :value)
19
+
20
+ | options = { format: 'csv', limit: 5, useless_arg: :value }
21
+ | generate_1(1, options) #=> ["csv", 5, {:useless_arg=>:value}]
22
+ | generate_1(1, format: 'csv', limit: 5, useless_arg: :value) #=> ["csv", 5, {:useless_arg=>:value}]
20
23
 
21
24
  | # vs
22
25
 
@@ -24,10 +27,19 @@ module Ducalis
24
27
  | # ...
25
28
  | [format, limit, options]
26
29
  | end
27
- | generate_2(1, format: 'csv', limit: 5, useless_arg: :value)
30
+
31
+ | options = { format: 'csv', limit: 5, useless_arg: :value }
32
+ | generate_2(1, **options) #=> ["csv", 5, {:useless_arg=>:value}]
33
+ | generate_2(1, format: 'csv', limit: 5, useless_arg: :value) #=> ["csv", 5, {:useless_arg=>:value}]
34
+
28
35
  | ```
29
36
  MESSAGE
30
37
 
38
+ BLACK_LIST = %i(
39
+ options
40
+ args
41
+ ).freeze
42
+
31
43
  def on_def(node)
32
44
  _name, args, _body = *node
33
45
  return unless default_options?(args)
@@ -36,13 +48,17 @@ module Ducalis
36
48
 
37
49
  private
38
50
 
39
- def_node_search :options_arg?, '(arg :options)'
40
- def_node_search :options_arg_with_default?, '(optarg :options ...)'
51
+ def_node_search :options_arg?, '(arg #blacklisted?)'
52
+ def_node_search :options_arg_with_default?, '(optarg #blacklisted? ...)'
41
53
 
42
54
  def default_options?(args)
43
55
  args.children.any? do |node|
44
56
  options_arg?(node) || options_arg_with_default?(node)
45
57
  end
46
58
  end
59
+
60
+ def blacklisted?(name)
61
+ BLACK_LIST.include?(name)
62
+ end
47
63
  end
48
64
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ducalis
4
- VERSION = '0.5.11'
4
+ VERSION = '0.5.12'
5
5
  end
data/lib/ducalis.rb CHANGED
@@ -35,13 +35,14 @@ require 'ducalis/cops/black_list_suffix'
35
35
  require 'ducalis/cops/callbacks_activerecord'
36
36
  require 'ducalis/cops/case_mapping'
37
37
  require 'ducalis/cops/controllers_except'
38
+ require 'ducalis/cops/only_defs_cope'
38
39
  require 'ducalis/cops/keyword_defaults'
39
40
  require 'ducalis/cops/module_like_class'
40
41
  require 'ducalis/cops/options_argument'
41
42
  require 'ducalis/cops/params_passing'
42
43
  require 'ducalis/cops/possible_tap'
43
- require 'ducalis/cops/private_instance_assign'
44
44
  require 'ducalis/cops/preferable_methods'
45
+ require 'ducalis/cops/private_instance_assign'
45
46
  require 'ducalis/cops/protected_scope_cop'
46
47
  require 'ducalis/cops/raise_without_error_class'
47
48
  require 'ducalis/cops/regex_cop'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ducalis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.11
4
+ version: 0.5.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ignat Zakrevsky
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-07 00:00:00.000000000 Z
11
+ date: 2017-12-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: git
@@ -136,6 +136,7 @@ files:
136
136
  - lib/ducalis/cops/controllers_except.rb
137
137
  - lib/ducalis/cops/keyword_defaults.rb
138
138
  - lib/ducalis/cops/module_like_class.rb
139
+ - lib/ducalis/cops/only_defs_cope.rb
139
140
  - lib/ducalis/cops/options_argument.rb
140
141
  - lib/ducalis/cops/params_passing.rb
141
142
  - lib/ducalis/cops/possible_tap.rb