rubocop-rails 2.6.0 → 2.7.0

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
  SHA256:
3
- metadata.gz: b6b55ee8df864d6eaee4a491f4324343ee2274eafcb352952a81ff045832aa22
4
- data.tar.gz: 344ea324a589dc25ce3e87366c4af33bde4e392acf6acaccf9b9296066680824
3
+ metadata.gz: 5a83fc9ded75b4055903b32234c6c9b878e76b22ee64b7e0d88cf2f54ac690d5
4
+ data.tar.gz: cb9cbde85b8117645e16c66d1670cffc61893eba8b5d5e3f530e7e42d81b147f
5
5
  SHA512:
6
- metadata.gz: 5bdccc2a5e2a45533cb5bb33b2df26872f806dd590c13d640d7449315e56ec6250aebdb876fb37812bb3dd47cdaeda61c6049bc5cf98b01b473a616e9061491b
7
- data.tar.gz: 6f8673f2e8d0068bcdbe1599936793461bab38f4b333a4ac6e22e03e7162851d6fc20543ec58e3f2fabdf404764b09f8ff47e6a5c23d492f0c8bb28acd012296
6
+ metadata.gz: 9df513d510b7a71d81bcf655088528ca642599702eca3f20d83eac18adcc15a3d2ab277760b78b9f86fc90df474409eaee454c6857623a2f459304fb74fdde00
7
+ data.tar.gz: 252a9b09c51b33b4ff53454fcc6ccaec41e719c283939475e643074305221a33652a9ab5649b9b2c51f36784bb67eeef5dbceee9b3852de936fed78073241dc0
@@ -37,6 +37,14 @@ Rails/ActiveRecordAliases:
37
37
  VersionAdded: '0.53'
38
38
  SafeAutoCorrect: false
39
39
 
40
+ Rails/ActiveRecordCallbacksOrder:
41
+ Description: 'Order callback declarations in the order in which they will be executed.'
42
+ StyleGuide: 'https://rails.rubystyle.guide/#callbacks-order'
43
+ Enabled: 'pending'
44
+ VersionAdded: '2.7'
45
+ Include:
46
+ - app/models/**/*.rb
47
+
40
48
  Rails/ActiveRecordOverride:
41
49
  Description: >-
42
50
  Check for overriding Active Record methods instead of using
@@ -153,6 +161,12 @@ Rails/Date:
153
161
  - strict
154
162
  - flexible
155
163
 
164
+ Rails/DefaultScope:
165
+ Description: 'Avoid use of `default_scope`.'
166
+ StyleGuide: 'https://rails.rubystyle.guide#avoid-default-scope'
167
+ Enabled: false
168
+ VersionAdded: '2.7'
169
+
156
170
  Rails/Delegate:
157
171
  Description: 'Prefer delegate method for delegations.'
158
172
  Enabled: true
@@ -234,6 +248,14 @@ Rails/FindBy:
234
248
  Include:
235
249
  - app/models/**/*.rb
236
250
 
251
+ Rails/FindById:
252
+ Description: >-
253
+ Favor the use of `find` over `where.take!`, `find_by!`, and `find_by_id!` when you
254
+ need to retrieve a single record by primary key when you expect it to be found.
255
+ StyleGuide: 'https://rails.rubystyle.guide/#find'
256
+ Enabled: 'pending'
257
+ VersionAdded: '2.7'
258
+
237
259
  Rails/FindEach:
238
260
  Description: 'Prefer all.find_each over all.find.'
239
261
  StyleGuide: 'https://rails.rubystyle.guide#find-each'
@@ -300,6 +322,12 @@ Rails/IndexWith:
300
322
  Enabled: true
301
323
  VersionAdded: '2.5'
302
324
 
325
+ Rails/Inquiry:
326
+ Description: "Prefer Ruby's comparison operators over Active Support's `Array#inquiry` and `String#inquiry`."
327
+ StyleGuide: 'https://rails.rubystyle.guide/#inquiry'
328
+ Enabled: 'pending'
329
+ VersionAdded: '2.7'
330
+
303
331
  Rails/InverseOf:
304
332
  Description: 'Checks for associations where the inverse cannot be determined automatically.'
305
333
  Enabled: true
@@ -325,6 +353,31 @@ Rails/LinkToBlank:
325
353
  Enabled: true
326
354
  VersionAdded: '0.62'
327
355
 
356
+ Rails/MailerName:
357
+ Description: 'Mailer should end with `Mailer` suffix.'
358
+ StyleGuide: 'https://rails.rubystyle.guide/#mailer-name'
359
+ Enabled: 'pending'
360
+ VersionAdded: '2.7'
361
+ Include:
362
+ - app/mailers/**/*.rb
363
+
364
+ Rails/MatchRoute:
365
+ Description: >-
366
+ Don't use `match` to define any routes unless there is a need to map multiple request types
367
+ among [:get, :post, :patch, :put, :delete] to a single action using the `:via` option.
368
+ StyleGuide: 'https://rails.rubystyle.guide/#no-match-routes'
369
+ Enabled: 'pending'
370
+ VersionAdded: '2.7'
371
+ Include:
372
+ - config/routes.rb
373
+ - config/routes/**/*.rb
374
+
375
+ Rails/NegateInclude:
376
+ Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.'
377
+ StyleGuide: 'https://rails.rubystyle.guide#exclude'
378
+ Enabled: 'pending'
379
+ VersionAdded: '2.7'
380
+
328
381
  Rails/NotNullColumn:
329
382
  Description: 'Do not add a NOT NULL column without a default value.'
330
383
  Enabled: true
@@ -350,10 +403,30 @@ Rails/OutputSafety:
350
403
 
351
404
  Rails/Pick:
352
405
  Description: 'Prefer `pick` over `pluck(...).first`.'
406
+ StyleGuide: 'https://rails.rubystyle.guide#pick'
353
407
  Enabled: true
354
408
  Safe: false
355
409
  VersionAdded: '2.6'
356
410
 
411
+ Rails/Pluck:
412
+ Description: 'Prefer `pluck` over `map { ... }`.'
413
+ StyleGuide: 'https://rails.rubystyle.guide#pluck'
414
+ Enabled: 'pending'
415
+ VersionAdded: '2.7'
416
+
417
+ Rails/PluckId:
418
+ Description: 'Use `ids` instead of `pluck(:id)` or `pluck(primary_key)`.'
419
+ StyleGuide: 'https://rails.rubystyle.guide/#ids'
420
+ Enabled: 'pending'
421
+ Safe: false
422
+ VersionAdded: '2.7'
423
+
424
+ Rails/PluckInWhere:
425
+ Description: 'Use `select` instead of `pluck` in `where` query methods.'
426
+ Enabled: 'pending'
427
+ Safe: false
428
+ VersionAdded: '2.7'
429
+
357
430
  Rails/PluralizationGrammar:
358
431
  Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.'
359
432
  Enabled: true
@@ -441,6 +514,20 @@ Rails/RelativeDateConstant:
441
514
  VersionChanged: '0.59'
442
515
  AutoCorrect: false
443
516
 
517
+ Rails/RenderInline:
518
+ Description: 'Prefer using a template over inline rendering.'
519
+ StyleGuide: 'https://rails.rubystyle.guide/#inline-rendering'
520
+ Enabled: 'pending'
521
+ VersionAdded: '2.7'
522
+
523
+ Rails/RenderPlainText:
524
+ Description: 'Prefer `render plain:` over `render text:`.'
525
+ StyleGuide: 'https://rails.rubystyle.guide/#plain-text-rendering'
526
+ Enabled: 'pending'
527
+ VersionAdded: '2.7'
528
+ # Convert only when `content_type` is explicitly set to `text/plain`.
529
+ ContentTypeCompatibility: true
530
+
444
531
  Rails/RequestReferer:
445
532
  Description: 'Use consistent syntax for request.referer.'
446
533
  Enabled: true
@@ -498,6 +585,16 @@ Rails/ScopeArgs:
498
585
  Include:
499
586
  - app/models/**/*.rb
500
587
 
588
+ Rails/ShortI18n:
589
+ Description: 'Use the short form of the I18n methods: `t` instead of `translate` and `l` instead of `localize`.'
590
+ StyleGuide: 'https://rails.rubystyle.guide/#short-i18n'
591
+ Enabled: 'pending'
592
+ VersionAdded: '2.7'
593
+ EnforcedStyle: conservative
594
+ SupportedStyles:
595
+ - conservative
596
+ - aggressive
597
+
501
598
  Rails/SkipsModelValidations:
502
599
  Description: >-
503
600
  Use methods that skips model validations with caution.
@@ -505,20 +602,27 @@ Rails/SkipsModelValidations:
505
602
  Reference: 'https://guides.rubyonrails.org/active_record_validations.html#skipping-validations'
506
603
  Enabled: true
507
604
  VersionAdded: '0.47'
508
- VersionChanged: '0.60'
509
- Blacklist:
605
+ VersionChanged: '2.7'
606
+ ForbiddenMethods:
510
607
  - decrement!
511
608
  - decrement_counter
512
609
  - increment!
513
610
  - increment_counter
611
+ - insert
612
+ - insert!
613
+ - insert_all
614
+ - insert_all!
514
615
  - toggle!
515
616
  - touch
617
+ - touch_all
516
618
  - update_all
517
619
  - update_attribute
518
620
  - update_column
519
621
  - update_columns
520
622
  - update_counters
521
- Whitelist: []
623
+ - upsert
624
+ - upsert_all
625
+ AllowedMethods: []
522
626
 
523
627
  Rails/TimeZone:
524
628
  Description: 'Checks the correct usage of time zone aware methods.'
@@ -570,6 +674,11 @@ Rails/Validation:
570
674
  Include:
571
675
  - app/models/**/*.rb
572
676
 
677
+ Rails/WhereExists:
678
+ Description: 'Prefer `exists?(...)` over `where(...).exists?`.'
679
+ Enabled: 'pending'
680
+ VersionAdded: '2.7'
681
+
573
682
  # Accept `redirect_to(...) and return` and similar cases.
574
683
  Style/AndOr:
575
684
  EnforcedStyle: conditionals
@@ -6,6 +6,8 @@ module RuboCop
6
6
  module ActiveRecordHelper
7
7
  extend NodePattern::Macros
8
8
 
9
+ WHERE_METHODS = %i[where rewhere].freeze
10
+
9
11
  def_node_search :find_set_table_name, <<~PATTERN
10
12
  (send self :table_name= {str sym})
11
13
  PATTERN
@@ -72,6 +74,11 @@ module RuboCop
72
74
  break pair.value.value.to_s
73
75
  end
74
76
  end
77
+
78
+ def in_where?(node)
79
+ send_node = node.each_ancestor(:send).first
80
+ send_node && WHERE_METHODS.include?(send_node.method_name)
81
+ end
75
82
  end
76
83
  end
77
84
  end
@@ -0,0 +1,145 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop checks that Active Record callbacks are declared
7
+ # in the order in which they will be executed.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class Person < ApplicationRecord
12
+ # after_commit :after_commit_callback
13
+ # before_validation :before_validation_callback
14
+ # end
15
+ #
16
+ # # good
17
+ # class Person < ApplicationRecord
18
+ # before_validation :before_validation_callback
19
+ # after_commit :after_commit_callback
20
+ # end
21
+ #
22
+ class ActiveRecordCallbacksOrder < Cop
23
+ MSG = '`%<current>s` is supposed to appear before `%<previous>s`.'
24
+
25
+ CALLBACKS_IN_ORDER = %i[
26
+ after_initialize
27
+ before_validation
28
+ after_validation
29
+ before_save
30
+ around_save
31
+ before_create
32
+ around_create
33
+ after_create
34
+ before_update
35
+ around_update
36
+ after_update
37
+ before_destroy
38
+ around_destroy
39
+ after_destroy
40
+ after_save
41
+ after_commit
42
+ after_rollback
43
+ after_find
44
+ after_touch
45
+ ].freeze
46
+
47
+ CALLBACKS_ORDER_MAP = Hash[
48
+ CALLBACKS_IN_ORDER.map.with_index { |name, index| [name, index] }
49
+ ].freeze
50
+
51
+ def on_class(class_node)
52
+ previous_index = -1
53
+ previous_callback = nil
54
+
55
+ defined_callbacks(class_node).each do |node|
56
+ callback = node.method_name
57
+ index = CALLBACKS_ORDER_MAP[callback]
58
+
59
+ if index < previous_index
60
+ message = format(MSG, current: callback,
61
+ previous: previous_callback)
62
+ add_offense(node, message: message)
63
+ end
64
+ previous_index = index
65
+ previous_callback = callback
66
+ end
67
+ end
68
+
69
+ # Autocorrect by swapping between two nodes autocorrecting them
70
+ def autocorrect(node)
71
+ previous = left_siblings_of(node).find do |sibling|
72
+ callback?(sibling)
73
+ end
74
+
75
+ current_range = source_range_with_comment(node)
76
+ previous_range = source_range_with_comment(previous)
77
+
78
+ lambda do |corrector|
79
+ corrector.insert_before(previous_range, current_range.source)
80
+ corrector.remove(current_range)
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def defined_callbacks(class_node)
87
+ class_def = class_node.body
88
+
89
+ if class_def
90
+ class_def.each_child_node.select { |c| callback?(c) }
91
+ else
92
+ []
93
+ end
94
+ end
95
+
96
+ def callback?(node)
97
+ node.send_type? && CALLBACKS_ORDER_MAP.key?(node.method_name)
98
+ end
99
+
100
+ def left_siblings_of(node)
101
+ siblings_of(node)[0, node.sibling_index]
102
+ end
103
+
104
+ def siblings_of(node)
105
+ node.parent.children
106
+ end
107
+
108
+ def source_range_with_comment(node)
109
+ begin_pos = begin_pos_with_comment(node)
110
+ end_pos = end_position_for(node)
111
+
112
+ Parser::Source::Range.new(buffer, begin_pos, end_pos)
113
+ end
114
+
115
+ def end_position_for(node)
116
+ end_line = buffer.line_for_position(node.loc.expression.end_pos)
117
+ buffer.line_range(end_line).end_pos
118
+ end
119
+
120
+ def begin_pos_with_comment(node)
121
+ annotation_line = node.first_line - 1
122
+ first_comment = nil
123
+
124
+ processed_source.comments_before_line(annotation_line)
125
+ .reverse_each do |comment|
126
+ if comment.location.line == annotation_line
127
+ first_comment = comment
128
+ annotation_line -= 1
129
+ end
130
+ end
131
+
132
+ start_line_position(first_comment || node)
133
+ end
134
+
135
+ def start_line_position(node)
136
+ buffer.line_range(node.loc.line).begin_pos - 1
137
+ end
138
+
139
+ def buffer
140
+ processed_source.buffer
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -40,8 +40,12 @@ module RuboCop
40
40
  def autocorrect(node)
41
41
  lambda do |corrector|
42
42
  if method_name?(node.first_argument)
43
- replace_method_with_tag_method(corrector, node)
44
- remove_first_argument(corrector, node)
43
+ range = correction_range(node)
44
+
45
+ rest_args = node.arguments.drop(1)
46
+ replacement = "tag.#{node.first_argument.value}(#{rest_args.map(&:source).join(', ')})"
47
+
48
+ corrector.replace(range, replacement)
45
49
  else
46
50
  corrector.replace(node.loc.selector, 'tag')
47
51
  end
@@ -56,25 +60,8 @@ module RuboCop
56
60
  /^[a-zA-Z_][a-zA-Z_0-9]*$/.match?(node.value)
57
61
  end
58
62
 
59
- def replace_method_with_tag_method(corrector, node)
60
- corrector.replace(
61
- node.loc.selector,
62
- "tag.#{node.first_argument.value}"
63
- )
64
- end
65
-
66
- def remove_first_argument(corrector, node)
67
- if node.arguments.length > 1
68
- corrector.remove(
69
- range_between(child_node_beg(node, 0), child_node_beg(node, 1))
70
- )
71
- elsif node.arguments.length == 1
72
- corrector.remove(node.arguments[0].loc.expression)
73
- end
74
- end
75
-
76
- def child_node_beg(node, index)
77
- node.arguments[index].loc.expression.begin_pos
63
+ def correction_range(node)
64
+ range_between(node.loc.selector.begin_pos, node.loc.expression.end_pos)
78
65
  end
79
66
  end
80
67
  end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # This cop looks for uses of `default_scope`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # default_scope -> { where(hidden: false) }
11
+ #
12
+ # # good
13
+ # scope :published, -> { where(hidden: false) }
14
+ #
15
+ # # bad
16
+ # def self.default_scope
17
+ # where(hidden: false)
18
+ # end
19
+ #
20
+ # # good
21
+ # def self.published
22
+ # where(hidden: false)
23
+ # end
24
+ #
25
+ class DefaultScope < Cop
26
+ MSG = 'Avoid use of `default_scope`. It is better to use explicitly named scopes.'
27
+
28
+ def_node_matcher :method_call?, <<~PATTERN
29
+ (send nil? :default_scope ...)
30
+ PATTERN
31
+
32
+ def_node_matcher :class_method_definition?, <<~PATTERN
33
+ (defs _ :default_scope args ...)
34
+ PATTERN
35
+
36
+ def_node_matcher :eigenclass_method_definition?, <<~PATTERN
37
+ (sclass (self) $(def :default_scope args ...))
38
+ PATTERN
39
+
40
+ def on_send(node)
41
+ add_offense(node, location: :selector) if method_call?(node)
42
+ end
43
+
44
+ def on_defs(node)
45
+ add_offense(node, location: :name) if class_method_definition?(node)
46
+ end
47
+
48
+ def on_sclass(node)
49
+ eigenclass_method_definition?(node) { |default_scope| add_offense(default_scope, location: :name) }
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end