やりたいこと
現在時刻が特定の時間範囲内かどうかをスマートに判断したいです。
例えば、特定の時間帯、ユーザーグループごとシステムへのアクセスや一部機能を制限するのに使えるかと思います。
今日も弊社先輩のリファクタリングに息を呑んでしまったのでメモメモ。
Modelは例えばこんな感じ↓
「利用一時停止」をsuspensionとしてその期間を持たせています。
# == Schema Information
#
# Table name: user_groups
#
# id :bigint not null, primary key
# name :text not null
# description :text
# created_at :datetime not null
# updated_at :datetime not null
# suspension_started_at :datetime
# suspension_ended_at :datetime
環境
ruby 3.0.0
Rails 6.0.3
実装!
Ruby歴8ヶ月の人の実装例
def suspension?
return if suspension_started_at.nil? || suspension_ended_at.nil?
current_time = Time.current
current_time >= suspension_started_at && current_time < suspension_ended_at
end
リファクタリング例
def suspension?
return false if suspension_started_at.nil? || suspension_ended_at.nil?
current_time = Time.current
(suspension_started_at...suspension_ended_at).cover?(current_time)
end
最終行の可読性がグッと上がった印象です。
ポイントを以下に3つまとめておきます。
####?で終わるメソッド
先輩から「?
で終わるメソッドは毎回Booleanを返すべき」とレビューが返ってきました。それを読んだ僕は、「何をおっしゃいます。このメソッドの最終行はちゃんとtrue/falseを返しますよ?ふふ」と思ったら...あ、一行目が...!参りました!というわけで、return false
にしました。
####範囲演算子...
...
は範囲演算子で、x以上y未満という範囲オブジェクトクラスのインスタンスを生成することができます。ちなみに今回はドット2つだけど..
も見かけるような?と思ったら、そちらは未満ではなく以下の意味になるそうです。下記、Rubyのリファレンスマニュアルから引用です。
Range.new(1, 5) # 1 以上 5 以下
1..5 # 同上
1...5 # 1 以上 5 未満
####cover?
メソッド
cover?
は、include?
と似ていますが、違いがあるようで、上のコードをRspecテストの中で単純に置き換えてみるとテストはパスしますが、下記のような注意を受けました。
DEPRECATION WARNING: Using
Range#include?
to check the inclusion of a value in a date time range is deprecated. It is recommended to useRange#cover?
instead ofRange#include?
to check the inclusion of a value in a date time range. (called from suspension? at /Users/kakudaisuke/.../app/models/user_group.rb:83)
datetimeの範囲に値が含まれているかをチェックするにはinclude?
は非推奨だよってことですね。ちなみに..
にするとこのwarningは出現しませんでした。
cover?
とinclude?
両者の違いは、ドキュメントに書いてありました↓
Range#include? と異なり <=> メソッドによる演算により範囲内かどうかを判定します。 Range#include? は原則として離散値を扱い、 Range#cover? は連続値を扱います。(数値については、例外として Range#include? も連続的に扱います。)
(Rubyリファレンスマニュアルより https://docs.ruby-lang.org/ja/latest/method/Range/i/cover=3f.html)
最後に
何かご指摘あれば、ぜひよろしくお願いします。
Comments
Let's comment your feelings that are more than good