diff --git a/spec/data/planned-dates.json b/spec/data/planned-dates.json deleted file mode 100644 index 0eecd84..0000000 --- a/spec/data/planned-dates.json +++ /dev/null @@ -1,14 +0,0 @@ -[ - { - "date": "2019-01-01", - "hours": 10 - }, - { - "date": "2019-01-02", - "hours": 6 - }, - { - "date": "2019-01-03", - "hours": 4 - } -] \ No newline at end of file diff --git a/spec/data/work-records.json b/spec/data/work-records.json deleted file mode 100644 index 9c2df8d..0000000 --- a/spec/data/work-records.json +++ /dev/null @@ -1,6 +0,0 @@ -[ - { - "start": "2019-01-01 10:00:00", - "finish": "2019-01-01 20:00:00" - } -] \ No newline at end of file diff --git a/spec/dayoff_spec.cr b/spec/dayoff_spec.cr index 4e61eaf..da435cb 100644 --- a/spec/dayoff_spec.cr +++ b/spec/dayoff_spec.cr @@ -1,15 +1,48 @@ require "./spec_helper" -describe Dayoff do - it "can calc work hours" do - app = Dayoff::App.new - prof = app.profile("./spec/data") - prof.get_planned_hours.should eq 20 +module Dayoff::Test + extend self + + def t(day, hour, min = 0) + location = Time::Location.load("Europe/Moscow") + Time.local(2019, 1, day, hour, min, location: location) end - it "can calc work hours" do - app = Dayoff::App.new - prof = app.profile("./spec/data") - prof.get_work_hours.should eq 10 + describe Dayoff do + it "can calc work hours" do + storage = MemoryStorage.new + storage.set_work_records [ + WorkRecord.new(t(1, 10), t(1, 20)), + ] + prof = Profile.new(storage) + prof.get_work_hours.should eq 10 + end + + it "can write new record" do + storage = MemoryStorage.new + storage.set_work_records [ + WorkRecord.new(t(1, 10), t(1, 20)), + ] + prof = Profile.new(storage) + start_time = t(2, 10) + prof.start start_time + records = storage.get_work_records + records.size.should eq 2 + records.last.finish.should be_nil + end + + it "can finish started record" do + storage = MemoryStorage.new + storage.set_work_records [ + WorkRecord.new(t(1, 10), t(1, 20)), + WorkRecord.new(t(2, 10), nil), + ] + prof = Profile.new(storage) + finish_time = t(2, 20) + prof.finish finish_time + records = storage.get_work_records + records.size.should eq 2 + records.last.finish_time.should eq finish_time + end end end diff --git a/src/dayoff.cr b/src/dayoff.cr index 095886b..9f5cf6e 100644 --- a/src/dayoff.cr +++ b/src/dayoff.cr @@ -13,8 +13,64 @@ module Dayoff class WorkRecord JSON.mapping( start: String, - finish: String, + finish: String | Nil, ) + + FORMAT = "%Y-%m-%d %H:%M:%S" + + def initialize(start : Time, finish : Time | Nil = nil) + @start = start.to_s FORMAT + @finish = nil + if finish + @finish = finish.to_s FORMAT + end + end + + def start_time : Time + location = Time::Location.load("Europe/Moscow") + Time.parse(start, FORMAT, location) + end + + def finish_time : Time + location = Time::Location.load("Europe/Moscow") + Time.parse(finish.as(String), FORMAT, location) + end + + def finish_time=(v : Time) + @finish = v.to_s FORMAT + end + + def started? : Bool + @finish.nil? + end + end + + abstract class Storage + abstract def get_planned_dates : Array(PlannedDate) + abstract def set_planned_dates(items : Array(PlannedDate)) + abstract def get_work_records : Array(WorkRecord) + abstract def set_work_records(items : Array(WorkRecord)) + end + + class MemoryStorage < Storage + @planned_dates = [] of PlannedDate + @work_records = [] of WorkRecord + + def get_planned_dates : Array(PlannedDate) + @planned_dates + end + + def set_planned_dates(items : Array(PlannedDate)) + @planned_dates = items + end + + def get_work_records : Array(WorkRecord) + @work_records + end + + def set_work_records(items : Array(WorkRecord)) + @work_records = items + end end class Collection(T) @@ -31,11 +87,28 @@ module Dayoff end def write(items : Array(T)) - content = items.to_json + content = items.to_pretty_json indent: " " File.write @path, content end end + class CrossedTimeSpan < Exception + end + + class StartedRecordNotFound < Exception + end + + struct ProfileId + def initialize(@id : String) + end + + getter id + + def to_s : String + @id + end + end + class Profile PLANNED_DATES = "planned-dates.json" WORK_RECORDS = "work-records.json" @@ -43,9 +116,9 @@ module Dayoff @pdates = [] of PlannedDate @wrecords = [] of WorkRecord - def initialize(@path : String) - @pdates = Collection(PlannedDate).new(File.join(@path, PLANNED_DATES)).get_all - @wrecords = Collection(WorkRecord).new(File.join(@path, WORK_RECORDS)).get_all + def initialize(@storage : Storage) + @pdates = @storage.get_planned_dates + @wrecords = @storage.get_work_records end def get_planned_hours @@ -60,18 +133,36 @@ module Dayoff sum = 0 location = Time::Location.load("Europe/Moscow") @wrecords.each do |wr| - s = Time.parse(wr.start, "%Y-%m-%d %H:%M:%S", location) - f = Time.parse(wr.finish, "%Y-%m-%d %H:%M:%S", location) - diff = f - s + diff = wr.finish_time - wr.start_time sum += diff.total_hours.to_i32 end sum end + + def start(time : Time) + @wrecords.each do |wr| + if time <= wr.start_time || time <= wr.finish_time + raise CrossedTimeSpan.new + end + end + new_record = WorkRecord.new time + @wrecords.push(new_record) + @storage.set_work_records @wrecords + end + + def finish(time : Time) + started = @wrecords.find { |x| x.started? } + if started.nil? + raise StartedRecordNotFound.new + end + started.finish_time = time + @storage.set_work_records @wrecords + end end class App - def profile(path) - Profile.new(path) + def profile(profile_id : ProfileId) + Profile.new(profile_id.to_s) end end end