work_days 0.0.3

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,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in work_days.gemspec
4
+ gemspec
5
+
6
+ gem 'pry'
7
+ gem 'rspec'
8
+ gem 'guard-rspec'
9
+ gem 'rb-fsevent'
@@ -0,0 +1,46 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
25
+
26
+ guard 'rspec' do
27
+ watch(%r{^spec/.+_spec\.rb$})
28
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
29
+ watch('spec/spec_helper.rb') { "spec" }
30
+
31
+ # Rails example
32
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
33
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
34
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
35
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
36
+ watch('config/routes.rb') { "spec/routing" }
37
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
38
+
39
+ # Capybara features specs
40
+ watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
41
+
42
+ # Turnip features and steps
43
+ watch(%r{^spec/acceptance/(.+)\.feature$})
44
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
45
+ end
46
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Robert Jackson
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,63 @@
1
+ # WorkDays
2
+
3
+ Calculate the number of business days in a given period. Also, add convenience methods to Range, Date, and Time.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'work_days'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install work_days
18
+
19
+ ## Usage
20
+
21
+ Use your own custom work schedule by creating a class implementing
22
+ your custom holiday methods and including the WorkDays::CalculationMethods module
23
+ (and optionally the WorkDays::HolidayMethods module for a few of the presets).
24
+
25
+ class SampleSchedule
26
+ WorkDays::CalculationMethods
27
+ WorkDays::HolidayMethods
28
+
29
+ def observed_holidays
30
+ [:new_years_day, :christmas_day]
31
+ end
32
+ end
33
+
34
+ Then tell the library to use your new schedule:
35
+
36
+ WorkDays.work_schedule = SampleSchedule.new
37
+
38
+ You can also use a few pre-built schedules (WorkDays::WorkSchedules::Default, WorkDays::WorkSchedules::Bank).
39
+
40
+ By default a day is considered a work day as long as it is a week day and it isn't a holiday.
41
+ You can configure your own week days by overriding the week_day? method in your work schedule class.
42
+
43
+ ### Methods
44
+
45
+ These methods can be called either on an instance of your work schedule class or directly
46
+ on the WorkDays module (as long as you set the WorkDays.work_schedule).
47
+
48
+ * work_day?(date)
49
+ * Returns true for week days as long as it isn't a holiday.
50
+ * non_work_day?(date)
51
+ * The opposite of work_day?.
52
+ * work_days_in_range(start_date, end_date)
53
+ * Returns an array of the work days between the start and end dates.
54
+ * work_days_in_month(date)
55
+ * Returns an array of the work days for the year and month of the passed in date.
56
+
57
+ ## Contributing
58
+
59
+ 1. Fork it
60
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
61
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
62
+ 4. Push to the branch (`git push origin my-new-feature`)
63
+ 5. Create new Pull Request
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,33 @@
1
+ require 'date'
2
+
3
+ require_relative 'work_days/version'
4
+ require_relative 'work_days/calculation_methods'
5
+ require_relative 'work_days/holiday_methods'
6
+ require_relative 'work_days/work_schedules/default'
7
+ require_relative 'work_days/work_schedules/bank'
8
+ require_relative 'work_days/ext/date'
9
+ require_relative 'work_days/ext/time'
10
+ require_relative 'work_days/ext/date_time'
11
+ require_relative 'work_days/ext/range'
12
+
13
+ module WorkDays
14
+ def self.work_schedule=(schedule)
15
+ @work_schedule = schedule
16
+ end
17
+
18
+ def self.work_schedule
19
+ @work_schedule ||= WorkDays::WorkSchedules::Default.new
20
+ end
21
+
22
+ def self.respond_to_missing?(method_name, include_private = false)
23
+ work_schedule.respond_to?(method_name)
24
+ end
25
+
26
+ def self.method_missing(name, *args, &block)
27
+ if work_schedule.respond_to?(name)
28
+ work_schedule.public_send(name, *args, &block)
29
+ else
30
+ super
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,103 @@
1
+ module WorkDays::CalculationMethods
2
+ def holiday?(date)
3
+ observed_holidays.any? do |sym|
4
+ next if caller.any?{|c| c =~ /`#{sym.to_s}'\z/}
5
+ send(sym, date.year) == date
6
+ end
7
+ end
8
+
9
+ def weekend_day?(date)
10
+ date.sunday? || date.saturday?
11
+ end
12
+
13
+ def week_day?(date)
14
+ !weekend_day?(date)
15
+ end
16
+
17
+ def work_day?(date)
18
+ week_day?(date) && !holiday?(date)
19
+ end
20
+
21
+ def non_work_day?(date)
22
+ !work_day?(date)
23
+ end
24
+
25
+ def work_days_in_range(start, stop)
26
+ working_days = []
27
+
28
+ (start.to_date..stop.to_date).each do |date|
29
+ working_days << date if work_day?(date)
30
+ end
31
+
32
+ working_days
33
+ end
34
+
35
+ def work_days_in_month(date)
36
+ start_date = Date.new(date.year, date.month, 1)
37
+ end_date = Date.new(date.year, date.month, -1)
38
+
39
+ work_days_in_range(start_date, end_date)
40
+ end
41
+
42
+ def previous_work_day(date)
43
+ loop do
44
+ date = date.to_date.prev_day
45
+ break if work_day?(date)
46
+ end
47
+
48
+ date
49
+ end
50
+
51
+ def next_work_day(date)
52
+ loop do
53
+ date = date.to_date.next_day
54
+ break if work_day?(date)
55
+ end
56
+
57
+ date
58
+ end
59
+
60
+ def work_days_from(number_of_days, date)
61
+ number_of_days.times do
62
+ date = next_work_day(date)
63
+ end
64
+
65
+ date
66
+ end
67
+
68
+ def observed_holidays
69
+ raise NotImplementedError, 'You must override this method.'
70
+ end
71
+
72
+ def monthly_work_days(year=nil)
73
+ year = format_year(year)
74
+
75
+ (1..12).collect{|month| work_days_in_month(Date.new(year, month))}
76
+ end
77
+
78
+ private
79
+
80
+ def weekday_if_weekend(date)
81
+ date -= 1 if date.saturday?
82
+ date += 1 if date.sunday?
83
+
84
+ date
85
+ end
86
+
87
+ def format_year(year=nil)
88
+ year ||= Date.today.year
89
+ year.to_i
90
+ end
91
+
92
+ def day_of_week_occurence(year, month, test, count=nil)
93
+ year = format_year(year)
94
+ count ||= 1
95
+ counter = 0
96
+
97
+ 1.upto(31).each do |day|
98
+ date = Date.new(year, month, day)
99
+ counter += 1 if date.send(test)
100
+ return date if counter == count
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,5 @@
1
+ class Date
2
+ def work_day?
3
+ WorkDays.work_day?(self)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class DateTime
2
+ def work_day?
3
+ WorkDays.work_day?(self)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Range
2
+ def work_days
3
+ WorkDays.work_days_in_range(self.first, self.last)
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class Time
2
+ def work_day?
3
+ WorkDays.work_day?(self)
4
+ end
5
+ end
@@ -0,0 +1,87 @@
1
+ require_relative 'calculation_methods'
2
+
3
+ module WorkDays::HolidayMethods
4
+ include WorkDays::CalculationMethods
5
+
6
+ def new_years_day(year=nil)
7
+ year = format_year(year)
8
+ weekday_if_weekend(Date.new(year,1,1))
9
+ end
10
+
11
+ def martin_luther_king_day(year=nil)
12
+ year = format_year(year)
13
+
14
+ return nil if year < 1986
15
+
16
+ day_of_week_occurence(year, 1, :monday?, 3)
17
+ end
18
+
19
+ def presidents_day(year=nil)
20
+ day_of_week_occurence(year, 2, :monday?, 3)
21
+ end
22
+
23
+ def easter_sunday(year=nil)
24
+ year = format_year(year)
25
+ y = year
26
+ a = y % 19
27
+ b = y / 100
28
+ c = y % 100
29
+ d = b / 4
30
+ e = b % 4
31
+ f = (b + 8) / 25
32
+ g = (b - f + 1) / 3
33
+ h = (19 * a + b - d - g + 15) % 30
34
+ i = c / 4
35
+ k = c % 4
36
+ l = (32 + 2 * e + 2 * i - h - k) % 7
37
+ m = (a + 11 * h + 22 * l) / 451
38
+ month = (h + l - 7 * m + 114) / 31
39
+ day = ((h + l - 7 * m + 114) % 31) + 1
40
+ Date.new(year, month, day)
41
+ end
42
+
43
+ def memorial_day(year=nil)
44
+ year = format_year(year)
45
+
46
+ 31.downto(1).each do |day|
47
+ date = Date.new(year, 5, day)
48
+ return date if date.monday?
49
+ end
50
+ end
51
+
52
+ def independence_day(year=nil)
53
+ year = format_year(year)
54
+ weekday_if_weekend(Date.new(year,7,4))
55
+ end
56
+
57
+ def labor_day(year=nil)
58
+ day_of_week_occurence(year, 9, :monday?)
59
+ end
60
+
61
+ def columbus_day(year=nil)
62
+ day_of_week_occurence(year, 10, :monday?, 2)
63
+ end
64
+
65
+ def veterans_day(year=nil)
66
+ year = format_year(year)
67
+ weekday_if_weekend(Date.new(year,11,11))
68
+ end
69
+
70
+ def thanksgiving_day(year=nil)
71
+ day_of_week_occurence(year, 11, :thursday?, 4)
72
+ end
73
+
74
+ def black_friday(year=nil)
75
+ thanksgiving_day(year).next_day
76
+ end
77
+
78
+ def christmas_eve_day(year=nil)
79
+ previous_work_day(christmas_day(year))
80
+ end
81
+
82
+ def christmas_day(year=nil)
83
+ year = format_year(year)
84
+ weekday_if_weekend(Date.new(year,12,25))
85
+ end
86
+
87
+ end
@@ -0,0 +1,3 @@
1
+ module WorkDays
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,19 @@
1
+ module WorkDays::WorkSchedules
2
+ class Bank
3
+ include WorkDays::CalculationMethods
4
+ include WorkDays::HolidayMethods
5
+
6
+ def observed_holidays
7
+ [ :new_years_day,
8
+ :martin_luther_king_day,
9
+ :presidents_day,
10
+ :memorial_day,
11
+ :independence_day,
12
+ :labor_day,
13
+ :columbus_day,
14
+ :veterans_day,
15
+ :thanksgiving_day,
16
+ :christmas_day ]
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module WorkDays::WorkSchedules
2
+ class Default
3
+ include WorkDays::CalculationMethods
4
+ include WorkDays::HolidayMethods
5
+
6
+ def observed_holidays
7
+ [ :new_years_day,
8
+ :memorial_day,
9
+ :independence_day,
10
+ :labor_day,
11
+ :thanksgiving_day,
12
+ :black_friday,
13
+ :christmas_eve_day,
14
+ :christmas_day ]
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,198 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe WorkDays::CalculationMethods, :type => :holiday_helpers do
4
+ let(:today) {Date.today}
5
+ let(:current_year) {Date.today.year}
6
+
7
+ let(:dummy_class) do
8
+ Class.new do
9
+ include(WorkDays::CalculationMethods)
10
+ end
11
+ end
12
+
13
+ subject{dummy_class.new}
14
+
15
+ context "#weekend_day?" do
16
+ let(:date) {double('date', :sunday? => false, :saturday? => false)}
17
+
18
+ it "should be true for sundays" do
19
+ date.should_receive(:sunday?).and_return(true)
20
+ subject.weekend_day?(date).should be_true
21
+ end
22
+
23
+ it "should be true for saturdays" do
24
+ date.should_receive(:saturday?).and_return(true)
25
+ subject.weekend_day?(date).should be_true
26
+ end
27
+
28
+ it "should be false for non-saturdays/non-sundays" do
29
+ date.should_receive(:sunday?).and_return(false)
30
+ date.should_receive(:saturday?).and_return(false)
31
+ subject.weekend_day?(date).should be_false
32
+ end
33
+ it "should be true for weekday holidays" do
34
+ all_holiday_dates.each do |date|
35
+ date = Date.parse(date)
36
+ weekend_flag = date.saturday? || date.sunday?
37
+
38
+ subject.weekend_day?(date).should == weekend_flag
39
+ end
40
+ end
41
+ end
42
+
43
+ context "#week_day?" do
44
+ it "is true when weekend_day? is false" do
45
+ subject.should_receive(:weekend_day?).and_return(false)
46
+ subject.week_day?(today).should be_true
47
+ end
48
+
49
+ it "is false when weekend_day? is true" do
50
+ subject.should_receive(:weekend_day?).and_return(true)
51
+ subject.week_day?(today).should be_false
52
+ end
53
+ end
54
+
55
+ context "#work_day?" do
56
+ it "should be true for a non-holiday weekday" do
57
+ subject.should_receive(:week_day?).and_return(true)
58
+ subject.should_receive(:holiday?).and_return(false)
59
+
60
+ subject.work_day?(today).should be_true
61
+ end
62
+
63
+ it "should be false for a holiday" do
64
+ subject.should_receive(:week_day?).and_return(true)
65
+ subject.should_receive(:holiday?).and_return(true)
66
+
67
+ subject.work_day?(today).should be_false
68
+ end
69
+
70
+ it "should be false for a weekend" do
71
+ subject.should_receive(:week_day?).and_return(false)
72
+ subject.should_not_receive(:holiday?)
73
+
74
+ subject.work_day?(today).should be_false
75
+ end
76
+ end
77
+
78
+ context "#non_work_day?" do
79
+ it "is true when work_day? is false" do
80
+ subject.should_receive(:work_day?).and_return(false)
81
+ subject.non_work_day?(today).should be_true
82
+ end
83
+
84
+ it "is false when work_day? is true" do
85
+ subject.should_receive(:work_day?).and_return(true)
86
+ subject.non_work_day?(today).should be_false
87
+ end
88
+ end
89
+
90
+ context "#work_days_in_range" do
91
+ let(:start_date) {random_date}
92
+ let(:end_date) {start_date + rand(45)}
93
+
94
+ it "should return an array of the work days between two dates" do
95
+ valid_work_days = []
96
+
97
+ (start_date..end_date).each do |date|
98
+ work_day = random_boolean
99
+
100
+ valid_work_days << date if work_day
101
+ subject.should_receive(:work_day?).with(date).and_return(work_day)
102
+ end
103
+
104
+ subject.work_days_in_range(start_date, end_date).should eq(valid_work_days)
105
+ end
106
+ end
107
+
108
+ context "#work_days_in_month" do
109
+ let(:date) {random_date}
110
+ let(:range_start_date) {Date.new(date.year, date.month, 1)}
111
+ let(:range_end_date) {Date.new(date.year, date.month, -1)}
112
+ let(:range_work_days) {rand(1..31)}
113
+
114
+ it "should return the number of days in the month specified" do
115
+ subject.should_receive(:work_days_in_range).with(range_start_date, range_end_date).and_return(range_work_days)
116
+ subject.work_days_in_month(date).should eq(range_work_days)
117
+ end
118
+ end
119
+
120
+ context "#monthly_work_days" do
121
+ let(:year) {rand(1900..2500)}
122
+ let(:monthly_work_days) do
123
+ Hash[(1..12).collect{|i| [Date.new(year, i, 1), i]}]
124
+ end
125
+
126
+ it "should return an array of the work_days in each month of the given year" do
127
+ monthly_work_days.each do |start_date, days|
128
+ subject.should_receive(:work_days_in_month).with(start_date).and_return(days)
129
+ end
130
+
131
+ subject.monthly_work_days(year).should eql(monthly_work_days.values)
132
+ end
133
+ end
134
+
135
+ context "#next_work_day" do
136
+ it "should never return the same date" do
137
+ starting_date = random_date
138
+ ending_date = starting_date + 1
139
+
140
+ subject.should_receive(:work_day?).and_return(true)
141
+ subject.next_work_day(starting_date).should eq(ending_date)
142
+ end
143
+
144
+ it "iterates through each day until it finds the first non-holiday/weekend" do
145
+ first_work_day = random_date
146
+ starting_date = first_work_day - 2
147
+
148
+ subject.should_receive(:work_day?).and_return(false)
149
+ subject.should_receive(:work_day?).with(first_work_day).and_return(true)
150
+
151
+ subject.next_work_day(starting_date).should eq(first_work_day)
152
+ end
153
+ end
154
+
155
+ context "#previous_work_day" do
156
+ it "should never return the same date" do
157
+ starting_date = random_date
158
+ ending_date = starting_date - 1
159
+
160
+ subject.should_receive(:work_day?).and_return(true)
161
+ subject.previous_work_day(starting_date).should eq(ending_date)
162
+ end
163
+
164
+ it "iterates backwards through each day until it finds the first non-holiday/weekend" do
165
+ first_work_day = random_date
166
+ starting_date = first_work_day + 2
167
+
168
+ subject.should_receive(:work_day?).and_return(false)
169
+ subject.should_receive(:work_day?).with(first_work_day).and_return(true)
170
+
171
+ subject.previous_work_day(starting_date).should eq(first_work_day)
172
+ end
173
+ end
174
+
175
+ context "#work_days_from" do
176
+ it "should accept the number of days and starting date" do
177
+ should respond_to(:work_days_from)
178
+ end
179
+
180
+ it "should call next_work_day the specified number of times" do
181
+ start_date = random_date
182
+ current_date = start_date
183
+ days_from_start = rand(1..100)
184
+
185
+ days_from_start.downto(1) do
186
+ subject.should_receive(:next_work_day).with(current_date).and_return(current_date += 1)
187
+ end
188
+
189
+ subject.work_days_from(days_from_start, start_date).should eq(current_date)
190
+ end
191
+ end
192
+
193
+ context "#observed_holidays" do
194
+ it "should raise an exception" do
195
+ expect{subject.observed_holidays}.to raise_error
196
+ end
197
+ end
198
+ end
@@ -0,0 +1,5 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe Date do
4
+ it_behaves_like "a proxy for WorkDays.work_day?"
5
+ end
@@ -0,0 +1,5 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe DateTime do
4
+ it_behaves_like "a proxy for WorkDays.work_day?"
5
+ end
@@ -0,0 +1,12 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe Range, :type => :holiday_helpers do
4
+ let(:start_date) { random_date}
5
+ let(:end_date) { start_date + rand(35)}
6
+ let(:range) { start_date..end_date}
7
+
8
+ it "should call WorkDays.work_days_in_range" do
9
+ WorkDays.should_receive(:work_days_in_range).with(range.first, range.last)
10
+ range.work_days
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ require_relative '../../../spec_helper'
2
+
3
+ describe Time do
4
+ it_behaves_like "a proxy for WorkDays.work_day?"
5
+ end
@@ -0,0 +1,38 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe WorkDays::HolidayMethods, :type => :holiday_helpers do
4
+ let(:today) {Date.today}
5
+ let(:current_year) {Date.today.year}
6
+
7
+ let(:dummy_class) do
8
+ Class.new do
9
+ include(WorkDays::HolidayMethods)
10
+
11
+ def observed_holidays
12
+ [:christmas_day]
13
+ end
14
+ end
15
+ end
16
+
17
+ holidays.each do |holiday, dates|
18
+ context "##{holiday.to_s}" do
19
+ subject {dummy_class.new}
20
+
21
+ it "should accept a string as the year input" do
22
+ subject.public_send(holiday, '2012')
23
+ end
24
+
25
+ it "should default to the current year" do
26
+ current_year_holiday = subject.public_send(holiday, current_year)
27
+ subject.public_send(holiday).should eq(current_year_holiday)
28
+ end
29
+
30
+ it "should return the proper date given a year" do
31
+ dates.each do |date|
32
+ date = Date.parse(date)
33
+ subject.public_send(holiday, date.year).should eq(date)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../../spec_helper'
2
+
3
+ describe WorkDays, :type => :holiday_helpers do
4
+ subject {WorkDays}
5
+
6
+ before do
7
+ subject.instance_variable_set(:@work_schedule, nil)
8
+ end
9
+
10
+ after do
11
+ subject.instance_variable_set(:@work_schedule, nil)
12
+ end
13
+
14
+
15
+ context ".work_schedule=" do
16
+ it "sets a module instance variable to the passed value" do
17
+ subject.work_schedule = 'random value'
18
+ subject.instance_variable_get(:@work_schedule).should eq('random value')
19
+ end
20
+ end
21
+
22
+ context ".work_schedule" do
23
+ it "returns the value of the currently set work_schedule" do
24
+ subject.work_schedule = 'random value'
25
+ subject.work_schedule.should eq('random value')
26
+ end
27
+
28
+ it "returns new WorkSchedules::Default if the work_schedule wasn't already set" do
29
+ subject.work_schedule.should be_an_instance_of(WorkDays::WorkSchedules::Default)
30
+ end
31
+ end
32
+
33
+ context ".method_missing" do
34
+ before do
35
+ subject.work_schedule = double('schedule',:random_method => 'non_nil', :foo => 'bar')
36
+ end
37
+
38
+ after do
39
+ subject.work_schedule = nil
40
+ end
41
+
42
+ it "raises NoMethodError when a method is called that the current WorkSchedule doesn't implement" do
43
+ expect{ subject.adsfakjlk }.to raise_error(NoMethodError)
44
+ end
45
+
46
+ it "proxies all calls to current work_schedule" do
47
+ subject.work_schedule.should_receive(:random_method)
48
+ subject.work_schedule.should_receive(:foo)
49
+ subject.random_method.should eq('non_nil')
50
+ subject.foo.should eq('bar')
51
+ end
52
+
53
+ it "indicates that it responds to methods implemented by the current WorkSchedule" do
54
+ subject.respond_to?(:random_method).should be_true
55
+ subject.respond_to?(:foo).should be_true
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe WorkDays::WorkSchedules::Bank do
4
+ it_behaves_like "a work schedule"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe WorkDays::WorkSchedules::Default do
4
+ it_behaves_like "a work schedule"
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'pry'
2
+
3
+ require_relative '../lib/work_days'
4
+ Dir["./spec/support/**/*.rb"].sort.each {|f| require f}
5
+
6
+ RSpec.configure do |config|
7
+ config.treat_symbols_as_metadata_keys_with_true_values = true
8
+ config.run_all_when_everything_filtered = true
9
+ config.filter_run :focus
10
+
11
+ # Run specs in random order to surface order dependencies. If you find an
12
+ # order dependency and want to debug it, you can fix the order by providing
13
+ # the seed, which is printed after each run.
14
+ # --seed 1234
15
+ config.order = 'random'
16
+ end
@@ -0,0 +1,43 @@
1
+ module WorkDays::SpecHelpers
2
+ def holidays
3
+ @holidays ||= {
4
+ :new_years_day => %w{1980-01-01 1987-01-01 1993-01-01 2001-01-01 2006-01-02 2015-01-01},
5
+ :martin_luther_king_day => %w{1986-01-20 1989-01-16 1993-01-18 2001-01-15 2006-01-16 2015-01-19},
6
+ :presidents_day => %w{1986-02-17 1989-02-20 1993-02-15 2001-02-19 2006-02-20 2015-02-16},
7
+ :easter_sunday => %w{1980-04-06 1987-04-19 1993-04-11 2001-04-15 2002-03-31 2015-04-05},
8
+ :memorial_day => %w{1980-05-26 1987-05-25 1993-05-31 2001-05-28 2006-05-29 2015-05-25},
9
+ :independence_day => %w{1980-07-04 1987-07-03 1993-07-05 2001-07-04 2002-07-04 2015-07-03},
10
+ :labor_day => %w{1980-09-01 1987-09-07 1993-09-06 2001-09-03 2006-09-04 2015-09-07},
11
+ :columbus_day => %w{1980-10-13 1987-10-12 1993-10-11 2001-10-08 2006-10-09 2015-10-12},
12
+ :veterans_day => %w{1980-11-11 1987-11-11 1993-11-11 2001-11-12 2006-11-10 2015-11-11},
13
+ :thanksgiving_day => %w{1980-11-27 1987-11-26 1993-11-25 2001-11-22 2006-11-23 2015-11-26},
14
+ :black_friday => %w{1980-11-28 1987-11-27 1993-11-26 2001-11-23 2006-11-24 2015-11-27},
15
+ :christmas_eve_day => %w{1982-12-23 1987-12-24 1994-12-23 2001-12-24 2006-12-22 2015-12-24},
16
+ :christmas_day => %w{1982-12-24 1987-12-25 1994-12-26 2001-12-25 2006-12-25 2015-12-25},
17
+ }
18
+ end
19
+
20
+ def all_holiday_dates
21
+ @all_holiday_dates ||= holidays.values.flatten
22
+ end
23
+
24
+ def default_holiday_dates
25
+ WorkDays.send(:default_holiday_methods).collect do |holiday|
26
+ holidays[holiday]
27
+ end.flatten.compact
28
+ end
29
+
30
+ def random_date
31
+ Date.new(rand(1900..2500), rand(1..12), rand(1..28))
32
+ end
33
+
34
+ def random_boolean
35
+ rand(0..1) == 0
36
+ end
37
+ end
38
+
39
+ RSpec.configure do |c|
40
+ c.extend WorkDays::SpecHelpers, :type => :holiday_helpers
41
+ c.include WorkDays::SpecHelpers, :type => :holiday_helpers
42
+ end
43
+
@@ -0,0 +1,21 @@
1
+ shared_examples "a work schedule" do
2
+ context "included modules" do
3
+ it "includes WorkDays::HolidayMethods" do
4
+ described_class.ancestors.should include(WorkDays::HolidayMethods)
5
+ end
6
+
7
+ it "includes WorkDays::CalculationMethods" do
8
+ described_class.ancestors.should include(WorkDays::CalculationMethods)
9
+ end
10
+ end
11
+
12
+ context "#observed_holidays" do
13
+ it {should respond_to(:observed_holidays)}
14
+
15
+ it "returns an enumerable of holiday methods" do
16
+ subject.observed_holidays.each do |sym|
17
+ subject.should respond_to(sym)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ shared_examples "a proxy for WorkDays.work_day?" do
2
+ context "#work_day?" do
3
+ it "should respond_to work_day?" do
4
+ should respond_to(:work_day?)
5
+ end
6
+
7
+ it "should call WorkDays.work_day? passing self" do
8
+ WorkDays.should_receive(:work_day?).with(subject)
9
+
10
+ subject.work_day?
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,19 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/work_days/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Robert Jackson"]
6
+ gem.email = ["robertj@promedicalinc.com"]
7
+ gem.description = %q{Calculate the number of business days in a given period. Also, add convenience methods to Range, Date, DateTime, and Time.}
8
+ gem.summary = %q{Simple business day calculations.}
9
+ gem.homepage = "https://github.com/rjackson/work_days"
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = "work_days"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = WorkDays::VERSION
17
+
18
+ gem.add_development_dependency 'rspec'
19
+ end
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: work_days
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Robert Jackson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-31 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ prerelease: false
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ none: false
23
+ type: :development
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ none: false
30
+ description: Calculate the number of business days in a given period. Also, add convenience
31
+ methods to Range, Date, DateTime, and Time.
32
+ email:
33
+ - robertj@promedicalinc.com
34
+ executables: []
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .gitignore
39
+ - .rspec
40
+ - Gemfile
41
+ - Guardfile
42
+ - LICENSE
43
+ - README.md
44
+ - Rakefile
45
+ - lib/work_days.rb
46
+ - lib/work_days/calculation_methods.rb
47
+ - lib/work_days/ext/date.rb
48
+ - lib/work_days/ext/date_time.rb
49
+ - lib/work_days/ext/range.rb
50
+ - lib/work_days/ext/time.rb
51
+ - lib/work_days/holiday_methods.rb
52
+ - lib/work_days/version.rb
53
+ - lib/work_days/work_schedules/bank.rb
54
+ - lib/work_days/work_schedules/default.rb
55
+ - spec/lib/work_days/calculation_methods_spec.rb
56
+ - spec/lib/work_days/ext/date_spec.rb
57
+ - spec/lib/work_days/ext/datetime_spec.rb
58
+ - spec/lib/work_days/ext/range_spec.rb
59
+ - spec/lib/work_days/ext/time_spec.rb
60
+ - spec/lib/work_days/holiday_methods_spec.rb
61
+ - spec/lib/work_days/work_days_spec.rb
62
+ - spec/lib/work_days/work_schedules/bank_spec.rb
63
+ - spec/lib/work_days/work_schedules/default_spec.rb
64
+ - spec/spec_helper.rb
65
+ - spec/support/holiday_helpers.rb
66
+ - spec/support/shared_work_schedule.rb
67
+ - spec/support/work_day_proxy.rb
68
+ - work_days.gemspec
69
+ homepage: https://github.com/rjackson/work_days
70
+ licenses: []
71
+ post_install_message:
72
+ rdoc_options: []
73
+ require_paths:
74
+ - lib
75
+ required_ruby_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ none: false
81
+ required_rubygems_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ none: false
87
+ requirements: []
88
+ rubyforge_project:
89
+ rubygems_version: 1.8.24
90
+ signing_key:
91
+ specification_version: 3
92
+ summary: Simple business day calculations.
93
+ test_files:
94
+ - spec/lib/work_days/calculation_methods_spec.rb
95
+ - spec/lib/work_days/ext/date_spec.rb
96
+ - spec/lib/work_days/ext/datetime_spec.rb
97
+ - spec/lib/work_days/ext/range_spec.rb
98
+ - spec/lib/work_days/ext/time_spec.rb
99
+ - spec/lib/work_days/holiday_methods_spec.rb
100
+ - spec/lib/work_days/work_days_spec.rb
101
+ - spec/lib/work_days/work_schedules/bank_spec.rb
102
+ - spec/lib/work_days/work_schedules/default_spec.rb
103
+ - spec/spec_helper.rb
104
+ - spec/support/holiday_helpers.rb
105
+ - spec/support/shared_work_schedule.rb
106
+ - spec/support/work_day_proxy.rb
107
+ has_rdoc: