Skip to content

Commit

Permalink
Merge pull request #280 from fatkodima/short-i18n-cop
Browse files Browse the repository at this point in the history
Add new `Rails/ShortI18n` cop
  • Loading branch information
koic authored Jul 6, 2020
2 parents d939a22 + 1aa9e31 commit 2c46328
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* [#275](https://github.com/rubocop-hq/rubocop-rails/pull/275): Add new `Rails/MatchRoute` cop. ([@fatkodima][])
* [#271](https://github.com/rubocop-hq/rubocop-rails/pull/271): Add new `Rails/RenderInline` cop. ([@fatkodima][])
* [#281](https://github.com/rubocop-hq/rubocop-rails/pull/281): Add new `Rails/MailerName` cop. ([@fatkodima][])
* [#280](https://github.com/rubocop-hq/rubocop-rails/pull/280): Add new `Rails/ShortI18n` cop. ([@fatkodima][])
* [#246](https://github.com/rubocop-hq/rubocop-rails/issues/246): Add new `Rails/PluckInWhere` cop. ([@fatkodima][])
* [#17](https://github.com/rubocop-hq/rubocop-rails/issues/17): Add new `Rails/NegateInclude` cop. ([@fatkodima][])
* [#278](https://github.com/rubocop-hq/rubocop-rails/pull/278): Add new `Rails/Pluck` cop. ([@eugeneius][])
Expand Down
10 changes: 10 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -558,6 +558,16 @@ Rails/ScopeArgs:
Include:
- app/models/**/*.rb

Rails/ShortI18n:
Description: 'Use the short form of the I18n methods: `t` instead of `translate` and `l` instead of `localize`.'
StyleGuide: 'https://rails.rubystyle.guide/#short-i18n'
Enabled: 'pending'
VersionAdded: '2.7'
EnforcedStyle: conservative
SupportedStyles:
- conservative
- aggressive

Rails/SkipsModelValidations:
Description: >-
Use methods that skips model validations with caution.
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
* xref:cops_rails.adoc#railssafenavigationwithblank[Rails/SafeNavigationWithBlank]
* xref:cops_rails.adoc#railssavebang[Rails/SaveBang]
* xref:cops_rails.adoc#railsscopeargs[Rails/ScopeArgs]
* xref:cops_rails.adoc#railsshorti18n[Rails/ShortI18n]
* xref:cops_rails.adoc#railsskipsmodelvalidations[Rails/SkipsModelValidations]
* xref:cops_rails.adoc#railstimezone[Rails/TimeZone]
* xref:cops_rails.adoc#railsuniqbeforepluck[Rails/UniqBeforePluck]
Expand Down
73 changes: 73 additions & 0 deletions docs/modules/ROOT/pages/cops_rails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3458,6 +3458,79 @@ scope :something, -> { where(something: true) }
| Array
|===

== Rails/ShortI18n

|===
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged

| Pending
| Yes
| Yes
| 2.7
| -
|===

This cop enforces that short forms of `I18n` methods are used:
`t` instead of `translate` and `l` instead of `localize`.

This cop has two different enforcement modes. When the EnforcedStyle
is conservative (the default) then only `I18n.translate` and `I18n.localize`
calls are added as offenses.

When the EnforcedStyle is aggressive then all `translate` and `localize` calls
without a receiver are added as offenses.

=== Examples

[source,ruby]
----
# bad
I18n.translate :key
I18n.localize Time.now
# good
I18n.t :key
I18n.l Time.now
----

==== EnforcedStyle: conservative (default)

[source,ruby]
----
# good
translate :key
localize Time.now
t :key
l Time.now
----

==== EnforcedStyle: aggressive

[source,ruby]
----
# bad
translate :key
localize Time.now
# good
t :key
l Time.now
----

=== Configurable attributes

|===
| Name | Default value | Configurable values

| EnforcedStyle
| `conservative`
| `conservative`, `aggressive`
|===

=== References

* https://rails.rubystyle.guide/#short-i18n

== Rails/SkipsModelValidations

|===
Expand Down
76 changes: 76 additions & 0 deletions lib/rubocop/cop/rails/short_i18n.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# This cop enforces that short forms of `I18n` methods are used:
# `t` instead of `translate` and `l` instead of `localize`.
#
# This cop has two different enforcement modes. When the EnforcedStyle
# is conservative (the default) then only `I18n.translate` and `I18n.localize`
# calls are added as offenses.
#
# When the EnforcedStyle is aggressive then all `translate` and `localize` calls
# without a receiver are added as offenses.
#
# @example
# # bad
# I18n.translate :key
# I18n.localize Time.now
#
# # good
# I18n.t :key
# I18n.l Time.now
#
# @example EnforcedStyle: conservative (default)
# # good
# translate :key
# localize Time.now
# t :key
# l Time.now
#
# @example EnforcedStyle: aggressive
# # bad
# translate :key
# localize Time.now
#
# # good
# t :key
# l Time.now
#
class ShortI18n < Cop
include ConfigurableEnforcedStyle

MSG = 'Use `%<good_method>s` instead of `%<bad_method>s`.'

PREFERRED_METHODS = {
translate: :t,
localize: :l
}.freeze

def_node_matcher :long_i18n?, <<~PATTERN
(send {nil? (const nil? :I18n)} ${:translate :localize} ...)
PATTERN

def on_send(node)
return if style == :conservative && !node.receiver

long_i18n?(node) do |method_name|
good_method = PREFERRED_METHODS[method_name]
message = format(MSG, good_method: good_method, bad_method: method_name)

add_offense(node, location: :selector, message: message)
end
end

def autocorrect(node)
long_i18n?(node) do |method_name|
lambda do |corrector|
corrector.replace(node.loc.selector, PREFERRED_METHODS[method_name])
end
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 @@ -69,6 +69,7 @@
require_relative 'rails/safe_navigation_with_blank'
require_relative 'rails/save_bang'
require_relative 'rails/scope_args'
require_relative 'rails/short_i18n'
require_relative 'rails/skips_model_validations'
require_relative 'rails/time_zone'
require_relative 'rails/uniq_before_pluck'
Expand Down
91 changes: 91 additions & 0 deletions spec/rubocop/cop/rails/short_i18n_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::ShortI18n, :config do
subject(:cop) { described_class.new(config) }

shared_examples_for 'ShortI18n cop' do
it 'registers an offense and corrects when using `I18n.translate`' do
expect_offense(<<~RUBY)
I18n.translate :key
^^^^^^^^^ Use `t` instead of `translate`.
RUBY

expect_correction(<<~RUBY)
I18n.t :key
RUBY
end

it 'registers an offense and corrects when using `I18n.localize`' do
expect_offense(<<~RUBY)
I18n.localize Time.now
^^^^^^^^ Use `l` instead of `localize`.
RUBY

expect_correction(<<~RUBY)
I18n.l Time.now
RUBY
end

it 'does not register an offense when using `I18n.t`' do
expect_no_offenses('I18n.t :key')
end

it 'does not register an offense when using `I18n.l`' do
expect_no_offenses('I18n.l Time.now')
end

it 'does not register an offense when using `t`' do
expect_no_offenses('t :key')
end

it 'does not register an offense when using `l`' do
expect_no_offenses('l Time.now')
end
end

context 'when EnforcedStyle set to conservative' do
let(:cop_config) do
{ 'EnforcedStyle' => 'conservative' }
end

it_behaves_like 'ShortI18n cop'

it 'does not register an offense when using `translate`' do
expect_no_offenses('translate :key')
end

it 'does not register an offense when using `localize`' do
expect_no_offenses('localize Time.now')
end
end

context 'when EnforcedStyle set to aggressive' do
let(:cop_config) do
{ 'EnforcedStyle' => 'aggressive' }
end

it_behaves_like 'ShortI18n cop'

it 'registers an offense and corrects when using `translate`' do
expect_offense(<<~RUBY)
translate :key
^^^^^^^^^ Use `t` instead of `translate`.
RUBY

expect_correction(<<~RUBY)
t :key
RUBY
end

it 'registers an offense and corrects when using `localize`' do
expect_offense(<<~RUBY)
localize Time.now
^^^^^^^^ Use `l` instead of `localize`.
RUBY

expect_correction(<<~RUBY)
l Time.now
RUBY
end
end
end

0 comments on commit 2c46328

Please sign in to comment.