ここでの本当の問題は、(あなたが発見したように)非常に複雑にnumber_of_uses
なる可能性があることだと思います。nil
まずその問題を解消するようにしてください。
何らかの理由でそれができない場合は、各方法を改善できます。
condition ? true : false
常にコードのにおいがします。Boolean 演算子は boolean(ish) 値を返すので、その仕事をさせてください:
def is_valid?
!has_expired? && has_uses_remaining?
end
個人的には、Rails を使用するのは通常、コードの匂いがすると思いますObject#try
が、ここでは非常に適しています。
def has_expired?
expiry_date.try(:past?)
end
または:
def has_expired?
expiry_date.present? && expiry_date.past?
end
これを大幅に改善することはできませんが、個人的には、ブロックreturn
にラップされたメソッドよりも早い方が好きです。if
def remaining_uses
return if number_of_uses.nil?
number_of_uses - uses_count
end
あなたもすることができますnumber_of_uses && number_of_uses - uses_count
(または、number_of_uses.try(:-, uses_count)
しかし私はこれがより明確だと思います.
このメソッドがビットのtrue
場合に返すのは少し奇妙です。これは、次のように単純化できるためです。number_of_uses
nil
def has_uses_remaining?
remaining_uses.nil? || remaining_uses > 0
end
;remaining_uses.nil?
の代わりに呼び出すことに注意してください。number_of_uses.nil?
一方から同じ結果が得られる場合、両方に依存する必要はありません。
さらなる改善
さらに検討すると、別の方法を導入することで、このコードの意図をより明確にすることができると思います: has_unlimited_uses?
:
def has_unlimited_uses?
number_of_uses.nil?
end
def is_valid?
!has_expired? &&
has_unlimited_uses? || has_uses_remaining?
end
def remaining_uses
return if has_unlimited_uses?
number_of_uses - uses_count
end
def has_uses_remaining?
has_unlimited_uses? || remaining_uses > 0
end
このようにして、チェック対象についてあいまいさがなくなります。これにより、コードを次に読む人 (または今から 6 か月後のあなた) にとってコードが読みやすくなり、バグの追跡が容易になります。
しかし、それはまだ私を悩ませていremaining_uses
ますnil
。代わりに を返すFloat::INFINITY
と、has_uses_remaining?
単純な比較になることがわかります。
def remaining_uses
return Float::INFINITY if has_unlimited_uses?
number_of_uses - uses_count
end
def has_uses_remaining?
remaining_uses > 0
end