gb_work_day 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,33 @@
1
+ require 'gb_work_day/interval'
2
+ module GBWorkDay
3
+ class Date < ::Date
4
+ attr_accessor :work_week
5
+
6
+ def -(other)
7
+ if other.is_a?(::Date) || other.is_a?(::Time)
8
+ Interval.new(self, other, week: self.work_week).work_days
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ # @return [GBWorkDay::WorkWeek]
17
+ def default_week
18
+ self.work_week || GBWorkDay::WorkWeek.current
19
+ end
20
+
21
+ class << self
22
+ # Create {GBWorkingDay::Date} object from a given Date object.
23
+ # Copy constructor.
24
+ #
25
+ # @param date [Date]
26
+ def from_date(date, work_week = nil)
27
+ new_date = self.jd(date.jd)
28
+ new_date.work_week = work_week if work_week
29
+ new_date
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ require 'gb_work_day/interval'
2
+ module GBWorkDay
3
+ class Time < ::Time
4
+ attr_accessor :work_week
5
+
6
+ def -(other)
7
+ if other.is_a?(::Time) || other.is_a?(::Date)
8
+ Interval.new(self, other, week: work_week).work_days
9
+ else
10
+ super
11
+ end
12
+ end
13
+
14
+ private
15
+
16
+ # @return [GBWorkDay::WorkWeek]
17
+ def default_week
18
+ self.work_week || GBWorkDay::WorkWeek.current
19
+ end
20
+
21
+ class << self
22
+ # Create {GBWorkingDay::Time} object from a given Time object.
23
+ # Copy constructor.
24
+ #
25
+ # @param time [Time]
26
+ def from_time(time, work_week=nil)
27
+ new_time = self.at(time)
28
+ new_time.work_week = work_week if work_week
29
+ new_time
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,55 @@
1
+ require 'gb_work_day/work_week'
2
+ require 'gb_work_day/duration'
3
+ module GBWorkDay
4
+ class Interval
5
+ attr_reader :start_time, :end_time
6
+
7
+ # @param start_time [Time, Date]
8
+ # @param end_time [Time, Date]
9
+ # @param params [Hash]
10
+ # @option params [Fixnum] :work_days number of work days in a week, default is 7
11
+ # @option params [Fixnum] :week_start first working day in a week as number. Default value is 1 corresponding to Monday.
12
+ def initialize(start_time, end_time, params=Hash.new)
13
+ @start_time = start_time
14
+ @end_time = end_time
15
+ @symbol = 1
16
+ revert if @start_time > @end_time
17
+ @working_week = params[:week]
18
+ unless @working_week
19
+ if params[:work_days] || params[:week_start]
20
+ work_days = params.fetch(:work_days, 7)
21
+ week_start = params.fetch(:week_start, 1)
22
+ @working_week = WorkWeek.new work_days, week_start
23
+ else
24
+ @working_week = WorkWeek.current
25
+ end
26
+ end
27
+ end
28
+
29
+ # @return [Integer] Number of working days in a given period
30
+ def work_days
31
+ date = @start_time
32
+ work_days = 0
33
+ while date < end_time
34
+ work_days += 1 if @working_week.work_day?(date)
35
+ date += 1.day
36
+ end
37
+ Duration.new(work_days * @symbol, @working_week)
38
+ end
39
+
40
+ alias_method :duration, :work_days
41
+
42
+ def endpoints
43
+ [start_time, end_time]
44
+ end
45
+
46
+ private
47
+
48
+ def revert
49
+ new_end_time = @start_time
50
+ @start_time = @end_time
51
+ @end_time = new_end_time
52
+ @symbol= @symbol * -1
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,3 @@
1
+ module GBWorkDay
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,58 @@
1
+ module GBWorkDay
2
+ class WorkWeek
3
+ attr_reader :work_days_per_week, :free_days_per_week, :work_days, :free_days, :week_start
4
+
5
+ # @param work_days [#to_i] Amount of working days in a week. Default value is 7.
6
+ # @param week_start [#to_i] Number of a week day, when work starts. Default value is 1 corresponding to Monday
7
+ def initialize(work_days=7, week_start=1)
8
+ work_days = work_days.to_i
9
+ week_start = week_start.to_i
10
+ raise ArgumentError, 'Work days have to be between 0 and 7!' unless work_days >= 0 && work_days <= 7
11
+ @work_days_per_week = work_days
12
+ @week_start = week_start % 7
13
+ @free_days_per_week = 7 - @work_days_per_week
14
+ @work_days = []
15
+ @work_days_per_week.times do
16
+ day = week_start % 7
17
+ @work_days << (day != 0 ? day : 7)
18
+ week_start += 1
19
+ end
20
+ @work_days.sort!
21
+ @free_days = (1..7).to_a - @work_days
22
+ end
23
+
24
+ # Check if given day is a work day
25
+ # @param day [Time, Date]
26
+ def work_day?(day)
27
+ week_day = day.wday
28
+ week_day = 7 if week_day == 0
29
+ work_days.include? week_day
30
+ end
31
+
32
+ # Check if given day is a work day
33
+ # @param day [Time, Date]
34
+ def free_day?(day)
35
+ week_day = day.wday
36
+ week_day = 7 if week_day == 0
37
+ free_days.include? week_day
38
+ end
39
+
40
+ def ==(other) # :nodoc:
41
+ work_days_per_week == other.work_days_per_week && week_start == other.week_start
42
+ end
43
+
44
+ def eql?(other) # :nodoc:
45
+ work_days_per_week.eql?(other.work_days_per_week) && week_start.eql?(other.week_start)
46
+ end
47
+
48
+ class << self
49
+ def current
50
+ Thread.current[:working_week] ||= self.new
51
+ end
52
+
53
+ def current=(new_week)
54
+ Thread.current[:working_week] = new_week if WorkWeek === new_week
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'gb_work_day/core_ext/date'
3
+ require 'gb_work_day/core_ext/integer'
4
+ require 'active_support/time'
5
+
6
+ describe 'Date extensions' do
7
+ before(:all) { GBWorkDay::WorkWeek.current = GBWorkDay::WorkWeek.new(5) }
8
+ after(:all) { GBWorkDay::WorkWeek.current = GBWorkDay::WorkWeek.new() }
9
+
10
+ it 'should respond to work?' do
11
+ expect(Date.today.beginning_of_week.work?).to be_truthy
12
+ expect(Date.today.end_of_week.work?).to be_falsey
13
+ end
14
+
15
+ it 'should respond to free?' do
16
+ expect(Date.today.beginning_of_week.free?).to be_falsey
17
+ expect(Date.today.end_of_week.free?).to be_truthy
18
+ end
19
+
20
+ it 'should respond to work_date' do
21
+ date = Date.today
22
+ expect(date.work_date).to be_kind_of GBWorkDay::Date
23
+ expect(date.work_date).to eq date
24
+ end
25
+
26
+ it 'should respond to to_work_date' do
27
+ date = Date.today
28
+ expect(date.to_work_date).to be_kind_of GBWorkDay::Date
29
+ expect(date.to_work_date).to eq date
30
+ end
31
+
32
+ it 'should respond to to_work' do
33
+ date = Date.today
34
+ expect(date.to_work).to be_kind_of GBWorkDay::Date
35
+ expect(date.to_work).to eq date
36
+ end
37
+
38
+ it 'should properly subtract work dates' do
39
+ expect(Date.today - Date.tomorrow.to_work_date).to be_a_kind_of GBWorkDay::Duration
40
+ end
41
+
42
+ it 'should return next_work_day' do
43
+ monday = Date.today.beginning_of_week
44
+ friday = monday + 4.days
45
+ sunday = Date.today.end_of_week
46
+ expect(monday.next_work_day). to eq (monday + 1.day)
47
+ expect(friday.next_work_day). to eq (friday + 3.day)
48
+ expect(sunday.next_work_day). to eq (sunday + 1.day)
49
+ end
50
+
51
+ it 'should properly subtract work duration' do
52
+ monday = Date.today.beginning_of_week
53
+ wednesday = monday + 2.days
54
+ expect(monday - 1.work_day).to eq (monday - 3.days)
55
+ expect(wednesday - 2.work_day).to eq (wednesday - 2.days)
56
+ end
57
+
58
+ it 'should properly add work duration' do
59
+ monday = Date.today.beginning_of_week
60
+ wednesday = monday + 2.days
61
+ friday = monday + 4.days
62
+ expect(monday + 1.work_day).to eq (monday + 1.days)
63
+ expect(friday + 1.work_day).to eq (friday + 3.days)
64
+ expect(wednesday + 2.work_day).to eq (wednesday + 2.days)
65
+ end
66
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+ require 'gb_work_day/core_ext/integer'
3
+ require 'gb_work_day/duration'
4
+
5
+ describe 'Integer extensions' do
6
+
7
+ it 'should respond work_days' do
8
+ expect(2.work_days).to be_kind_of GBWorkDay::Duration
9
+ expect(2.work_days.work_days).to eq 2
10
+ expect(2.work_days.week).to eq GBWorkDay::WorkWeek.current
11
+ end
12
+
13
+ it 'should respond work_day' do
14
+ expect(1.work_day).to be_kind_of GBWorkDay::Duration
15
+ expect(1.work_day.work_days).to eq 1
16
+ expect(1.work_day.week).to eq GBWorkDay::WorkWeek.current
17
+ end
18
+
19
+ it 'should setup proper week on work_days' do
20
+ week = GBWorkDay::WorkWeek.new(5, 1)
21
+ expect(2.work_days(week).week).to eq week
22
+ end
23
+
24
+ it 'should be able to sum' do
25
+ expect(1.work_day + 2).to eq 3.work_days
26
+ expect(1.work_day + 2.work_day).to eq 3.work_days
27
+ end
28
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+ require 'gb_work_day/core_ext/time'
3
+ require 'gb_work_day/core_ext/integer'
4
+ require 'active_support/time'
5
+
6
+ describe 'Time extensions' do
7
+ before(:all) { GBWorkDay::WorkWeek.current = GBWorkDay::WorkWeek.new(5) }
8
+ after(:all) { GBWorkDay::WorkWeek.current = GBWorkDay::WorkWeek.new() }
9
+
10
+ it 'should respond to work?' do
11
+ expect(Time.now.beginning_of_week.work?).to be_truthy
12
+ expect(Time.now.end_of_week.work?).to be_falsey
13
+ end
14
+
15
+ it 'should respond to free?' do
16
+ expect(Time.now.beginning_of_week.free?).to be_falsey
17
+ expect(Time.now.end_of_week.free?).to be_truthy
18
+ end
19
+
20
+ it 'should respond to work_time' do
21
+ time = Time.now
22
+ expect(time.work_time).to be_kind_of GBWorkDay::Time
23
+ expect(time.work_time).to eq time
24
+ end
25
+
26
+ it 'should respond to to_work_time' do
27
+ time = Time.now
28
+ expect(time.to_work_time).to be_kind_of GBWorkDay::Time
29
+ expect(time.to_work_time).to eq time
30
+ end
31
+
32
+ it 'should respond to to_work' do
33
+ time = Time.now
34
+ expect(time.to_work).to be_kind_of GBWorkDay::Time
35
+ expect(time.to_work).to eq time
36
+ end
37
+
38
+ it 'should properly subtract work times' do
39
+ expect(Time.now - (Time.now + 1.day).to_work_time).to be_a_kind_of GBWorkDay::Duration
40
+ end
41
+
42
+ it 'should return next_work_day' do
43
+ monday = Time.now.beginning_of_week
44
+ friday = monday + 4.days
45
+ sunday = Time.now.end_of_week
46
+ expect(monday.next_work_day). to eq (monday + 1.day)
47
+ expect(friday.next_work_day). to eq (friday + 3.day)
48
+ expect(sunday.next_work_day). to eq (sunday + 1.day)
49
+ end
50
+
51
+ it 'should properly subtract work duration' do
52
+ monday = Time.now.beginning_of_week
53
+ wednesday = monday + 2.days
54
+ expect(monday - 1.work_day).to eq (monday - 3.days)
55
+ expect(wednesday - 2.work_day).to eq (wednesday - 2.days)
56
+ end
57
+
58
+ it 'should properly add work duration' do
59
+ monday = Time.now.beginning_of_week
60
+ wednesday = monday + 2.days
61
+ friday = monday + 4.days
62
+ expect(monday + 1.work_day).to eq (monday + 1.days)
63
+ expect(friday + 1.work_day).to eq (friday + 3.days)
64
+ expect(wednesday + 2.work_day).to eq (wednesday + 2.days)
65
+ end
66
+ end
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+ require 'gb_work_day/duration'
3
+ require 'active_support/time'
4
+
5
+ describe GBWorkDay::Duration do
6
+
7
+ it 'should add durations' do
8
+ expect(GBWorkDay::Duration.new(1) + GBWorkDay::Duration.new(1)).to eq GBWorkDay::Duration.new(2)
9
+ expect(GBWorkDay::Duration.new(1) + 1).to eq GBWorkDay::Duration.new(2)
10
+ end
11
+
12
+ it 'should subtract durations' do
13
+ expect(GBWorkDay::Duration.new(10) - GBWorkDay::Duration.new(7)).to eq GBWorkDay::Duration.new(3)
14
+ expect(GBWorkDay::Duration.new(10) - 3).to eq GBWorkDay::Duration.new(7)
15
+ end
16
+
17
+ it 'should negate durations' do
18
+ expect(-GBWorkDay::Duration.new(7)).to eq GBWorkDay::Duration.new(-7)
19
+ end
20
+
21
+ it 'should respond to is_a?' do
22
+ expect(GBWorkDay::Duration.new(1).is_a? GBWorkDay::Duration).to be_truthy
23
+ expect(GBWorkDay::Duration.new(1).is_a? Numeric).to be_truthy
24
+ end
25
+
26
+ it 'should respond to instance_of?' do
27
+ expect(GBWorkDay::Duration.new(1).instance_of? GBWorkDay::Duration).to be_truthy
28
+ expect(GBWorkDay::Duration.new(1).instance_of? Fixnum).to be_truthy
29
+ end
30
+
31
+ it 'should respond do equality signs' do
32
+ expect(GBWorkDay::Duration.new(1) == GBWorkDay::Duration.new(1)).to be_truthy
33
+ expect(GBWorkDay::Duration.new(1) == GBWorkDay::Duration.new(2)).to be_falsey
34
+ expect(GBWorkDay::Duration.new(1) == 1).to be_truthy
35
+ expect(GBWorkDay::Duration.new(1) == 2).to be_falsey
36
+
37
+ week = GBWorkDay::WorkWeek.new(3, 3)
38
+ expect(GBWorkDay::Duration.new(1, week) == GBWorkDay::Duration.new(1)).to be_falsey
39
+ expect(GBWorkDay::Duration.new(1, week) == GBWorkDay::Duration.new(2)).to be_falsey
40
+
41
+ expect(GBWorkDay::Duration.new(1).eql? GBWorkDay::Duration.new(1)).to be_truthy
42
+ expect(GBWorkDay::Duration.new(1).eql? GBWorkDay::Duration.new(2)).to be_falsey
43
+ end
44
+
45
+ it 'should return number of sec for to_s' do
46
+ expect(GBWorkDay::Duration.new(1).to_s).to eq '86400'
47
+ end
48
+
49
+
50
+ it 'should respond to_i' do
51
+ expect(GBWorkDay::Duration.new(1).to_i).to eq 86400
52
+ expect(GBWorkDay::Duration.new(1).to_i(:days)).to eq 1
53
+ end
54
+
55
+ it 'should respond to inspect' do
56
+ expect(GBWorkDay::Duration.new(1).inspect).to be_kind_of String
57
+ end
58
+
59
+ it 'should calculate proper time for future' do
60
+ week = GBWorkDay::WorkWeek.new(5, 1)
61
+ monday = Time.now.beginning_of_week
62
+
63
+ expect(GBWorkDay::Duration.new(1, week).since(monday)).to eq monday + 1.day
64
+ expect(GBWorkDay::Duration.new(-1, week).since(monday)).to eq monday - 3.days
65
+ expect(GBWorkDay::Duration.new(3, week).since(monday)).to eq monday + 3.days
66
+ expect(GBWorkDay::Duration.new(5, week).since(monday)).to eq monday + 7.days
67
+ expect(GBWorkDay::Duration.new(6, week).since(monday)).to eq monday + 8.days
68
+ expect(GBWorkDay::Duration.new(16, week).since(monday)).to eq monday + 22.days
69
+ end
70
+
71
+ it 'should calculate proper date for future' do
72
+ week = GBWorkDay::WorkWeek.new(5, 1)
73
+ monday = Date.today.beginning_of_week
74
+
75
+ expect(GBWorkDay::Duration.new(1, week).since(monday)).to eq monday + 1.day
76
+ expect(GBWorkDay::Duration.new(-1, week).since(monday)).to eq monday - 3.days
77
+ expect(GBWorkDay::Duration.new(3, week).since(monday)).to eq monday + 3.days
78
+ expect(GBWorkDay::Duration.new(5, week).since(monday)).to eq monday + 7.days
79
+ expect(GBWorkDay::Duration.new(6, week).since(monday)).to eq monday + 8.days
80
+ expect(GBWorkDay::Duration.new(16, week).since(monday)).to eq monday + 22.days
81
+ end
82
+
83
+ it 'should calculate proper time for past' do
84
+ week = GBWorkDay::WorkWeek.new(5, 1)
85
+ monday = Time.now.beginning_of_week
86
+
87
+ expect(GBWorkDay::Duration.new(1, week).until(monday)).to eq monday - 3.days
88
+ expect(GBWorkDay::Duration.new(-1, week).until(monday)).to eq monday + 1.days
89
+ expect(GBWorkDay::Duration.new(3, week).until(monday)).to eq monday - 5.days
90
+ expect(GBWorkDay::Duration.new(6, week).until(monday)).to eq monday - 10.days
91
+ expect(GBWorkDay::Duration.new(16, week).until(monday)).to eq monday - 24.days
92
+ end
93
+
94
+ it 'should calculate proper date for past' do
95
+ week = GBWorkDay::WorkWeek.new(5, 1)
96
+ monday = Date.today.beginning_of_week
97
+
98
+ expect(GBWorkDay::Duration.new(1, week).until(monday)).to eq monday - 3.days
99
+ expect(GBWorkDay::Duration.new(-1, week).until(monday)).to eq monday + 1.days
100
+ expect(GBWorkDay::Duration.new(3, week).until(monday)).to eq monday - 5.days
101
+ expect(GBWorkDay::Duration.new(6, week).until(monday)).to eq monday - 10.days
102
+ expect(GBWorkDay::Duration.new(16, week).until(monday)).to eq monday - 24.days
103
+ end
104
+ end