business 0.1.0

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.
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