Rubyでこんな感じのクラスを作りたかった。

基準となる時間で初期化をしておいて、基準の時間に分数を追加するとその追加した分数分加算された時間が取得できる、というもの。

$ time = TodoTime.new('20:30')
$ time + 30
# 分を加算した時間が返ってくる
=> '21:00'

普通にやるとaddみたいな名前のメソッドを用意してtime.add(30)みたく実行することになるんだけど、より直感的にわかりやすくかけるようにしたいと思ってプラスマークを使えないかと思った。

以下のようにクラスの中で演算子を再定義するとできました。

def +(minutes)とすると、右辺の値を引数として受け取ることができます。(この記事の下に改良版があります)

class TodoTime
  def initialize(start_at_string)
    s = start_at_string.split(':')
    @hour = s[0].to_i
    @minute = s[1].to_i
  end

  def +(minutes)
    h = minutes / 60
    m = minutes % 60
    "#{(@hour + h).to_s.rjust(2, '0')}:#{(@minute + m).to_s.rjust(2, '0')}"
  end
end

実行してみると以下のようになりました。素晴らしい。

irb(main):001:0> t = TodoTime.new('09:15')
=> #<TodoTime:0x0000000108a34310 @hour=9, @minute=15>
irb(main):002:0> t + 30
=> "09:45"
irb(main):003:0> t + 60
=> "10:15"
irb(main):004:0> t + 61
=> "10:16"

TodoTimeというのは今作っているサービスで必要になるクラス名です。

そこらへんはお好きなものをご利用ください。

改良版

上のサンプルだと、TodoTime.new('10:30') + 30とかしたときに10:60になってしまうので、改良したコードも置いておきます。

もっとスマートなやり方もあると思います。思いついた人は教えてください。

class TodoTime
  def initialize(start_at_string)
    s = start_at_string.split(':')
    @hour = s[0].to_i
    @minute = s[1].to_i
  end

  def +(minutes)
    added_minutes = base_minutes + minutes
    h = added_minutes / 60
    m = added_minutes % 60
    "#{(h).to_s.rjust(2, '0')}:#{(m).to_s.rjust(2, '0')}"
  end

  private

  def base_minutes
    @hour * 60 + @minute
  end
end

この記事の環境情報

  • Ruby 3.1.2
  • 焼き鳥を食べた次の日の朝