rubocop-rails 2.6.0 → 2.7.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: 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