Skip to content

Commit

Permalink
Add new Rails/TimeUnitPluralization cop
Browse files Browse the repository at this point in the history
This PR adds new `Rails/TimeUnitPluralization` cop.

It checks the usage of singular and plural method forms for
`year`, `week`, `month`, `day`, `hour`, `minute`, and `second`.

```ruby
# bad
1.hours
42.minute

# good
1.hour
42.minutes
```
  • Loading branch information
koic committed Aug 22, 2023
1 parent 235b33d commit 87a5013
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 0 deletions.
1 change: 1 addition & 0 deletions changelog/new_add_new_rails_time_unit_pluralization_cop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#1074](https://github.com/rubocop/rubocop-rails/pull/1074): Add new `Rails/TimeUnitPluralization` cop. ([@koic][])
5 changes: 5 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1039,6 +1039,11 @@ Rails/ThreeStateBooleanColumn:
Include:
- db/**/*.rb

Rails/TimeUnitPluralization:
Description: 'Checks the usage of singular and plural method forms for time units.'
Enabled: pending
VersionAdded: '<<next>>'

Rails/TimeZone:
Description: 'Checks the correct usage of time zone aware methods.'
StyleGuide: 'https://rails.rubystyle.guide#time'
Expand Down
57 changes: 57 additions & 0 deletions lib/rubocop/cop/rails/time_unit_pluralization.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# Checks the usage of singular and plural method forms for
# `year`, `week`, `month`, `day`, `hour`, `minute`, and `second`.
#
# @example
#
# # bad
# 1.hours
# 42.minute
#
# # good
# 1.hour
# 42.minutes
#
class TimeUnitPluralization < Base
extend AutoCorrector

MSG = 'Use `%<preferred_method>s`.'

RESTRICT_ON_SEND = %i[
year years month months week weeks day days hour hours minute minutes second seconds
].freeze

PLURALS = {
year: :years,
month: :months,
week: :weeks,
day: :days,
hour: :hours,
minute: :minutes,
second: :seconds
}.freeze

SINGULARS = PLURALS.invert.freeze

def on_send(node)
return unless node.receiver.int_type?

method_name = node.method_name
preferred_method = node.receiver.source == '1' ? SINGULARS[method_name] : PLURALS[method_name]
return unless preferred_method

range = node.loc.selector
message = format(MSG, preferred_method: preferred_method)

add_offense(range, message: message) do |corrector|
corrector.replace(range, preferred_method)
end
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rails_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
require_relative 'rails/strip_heredoc'
require_relative 'rails/table_name_assignment'
require_relative 'rails/three_state_boolean_column'
require_relative 'rails/time_unit_pluralization'
require_relative 'rails/time_zone'
require_relative 'rails/time_zone_assignment'
require_relative 'rails/to_formatted_s'
Expand Down
80 changes: 80 additions & 0 deletions spec/rubocop/cop/rails/time_unit_pluralization_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::TimeUnitPluralization, :config do
it 'registers an offense when using incorrect singulars' do
expect_offense(<<~RUBY)
1.years
^^^^^ Use `year`.
1.months
^^^^^^ Use `month`.
1.weeks
^^^^^ Use `week`.
1.days
^^^^ Use `day`.
1.hours
^^^^^ Use `hour`.
1.minutes
^^^^^^^ Use `minute`.
1.seconds
^^^^^^^ Use `second`.
RUBY

expect_correction(<<~RUBY)
1.year
1.month
1.week
1.day
1.hour
1.minute
1.second
RUBY
end

it 'registers an offense when using incorrect plural form' do
expect_offense(<<~RUBY)
0.year
^^^^ Use `years`.
0.month
^^^^^ Use `months`.
0.week
^^^^ Use `weeks`.
0.day
^^^ Use `days`.
0.hour
^^^^ Use `hours`.
0.minute
^^^^^^ Use `minutes`.
0.second
^^^^^^ Use `seconds`.
RUBY

expect_correction(<<~RUBY)
0.years
0.months
0.weeks
0.days
0.hours
0.minutes
0.seconds
RUBY
end

it 'does not register an offense when using correct singular form' do
expect_no_offenses(<<~RUBY)
1.hour
RUBY
end

it 'does not register an offense when using correct plural form' do
expect_no_offenses(<<~RUBY)
0.hours
RUBY
end

it 'does not register an offense when receiver is a variable' do
expect_no_offenses(<<~RUBY)
var.hour
var.hours
RUBY
end
end

0 comments on commit 87a5013

Please sign in to comment.