From b5e7e61d643243de9ca5077687d971c77bfeba5b Mon Sep 17 00:00:00 2001 From: Anton Vakhrushev Date: Mon, 4 Nov 2019 19:59:55 +0300 Subject: [PATCH] Divide code --- spec/{dayoff_spec.cr => profile_spec.cr} | 2 +- spec/spec_helper.cr | 2 +- src/dayoff.cr | 156 ----------------------- src/dayoff/entities.cr | 45 +++++++ src/dayoff/exceptions.cr | 7 + src/dayoff/profile.cr | 57 +++++++++ src/dayoff/storage.cr | 31 +++++ 7 files changed, 142 insertions(+), 158 deletions(-) rename spec/{dayoff_spec.cr => profile_spec.cr} (98%) create mode 100644 src/dayoff/entities.cr create mode 100644 src/dayoff/exceptions.cr create mode 100644 src/dayoff/profile.cr create mode 100644 src/dayoff/storage.cr diff --git a/spec/dayoff_spec.cr b/spec/profile_spec.cr similarity index 98% rename from spec/dayoff_spec.cr rename to spec/profile_spec.cr index da435cb..2688027 100644 --- a/spec/dayoff_spec.cr +++ b/spec/profile_spec.cr @@ -8,7 +8,7 @@ module Dayoff::Test Time.local(2019, 1, day, hour, min, location: location) end - describe Dayoff do + describe Profile do it "can calc work hours" do storage = MemoryStorage.new storage.set_work_records [ diff --git a/spec/spec_helper.cr b/spec/spec_helper.cr index f1e1665..1527d2f 100644 --- a/spec/spec_helper.cr +++ b/spec/spec_helper.cr @@ -1,2 +1,2 @@ require "spec" -require "../src/dayoff" +require "../src/**" diff --git a/src/dayoff.cr b/src/dayoff.cr index b858b91..71c63e1 100644 --- a/src/dayoff.cr +++ b/src/dayoff.cr @@ -1,162 +1,6 @@ -require "json" - module Dayoff VERSION = "0.1.0" - class PlannedDate - JSON.mapping( - date: String, - hours: Int32, - ) - end - - class WorkRecord - JSON.mapping( - start: 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) - def initialize(@path : String) - end - - def get_all : Array(T) - if File.file? @path - content = File.read @path - Array(T).from_json(content) - else - [] of T - end - end - - def write(items : Array(T)) - 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" - - @pdates = [] of PlannedDate - @wrecords = [] of WorkRecord - - def initialize(@storage : Storage) - @pdates = @storage.get_planned_dates - @wrecords = @storage.get_work_records - end - - def get_planned_hours - sum = 0 - @pdates.each do |wd| - sum += wd.hours - end - sum - end - - def get_work_hours - @wrecords.reduce 0 do |acc, wr| - diff = wr.finish_time - wr.start_time - acc + diff.total_hours.to_i32 - end - 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(profile_id : ProfileId) Profile.new(profile_id.to_s) diff --git a/src/dayoff/entities.cr b/src/dayoff/entities.cr new file mode 100644 index 0000000..5572993 --- /dev/null +++ b/src/dayoff/entities.cr @@ -0,0 +1,45 @@ +require "json" + +module Dayoff + class PlannedDate + JSON.mapping( + date: String, + hours: Int32, + ) + end + + class WorkRecord + JSON.mapping( + start: 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 +end diff --git a/src/dayoff/exceptions.cr b/src/dayoff/exceptions.cr new file mode 100644 index 0000000..0399476 --- /dev/null +++ b/src/dayoff/exceptions.cr @@ -0,0 +1,7 @@ +module Dayoff + class CrossedTimeSpan < Exception + end + + class StartedRecordNotFound < Exception + end +end diff --git a/src/dayoff/profile.cr b/src/dayoff/profile.cr new file mode 100644 index 0000000..e893597 --- /dev/null +++ b/src/dayoff/profile.cr @@ -0,0 +1,57 @@ +module Dayoff + struct ProfileId + def initialize(@id : String) + end + + getter id + + def to_s : String + @id + end + end + + class Profile + @pdates = [] of PlannedDate + @wrecords = [] of WorkRecord + + def initialize(@storage : Storage) + @pdates = @storage.get_planned_dates + @wrecords = @storage.get_work_records + end + + def get_planned_hours + sum = 0 + @pdates.each do |wd| + sum += wd.hours + end + sum + end + + def get_work_hours + @wrecords.reduce 0 do |acc, wr| + diff = wr.finish_time - wr.start_time + acc + diff.total_hours.to_i32 + end + 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 +end diff --git a/src/dayoff/storage.cr b/src/dayoff/storage.cr new file mode 100644 index 0000000..6631bfd --- /dev/null +++ b/src/dayoff/storage.cr @@ -0,0 +1,31 @@ +require "json" + +module Dayoff + 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 +end