business 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5c69d99c21ef0905de463bc82315c5f3829f6c23
4
+ data.tar.gz: 2d333b66d2d26a1cd9664b7415033012ab898339
5
+ SHA512:
6
+ metadata.gz: a020144ad1d875fe40df7dfd91d2cec5fe5623134921a40cc45669202bc0c76a43f98cde0f9cf1da3f8334eaabbb245823f8f542ac3a6985b3055b869e8c663e
7
+ data.tar.gz: c0ce8a9993aad1a8be8378ae9bdeb77368979be818ca1cca84ccf9ed2eddd0ba2811c81d03dbdfb072da3134e63c9abe75ce9a7ff6e96138105f606439725db7
data/.gitignore ADDED
@@ -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/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in business.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # BankTime
2
+
3
+ Date calculations based on bank calendars
4
+
5
+ ## Usage
6
+
7
+ ```ruby
8
+ calendar = BankTime::Calendar.load('bacs')
9
+ date = Date.parse("2013-10-18")
10
+ calendar.add_business_days(date, 1)
11
+ # => 2013-10-21
12
+ ```
13
+
data/business.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'business/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "business"
8
+ spec.version = Business::VERSION
9
+ spec.authors = ["Harry Marr"]
10
+ spec.email = ["engineering@gocardless.com"]
11
+ spec.description = %q{Date calculations based on business calendars}
12
+ spec.summary = %q{Date calculations based on business calendars}
13
+ spec.homepage = "https://github.com/gocardless/business"
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
+ spec.require_paths = ["lib"]
19
+
20
+ spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "rspec", "~> 2.14.1"
22
+ end
data/lib/business.rb ADDED
@@ -0,0 +1 @@
1
+ require 'business/calendar'
@@ -0,0 +1,156 @@
1
+ require 'yaml'
2
+
3
+ module Business
4
+ class Calendar
5
+ def self.load(calendar)
6
+ path = File.join(File.dirname(__FILE__), 'data', "#{calendar}.yml")
7
+ raise "No such calendar '#{calendar}'" unless File.exists?(path)
8
+ yaml = YAML.load_file(path)
9
+ self.new(holidays: yaml['holidays'], business_days: yaml['business_days'])
10
+ end
11
+
12
+ @lock = Mutex.new
13
+ def self.load_cached(calendar)
14
+ @lock.synchronize do
15
+ @cache ||= { }
16
+ unless @cache.include?(calendar)
17
+ @cache[calendar] = self.load(calendar)
18
+ end
19
+ @cache[calendar]
20
+ end
21
+ end
22
+
23
+ DAY_NAMES = %( mon tue wed thu fri sat sun )
24
+
25
+ attr_reader :business_days, :holidays
26
+
27
+ def initialize(config)
28
+ set_business_days(config[:business_days])
29
+ set_holidays(config[:holidays])
30
+ end
31
+
32
+ # Return true if the date given is a business day (typically that means a
33
+ # non-weekend day) and not a holiday.
34
+ def business_day?(date)
35
+ date = date.to_date
36
+ return false unless business_days.include?(date.strftime('%a').downcase)
37
+ return false if holidays.include?(date)
38
+ true
39
+ end
40
+
41
+ # Roll forward to the next business day. If the date given is a business
42
+ # day, that day will be returned. If the day given is a holiday or
43
+ # non-working day, the next non-holiday working day will be returned.
44
+ def roll_forward(date)
45
+ interval = date.is_a?(Date) ? 1 : 3600 * 24
46
+ date += interval until business_day?(date)
47
+ date
48
+ end
49
+
50
+ # Roll backward to the previous business day. If the date given is a
51
+ # business day, that day will be returned. If the day given is a holiday or
52
+ # non-working day, the previous non-holiday working day will be returned.
53
+ def roll_backward(date)
54
+ date -= day_interval_for(date) until business_day?(date)
55
+ date
56
+ end
57
+
58
+ # Roll forward to the next business day regardless of whether the given
59
+ # date is a business day or not.
60
+ def next_business_day(date)
61
+ begin
62
+ date += day_interval_for(date)
63
+ end until business_day?(date)
64
+ date
65
+ end
66
+
67
+ # Add a number of business days to a date. If a non-business day is given,
68
+ # counting will start from the next business day. So,
69
+ # monday + 1 = tuesday
70
+ # friday + 1 = monday
71
+ # sunday + 1 = tuesday
72
+ def add_business_days(date, delta)
73
+ date = roll_forward(date)
74
+ delta.times do
75
+ begin
76
+ date += day_interval_for(date)
77
+ end until business_day?(date)
78
+ end
79
+ date
80
+ end
81
+
82
+ # Subtract a number of business days to a date. If a non-business day is
83
+ # given, counting will start from the previous business day. So,
84
+ # friday - 1 = thursday
85
+ # monday - 1 = friday
86
+ # sunday - 1 = thursday
87
+ def subtract_business_days(date, delta)
88
+ date = roll_backward(date)
89
+ delta.times do
90
+ begin
91
+ date -= day_interval_for(date)
92
+ end until business_day?(date)
93
+ end
94
+ date
95
+ end
96
+
97
+ # Count the number of business days between two dates.
98
+ # This method counts from start of date1 to start of date2. So,
99
+ # business_days_between(mon, weds) = 2 (assuming no holidays)
100
+ def business_days_between(date1, date2)
101
+ date1, date2 = date1.to_date, date2.to_date
102
+
103
+ # To optimise this method we split the range into full weeks and a
104
+ # remaining period.
105
+ #
106
+ # We then calculate business days in the full weeks period by
107
+ # multiplying number of weeks by number of working days in a week and
108
+ # removing holidays one by one.
109
+
110
+ # For the remaining period, we just loop through each day and check
111
+ # whether it is a business day.
112
+
113
+ # Calculate number of full weeks and remaining days
114
+ num_full_weeks, remaining_days = (date2 - date1).to_i.divmod(7)
115
+
116
+ # First estimate for full week range based on # biz days in a week
117
+ num_biz_days = num_full_weeks * business_days.length
118
+
119
+ full_weeks_range = (date1...(date2 - remaining_days))
120
+ num_biz_days -= holidays.count do |holiday|
121
+ in_range = full_weeks_range.cover?(holiday)
122
+ # Only pick a holiday if its on a working day (e.g., not a weekend)
123
+ on_biz_day = business_days.include?(holiday.strftime('%a').downcase)
124
+ in_range && on_biz_day
125
+ end
126
+
127
+ remaining_range = (date2-remaining_days...date2)
128
+ # Loop through each day in remaining_range and count if a business day
129
+ num_biz_days + remaining_range.count { |a| business_day?(a) }
130
+ end
131
+
132
+ def day_interval_for(date)
133
+ date.is_a?(Date) ? 1 : 3600 * 24
134
+ end
135
+
136
+ # Internal method for assigning business days from a calendar config.
137
+ def set_business_days(business_days)
138
+ @business_days = (business_days || default_business_days).map do |day|
139
+ day.downcase.strip[0..2].tap do |normalised_day|
140
+ raise "Invalid day #{day}" unless DAY_NAMES.include?(normalised_day)
141
+ end
142
+ end
143
+ end
144
+
145
+ # Internal method for assigning holidays from a calendar config.
146
+ def set_holidays(holidays)
147
+ @holidays = (holidays || []).map { |holiday| Date.parse(holiday) }
148
+ end
149
+
150
+ # If no business days are provided in the calendar config, these are used.
151
+ def default_business_days
152
+ %w( mon tue wed thu fri )
153
+ end
154
+ end
155
+ end
156
+
@@ -0,0 +1,25 @@
1
+ business_days:
2
+ - monday
3
+ - tuesday
4
+ - wednesday
5
+ - thursday
6
+ - friday
7
+
8
+ holidays:
9
+ - January 1st, 2013
10
+ - March 29th, 2013
11
+ - April 1st, 2013
12
+ - May 6th, 2013
13
+ - May 27th, 2013
14
+ - August 26th, 2013
15
+ - December 25th, 2013
16
+ - December 26th, 2013
17
+ - January 1st, 2014
18
+ - April 18th, 2014
19
+ - April 21st, 2014
20
+ - May 5th, 2014
21
+ - May 26th, 2014
22
+ - August 25th, 2014
23
+ - December 25th, 2014
24
+ - December 26th, 2014
25
+
@@ -0,0 +1,35 @@
1
+ business_days:
2
+ - monday
3
+ - tuesday
4
+ - wednesday
5
+ - thursday
6
+ - friday
7
+
8
+ holidays:
9
+ - January 1st, 2013
10
+ - March 29th, 2013
11
+ - April 1st, 2013
12
+ - May 1st, 2013
13
+ - May 9th, 2013
14
+ - May 20th, 2013
15
+ - May 30th, 2013
16
+ - October 3rd, 2013
17
+ - November 1st, 2013
18
+ - December 24th, 2013
19
+ - December 25th, 2013
20
+ - December 26th, 2013
21
+ - December 31st, 2013
22
+ - January 1st, 2014
23
+ - April 18th, 2014
24
+ - April 21st, 2014
25
+ - May 1st, 2014
26
+ - May 9th, 2014
27
+ - May 29th, 2014
28
+ - June 9th, 2014
29
+ - June 19th, 2014
30
+ - October 3rd, 2014
31
+ - November 1st, 2014
32
+ - December 24th, 2014
33
+ - December 25th, 2014
34
+ - December 26th, 2014
35
+ - December 31st, 2014
@@ -0,0 +1,6 @@
1
+ business_days:
2
+ - monday
3
+ - tuesday
4
+ - wednesday
5
+ - thursday
6
+ - friday
@@ -0,0 +1,3 @@
1
+ module Business
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,408 @@
1
+ require "business/calendar"
2
+ require "time"
3
+
4
+ describe Business::Calendar do
5
+ describe ".load" do
6
+ context "when given a valid calendar" do
7
+ subject { Business::Calendar.load("weekdays") }
8
+
9
+ it "loads the yaml file" do
10
+ YAML.should_receive(:load_file) do |path|
11
+ path.should match(/weekdays\.yml$/)
12
+ end.and_return({})
13
+ subject
14
+ end
15
+
16
+ it { should be_a Business::Calendar }
17
+ end
18
+
19
+ context "when given an invalid calendar" do
20
+ subject { Business::Calendar.load("invalid-calendar") }
21
+ specify { ->{ subject }.should raise_error }
22
+ end
23
+ end
24
+
25
+ describe "#set_business_days" do
26
+ let(:calendar) { Business::Calendar.new({}) }
27
+ let(:business_days) { [] }
28
+ subject { calendar.set_business_days(business_days) }
29
+
30
+ context "when given valid business days" do
31
+ let(:business_days) { %w( mon fri ) }
32
+ before { subject }
33
+
34
+ it "assigns them" do
35
+ calendar.business_days.should == business_days
36
+ end
37
+
38
+ context "that are unnormalised" do
39
+ let(:business_days) { %w( Monday Friday ) }
40
+ it "normalises them" do
41
+ calendar.business_days.should == %w( mon fri )
42
+ end
43
+ end
44
+ end
45
+
46
+ context "when given an invalid business day" do
47
+ let(:business_days) { %w( Notaday ) }
48
+ specify { ->{ subject }.should raise_exception }
49
+ end
50
+
51
+ context "when given nil" do
52
+ let(:business_days) { nil }
53
+ it "uses the default business days" do
54
+ calendar.business_days.should == calendar.default_business_days
55
+ end
56
+ end
57
+ end
58
+
59
+ describe "#set_holidays" do
60
+ let(:calendar) { Business::Calendar.new({}) }
61
+ let(:holidays) { [] }
62
+ before { calendar.set_holidays(holidays) }
63
+ subject { calendar.holidays }
64
+
65
+ context "when given valid business days" do
66
+ let(:holidays) { ["1st Jan, 2013"] }
67
+
68
+ it { should_not be_empty }
69
+
70
+ it "converts them to Date objects" do
71
+ subject.each { |h| h.should be_a Date }
72
+ end
73
+ end
74
+
75
+ context "when given nil" do
76
+ let(:holidays) { nil }
77
+ it { should be_empty }
78
+ end
79
+ end
80
+
81
+ # A set of examples that are supposed to work when given Date and Time
82
+ # objects. The implementation slightly differs, so i's worth running the
83
+ # tests for both Date *and* Time.
84
+ shared_examples "common" do
85
+ describe "#business_day?" do
86
+ let(:calendar) do
87
+ Business::Calendar.new(holidays: ["9am, Tuesday 1st Jan, 2013"])
88
+ end
89
+ subject { calendar.business_day?(day) }
90
+
91
+ context "when given a business day" do
92
+ let(:day) { date_class.parse("9am, Wednesday 2nd Jan, 2013") }
93
+ it { should be_true }
94
+ end
95
+
96
+ context "when given a non-business day" do
97
+ let(:day) { date_class.parse("9am, Saturday 5th Jan, 2013") }
98
+ it { should be_false }
99
+ end
100
+
101
+ context "when given a business day that is a holiday" do
102
+ let(:day) { date_class.parse("9am, Tuesday 1st Jan, 2013") }
103
+ it { should be_false }
104
+ end
105
+ end
106
+
107
+ describe "#roll_forward" do
108
+ let(:calendar) do
109
+ Business::Calendar.new(holidays: ["Tuesday 1st Jan, 2013"])
110
+ end
111
+ subject { calendar.roll_forward(date) }
112
+
113
+ context "given a business day" do
114
+ let(:date) { date_class.parse("Wednesday 2nd Jan, 2013") }
115
+ it { should == date }
116
+ end
117
+
118
+ context "given a non-business day" do
119
+ context "with a business day following it" do
120
+ let(:date) { date_class.parse("Tuesday 1st Jan, 2013") }
121
+ it { should == date + day_interval }
122
+ end
123
+
124
+ context "followed by another non-business day" do
125
+ let(:date) { date_class.parse("Saturday 5th Jan, 2013") }
126
+ it { should == date + 2 * day_interval }
127
+ end
128
+ end
129
+ end
130
+
131
+ describe "#roll_backward" do
132
+ let(:calendar) do
133
+ Business::Calendar.new(holidays: ["Tuesday 1st Jan, 2013"])
134
+ end
135
+ subject { calendar.roll_backward(date) }
136
+
137
+ context "given a business day" do
138
+ let(:date) { date_class.parse("Wednesday 2nd Jan, 2013") }
139
+ it { should == date }
140
+ end
141
+
142
+ context "given a non-business day" do
143
+ context "with a business day preceeding it" do
144
+ let(:date) { date_class.parse("Tuesday 1st Jan, 2013") }
145
+ it { should == date - day_interval }
146
+ end
147
+
148
+ context "preceeded by another non-business day" do
149
+ let(:date) { date_class.parse("Sunday 6th Jan, 2013") }
150
+ it { should == date - 2 * day_interval }
151
+ end
152
+ end
153
+ end
154
+
155
+ describe "#next_business_day" do
156
+ let(:calendar) do
157
+ Business::Calendar.new(holidays: ["Tuesday 1st Jan, 2013"])
158
+ end
159
+ subject { calendar.next_business_day(date) }
160
+
161
+ context "given a business day" do
162
+ let(:date) { date_class.parse("Wednesday 2nd Jan, 2013") }
163
+ it { should == date + day_interval }
164
+ end
165
+
166
+ context "given a non-business day" do
167
+ context "with a business day following it" do
168
+ let(:date) { date_class.parse("Tuesday 1st Jan, 2013") }
169
+ it { should == date + day_interval }
170
+ end
171
+
172
+ context "followed by another non-business day" do
173
+ let(:date) { date_class.parse("Saturday 5th Jan, 2013") }
174
+ it { should == date + 2 * day_interval }
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "#add_business_days" do
180
+ let(:calendar) do
181
+ Business::Calendar.new(holidays: ["Tuesday 1st Jan, 2013"])
182
+ end
183
+ let(:delta) { 2 }
184
+ subject { calendar.add_business_days(date, delta) }
185
+
186
+ context "given a business day" do
187
+ context "and a period that includes only business days" do
188
+ let(:date) { date_class.parse("Wednesday 2nd Jan, 2013") }
189
+ it { should == date + delta * day_interval }
190
+ end
191
+
192
+ context "and a period that includes a weekend" do
193
+ let(:date) { date_class.parse("Friday 4th Jan, 2013") }
194
+ it { should == date + (delta + 2) * day_interval }
195
+ end
196
+
197
+ context "and a period that includes a holiday day" do
198
+ let(:date) { date_class.parse("Monday 31st Dec, 2012") }
199
+ it { should == date + (delta + 1) * day_interval }
200
+ end
201
+ end
202
+
203
+ context "given a non-business day" do
204
+ let(:date) { date_class.parse("Tuesday 1st Jan, 2013") }
205
+ it { should == date + (delta + 1) * day_interval }
206
+ end
207
+ end
208
+
209
+ describe "#subtract_business_days" do
210
+ let(:calendar) do
211
+ Business::Calendar.new(holidays: ["Thursday 3rd Jan, 2013"])
212
+ end
213
+ let(:delta) { 2 }
214
+ subject { calendar.subtract_business_days(date, delta) }
215
+
216
+ context "given a business day" do
217
+ context "and a period that includes only business days" do
218
+ let(:date) { date_class.parse("Wednesday 2nd Jan, 2013") }
219
+ it { should == date - delta * day_interval }
220
+ end
221
+
222
+ context "and a period that includes a weekend" do
223
+ let(:date) { date_class.parse("Monday 31st Dec, 2012") }
224
+ it { should == date - (delta + 2) * day_interval }
225
+ end
226
+
227
+ context "and a period that includes a holiday day" do
228
+ let(:date) { date_class.parse("Friday 4th Jan, 2013") }
229
+ it { should == date - (delta + 1) * day_interval }
230
+ end
231
+ end
232
+
233
+ context "given a non-business day" do
234
+ let(:date) { date_class.parse("Thursday 3rd Jan, 2013") }
235
+ it { should == date - (delta + 1) * day_interval }
236
+ end
237
+ end
238
+
239
+ describe "#business_days_between" do
240
+ let(:holidays) do
241
+ ["Thu 12/6/2014", "Wed 18/6/2014", "Fri 20/6/2014", "Sun 22/6/2014"]
242
+ end
243
+ let(:calendar) { Business::Calendar.new(holidays: holidays) }
244
+ subject { calendar.business_days_between(date_1, date_2) }
245
+
246
+
247
+ context "starting on a business day" do
248
+ let(:date_1) { date_class.parse("Mon 2/6/2014") }
249
+
250
+ context "ending on a business day" do
251
+ context "including only business days" do
252
+ let(:date_2) { date_class.parse("Thu 5/6/2014") }
253
+ it { should == 3 }
254
+ end
255
+
256
+ context "including only business days & weekend days" do
257
+ let(:date_2) { date_class.parse("Mon 9/6/2014") }
258
+ it { should == 5 }
259
+ end
260
+
261
+ context "including only business days & holidays" do
262
+ let(:date_1) { date_class.parse("Mon 9/6/2014") }
263
+ let(:date_2) { date_class.parse("Fri 13/6/2014") }
264
+ it { should == 3 }
265
+ end
266
+
267
+ context "including business, weekend days, and holidays" do
268
+ let(:date_2) { date_class.parse("Fri 13/6/2014") }
269
+ it { should == 8 }
270
+ end
271
+ end
272
+
273
+ context "ending on a weekend day" do
274
+ context "including only business days & weekend days" do
275
+ let(:date_2) { date_class.parse("Sun 8/6/2014") }
276
+ it { should == 5 }
277
+ end
278
+
279
+ context "including business, weekend days, and holidays" do
280
+ let(:date_2) { date_class.parse("Sat 14/6/2014") }
281
+ it { should == 9 }
282
+ end
283
+ end
284
+
285
+ context "ending on a holiday" do
286
+ context "including only business days & holidays" do
287
+ let(:date_1) { date_class.parse("Mon 9/6/2014") }
288
+ let(:date_2) { date_class.parse("Thu 12/6/2014") }
289
+ it { should == 3 }
290
+ end
291
+
292
+ context "including business, weekend days, and holidays" do
293
+ let(:date_2) { date_class.parse("Thu 12/6/2014") }
294
+ it { should == 8 }
295
+ end
296
+ end
297
+ end
298
+
299
+ context "starting on a weekend" do
300
+ let(:date_1) { date_class.parse("Sat 7/6/2014") }
301
+
302
+ context "ending on a business day" do
303
+
304
+ context "including only business days & weekend days" do
305
+ let(:date_2) { date_class.parse("Mon 9/6/2014") }
306
+ it { should == 0 }
307
+ end
308
+
309
+ context "including business, weekend days, and holidays" do
310
+ let(:date_2) { date_class.parse("Fri 13/6/2014") }
311
+ it { should == 3 }
312
+ end
313
+ end
314
+
315
+ context "ending on a weekend day" do
316
+ context "including only business days & weekend days" do
317
+ let(:date_2) { date_class.parse("Sun 8/6/2014") }
318
+ it { should == 0 }
319
+ end
320
+
321
+ context "including business, weekend days, and holidays" do
322
+ let(:date_2) { date_class.parse("Sat 14/6/2014") }
323
+ it { should == 4 }
324
+ end
325
+ end
326
+
327
+ context "ending on a holiday" do
328
+ context "including business, weekend days, and holidays" do
329
+ let(:date_2) { date_class.parse("Thu 12/6/2014") }
330
+ it { should == 3 }
331
+ end
332
+ end
333
+ end
334
+
335
+ context "starting on a holiday" do
336
+ let(:date_1) { date_class.parse("Thu 12/6/2014") }
337
+
338
+ context "ending on a business day" do
339
+
340
+ context "including only business days & holidays" do
341
+ let(:date_2) { date_class.parse("Fri 13/6/2014") }
342
+ it { should == 0 }
343
+ end
344
+
345
+ context "including business, weekend days, and holidays" do
346
+ let(:date_2) { date_class.parse("Thu 19/6/2014") }
347
+ it { should == 3 }
348
+ end
349
+ end
350
+
351
+ context "ending on a weekend day" do
352
+ context "including business, weekend days, and holidays" do
353
+ let(:date_2) { date_class.parse("Sun 15/6/2014") }
354
+ it { should == 1 }
355
+ end
356
+ end
357
+
358
+ context "ending on a holiday" do
359
+ context "including only business days & holidays" do
360
+ let(:date_1) { date_class.parse("Wed 18/6/2014") }
361
+ let(:date_2) { date_class.parse("Fri 20/6/2014") }
362
+ it { should == 1 }
363
+ end
364
+
365
+ context "including business, weekend days, and holidays" do
366
+ let(:date_2) { date_class.parse("Wed 18/6/2014") }
367
+ it { should == 3 }
368
+ end
369
+ end
370
+ end
371
+
372
+ context "if a calendar has a holiday on a non-working (weekend) day" do
373
+ context "for a range less than a week long" do
374
+ let(:date_1) { date_class.parse("Thu 19/6/2014") }
375
+ let(:date_2) { date_class.parse("Tue 24/6/2014") }
376
+ it { should == 2 }
377
+ end
378
+ context "for a range more than a week long" do
379
+ let(:date_1) { date_class.parse("Mon 16/6/2014") }
380
+ let(:date_2) { date_class.parse("Tue 24/6/2014") }
381
+ it { should == 4 }
382
+ end
383
+ end
384
+ end
385
+ end
386
+
387
+ context "(using Date objects)" do
388
+ let(:date_class) { Date }
389
+ let(:day_interval) { 1 }
390
+
391
+ it_behaves_like "common"
392
+ end
393
+
394
+ context "(using Time objects)" do
395
+ let(:date_class) { Time }
396
+ let(:day_interval) { 3600 * 24 }
397
+
398
+ it_behaves_like "common"
399
+ end
400
+
401
+ context "(using DateTime objects)" do
402
+ let(:date_class) { DateTime }
403
+ let(:day_interval) { 1 }
404
+
405
+ it_behaves_like "common"
406
+ end
407
+ end
408
+
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: business
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Harry Marr
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 2.14.1
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 2.14.1
41
+ description: Date calculations based on business calendars
42
+ email:
43
+ - engineering@gocardless.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - Gemfile
50
+ - README.md
51
+ - business.gemspec
52
+ - lib/business.rb
53
+ - lib/business/calendar.rb
54
+ - lib/business/data/bacs.yml
55
+ - lib/business/data/sepa.yml
56
+ - lib/business/data/weekdays.yml
57
+ - lib/business/version.rb
58
+ - spec/calendar_spec.rb
59
+ homepage: https://github.com/gocardless/business
60
+ licenses: []
61
+ metadata: {}
62
+ post_install_message:
63
+ rdoc_options: []
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - '>='
69
+ - !ruby/object:Gem::Version
70
+ version: '0'
71
+ required_rubygems_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ requirements: []
77
+ rubyforge_project:
78
+ rubygems_version: 2.2.2
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Date calculations based on business calendars
82
+ test_files:
83
+ - spec/calendar_spec.rb