Делу - время, потехе - час

09.10.2013 в 18:00 ruby gem develop

Время самое ценное, что у нас есть и его учет - это очень важно! Немного пафосно, но от реальности не убежишь. :) Так вот... В одном из проектов мне понадобился учет рабочего времени. Т.е. не просто "пришел-ушел-прогулял", а в плане планирования рабочего времени на выполнение той или иной задачи. Например: на выполнение очень важной задачи нам отвели 10 часов, а рабочий день у многих из нас, скажем, 8 часов и еще бывают выходные (что это?!). Хотя многие "руководители" и "очень важные начальники" считают, что 24 часа, а то и 36! И никаких выходных! :) Как нам выставить конечный срок выполнения задачи, если она поступила к нам, скажем, в пятницу (ура!) в 16:45 (троекратное ура!)? Можно, конечно, изобрести велосипед и написать функцию с кучей условий (обед? вечер? ночь? выходные?), которая будет высчитывать конечный срок исполнения из полученных начала выполнения и времени на выполнение (в часах или минутах). Я, признаться, собирался именно так и поступить. И тут, совершенно случайно, в ленте твиттера проскочил пост от @rubygems о том, что он рад мне помочь в этом - есть (оказывается) такой gem workpattern. Он умеет все это делать в лучшем виде!

Все объясняет простой пример кода:

 1 # пишем инициалайзер (например config/initializers/workpattern.rb), ибо паттерны именованые и создаются единожды при старте приложения
 2   # разумеентся их можно создавать в runtime, но не забывайте их удалять, иначе получите exception при повторном создании
 3 
 4   # создаем новый паттерн
 5   MyCoolApp::Application.config.workpattern = Workpattern.new('8х5 Workpattern', 2013, 01)
 6   # выходные у нас есть, что бы кто не говорил!
 7   MyCoolApp::Application.config.workpattern.resting(days: :weekend)
 8   # ночью (с 00:00 до 08:59) мы спим (ага!)
 9   MyCoolApp::Application.config.workpattern.resting(days: :weekday, from_time: Workpattern.clock(0, 0), to_time: Workpattern.clock(8, 59))
10   # в обед (с 13:00 до 13:59) мы обедаем (ваш КО)
11   MyCoolApp::Application.config.workpattern.resting(days: :weekday, from_time: Workpattern.clock(13, 0), to_time: Workpattern.clock(13, 59)) 
12   # вечером (с 18:00 до 23:59) решаем личные проблемы
13   MyCoolApp::Application.config.workpattern.resting(days: :weekday, from_time: Workpattern.clock(18, 0), to_time: Workpattern.clock(23, 59)) 
14 
15   # бла-бла-бла...
16 
17   # простой хелпер для высчитывания конечного срока
18   def get_datetime start_datetime, duration, all_arround_day = false
19     unless all_arround_day # класс обслуживания НЕ круглосуточный (8х5)
20       return MyCoolApp::Application.config.workpattern.calc(start_datetime, duration.minutes)
21     else # класс обслуживания круглосуточный (24х7)
22       return (start_datetime + duration.hours)
23     end
24   end
25 
26   # бла-бла-бла...
27 
28   # GET /incedents/new
29   def new
30     @incedent = Incedent.new
31 
32     # бла-бла-бла...
33 
34     if params[:service_class_id]
35       # у нас присутствует класс обслуживания с указанными заранее параметрами срока исполнения и т.п.
36       @incedent.service_class = ServiceClass.find(params[:service_class_id])
37 
38       # бла-бла-бла...
39 
40       # performance_hours - количество часов на выполнение в данном классе обслуживания
41       # all_around_day = true - круглосуточно
42       @incedent.finish_at = get_datetime(DateTime.now, @incedent.service_class.performance_hours, @incedent.service_class.all_around_day)
43     else
44       @incedent.finish_at = get_datetime(DateTime.now, 8) # по умолчанию на выполнение 8 рабочих часов
45     end
46 
47     respond_to do |format|
48       format.html # new.html.erb
49     end
50   end

Я полагаю дальнейшие объяснения излишни, все и так ясно из примера кода. Повторюсь, что создавать статичные паттерны лучше в инициалайзере, но если есть необходимость можно клепать их прямо в runtime.

Удачного программирования!