gb_work_day 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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