From 7842d09f22d739543a52b6da829613de31089302 Mon Sep 17 00:00:00 2001 From: "Josep M. Bach" Date: Mon, 29 Aug 2011 17:40:00 +0200 Subject: [PATCH] wip --- Readme.md | 28 ++++++-- lib/domodoro.rb | 2 + lib/domodoro/channel.rb | 34 +++------- lib/domodoro/client.rb | 77 ++++++++++++++++----- lib/domodoro/config.rb | 33 ++++++++- lib/domodoro/schedule.rb | 82 ++++++++++++++++++++++ lib/domodoro/server.rb | 24 +++++-- lib/domodoro/timepoint.rb | 68 +++++++++++++++++++ test/domodoro/channel_test.rb | 117 +++----------------------------- test/domodoro/config_test.rb | 4 +- test/domodoro/schedule_test.rb | 108 +++++++++++++++++++++++++++++ test/domodoro/server_test.rb | 44 +++++++++--- test/domodoro/timepoint_test.rb | 87 ++++++++++++++++++++++++ 13 files changed, 536 insertions(+), 172 deletions(-) create mode 100644 lib/domodoro/schedule.rb create mode 100644 lib/domodoro/timepoint.rb create mode 100644 test/domodoro/schedule_test.rb create mode 100644 test/domodoro/timepoint_test.rb diff --git a/Readme.md b/Readme.md index f6872a6..71415fa 100644 --- a/Readme.md +++ b/Readme.md @@ -51,13 +51,10 @@ The clients will receive notifications via sound/growl (configurable in a If you're not using OSX, try to install the `afplay` program manually or... send a patch to make it work with your OS :) -* The pomodoro schedule is (as of v0.0.3) hard-coded. It starts at 8:00 AM, - stops at 13:00 for lunch, and starts again at 13:20. In the following - versions this will be freely configurable. - - ## Configuration +### Client configuration + By default, both sound and visual notifications are displayed on each event. If you want to configure this, create a file in your home directory named `.domodororc` with some YAML configuration: @@ -66,8 +63,25 @@ If you want to configure this, create a file in your home directory named $ echo "visual: true" >> ~/.domodororc $ echo "sound: false" >> ~/.domodororc -## Copyright +### Server configuration -Copyright (c) 2011 Josep M. Bach. Released under the MIT license. +Inside the server machine, to configure the pomodoro schedule, create a +`~/.domodororc` file with YAML configuration (the values provided below are +those that will be used by default if you don't specify them): +````yaml +server: + pomodoro_duration: 25 # in minutes + pomodoro_break: 5 # in minutes + long_break_after: 4 # pomodoros + day_start: "08:30" + day_end: "16:30" + + lunch_time: "13:00" + lunch_duration: 30 # in minutes +```` + +## Copyright + +Copyright (c) 2011 Josep M. Bach. Released under the MIT license. diff --git a/lib/domodoro.rb b/lib/domodoro.rb index 14c9dc9..6b8f18c 100644 --- a/lib/domodoro.rb +++ b/lib/domodoro.rb @@ -1,6 +1,8 @@ require 'eventmachine' require "domodoro/version" +require "domodoro/schedule" +require "domodoro/timepoint" require "domodoro/config" require "domodoro/channel" require "domodoro/server" diff --git a/lib/domodoro/channel.rb b/lib/domodoro/channel.rb index 3e44ae4..7950039 100644 --- a/lib/domodoro/channel.rb +++ b/lib/domodoro/channel.rb @@ -1,6 +1,6 @@ module Domodoro class Channel < EM::Channel - def broadcast(hour, min) + def broadcast(timestamp, schedule) if ENV['DEBUG'] puts 'DEBUG MODE: Start on even minutes, stop on odd minutes' if min % 2 == 0 @@ -13,31 +13,13 @@ def broadcast(hour, min) return end - if (hour >= 8 && hour < 13) - morning(min) - elsif (hour >= 13 && min >= 20) && - afternoon(min) - end - end - def morning(min) - case min - when 0, 30 - puts "#{Time.now} - Starting pomodoro!" - self << :start - when 25, 55 - puts "#{Time.now} - Pomodoro break!" - self << :stop - end - end - - def afternoon(min) - case min - when 20, 50 - puts "#{Time.now} - Starting pomodoro!" - self << :start - when 45, 15 - puts "#{Time.now} - Pomodoro break!" - self << :stop + action = schedule.to_hash[timestamp] + if action + next_action = schedule.action_after(timestamp) + self << { + :action => action, + :next_action => next_action + } end end end diff --git a/lib/domodoro/client.rb b/lib/domodoro/client.rb index 8926e00..249b795 100644 --- a/lib/domodoro/client.rb +++ b/lib/domodoro/client.rb @@ -12,34 +12,49 @@ def connected=(value) @connected = true end + def next_action + @next_action + end + + def next_action=(action) + @next_action = action + end + def start(host, port='9111') - Config.load + Config.load_client_configuration puts "#{Time.now} - Domodoro listening on #{host}:#{port}" puts "Visual notifications: #{Config.visual}" puts "Sound notifications: #{Config.sound}\n" EM.run do EM.connect(host, port) do |c| - c.extend EM::P::LineText2 + c.extend EM::P::ObjectProtocol def c.connection_completed puts " - Connected to server!" Client.connected = true end - def c.receive_line(line) - case line - when /start/ - puts " - Starting pomodoro!" - Client.work - when /stop/ - puts " - Pomodoro break!" - Client.break + def c.receive_object(object) + case object[:current_action].last + when :start + puts "[#{object[:current_action]}] - Starting pomodoro!" + Client.work + when :stop + puts "[#{object[:current_action]}] - Pomodoro break!" + Client.break + when :lunch + puts "[#{object[:current_action]}] - Lunch time!" + Client.lunch + when :go_home + puts "[#{object[:current_action]}] - Time to go home!" + Client.home end + Client.next_action = object[:next_action] end end EM.add_periodic_timer(1) do EM.next_tick do if Client.connected - print_time + print_next_action else puts 'Cannot connect to server. Is it running?' end @@ -71,20 +86,48 @@ def break end end + def lunch + EM.defer do + if Config.visual + Notify.notify "Domodoro", "Lunch time!" + end + if Config.sound + system("afplay #{path_to('lunch.wav')}") + end + end + end + + def home + EM.defer do + if Config.visual + Notify.notify "Domodoro", "Time to go home!" + end + if Config.sound + system("afplay #{path_to('home.wav')}") + end + end + end + private def path_to(asset) File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'assets', asset)) end - def print_time - hour = Time.now.hour.to_s.rjust(2, '0') - min = Time.now.min.to_s.rjust(2, '0') - secs = Time.now.sec.to_s.rjust(2, '0') + def print_next_action + timestamp = Timepoint.new(Client.next_action.first) + action = case Client.next_action.last + when :start then "Pomodoro" + when :stop then "Pomodoro Break" + when :lunch then "Lunch time" + when :go_home then "Go home" + + time_left = timestamp.left_until + $stdout.print "\r" - $stdout.print " " * 20 + $stdout.print " " * 50 $stdout.print "\r" - $stdout.print "#{hour}:#{min}:#{secs}" + $stdout.print "Next: #{action} in #{time_left}" $stdout.flush end diff --git a/lib/domodoro/config.rb b/lib/domodoro/config.rb index 0f8895f..958fab7 100644 --- a/lib/domodoro/config.rb +++ b/lib/domodoro/config.rb @@ -1,11 +1,12 @@ require 'yaml' +require 'ostruct' module Domodoro module Config attr_accessor :visual, :sound extend self - def load + def load_client_configuration if File.exist?(File.expand_path('~/.domodororc')) file = YAML.load(File.read(File.expand_path('~/.domodororc'))) @@ -16,5 +17,35 @@ def load self.sound = true end end + + def get_server_configuration + config = OpenStruct.new + + if File.exist?(File.expand_path('~/.domodororc')) + file = YAML.load(File.read(File.expand_path('~/.domodororc')))['server'] + + config.pomodoro_duration = file['pomodoro_duration'] + config.pomodoro_break = file['pomodoro_break'] + config.long_break_after = file['long_break_after'] + + config.day_start = Timepoint.new(file['day_start']) + config.day_end = Timepoint.new(file['day_end']) + + config.lunch_time = Timepoint.new(file['lunch_time']) + config.lunch_duration = file['lunch_duration'] + end + + config.pomodoro_duration ||= 25 + config.pomodoro_break ||= 5 + config.long_break_after ||= 4 + + config.day_start ||= Timepoint.new('08:30') + config.day_end ||= Timepoint.new('16:30') + + config.lunch_time ||= Timepoint.new('13:00') + config.lunch_duration ||= 30 + + config + end end end diff --git a/lib/domodoro/schedule.rb b/lib/domodoro/schedule.rb new file mode 100644 index 0000000..26ef756 --- /dev/null +++ b/lib/domodoro/schedule.rb @@ -0,0 +1,82 @@ +module Domodoro + class Schedule + def initialize + @times = {} + @config = Config.get_server_configuration + end + + def generate! + # Key points + @times[@config.lunch_time.to_s] = :lunch + @times[@config.day_end.to_s] = :go_home + + + + generate_pomodoros_between(@config.day_start, @config.lunch_time) + generate_pomodoros_between(@config.lunch_time + @config.lunch_duration, @config.day_end) + end + + def to_hash + @times + end + + def current_action(timestamp) + times = @times.dup + + if times[timestamp] + minus_one = false + else + minus_one = true + times[timestamp] = :now + end + + sorted = times.sort + + idx = sorted.index do |element| + element == sorted.assoc(timestamp) + end + + idx = idx - 1 if minus_one + + sorted[idx] + end + + def action_after(timestamp) + times = @times.dup + times[timestamp] ||= :now + sorted = times.sort + + idx = sorted.index do |element| + element == sorted.assoc(timestamp) + end + + sorted[idx + 1] + end + + private + + def generate_pomodoros_between(start, finish) + duration = @config.pomodoro_duration + pomodoro_break = @config.pomodoro_break + + time = start + long_break_yet = 1 + + while time.before?(finish) + @times[time.to_s] = :start + time += duration + + break unless time.before?(finish) + + @times[time.to_s] = :stop + + break_rest = pomodoro_break + break_rest *= 2 if long_break_yet == @config.long_break_after + + time += break_rest + + long_break_yet += 1 + end + end + end +end diff --git a/lib/domodoro/server.rb b/lib/domodoro/server.rb index 982fc30..822274b 100644 --- a/lib/domodoro/server.rb +++ b/lib/domodoro/server.rb @@ -1,18 +1,23 @@ module Domodoro class Server < EM::Connection + include EM::P::ObjectProtocol + attr_reader :channel class << self def start(host='0.0.0.0', port='9111') + schedule = Schedule.new + schedule.generate! + puts "#{Time.now} - Domodoro serving at #{host}:#{port}" EM.run do channel = Channel.new - EM.start_server(host, port, self, channel) + EM.start_server(host, port, self, channel, schedule) EM.add_periodic_timer(1) do if Time.now.sec == 0 - channel.broadcast(Time.now.hour, Time.now.min) + channel.broadcast(timestamp, schedule) else EM.next_tick do print_time @@ -32,14 +37,25 @@ def print_time $stdout.print "#{hour}:#{min}:#{secs}" $stdout.flush end + + def timestamp + hour = Time.now.hour.to_s.rjust(2, '0') + min = Time.now.min.to_s.rjust(2, '0') + [hour, min].join(':') + end end - def initialize(channel) + def initialize(channel, schedule) @channel = channel + @schedule = schedule end def post_init - @sid = channel.subscribe { |m| send_data "#{m.inspect}\n" } + @sid = channel.subscribe { |m| send_object(m) } + send_object({ + :current_action => @schedule.current_action(Server.timestamp), + :next_action => @schedule.action_after(Server.timestamp) + }) end def unbind diff --git a/lib/domodoro/timepoint.rb b/lib/domodoro/timepoint.rb new file mode 100644 index 0000000..1196dde --- /dev/null +++ b/lib/domodoro/timepoint.rb @@ -0,0 +1,68 @@ +module Domodoro + class Timepoint + attr_reader :hour, :min + + def initialize(*args) + case args.first + when String + @hour, @min = args.first.split(':').map(&:to_i) + when Fixnum + @hour, @min = args.first, args.last + end + end + + def +(minutes) + hours_to_advance = ((@min + minutes) / 60).to_i + + h = @hour + hours_to_advance + m = (@min + minutes) % 60 + + Timepoint.new("#{h}:#{m}") + end + + def after?(timepoint) + if @hour > timepoint.hour + true + elsif @hour == timepoint.hour + @min >= timepoint.min + else + false + end + end + + def before?(timepoint) + if @hour < timepoint.hour + true + elsif @hour == timepoint.hour + @min < timepoint.min + else + false + end + end + + def ==(timepoint) + case timepoint + when String + Timepoint.new(timepoint) == self + when Timepoint + @hour == timepoint.hour && @min == timepoint.min + end + end + + def to_s + [@hour, @min].map(&:to_s).map do |number| + number.rjust(2, '0') + end.join(':') + end + + def left_until(timestamp) + hours_to_reduce = (60 / @min - minutes).to_i + + h = @hour - hours_to_reduce + m = (@min - minutes) % 60 + s = 60 - Time.now.sec + + "#{h}:#{m}:#{s}" + end + end +end diff --git a/test/domodoro/channel_test.rb b/test/domodoro/channel_test.rb index 95fd6f0..53a4a65 100644 --- a/test/domodoro/channel_test.rb +++ b/test/domodoro/channel_test.rb @@ -11,123 +11,28 @@ module Domodoro end describe 'broadcast' do - describe 'in the morning' do - it 'broadcasts from 8:00 until 12:59' do - @channel.expects(:morning).with(5).never - @channel.expects(:morning).with(10).once - @channel.expects(:morning).with(15).once - @channel.expects(:morning).with(20).once - @channel.expects(:morning).with(25).once - @channel.expects(:morning).with(30).once - @channel.expects(:morning).with(35).never - - min = 0 - (7..13).each do |hour| - min += 5 - @channel.broadcast(hour, min) - end - end - end - - describe 'in the afternoon' do - it 'broadcasts from 13:20 on' do - @channel.expects(:afternoon).with(5).never - @channel.expects(:afternoon).with(10).never - @channel.expects(:afternoon).with(15).never - @channel.expects(:afternoon).with(20).once - @channel.expects(:afternoon).with(25).once - @channel.expects(:afternoon).with(30).once - @channel.expects(:afternoon).with(35).once - - min = 0 - (13..19).each do |hour| - min += 5 - @channel.broadcast(hour, min) - end - end + before do + @schedule = {'08:30' => :start, '09:00' => :stop} end - it 'does not broadcast during lunch time' do - %w(morning afternoon).each do |timespan| - @channel.expects(timespan).with(5).never - end - - (0..19).each do |min| - @channel.broadcast(13, min) - end - end - end - - describe '#morning' do - describe 'pomodoro starts' do - it 'broadcasts a :start message when the time is XX:00' do - @channel.expects(:<<).with(:start) - @channel.morning 0 - end - - it 'broadcasts a :start message when the time is XX:30' do + describe 'if theres an action for the timestamp' do + it 'broadcasts it' do @channel.expects(:<<).with(:start) - @channel.morning 30 - end - end - - describe 'pomodoro stops' do - it 'broadcasts a :stop message when the time is XX:25' do @channel.expects(:<<).with(:stop) - @channel.morning 25 - end - it 'broadcasts a :stop message when the time is XX:55' do - @channel.expects(:<<).with(:stop) - @channel.morning 55 - end - end - - it 'does not broadcast anything at other times' do - @channel.expects(:<<).never - - @channel.morning 5 - @channel.morning 10 - @channel.morning 20 - @channel.morning 40 - @channel.morning 50 - end - end - - describe '#afternoon' do - describe 'pomodoro starts' do - it 'broadcasts a :start message when the time is XX:20' do - @channel.expects(:<<).with(:start) - @channel.afternoon 20 - end - - it 'broadcasts a :start message when the time is XX:50' do - @channel.expects(:<<).with(:start) - @channel.afternoon 50 + @channel.broadcast("08:30", @schedule) + @channel.broadcast("09:00", @schedule) end end - describe 'pomodoro stops' do - it 'broadcasts a :stop message when the time is XX:45' do - @channel.expects(:<<).with(:stop) - @channel.afternoon 45 - end + describe 'otherwise' do + it 'does not' do + @channel.expects(:<<).never - it 'broadcasts a :stop message when the time is XX:15' do - @channel.expects(:<<).with(:stop) - @channel.afternoon 15 + @channel.broadcast("07:30", @schedule) + @channel.broadcast("08:31", @schedule) end end - - it 'does not broadcast anything at other times' do - @channel.expects(:<<).never - - @channel.afternoon 5 - @channel.afternoon 10 - @channel.afternoon 25 - @channel.afternoon 40 - @channel.afternoon 55 - end end end end diff --git a/test/domodoro/config_test.rb b/test/domodoro/config_test.rb index a532d57..37a455f 100644 --- a/test/domodoro/config_test.rb +++ b/test/domodoro/config_test.rb @@ -9,7 +9,7 @@ module Domodoro visual: true sound: false """ - Domodoro::Config.load + Domodoro::Config.load_client_configuration assert_equal true, Domodoro::Config.visual assert_equal false, Domodoro::Config.sound @@ -20,7 +20,7 @@ module Domodoro it 'sets both options to true' do File.stubs(:exist?).returns false - Domodoro::Config.load + Domodoro::Config.load_client_configuration assert_equal true, Domodoro::Config.visual assert_equal true, Domodoro::Config.sound diff --git a/test/domodoro/schedule_test.rb b/test/domodoro/schedule_test.rb new file mode 100644 index 0000000..67335c7 --- /dev/null +++ b/test/domodoro/schedule_test.rb @@ -0,0 +1,108 @@ +require 'test_helper' +require 'ostruct' +require 'pp' + +module Domodoro + describe Schedule do + before do + File.stubs(:exist?).returns false + @schedule = Schedule.new + @schedule.generate! + @times = @schedule.to_hash + end + + describe "before lunch" do + it 'generates start times correctly' do + %w(08:30 09:00 09:30 10:00 10:35 11:05 11:35 12:05 12:35).each do |time| + assert_equal :start, @times[time] + end + end + + it 'generates stop times correctly' do + %w(08:55 09:25 09:55 10:25 11:00 11:30 12:00 12:30).each do |time| + assert_equal :stop, @times[time] + end + assert_equal :lunch, @times["13:00"] + end + end + + describe 'after lunch' do + it 'generates start times correctly' do + %w(13:30 14:00 14:30 15:00 15:35 16:05).each do |time| + assert_equal :start, @times[time] + end + end + + it 'generates stop times correctly' do + %w(13:55 14:25 14:55 15:25 16:00).each do |time| + assert_equal :stop, @times[time] + end + assert_equal :go_home, @times["16:30"] + end + end + + describe 'uneven, weird schedules' do + before do + config = OpenStruct.new + config.pomodoro_duration = 25 + config.pomodoro_break = 5 + config.long_break_after = 4 + config.day_start = Timepoint.new('9:13') + config.lunch_time = Timepoint.new('12:49') + config.lunch_duration = 120 + config.day_end = Timepoint.new('15:00') + + Config.expects(:get_server_configuration).returns config + + @schedule = Schedule.new + @schedule.generate! + @times = @schedule.to_hash + end + + it 'respect lunch' do + assert_equal :lunch, @times["12:49"] + assert_equal :start, @times["14:49"] + end + + it 'respect home' do + assert_equal :go_home, @times["15:00"] + end + end + + describe '#action_after' do + it 'returns the next action after a given timestamp' do + times = { + "08:30" => :start, + "09:15" => :stop, + "10:15" => :start, + } + + @schedule = Schedule.new + @schedule.instance_variable_set(:@times, times) + + @schedule.action_after("08:30").must_equal ['09:15', :stop] + @schedule.action_after("08:45").must_equal ['09:15', :stop] + @schedule.action_after("09:31").must_equal ['10:15', :start] + end + end + + describe '#current_action' do + it 'returns the current or past action on a given timestamp' do + times = { + "08:30" => :start, + "09:15" => :stop, + "10:15" => :start, + } + + @schedule = Schedule.new + @schedule.instance_variable_set(:@times, times) + + @schedule.current_action("08:30").must_equal ['08:30', :start] + @schedule.current_action("08:31").must_equal ['08:30', :start] + @schedule.current_action("09:18").must_equal ['09:15', :stop] + @schedule.current_action("12:18").must_equal ['10:15', :start] + end + end + + end +end diff --git a/test/domodoro/server_test.rb b/test/domodoro/server_test.rb index 2548590..2a6e7b1 100644 --- a/test/domodoro/server_test.rb +++ b/test/domodoro/server_test.rb @@ -6,18 +6,14 @@ module Domodoro before do @channel = Channel.new - end - - it 'initializes with a channel' do - server = Domodoro::Server.new(nil, @channel) - assert_equal @channel, server.channel + @schedule = Schedule.new + @schedule.generate! end it 'repeats every message broadcasted to the channel' do - server = Server.new(nil, @channel) - EM.start_server('127.0.0.1', 8888, Server, :app => server) + EM.start_server('127.0.0.1', 8888, Server, @channel, @schedule) - server.expects(:send_data).with(":start\n") + Server.any_instance.expects(:send_data).with(":start\n") @channel << :start end @@ -25,7 +21,8 @@ module Domodoro describe '.start' do it 'opens a server with a new channel' do Channel.expects(:new).returns @channel - EM.expects(:start_server).with('0.0.0.0', '8888', Server, @channel) + Schedule.expects(:new).returns @schedule + EM.expects(:start_server).with('0.0.0.0', '8888', Server, @channel, @schedule) Server.start('0.0.0.0', '8888') end @@ -61,5 +58,34 @@ def @channel.broadcast(*args) end end + describe 'on connection' do + it 'sends the current and next actions to the client', :timeout => 0.2 do + Server.stubs(:timestamp).returns "13:15" + + EM.start_server('127.0.0.1', 8888, Server, @channel, @schedule) + + FakeSocketClient = Class.new(EM::Connection) do + include EM::P::ObjectProtocol + @@object = nil + def receive_object(object) + @@object = object + end + end + + EM.connect('127.0.0.1', 8888, FakeSocketClient) + + EM.add_timer(0.1) do + object = FakeSocketClient.class_variable_get(:@@object) + + assert_equal ["13:00", :lunch], object[:current_action] + assert_equal ["13:30", :start], object[:next_action] + + done! + end + + wait! + end + end + end end diff --git a/test/domodoro/timepoint_test.rb b/test/domodoro/timepoint_test.rb new file mode 100644 index 0000000..1ede082 --- /dev/null +++ b/test/domodoro/timepoint_test.rb @@ -0,0 +1,87 @@ +require 'test_helper' + +module Domodoro + describe Timepoint do + before do + @timepoint = Timepoint.new("08:30") + end + + it 'initializes with an hour/minute timestamp' do + assert_equal 8, @timepoint.hour + assert_equal 30, @timepoint.min + end + + it 'initializes with hours and minutes as fixnums' do + timepoint = Timepoint.new(8, 30) + assert_equal 8, timepoint.hour + assert_equal 30, timepoint.min + end + + describe '#to_s' do + it 'returns the original timestamp' do + assert_equal "08:30", @timepoint.to_s + end + end + + describe '+' do + describe 'when the added minutes belong to the next hour' do + it 'adds time appropriately returning a new timepoint' do + new_timepoint = @timepoint + 45 + + assert_equal 9, new_timepoint.hour + assert_equal 15, new_timepoint.min + end + end + + describe 'within the same hour' do + it 'works the same way' do + new_timepoint = @timepoint + 15 + + assert_equal 8, new_timepoint.hour + assert_equal 45, new_timepoint.min + end + end + end + + describe '#after?' do + before do + @timepoint = Timepoint.new(8, 30) + end + it 'tells if the timepoint is after another timepoint' do + Timepoint.new(8, 45).after?(@timepoint).must_equal true + Timepoint.new(9, 15).after?(@timepoint).must_equal true + Timepoint.new(8, 25).after?(@timepoint).must_equal false + Timepoint.new(7, 10).after?(@timepoint).must_equal false + end + end + + describe '#before?' do + before do + @timepoint = Timepoint.new(17, 30) + end + it 'tells if the timepoint is before another timepoint' do + Timepoint.new(17, 15).before?(@timepoint).must_equal true + Timepoint.new(13, 00).before?(@timepoint).must_equal true + Timepoint.new(17, 40).before?(@timepoint).must_equal false + Timepoint.new(19, 10).before?(@timepoint).must_equal false + end + end + + describe '#==' do + before do + @timepoint = Timepoint.new(8, 30) + end + it 'tells if the timepoint equals another timepoint' do + Timepoint.new(8, 30).must_equal @timepoint + Timepoint.new(8, 45).wont_equal @timepoint + Timepoint.new(8, 15).wont_equal @timepoint + end + + it 'tells if the timepoint equals another string' do + "08:30".must_equal @timepoint + "08:45".wont_equal @timepoint + "08:15".wont_equal @timepoint + end + end + end +end