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