👮

RuboCopのカスタムルールで、Time.currentに促す

2023/03/06に公開

はじめに

Railsアプリのレビューで、「ここではTime.current(またはTime.zone.now)をよく使ってます」というコメントをもらったことはありませんか?
新しい案件に参画したとき、空気を読まないといけない部分かな思っていましたが、RuboCopのカスタムルールを追加して解決できないかやってみました。

(個人的にはTime.current Time.zone.now のどちらでもいいかなと思ってます)

試した環境

  • Ruby 3.1.2
  • Rails 7.0.3
  • RuboCop 1.30.1
  • RuboCop Rails 2.14.2

カスタムルールの追加

Time.zone.nowをNGとし、Time.currentにする例です。

カスタムルールのファイルを作成

lib/custom_cops/no_time_zone_now.rb

return unless defined?(::RuboCop)

module CustomCops
  class NoTimeZoneNow < ::RuboCop::Cop::Base
    extend RuboCop::Cop::AutoCorrector

    def_node_matcher :time_zone_now_call?, '(send (send (const nil :Time) :zone) :now)'

    MSG = '`Time.zone.now`ではなく`Time.current`でお願いします。'
    RESTRICT_ON_SEND = [:now].freeze

    def on_send(node)
      return if time_zone_now_call?(node)

      add_offense(node) do |rewriter|
        rewriter.replace(node, 'Time.current')
      end
    end
  end
end

カスタムルールを有効にする

.rubocop.yml

 require:
   - rubocop-rails
+  - ./lib/custom_cops/no_time_zone_now.rb 
+CustomCops/NoTimeZoneNow:
+  Enabled: true

実行結果

$ bundle exec rubocop custom_cop_test.rb 
Inspecting 1 file
C

Offenses:

custom_cop_test.rb:3:7: C: [Correctable] CustomCops/NoTimeZoneNow: Time.zone.nowではなくTime.currentでお願いします。
now = Time.zone.now
      ^^^^^^^^^^^^^

1 file inspected, 1 offense detected, 1 offense autocorrectable
$ bundle exec rubocop -a custom_cop_test.rb 
Inspecting 1 file
C

Offenses:

custom_cop_test.rb:3:7: C: [Corrected] CustomCops/NoTimeZoneNow: Time.zone.nowではなくTime.currentでお願いします。
now = Time.zone.now
      ^^^^^^^^^^^^^

1 file inspected, 1 offense detected, 1 offense corrected

まとめ

RuboCopのカスタムルールを追加することで、Time.zone.nowをNGとし、Time.currentにすることができました。
今回のように仕組みで解決できる方法が思いついたとき、試しにやって改善できればいいですね。

Discussion