suprdate 1.0.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.
- data/LICENSE +10 -0
- data/README.md +108 -0
- data/TODO +6 -0
- data/VERSION +1 -0
- data/bin/coverage +19 -0
- data/bin/irb +6 -0
- data/dev_notes/week_definition.rb +62 -0
- data/lib/suprdate.rb +186 -0
- data/lib/suprdate/builder.rb +71 -0
- data/lib/suprdate/day.rb +94 -0
- data/lib/suprdate/month.rb +95 -0
- data/lib/suprdate/year.rb +62 -0
- data/spec/array_diff.spec.rb +17 -0
- data/spec/builder.spec.rb +65 -0
- data/spec/day.spec.rb +124 -0
- data/spec/inter_class_ranges.spec.rb +54 -0
- data/spec/month.spec.rb +149 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/suprdate.spec.rb +193 -0
- data/spec/year.spec.rb +167 -0
- data/suprdate.gemspec +17 -0
- metadata +92 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
# http://refactormycode.com/codes/681-rspec-example-does-not-contain-a-should
|
|
4
|
+
|
|
5
|
+
describe 'range enumeration' do
|
|
6
|
+
|
|
7
|
+
def enumerate_infinitely_with(expected)
|
|
8
|
+
simple_matcher('enumerate infinitely with') do |given, matcher|
|
|
9
|
+
matcher.failure_message = "expected #{given} to enumerate infinitely with #{expected}"
|
|
10
|
+
matcher.negative_failure_message = "expected #{given} not to enumerate infinitely with #{expected}"
|
|
11
|
+
test_times = 50
|
|
12
|
+
(given..expected).each do |x|
|
|
13
|
+
test_times -= 1
|
|
14
|
+
break if test_times <= 0
|
|
15
|
+
end
|
|
16
|
+
test_times == 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "each unit should had readers that return equivalents of another unit" do
|
|
21
|
+
y(2008).month.should == m(2008, 1)
|
|
22
|
+
y(2008).day.should === d(2008, 1, 1)
|
|
23
|
+
m(2008, 1).day.should === d(2008, 1, 1)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "should work with years and months" do
|
|
27
|
+
(y(2008)..m(2008, 03)).to_a.should == [y(2008)]
|
|
28
|
+
(y(2008)..m(2009, 03)).to_a.should == [y(2008), y(2009)]
|
|
29
|
+
(m(2008, 11)..y(2009)).to_a.should == [m(2008, 11), m(2008, 12), m(2009, 1)]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should work with years and days" do
|
|
33
|
+
(y(2008)..d(2008, 1, 3)).to_a.should == [y(2008)]
|
|
34
|
+
(y(2008)..d(2009, 1, 3)).to_a.should == [y(2008), y(2009)]
|
|
35
|
+
(d(2008, 12, 30)..y(2009)).to_a.should == [d(2008, 12, 30), d(2008, 12, 31), d(2009, 1, 1)]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should work with months and days" do
|
|
39
|
+
(d(2000, 1, 30)..m(2000, 2)).to_a.should == [d(2000, 1, 30), d(2000, 1, 31), d(2000, 2, 1)]
|
|
40
|
+
(m(2000, 1)..d(2000, 2, 1)).to_a.should == [m(2000, 1), m(2000, 2)]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should work with infinity" do
|
|
44
|
+
y(2008).should enumerate_infinitely_with(Infinity)
|
|
45
|
+
m(2008, 10).should enumerate_infinitely_with(Infinity)
|
|
46
|
+
d(2008, 10, 1).should enumerate_infinitely_with(Infinity)
|
|
47
|
+
w(2008, 1).should enumerate_infinitely_with(Infinity) if defined? Week
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should not have bug#1" do
|
|
51
|
+
lambda { d(2008, 12, 28)..m(2009, 4) }.should_not raise_error
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
data/spec/month.spec.rb
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Month, 'creation' do
|
|
4
|
+
|
|
5
|
+
it "should work from an integer" do
|
|
6
|
+
m(2000, 1).to_sym.should == :jan
|
|
7
|
+
lambda { m(2000, 13) }.should raise_error
|
|
8
|
+
lambda { m(2000, 0) }.should raise_error
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "should work from a symbol" do
|
|
12
|
+
m(2000, :jan).to_i.should == 1
|
|
13
|
+
m(2000, :feb).to_i.should == 2
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe Month, 'provides days correctly' do
|
|
19
|
+
|
|
20
|
+
def have_num_days(expected)
|
|
21
|
+
simple_matcher('have correct number of days') do |given, matcher|
|
|
22
|
+
matcher.failure_message = "expected #{given} to have #{expected} number of days"
|
|
23
|
+
given.num_days == expected && given.days.nitems == expected
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should know number of days" do
|
|
28
|
+
m(2000, 11).should have_num_days(30)
|
|
29
|
+
m(2000, 12).should have_num_days(31)
|
|
30
|
+
m(2001, 2 ).should have_num_days(28)
|
|
31
|
+
m(2000, 2 ).should have_num_days(29)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "should create days with day factory" do
|
|
35
|
+
month = m(2000, 1)
|
|
36
|
+
month.day_factory = mock_day_factory = mock('day factory')
|
|
37
|
+
mock_day_factory.should_receive(:new).
|
|
38
|
+
# RSpec is failing this part I'm pretty sure it shouldn't be:
|
|
39
|
+
#with(month, an_instance_of(Integer)).
|
|
40
|
+
at_least(:once)
|
|
41
|
+
month.days
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should return days in correct order" do
|
|
45
|
+
# CONSIDERATION: This spec is overzelously testing more than it claims. Consider using
|
|
46
|
+
# mocks over state or repurposing as an integration test.
|
|
47
|
+
day_numbers = m(2000, 1).days.map { |day| day.value }
|
|
48
|
+
day_numbers.sort.should == day_numbers
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe Month, 'provides individual days' do
|
|
54
|
+
|
|
55
|
+
before(:each) do
|
|
56
|
+
@month = m(2000, 1)
|
|
57
|
+
@month.day_factory = @mock_day_factory = mock('day factory')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should provide multiple individual days on demand" do
|
|
61
|
+
@mock_day_factory.should_receive(:new).with(@month, 1).once.and_return 1
|
|
62
|
+
@mock_day_factory.should_receive(:new).with(@month, 3).once.and_return 2
|
|
63
|
+
@mock_day_factory.should_receive(:new).with(@month, 5).once.and_return 3
|
|
64
|
+
@month.day(1, 3, 5).should == [1, 2, 3]
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should provide multiple individual days on demand specified with negative offset" do
|
|
68
|
+
@mock_day_factory.should_receive(:new).with(@month, 31).once.and_return :foo
|
|
69
|
+
@mock_day_factory.should_receive(:new).with(@month, 29).once.and_return :bar
|
|
70
|
+
@month.day(-1, -3).should == [:foo, :bar]
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should provide day 1 when no day value actually specified" do
|
|
74
|
+
@mock_day_factory.should_receive(:new).with(@month, 1).once.and_return(expected = rand_int)
|
|
75
|
+
@month.day.should == expected
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe Month, 'leap?' do
|
|
81
|
+
|
|
82
|
+
it "should not delegate to year if not Febuary" do
|
|
83
|
+
month = Month.new(y = mock('year'), 1)
|
|
84
|
+
y.should_not_receive(:leap?)
|
|
85
|
+
month.leap?.should == false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "should delegate to year if Febuary" do
|
|
89
|
+
month = Month.new(y = mock('year'), 2)
|
|
90
|
+
y.should_receive(:leap?).and_return(expected = rand_int)
|
|
91
|
+
month.leap?.should == expected
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe Month, 'math and logic' do
|
|
97
|
+
|
|
98
|
+
it "should be comparable" do
|
|
99
|
+
(m(2000, 11) == m(2000, 11)).should == true
|
|
100
|
+
(m(2000, 10) == m(2000, 11)).should == false
|
|
101
|
+
(m(2001, 11) == m(2000, 11)).should == false
|
|
102
|
+
(m(2000, 11) > m(2000, 12)).should == false
|
|
103
|
+
(m(2000, 12) > m(2000, 11)).should == true
|
|
104
|
+
(m(2001, 11) > m(2000, 11)).should == true
|
|
105
|
+
(m(2000, 11) > m(2001, 11)).should == false
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "should be able to add with integers" do
|
|
109
|
+
(m(2000, 11) + 1).should == m(2000, 12)
|
|
110
|
+
(m(1999, 11) + 2).should == m(2000, 1)
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
it "should be able to subtract with integers " do
|
|
114
|
+
(m(2001, 5) - 3).should == m(2001, 2)
|
|
115
|
+
(m(2001, 1) - 1).should == m(2000, 12)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "should hold state after arithmetic" do
|
|
119
|
+
a = m(2000, 5)
|
|
120
|
+
# day_factory is not used in any of these operations
|
|
121
|
+
# so it's ok to abuse it with a nonsense value
|
|
122
|
+
a.day_factory = :foo
|
|
123
|
+
b = a + 1
|
|
124
|
+
b.day_factory.should == :foo
|
|
125
|
+
b.object_id.should_not == a.object_id
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "should be rangeable" do
|
|
129
|
+
(m(2000, 1)..m(2000, 4)).to_a.should == [m(2000, 1), m(2000, 2), m(2000, 3), m(2000, 4)]
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "should be able to get months since and until other months" do
|
|
133
|
+
m(2000, 3).since(m(2000, 1)).should == 2
|
|
134
|
+
m(2000, 1).since(m(1999, 1)).should == 12
|
|
135
|
+
m(2000, 1).until(m(2000, 3)).should == 2
|
|
136
|
+
m(1999, 1).until(m(2000, 1)).should == 12
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should be able to get months since and until years" do
|
|
140
|
+
m(2000, 3).since(y(2000)).should == 2
|
|
141
|
+
m(2000, 10).until(y(2001)).should == 3
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should not permit you to get months since or until days" do
|
|
145
|
+
lambda { m.since(d) }.should raise_error
|
|
146
|
+
lambda { m.until(d) }.should raise_error
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..")) + '/lib/suprdate'
|
|
2
|
+
include Suprdate
|
|
3
|
+
|
|
4
|
+
def rand_int(size = 80_000) (rand * size).round - size / 2 end
|
|
5
|
+
def y_rand_int() (rand * 8000).round + 1600 end
|
|
6
|
+
|
|
7
|
+
def rand_between(range)
|
|
8
|
+
(rand * (range.last - range.first)).round + range.first
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def rand_year() rand_between(1600..2000) end
|
|
12
|
+
|
|
13
|
+
def date_parts(num_parts)
|
|
14
|
+
[rand_year, rand_between(1..12), rand_between(1..28)][0..num_parts - 1]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
alias :d :Day
|
|
18
|
+
alias :m :Month
|
|
19
|
+
alias :y :Year
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Suprdate, :every do
|
|
4
|
+
|
|
5
|
+
it "should filter lists by integer and symbol" do
|
|
6
|
+
list = (1..10).to_a
|
|
7
|
+
every(1, list).should == list
|
|
8
|
+
every(2, list).should == [1, 3, 5, 7, 9]
|
|
9
|
+
every(3, list).should == third = [1, 4, 7, 10]
|
|
10
|
+
every(4, list).should == [1, 5, 9]
|
|
11
|
+
every(:third, list).should == third
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should return the whole list if a block is provided" do
|
|
15
|
+
i = 0
|
|
16
|
+
every(2, [1,2]) { |x| x.should == 1; i+= 1 }.should == [1,2]
|
|
17
|
+
i.should == 1
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should raise if using an unknown symbol" do
|
|
21
|
+
lambda { every(:keith, [1,2,3]) }.should raise_error(IndexError)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
module BeAListOfIdenticalInstances
|
|
27
|
+
|
|
28
|
+
def be_a_list_of_identical_instances(expected)
|
|
29
|
+
simple_matcher('be a list of the same objects') do |given, matcher|
|
|
30
|
+
matcher.failure_message = "expected #{given.inspect} to be the same as #{expected.inspect}"
|
|
31
|
+
matcher.negative_failure_message =
|
|
32
|
+
"expected #{given.inspect} not to be the same as #{expected.inspect}"
|
|
33
|
+
sorted_object_ids(expected) == sorted_object_ids(given)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
def sorted_object_ids(list) list.map { |x| x.object_id }.sort end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe Suprdate::UNITS do
|
|
43
|
+
|
|
44
|
+
include BeAListOfIdenticalInstances
|
|
45
|
+
|
|
46
|
+
it "should contain all the units" do
|
|
47
|
+
units = []
|
|
48
|
+
Module.constants.each do |const|
|
|
49
|
+
const = Kernel.const_get(const)
|
|
50
|
+
next unless const.respond_to?(:ancestors)
|
|
51
|
+
const.ancestors[1..-1].find { |x| units << const if x == Unit }
|
|
52
|
+
end
|
|
53
|
+
UNITS.should be_a_list_of_identical_instances(units)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe Utility, :disarray do
|
|
59
|
+
|
|
60
|
+
it "should return unaltered array if 2 or more elements" do
|
|
61
|
+
Utility::disarray(array = Array.new(2)).should == array
|
|
62
|
+
Utility::disarray(array = Array.new(5)).should == array
|
|
63
|
+
Utility::disarray(array = Array.new(10)).should == array
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "should return first element of a single element array" do
|
|
67
|
+
Utility::disarray([:foo]).should == :foo
|
|
68
|
+
Utility::disarray([80081355]).should == 80081355
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe Utility, :english_list do
|
|
74
|
+
|
|
75
|
+
it "should return string forms of single items" do
|
|
76
|
+
Utility::english_list([1]).should == '1'
|
|
77
|
+
(mock_item = mock('item')).should_receive(:to_s).and_return(expected = rand_int.to_s)
|
|
78
|
+
Utility::english_list([mock_item]).should == expected
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "should return two-item lists with and in the middle" do
|
|
82
|
+
Utility::english_list([1, 2]).should == '1 and 2'
|
|
83
|
+
Utility::english_list([:Fox, :Hounds]).should == 'Fox and Hounds'
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should use commas in lists of any length greater than do" do
|
|
87
|
+
Utility::english_list([1, 2, 3]).should == '1, 2, and 3'
|
|
88
|
+
Utility::english_list(['Loud', 'scary', 'extremely flatulent']).should == 'Loud, scary, and extremely flatulent'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
describe Utility::CleanConstantName do
|
|
94
|
+
|
|
95
|
+
module FooNamespace
|
|
96
|
+
class Monkey
|
|
97
|
+
extend Utility::CleanConstantName
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should provide short version of the original" do
|
|
102
|
+
FooNamespace::Monkey.name.should == 'FooNamespace::Monkey'
|
|
103
|
+
FooNamespace::Monkey.name_singular.should == 'monkey'
|
|
104
|
+
FooNamespace::Monkey.to_sym.should == 'monkey'.to_sym
|
|
105
|
+
FooNamespace::Monkey.name_plural.should == 'monkeys'
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
describe 'self building integration' do
|
|
111
|
+
|
|
112
|
+
it "should allow years to build months and months to build days" do
|
|
113
|
+
|
|
114
|
+
year = Year.new(2000)
|
|
115
|
+
year.month_factory = mock_month_factory = mock('month factory')
|
|
116
|
+
year.day_factory = mock_day_factory = mock('day factory')
|
|
117
|
+
|
|
118
|
+
mock_month_factory.should_receive(:new).once.
|
|
119
|
+
with(year, month_value = rand_int).and_return(mock_month = mock('month'))
|
|
120
|
+
|
|
121
|
+
mock_month.should_receive(:day_factory=).once.
|
|
122
|
+
with(mock_day_factory).and_return(mock_day_factory)
|
|
123
|
+
|
|
124
|
+
mock_month.should_receive(:day).once.
|
|
125
|
+
with(day_value = rand_int).and_return(mock_day = rand_int)
|
|
126
|
+
|
|
127
|
+
year.month(month_value).day(day_value).should == mock_day
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
it "should allow months to build days" do
|
|
132
|
+
|
|
133
|
+
month = Month.new(Year.new(2008), 10)
|
|
134
|
+
month.day_factory = mock_day_factory = mock('day factory')
|
|
135
|
+
|
|
136
|
+
mock_day_factory.should_receive(:new).once.
|
|
137
|
+
with(month, day_value = rand_int.abs).and_return(mock_day = rand_int)
|
|
138
|
+
|
|
139
|
+
month.day(day_value).should == mock_day
|
|
140
|
+
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
it "should another one for weeks" do
|
|
144
|
+
pending if defined? Week
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
describe 'all unit classes' do
|
|
150
|
+
|
|
151
|
+
it "should have CleanConstantName included" do
|
|
152
|
+
UNITS.each do |klass|
|
|
153
|
+
class << klass
|
|
154
|
+
ancestors
|
|
155
|
+
end.include?(Utility::CleanConstantName).should == true
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "should have a leap? method" do
|
|
160
|
+
UNITS.each { |c| c.public_method_defined?(:leap?).should == true }
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
it "should know its significance related to each other unit" do
|
|
164
|
+
(Year <=> Year).should == 0
|
|
165
|
+
(Year <=> Month).should == 1
|
|
166
|
+
(Year <=> Day).should == 1
|
|
167
|
+
(Month <=> Year).should == -1
|
|
168
|
+
(Month <=> Month).should == 0
|
|
169
|
+
(Month <=> Day).should == 1
|
|
170
|
+
(Day <=> Year).should == -1
|
|
171
|
+
(Day <=> Month).should == -1
|
|
172
|
+
(Day <=> Day).should == 0
|
|
173
|
+
(Year > Month).should == true
|
|
174
|
+
(Year > Year).should == false
|
|
175
|
+
(Year <=> Array).should == nil
|
|
176
|
+
pending 'Missing weeks' if defined? Week
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
include BeAListOfIdenticalInstances
|
|
180
|
+
|
|
181
|
+
it "should have polymorphic interfaces" do
|
|
182
|
+
units = [y(2000), m(2000, 1), d(2000, 1, 1)]
|
|
183
|
+
# to make sure these really are all the units.
|
|
184
|
+
units.map { |i| i.class }.should be_a_list_of_identical_instances(UNITS)
|
|
185
|
+
units.each do |u|
|
|
186
|
+
u.day.class.should == Day
|
|
187
|
+
u.month.class.should == Month
|
|
188
|
+
u.year.class.should == Year
|
|
189
|
+
u.days[0].class.should == Day
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
data/spec/year.spec.rb
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
|
2
|
+
|
|
3
|
+
describe 'year is like an integer' do
|
|
4
|
+
|
|
5
|
+
it "should initialize with an integer" do
|
|
6
|
+
3.times { y(ex = y_rand_int).to_i.should == ex }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it "should be comparable with years" do
|
|
10
|
+
(y(ex = y_rand_int) == y(ex)).should == true
|
|
11
|
+
(y(ex = y_rand_int) == y(ex + 1)).should == false
|
|
12
|
+
(y(2001) > y(2000)).should == true
|
|
13
|
+
(y(2000) > y(2000)).should == false
|
|
14
|
+
(y(2000) < y(2001)).should == true
|
|
15
|
+
(y(2000) < y(2000)).should == false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should know the successive year" do
|
|
19
|
+
y(2000).succ.should == y(2001)
|
|
20
|
+
(y(2000) .. y(2003)).to_a.should == [y(2000), y(2001), y(2002), y(2003)]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "should respond to addition with an integer" do
|
|
24
|
+
(y(a = y_rand_int) + b = y_rand_int).should == y(a + b)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should respond to subtraction with an integer" do
|
|
28
|
+
(y(a = y_rand_int) - b = 10).should == y(a - b)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should hold state after arithmetic" do
|
|
32
|
+
a = Year.new(2000)
|
|
33
|
+
# month_factory is not used in any of these operations
|
|
34
|
+
# so it's ok to abuse it with a nonsense value
|
|
35
|
+
a.month_factory = :foo
|
|
36
|
+
b = a + 1
|
|
37
|
+
b.month_factory.should == :foo
|
|
38
|
+
b.object_id.should_not == a.object_id
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "should be able to get years since and until other years" do
|
|
42
|
+
y(2005).since(y(2000)).should == 5
|
|
43
|
+
y(2000).until(y(2005)).should == 5
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "should not permit you to get years since or until months or days" do
|
|
47
|
+
lambda { y.since(d) }.should raise_error
|
|
48
|
+
lambda { y.until(d) }.should raise_error
|
|
49
|
+
lambda { y.since(m) }.should raise_error
|
|
50
|
+
lambda { y.until(m) }.should raise_error
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
describe 'year comprised of months' do
|
|
56
|
+
|
|
57
|
+
before(:each) do
|
|
58
|
+
@year = y(2000)
|
|
59
|
+
@year.day_factory = @mock_day_factory = mock('day factory')
|
|
60
|
+
@mock_month = mock('month')
|
|
61
|
+
@year.month_factory = @month_factory = mock('month factory')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should return an array of months" do
|
|
65
|
+
nums = []
|
|
66
|
+
@month_factory.should_receive(:new) do |year, n|
|
|
67
|
+
year.should == @year
|
|
68
|
+
nums << n
|
|
69
|
+
@mock_month
|
|
70
|
+
end.exactly(NUM_MONTHS_IN_YEAR).times
|
|
71
|
+
|
|
72
|
+
@mock_month.should_receive(:day_factory=).with(@mock_day_factory).
|
|
73
|
+
exactly(NUM_MONTHS_IN_YEAR).times.and_return(@mock_day_factory)
|
|
74
|
+
|
|
75
|
+
@year.months[0].should == @mock_month
|
|
76
|
+
nums.sort.should == nums
|
|
77
|
+
nums[0].should == 1
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should provide individual months on demand" do
|
|
81
|
+
@month_factory.should_receive(:new).with(@year, 1).once.and_return @mock_month
|
|
82
|
+
@mock_month.should_receive(:day_factory=).with(@mock_day_factory).once.and_return(@mock_day_factory)
|
|
83
|
+
@year.month(1).should == @mock_month
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
it "should provide month 1 when no month value actually specified" do
|
|
87
|
+
@month_factory.should_receive(:new).with(@year, 1).once.and_return @mock_month
|
|
88
|
+
@mock_month.should_receive(:day_factory=).with(@mock_day_factory).once.and_return(@mock_day_factory)
|
|
89
|
+
@year.month.should == @mock_month
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "should provide multiple individual months on demand" do
|
|
93
|
+
@month_factory.should_receive(:new).with(@year, 1).once.and_return @mock_month
|
|
94
|
+
@month_factory.should_receive(:new).with(@year, 3).once.and_return @mock_month
|
|
95
|
+
@month_factory.should_receive(:new).with(@year, 5).once.and_return @mock_month
|
|
96
|
+
@mock_month.should_receive(:day_factory=).with(@mock_day_factory).
|
|
97
|
+
exactly(3).times.and_return(@mock_day_factory)
|
|
98
|
+
@year.month(1, 3, 5).should == Array.new(3, @mock_month)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe 'year misc' do
|
|
104
|
+
|
|
105
|
+
it "should not allow years before 1582 to be created" do
|
|
106
|
+
lambda { y(300) }.should raise_error(DateConstructionError)
|
|
107
|
+
lambda { y(1500) }.should raise_error(DateConstructionError)
|
|
108
|
+
lambda { y(1582); y(1600) }.should_not raise_error
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "should known when it's a leap year" do
|
|
112
|
+
# http://en.wikipedia.org/wiki/Leap_year#Gregorian_calendar
|
|
113
|
+
[1600, 1604, 1608, 1612, 2000, 2400, 2800].each do |year|
|
|
114
|
+
y(year).leap?.should be_true
|
|
115
|
+
end
|
|
116
|
+
[1700, 1800, 1900, 2100, 2200, 2300, 2500, 2600, 2700, 2900, 3000].each do |year|
|
|
117
|
+
y(year).leap?.should be_false
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
describe 'year comprised of days (via months)' do
|
|
124
|
+
|
|
125
|
+
NO_LEAP = false
|
|
126
|
+
LEAP = true
|
|
127
|
+
|
|
128
|
+
before(:each) do
|
|
129
|
+
@year = y(2000)
|
|
130
|
+
@expected = rand_int
|
|
131
|
+
@year.month_factory = @month_factory = mock('month factory')
|
|
132
|
+
@month = mock('month')
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
it "should return an array of days" do
|
|
136
|
+
# days can only be created through months
|
|
137
|
+
|
|
138
|
+
@month_factory.should_receive(:new).
|
|
139
|
+
# RSpec is failing this part I'm pretty sure it shouldn't be:
|
|
140
|
+
#with(@year, an_instance_of(Integer)).
|
|
141
|
+
exactly(NUM_MONTHS_IN_YEAR).times.and_return(@month)
|
|
142
|
+
|
|
143
|
+
@month.should_receive(:day_factory=).with(@year.day_factory).
|
|
144
|
+
exactly(NUM_MONTHS_IN_YEAR).times.and_return(@year.day_factory)
|
|
145
|
+
|
|
146
|
+
@month.should_receive(:days).with(no_args).
|
|
147
|
+
# each month creates only two days in this example...
|
|
148
|
+
exactly(NUM_MONTHS_IN_YEAR).times.and_return Array.new(list_size = (rand * 6).round + 1, @expected)
|
|
149
|
+
|
|
150
|
+
days = @year.days
|
|
151
|
+
days.nitems.should == list_size * NUM_MONTHS_IN_YEAR
|
|
152
|
+
days[0].should == @expected
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
describe 'year copies' do
|
|
158
|
+
|
|
159
|
+
it "should hold state" do
|
|
160
|
+
a = Year.new(2000)
|
|
161
|
+
a.month_factory = :foo
|
|
162
|
+
b= a.new(2001)
|
|
163
|
+
b.object_id.should_not == a.object_id
|
|
164
|
+
b.month_factory.should == a.month_factory
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|