by_star 0.2.5 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,23 @@
1
+ module ByStar
2
+ module Calculations
3
+ include Count
4
+ include Sum
5
+
6
+ private
7
+ def work_out_month(time, options = {})
8
+ year = options[:year] ||= Time.zone.now.year
9
+ # Work out what actual month is.
10
+ month = if time.is_a?(Numeric) && (1..12).include?(time)
11
+ time
12
+ elsif valid_time_or_date?(time)
13
+ year = time.year
14
+ time.month
15
+ elsif time.is_a?(String) && Date::MONTHNAMES.include?(time)
16
+ Date::MONTHNAMES.index(time)
17
+ else
18
+ raise ParseError, "Value is not an integer (between 1 and 12), time object or string (make sure you typed the name right)."
19
+ end
20
+ [year, month]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ module ByStar
2
+ module Calculations
3
+ module Count
4
+ def count_by_year(field=nil, year=Time.now.year, options={})
5
+ count(field, :conditions => conditions_for_range(start_of_year(year), end_of_year(year), options))
6
+ end
7
+
8
+ def count_by_month(field=nil, month=Time.now.month, options={})
9
+ year, month = work_out_month(month, options)
10
+ count(field, :conditions => conditions_for_range(start_of_month(month, year), end_of_month(month, year), options))
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module ByStar
2
+ module Calculations
3
+ module Sum
4
+ def sum_by_year(field, year=Time.zone.now.year, options={})
5
+ sum(field, :conditions => conditions_for_range(start_of_year(year), end_of_year(year), options))
6
+ end
7
+
8
+ def sum_by_month(field, month=Time.zone.now.month, options={})
9
+ year, month = work_out_month(month, options)
10
+ sum(field, :conditions => conditions_for_range(start_of_month(month, year), end_of_month(month, year), options))
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,23 @@
1
+ module ByStar
2
+ module RangeCalculations
3
+
4
+ private
5
+
6
+ def start_of_year(year=Time.now.year)
7
+ Time.utc(year, 1, 1)
8
+ end
9
+
10
+ def end_of_year(year=Time.now.year)
11
+ start_of_year.end_of_year
12
+ end
13
+
14
+ def start_of_month(month, year=Time.now.year)
15
+ Time.utc(year, month, 1)
16
+ end
17
+
18
+ def end_of_month(month, year=Time.now.year)
19
+ start_of_month(month, year).end_of_month
20
+ end
21
+ end
22
+
23
+ end
data/lib/shared.rb ADDED
@@ -0,0 +1,6 @@
1
+ module Shared
2
+ def conditions_for_range(start_time, end_time, options = {})
3
+ field = connection.quote_table_name(table_name) << '.' << connection.quote_column_name(options[:field] || "created_at")
4
+ ["#{field} >= ? AND #{field} <= ?", start_time.utc, end_time.utc]
5
+ end
6
+ end
data/lib/time_ext.rb ADDED
@@ -0,0 +1,20 @@
1
+ class Time
2
+ def beginning_of_weekend
3
+ friday = case self.wday
4
+ when 0
5
+ self.end_of_week.beginning_of_day.advance(:days => -2)
6
+ when 5
7
+ self.beginning_of_day
8
+ else
9
+ self.beginning_of_week.advance(:days => 4)
10
+ end
11
+ # 3pm, Friday.
12
+ (friday + 15.hours)
13
+ end
14
+
15
+ def end_of_weekend
16
+ # 3am, Monday.
17
+ # LOL I CHEATED.
18
+ beginning_of_weekend + 3.days - 12.hours
19
+ end
20
+ end
data/lib/vanilla.rb ADDED
@@ -0,0 +1,273 @@
1
+ module ByStar
2
+ module Vanilla
3
+ # Examples:
4
+ # by_year(2010)
5
+ # # 2-digit year:
6
+ # by_year(10)
7
+ # # Time or Date object:
8
+ # by_year(time)
9
+ # # String:
10
+ # by_year("2010")
11
+ def by_year(time=Time.zone.now.year, options={}, &block)
12
+ year = work_out_year(time)
13
+ start_time = start_of_year(year)
14
+ end_time = start_time.end_of_year
15
+ by_star(start_time, end_time, options, &block)
16
+ rescue ArgumentError
17
+ raise ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039). This is no longer a problem on Ruby versions >= 1.8.7, so we recommend you upgrade to at least 1.8.7."
18
+ end
19
+
20
+ # Examples:
21
+ # by_month(1)
22
+ # by_month("January")
23
+ # by_month("January", :year => 2008)
24
+ # by_month(time)
25
+ def by_month(time=Time.zone.now.month, options={}, &block)
26
+ time = Time.zone.now.month if time.nil?
27
+ year, month = work_out_month(time, options)
28
+
29
+ start_time = start_of_month(month, year)
30
+ end_time = start_time.end_of_month
31
+
32
+ by_star(start_time, end_time, options, &block)
33
+ end
34
+
35
+ # Examples:
36
+ # # 18th fortnight of 2004
37
+ # Post.by_fortnight(18, :year => 2004)
38
+ def by_fortnight(time=Time.zone.now, options = {}, &block)
39
+ time = parse(time)
40
+
41
+ # If options[:year] is passed in, use that year regardless.
42
+ year = work_out_year(options[:year]) if options[:year]
43
+ # If the first argument is a date or time, ask it for the year
44
+ year ||= time.year unless time.is_a?(Numeric)
45
+ # If the first argument is a fixnum, assume this year.
46
+ year ||= Time.zone.now.year
47
+
48
+ # Dodgy!
49
+ # Surely there's a method in Rails to do this.
50
+ start_time = if valid_time_or_date?(time)
51
+ time.beginning_of_year + (time.strftime("%U").to_i).weeks
52
+ elsif time.is_a?(Numeric) && time <= 26
53
+ Time.utc(year, 1, 1) + ((time.to_i) * 2).weeks
54
+ else
55
+ raise ParseError, "by_fortnight takes only a Time or Date object, a Fixnum (less than or equal to 26) or a Chronicable string."
56
+ end
57
+ start_time = start_time.beginning_of_week
58
+ end_time = start_time + 2.weeks
59
+ by_star(start_time, end_time, options, &block)
60
+ end
61
+
62
+ # Examples:
63
+ # # 36th week
64
+ # Post.by_week(36)
65
+ # Post.by_week(36.54)
66
+ # Post.by_week(36, :year => 2004)
67
+ # Post.by_week(<Time object>)
68
+ # Post.by_week(<Date object>)
69
+ # Post.by_week("next tuesday")
70
+ def by_week(time=Time.zone.now, options = {}, &block)
71
+ time = parse(time)
72
+
73
+ # If options[:year] is passed in, use that year regardless.
74
+ year = work_out_year(options[:year]) if options[:year]
75
+ # If the first argument is a date or time, ask it for the year
76
+ year ||= time.year unless time.is_a?(Numeric)
77
+ # If the first argument is a fixnum, assume this year.
78
+ year ||= Time.now.year
79
+
80
+ # Dodgy!
81
+ # Surely there's a method in Rails to do this.
82
+ start_time = if valid_time_or_date?(time)
83
+ weeks = time.strftime("%U").to_i
84
+ time.beginning_of_year
85
+ elsif time.is_a?(Numeric) && time < 53
86
+ weeks = time.to_i
87
+ Time.utc(year, 1, 1)
88
+ else
89
+ raise ParseError, "by_week takes only a Time or Date object, a Fixnum (less than or equal to 53) or a Chronicable string."
90
+ end
91
+ start_time += weeks.weeks
92
+ end_time = start_time + 1.week
93
+ by_star(start_time, end_time, options, &block)
94
+ end
95
+
96
+
97
+ # Examples:
98
+ # Post.by_weekend
99
+ # Post.by_weekend(Time.now + 5.days)
100
+ # Post.by_weekend(Date.today + 5)
101
+ # Post.by_weekend("next tuesday")
102
+ def by_weekend(time=Time.zone.now, options = {}, &block)
103
+ time = parse(time)
104
+ start_time = time.beginning_of_weekend
105
+ by_star(start_time, (start_time + 1.day).end_of_day, options, &block)
106
+ end
107
+
108
+
109
+ # Examples:
110
+ # Post.by_current_weekend
111
+ def by_current_weekend(options = {}, &block)
112
+ time = Time.zone.now
113
+ # Friday, 3pm
114
+ start_time = time.beginning_of_weekend
115
+ # Monday, 3am
116
+ end_time = time.end_of_weekend
117
+ by_star(start_time, end_time, options, &block)
118
+ end
119
+
120
+ # Examples:
121
+ # Post.by_current_work_week
122
+ def by_current_work_week(options = {}, &block)
123
+ time = Time.zone.now
124
+ # Monday, 3am
125
+ time = time + 1.week if time.wday == 6 || time.wday == 0
126
+ start_time = time.beginning_of_week + 3.hours
127
+ # Friday, 3pm
128
+ end_time = time.beginning_of_weekend
129
+ by_star(start_time, end_time, options, &block)
130
+ end
131
+
132
+
133
+ # Examples:
134
+ # Post.by_day
135
+ # Post.by_day(Time.yesterday)
136
+ # Post.by_day("next tuesday")
137
+ def by_day(time = Time.zone.now, options = {}, &block)
138
+ time = parse(time)
139
+ by_star(time.beginning_of_day, time.end_of_day, options, &block)
140
+ end
141
+ alias_method :today, :by_day
142
+
143
+ # Examples:
144
+ # Post.yesterday
145
+ # # 2 days ago:
146
+ # Post.yesterday(Time.yesterday)
147
+ # # day before next tuesday
148
+ # Post.yesterday("next tuesday")
149
+ def yesterday(time = Time.zone.now, options = {}, &block)
150
+ time = parse(time)
151
+ by_day(time.advance(:days => -1), options, &block)
152
+ end
153
+
154
+ # Examples:
155
+ # Post.tomorrow
156
+ # # 2 days from now:
157
+ # Post.tomorrow(Time.tomorrow)
158
+ # # day after next tuesday
159
+ # Post.tomorrow("next tuesday")
160
+ def tomorrow(time = Time.zone.now, options = {}, &block)
161
+ time = parse(time)
162
+ by_day(time.advance(:days => 1), options, &block)
163
+ end
164
+
165
+ # Scopes to records older than current or given time
166
+ # Post.past
167
+ # Post.past()
168
+ def past(time = Time.zone.now, options = {}, &block)
169
+ time = parse(time)
170
+ by_direction("<", time, options, &block)
171
+ end
172
+
173
+ # Scopes to records newer than current or given time
174
+ def future(time = Time.zone.now, options = {}, &block)
175
+ time = parse(time)
176
+ by_direction(">", time, options, &block)
177
+ end
178
+
179
+ private
180
+
181
+ def by_direction(condition, time, options = {}, &block)
182
+ field = connection.quote_table_name(table_name)
183
+ field << "." << connection.quote_column_name(options[:field] || "created_at")
184
+ with_scope(:find => { :conditions => ["#{field} #{condition} ?", time.utc] }) do
185
+ if block_given?
186
+ with_scope(:find => block.call) do
187
+ find(:all)
188
+ end
189
+ else
190
+ find(:all)
191
+ end
192
+ end
193
+ end
194
+
195
+ # scopes results between start_time and end_time
196
+ def by_star(start_time, end_time, options = {}, &block)
197
+ start_time = parse(start_time)
198
+ end_time = parse(end_time)
199
+
200
+ raise ParseError, "End time is before start time, searching like this will return no results." if end_time < start_time
201
+
202
+ with_scope(:find => { :conditions => conditions_for_range(start_time, end_time, options) }) do
203
+ if block_given?
204
+ with_scope(:find => block.call) do
205
+ find(:all)
206
+ end
207
+ else
208
+ find(:all)
209
+ end
210
+ end
211
+ end
212
+
213
+ alias :between :by_star
214
+ public :between
215
+
216
+ # This will work for the next 30 years (written in 2009)
217
+ def work_out_year(value)
218
+ case value
219
+ when 0..39
220
+ 2000 + value
221
+ when 40..99
222
+ 1900 + value
223
+ when nil
224
+ Time.zone.now.year
225
+ else
226
+ # We may be passed something that's not a straight out integer
227
+ # These things include: BigDecimals, Floats and Strings.
228
+ value.to_i
229
+ end
230
+ end
231
+
232
+ # Checks if the object is a Time, Date or TimeWithZone object.
233
+ def valid_time_or_date?(value)
234
+ value.is_a?(Time) || value.is_a?(Date) || value.is_a?(ActiveSupport::TimeWithZone)
235
+ end
236
+
237
+ def parse(object)
238
+ object = case object.class.to_s
239
+ when "NilClass"
240
+ o = Time.zone.now
241
+ when "String"
242
+ o = object
243
+ Chronic.parse(object, :now => Time.zone.now)
244
+ when "Date"
245
+ object.to_time(:utc)
246
+ else
247
+ object
248
+ end
249
+ raise ParseError, "Chronic couldn't work out #{o.inspect}; please be more precise." if object.nil?
250
+ object
251
+ end
252
+
253
+ def method_missing(method, *args)
254
+ if method.to_s =~ /^(as_of|up_to)_(.+)$/
255
+ method = $1
256
+ expr = $2.humanize
257
+ unless time = parse(expr)
258
+ raise ParseError, "Chronic couldn't work out #{expr.inspect}; please be more precise."
259
+ end
260
+
261
+ reference = args.first || Time.now
262
+
263
+ if "as_of" == method
264
+ between(time, reference)
265
+ else
266
+ between(reference, time)
267
+ end
268
+ else
269
+ super
270
+ end
271
+ end
272
+ end
273
+ end
data/spec/by_star_spec.rb CHANGED
@@ -2,7 +2,7 @@ require File.join(File.dirname(__FILE__), 'spec_helper')
2
2
  require 'by_star'
3
3
 
4
4
  describe Post do
5
-
5
+
6
6
  def stub_time(day=15, month=5, year=Time.zone.now.year, hour=0, minute=0)
7
7
  stub = "#{day}-#{month}-#{year} #{hour}:#{minute}".to_time
8
8
  Time.stub!(:now).and_return(stub)
@@ -26,479 +26,532 @@ describe Post do
26
26
  Post.send(method, *args).size
27
27
  end
28
28
 
29
+ ["mysql", "sqlite3"].each do |adapter|
30
+ ActiveRecord::Base.establish_connection(YAML::load_file(File.dirname(__FILE__) + "/database.yml")[adapter])
29
31
 
30
- describe "by year" do
31
- it "should be able to find all the posts in the current year" do
32
- size.should eql(Post.count - 1)
33
- end
32
+ describe "by year" do
33
+ it "should be able to find all the posts in the current year" do
34
+ size.should eql(Post.count - 1)
35
+ end
34
36
 
35
- it "should be able to find if given a string" do
36
- size(Time.zone.now.year.to_s).should eql(Post.count - 1)
37
- end
37
+ it "should be able to find if given a string" do
38
+ size(Time.zone.now.year.to_s).should eql(Post.count - 1)
39
+ end
38
40
 
39
- it "should be able to find a single post from last year" do
40
- size(Time.zone.now.year-1).should eql(1)
41
- end
41
+ it "should be able to find a single post from last year" do
42
+ size(Time.zone.now.year-1).should eql(1)
43
+ end
42
44
 
43
- it "should error when given an invalid year" do
44
- # This is broken on 1.8.6 (and previous versions), any patchlevel after & before 111
45
- major, minor, trivial = RUBY_VERSION.split(".").map(&:to_i)
46
- if major == 1 && ((minor == 8 && trivial <= 6) || (minor <= 8)) && RUBY_PATCHLEVEL.to_i > 111
47
- lambda { find(1901) }.should raise_error(ByStar::ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039)")
48
- lambda { find(2039) }.should raise_error(ByStar::ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039)")
49
- else
50
- find(1456).should be_empty
51
- find(1901).should be_empty
52
- find(2039).should be_empty
45
+ it "should error when given an invalid year" do
46
+ # This is broken on 1.8.6 (and previous versions), any patchlevel after & before 111
47
+ major, minor, trivial = RUBY_VERSION.split(".").map(&:to_i)
48
+ if major == 1 && ((minor == 8 && trivial <= 6) || (minor <= 8)) && RUBY_PATCHLEVEL.to_i > 111
49
+ lambda { find(1901) }.should raise_error(ByStar::ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039)")
50
+ lambda { find(2039) }.should raise_error(ByStar::ParseError, "Invalid arguments detected, year may possibly be outside of valid range (1902-2039)")
51
+ else
52
+ find(1456).should be_empty
53
+ find(1901).should be_empty
54
+ find(2039).should be_empty
55
+ end
53
56
  end
54
- end
55
57
 
56
- it "should be able to use an alternative field" do
57
- Event.by_year(nil, :field => "start_time").size.should eql(8)
58
+ it "should be able to use an alternative field" do
59
+ Event.by_year(nil, :field => "start_time").size.should eql(8)
60
+ end
58
61
  end
59
- end
60
62
 
61
- describe "by month" do
63
+ describe "by month" do
62
64
 
63
- it "should be able to find posts for the current month" do
64
- stub_time
65
- size.should eql(8)
66
- end
65
+ it "should be able to find posts for the current month" do
66
+ stub_time
67
+ size.should eql(8)
68
+ end
67
69
 
68
- it "should be able to find a single post for January" do
69
- size("January").should eql(1)
70
- end
70
+ it "should be able to find a single post for January" do
71
+ size("January").should eql(1)
72
+ end
71
73
 
72
- it "should be able to find two posts for the 2nd month" do
73
- size(2).should eql(2)
74
- end
74
+ it "should be able to find two posts for the 2nd month" do
75
+ size(2).should eql(2)
76
+ end
75
77
 
76
- it "should be able to find three posts for the 3rd month, using time instance" do
77
- # Hack... if we're running this test during march there's going to be more posts than usual.
78
- # This is due to the #today, #yesterday and #tomorrow methods.
78
+ it "should be able to find three posts for the 3rd month, using time instance" do
79
+ # Hack... if we're running this test during march there's going to be more posts than usual.
80
+ # This is due to the #today, #yesterday and #tomorrow methods.
79
81
 
80
- size(Time.local(Time.zone.now.year, 3, 1)).should eql(3)
81
- end
82
+ size(Time.local(Time.zone.now.year, 3, 1)).should eql(3)
83
+ end
82
84
 
83
- it "should be able to find a single post from January last year" do
84
- size("January", :year => Time.zone.now.year - 1).should eql(1)
85
- end
85
+ it "should be able to find a single post from January last year" do
86
+ size("January", :year => Time.zone.now.year - 1).should eql(1)
87
+ end
86
88
 
87
- it "should fail when given incorrect months" do
88
- lambda { find(0) }.should raise_error(ByStar::ParseError)
89
- lambda { find(13) }.should raise_error(ByStar::ParseError)
90
- lambda { find("Ryan") }.should raise_error(ByStar::ParseError)
91
- lambda { find([1,2,3]) }.should raise_error(ByStar::ParseError)
92
- end
89
+ it "should fail when given incorrect months" do
90
+ lambda { find(0) }.should raise_error(ByStar::ParseError)
91
+ lambda { find(13) }.should raise_error(ByStar::ParseError)
92
+ lambda { find("Ryan") }.should raise_error(ByStar::ParseError)
93
+ lambda { find([1,2,3]) }.should raise_error(ByStar::ParseError)
94
+ end
93
95
 
94
- it "should be able to take decimals" do
95
- size(1.5).should eql(1)
96
- end
96
+ it "should be able to take decimals" do
97
+ size(1.5).should eql(1)
98
+ end
97
99
 
98
- it "should be able to use an alternative field" do
99
- stub_time(1, 12)
100
- Event.by_month(nil, :field => "start_time").size.should eql(1)
101
- end
100
+ it "should be able to use an alternative field" do
101
+ stub_time(1, 12)
102
+ Event.by_month(nil, :field => "start_time").size.should eql(1)
103
+ end
102
104
 
103
- it "should be able to specify the year as a string" do
104
- size(1, :year => (Time.zone.now.year - 1).to_s).should eql(1)
105
- end
105
+ it "should be able to specify the year as a string" do
106
+ size(1, :year => (Time.zone.now.year - 1).to_s).should eql(1)
107
+ end
106
108
 
107
- end
109
+ end
108
110
 
109
- describe "by fortnight" do
111
+ describe "by fortnight" do
110
112
 
111
- it "should be able to find posts in the current fortnight" do
112
- stub_time
113
- size.should eql(3)
114
- end
113
+ it "should be able to find posts in the current fortnight" do
114
+ stub_time
115
+ size.should eql(3)
116
+ end
115
117
 
116
- it "should be able to find posts in the 1st fortnight" do
117
- size(0).should eql(1)
118
- end
118
+ it "should be able to find posts in the 1st fortnight" do
119
+ size(0).should eql(1)
120
+ end
119
121
 
120
- it "should be able to find posts for a fortnight ago" do
121
- stub_time
122
- size(2.weeks.ago).should eql(5)
123
- end
122
+ it "should be able to find posts for a fortnight ago" do
123
+ stub_time
124
+ size(2.weeks.ago).should eql(5)
125
+ end
124
126
 
125
- it "should raise an error when given an invalid argument" do
126
- lambda { find(27) }.should raise_error(ByStar::ParseError, "by_fortnight takes only a Time or Date object, a Fixnum (less than or equal to 26) or a Chronicable string.")
127
- end
127
+ it "should raise an error when given an invalid argument" do
128
+ lambda { find(27) }.should raise_error(ByStar::ParseError, "by_fortnight takes only a Time or Date object, a Fixnum (less than or equal to 26) or a Chronicable string.")
129
+ end
128
130
 
129
- it "should be able to use an alternative field" do
130
- stub_time
131
- Event.by_fortnight(nil, :field => "start_time").size.should eql(0)
131
+ it "should be able to use an alternative field" do
132
+ stub_time
133
+ Event.by_fortnight(nil, :field => "start_time").size.should eql(0)
134
+ end
132
135
  end
133
- end
134
136
 
135
- describe "by week" do
137
+ describe "by week" do
136
138
 
137
- it "should be able to find posts in the current week" do
138
- stub_time
139
- size.should eql(3)
140
- end
139
+ it "should be able to find posts in the current week" do
140
+ stub_time
141
+ size.should eql(3)
142
+ end
141
143
 
142
- it "should be able to find posts in the 1st week" do
143
- size(0).should eql(1)
144
- end
144
+ it "should be able to find posts in the 1st week" do
145
+ size(0).should eql(1)
146
+ end
145
147
 
146
- it "should be able to find posts in the 1st week of last year" do
147
- size(0, :year => Time.zone.now.year-1).should eql(1)
148
- end
148
+ it "should be able to find posts in the 1st week of last year" do
149
+ size(0, :year => Time.zone.now.year-1).should eql(1)
150
+ end
149
151
 
150
- it "should not find any posts from a week ago" do
151
- stub_time
152
- size(1.week.ago).should eql(0)
153
- end
152
+ it "should not find any posts from a week ago" do
153
+ stub_time
154
+ size(1.week.ago).should eql(0)
155
+ end
154
156
 
155
- it "should be able to find posts by a given date" do
156
- stub_time
157
- size(1.week.ago.to_date).should eql(0)
158
- end
157
+ it "should be able to find posts by a given date" do
158
+ stub_time
159
+ size(1.week.ago.to_date).should eql(0)
160
+ end
159
161
 
160
- it "should find, not size the posts for the current week" do
161
- stub_time
162
- find.map(&:text).include?("The 'Current' Week")
163
- find.map(&:text).include?("Weekend of May")
164
- end
162
+ it "should find, not size the posts for the current week" do
163
+ stub_time
164
+ find.map(&:text).include?("The 'Current' Week")
165
+ find.map(&:text).include?("Weekend of May")
166
+ end
165
167
 
166
- it "should raise an error when given an invalid argument" do
167
- lambda { find(54) }.should raise_error(ByStar::ParseError, "by_week takes only a Time or Date object, a Fixnum (less than or equal to 53) or a Chronicable string.")
168
- end
168
+ it "should raise an error when given an invalid argument" do
169
+ lambda { find(54) }.should raise_error(ByStar::ParseError, "by_week takes only a Time or Date object, a Fixnum (less than or equal to 53) or a Chronicable string.")
170
+ end
169
171
 
170
- it "should be able to use an alternative field" do
171
- stub_time
172
- Event.by_week(nil, :field => "start_time").size.should eql(0)
173
- end
172
+ it "should be able to use an alternative field" do
173
+ stub_time
174
+ Event.by_week(nil, :field => "start_time").size.should eql(0)
175
+ end
174
176
 
175
- it "should find posts at the start of the year" do
176
- size(0).should eql(1)
177
- end
177
+ it "should find posts at the start of the year" do
178
+ size(0).should eql(1)
179
+ end
178
180
 
179
- it "should find posts at the end of the year" do
180
- size(Time.zone.now.end_of_year).should eql(1)
181
- end
181
+ it "should find posts at the end of the year" do
182
+ size(Time.zone.now.end_of_year).should eql(1)
183
+ end
182
184
 
183
- end
184
-
185
- describe "by weekend" do
186
- it "should be able to find the posts on the weekend of the 1st May" do
187
- stub_time(1, 8)
188
- size.should eql(8)
189
185
  end
186
+
187
+ describe "by weekend" do
188
+ it "should be able to find the posts on the weekend of the 1st May" do
189
+ stub_time(1, 8)
190
+ size.should eql(8)
191
+ end
190
192
 
191
- it "should be able to use an alternative field" do
192
- year = Time.zone.now.year
193
- stub_time(1, 8)
194
- Event.by_weekend(nil, :field => "start_time").size.should eql(1)
193
+ it "should be able to use an alternative field" do
194
+ year = Time.zone.now.year
195
+ stub_time(1, 8)
196
+ Event.by_weekend(nil, :field => "start_time").size.should eql(1)
197
+ end
195
198
  end
196
- end
197
199
 
198
- describe "by current weekend" do
199
- it "should work" do
200
- range_test do
201
- Post.by_current_weekend
200
+ describe "by current weekend" do
201
+ it "should work" do
202
+ range_test do
203
+ Post.by_current_weekend
204
+ end
202
205
  end
203
206
  end
204
- end
205
207
 
206
- describe "by current work week" do
207
- it "should work" do
208
- range_test do
209
- Post.by_current_work_week
208
+ describe "by current work week" do
209
+ it "should work" do
210
+ range_test do
211
+ Post.by_current_work_week
212
+ end
210
213
  end
211
214
  end
212
- end
213
215
 
214
- describe "by day" do
215
- it "should be able to find a post for today" do
216
- stub_time
217
- size.should eql(2)
218
- end
216
+ describe "by day" do
217
+ it "should be able to find a post for today" do
218
+ stub_time
219
+ size.should eql(2)
220
+ end
219
221
 
220
- it "should be able to find a post by a given date" do
221
- stub_time
222
- size(Date.today).should eql(2)
223
- end
222
+ it "should be able to find a post by a given date" do
223
+ stub_time
224
+ size(Date.today).should eql(2)
225
+ end
224
226
 
225
- it "should be able to use an alternative field" do
226
- Event.by_day(nil, :field => "start_time").size.should eql(1)
227
+ it "should be able to use an alternative field" do
228
+ Event.by_day(nil, :field => "start_time").size.should eql(1)
229
+ end
227
230
  end
228
- end
229
231
 
230
- describe "today" do
231
- it "should show the post for today" do
232
- find.map(&:text).should include("Today's post")
233
- end
232
+ describe "today" do
233
+ it "should show the post for today" do
234
+ find.map(&:text).should include("Today's post")
235
+ end
234
236
 
235
- it "should be able to use an alternative field" do
236
- # Test may occur on an event day.
237
- stub_time
238
- Event.today(nil, :field => "start_time").size.should eql(0)
239
- end
237
+ it "should be able to use an alternative field" do
238
+ # Test may occur on an event day.
239
+ stub_time
240
+ Event.today(nil, :field => "start_time").size.should eql(0)
241
+ end
240
242
 
241
- end
243
+ end
242
244
 
243
- describe "tomorrow" do
244
- it "should show the post for tomorrow" do
245
- find.map(&:text).should include("Tomorrow's post")
245
+ describe "tomorrow" do
246
+ it "should show the post for tomorrow" do
247
+ find.map(&:text).should include("Tomorrow's post")
248
+ end
246
249
  end
247
- end
248
250
 
249
- describe "yesterday" do
250
- it "should show the post for yesterday" do
251
- find.map(&:text).should include("Yesterday's post")
252
- end
251
+ describe "yesterday" do
252
+ it "should show the post for yesterday" do
253
+ find.map(&:text).should include("Yesterday's post")
254
+ end
253
255
 
254
- it "should be able find yesterday, given a Date" do
255
- find(Time.now).map(&:text).should include("Yesterday's post")
256
- end
256
+ it "should be able find yesterday, given a Date" do
257
+ find(Time.now).map(&:text).should include("Yesterday's post")
258
+ end
257
259
 
258
- it "should be able to use an alternative field" do
259
- # Test may occur on an event day.
260
- stub_time
261
- Event.yesterday(nil, :field => "start_time").size.should eql(0)
262
- end
260
+ it "should be able to use an alternative field" do
261
+ # Test may occur on an event day.
262
+ stub_time
263
+ Event.yesterday(nil, :field => "start_time").size.should eql(0)
264
+ end
263
265
 
264
- end
265
-
266
- describe "tomorrow" do
267
- it "should show the post for tomorrow" do
268
- find.map(&:text).should include("Tomorrow's post")
269
266
  end
267
+
268
+ describe "tomorrow" do
269
+ it "should show the post for tomorrow" do
270
+ find.map(&:text).should include("Tomorrow's post")
271
+ end
270
272
 
271
- it "should be able find tomorrow, given a Date" do
272
- find(Time.now).map(&:text).should include("Tomorrow's post")
273
- end
273
+ it "should be able find tomorrow, given a Date" do
274
+ find(Time.now).map(&:text).should include("Tomorrow's post")
275
+ end
274
276
 
275
- it "should be able to use an alternative field" do
276
- # Test may occur on an event day.
277
- stub_time
278
- Event.tomorrow(nil, :field => "start_time").size.should eql(0)
277
+ it "should be able to use an alternative field" do
278
+ # Test may occur on an event day.
279
+ stub_time
280
+ Event.tomorrow(nil, :field => "start_time").size.should eql(0)
281
+ end
279
282
  end
280
- end
281
283
 
282
- describe "past" do
284
+ describe "past" do
283
285
 
284
- before do
285
- stub_time
286
- end
286
+ before do
287
+ stub_time
288
+ end
287
289
 
288
- it "should show the correct number of posts in the past" do
289
- size.should eql(16)
290
- end
290
+ it "should show the correct number of posts in the past" do
291
+ size.should eql(16)
292
+ end
291
293
 
292
- it "should find for a given time" do
293
- size(Time.zone.now - 2.days).should eql(16)
294
- end
294
+ it "should find for a given time" do
295
+ size(Time.zone.now - 2.days).should eql(16)
296
+ end
295
297
 
296
- it "should find for a given date" do
297
- size(Date.today - 2).should eql(16)
298
- end
298
+ it "should find for a given date" do
299
+ size(Date.today - 2).should eql(16)
300
+ end
299
301
 
300
- it "should find for a given string" do
301
- size("next tuesday").should eql(19)
302
- end
302
+ it "should find for a given string" do
303
+ size("next tuesday").should eql(19)
304
+ end
303
305
 
304
- it "should be able to find all events before Ryan's birthday using a non-standard field" do
305
- Event.past("04-12-#{Time.zone.now.year}".to_time, :field => "start_time").size.should eql(7)
306
- end
306
+ it "should be able to find all events before Ryan's birthday using a non-standard field" do
307
+ Event.past("04-12-#{Time.zone.now.year}".to_time, :field => "start_time").size.should eql(7)
308
+ end
307
309
 
308
- end
309
-
310
- describe "future" do
311
- before do
312
- stub_time
313
310
  end
311
+
312
+ describe "future" do
313
+ before do
314
+ stub_time
315
+ end
314
316
 
315
- it "should show the correct number of posts in the future" do
316
- size.should eql(71)
317
- end
317
+ it "should show the correct number of posts in the future" do
318
+ size.should eql(71)
319
+ end
318
320
 
319
- it "should find for a given date" do
320
- size(Date.today - 2).should eql(73)
321
- end
321
+ it "should find for a given date" do
322
+ size(Date.today - 2).should eql(73)
323
+ end
322
324
 
323
- it "should find for a given string" do
324
- size("next tuesday").should eql(70)
325
- end
325
+ it "should find for a given string" do
326
+ size("next tuesday").should eql(70)
327
+ end
326
328
 
327
- it "should be able to find all events after Dad's birthday using a non-standard field" do
328
- Event.past("05-07-#{Time.zone.now.year}".to_time, :field => "start_time").size.should eql(1)
329
+ it "should be able to find all events after Dad's birthday using a non-standard field" do
330
+ Event.past("05-07-#{Time.zone.now.year}".to_time, :field => "start_time").size.should eql(1)
331
+ end
329
332
  end
330
- end
331
333
 
332
- describe "as of" do
333
- it "should be able to find posts as of 2 weeks ago" do
334
- stub_time
335
- Post.as_of_2_weeks_ago.size.should eql(7)
336
- end
334
+ describe "as of" do
335
+ it "should be able to find posts as of 2 weeks ago" do
336
+ stub_time
337
+ Post.as_of_2_weeks_ago.size.should eql(7)
338
+ end
337
339
 
338
- it "should be able to find posts as of 2 weeks before a given time" do
339
- stub_time
340
- Post.as_of_2_weeks_ago(Time.zone.now + 1.month).size.should eql(14)
341
- end
340
+ it "should be able to find posts as of 2 weeks before a given time" do
341
+ stub_time
342
+ Post.as_of_2_weeks_ago(Time.zone.now + 1.month).size.should eql(14)
343
+ end
342
344
 
343
- it "should error if given a date in the past far enough back" do
344
- lambda { Post.as_of_6_weeks_ago(Time.zone.now - 2.months) }.should raise_error(ByStar::ParseError, "End time is before start time, searching like this will return no results.")
345
- end
345
+ it "should error if given a date in the past far enough back" do
346
+ lambda { Post.as_of_6_weeks_ago(Time.zone.now - 2.months) }.should raise_error(ByStar::ParseError, "End time is before start time, searching like this will return no results.")
347
+ end
346
348
 
347
- it "should not do anything if given an invalid date" do
348
- lambda { Post.as_of_ryans_birthday }.should raise_error(ByStar::ParseError, "Chronic couldn't work out \"Ryans birthday\"; please be more precise.")
349
+ it "should not do anything if given an invalid date" do
350
+ lambda { Post.as_of_ryans_birthday }.should raise_error(ByStar::ParseError, "Chronic couldn't work out \"Ryans birthday\"; please be more precise.")
351
+ end
349
352
  end
350
- end
351
353
 
352
- describe "between" do
353
- it "should find posts between last tuesday and next tuesday" do
354
- stub_time
355
- size("last tuesday", "next tuesday").should eql(3)
356
- end
354
+ describe "between" do
355
+ it "should find posts between last tuesday and next tuesday" do
356
+ stub_time
357
+ size("last tuesday", "next tuesday").should eql(3)
358
+ end
357
359
 
358
- it "should find between two times" do
359
- stub_time
360
- size(Time.zone.now - 5.days, Time.zone.now + 5.days).should eql(3)
361
- end
360
+ it "should find between two times" do
361
+ stub_time
362
+ size(Time.zone.now - 5.days, Time.zone.now + 5.days).should eql(3)
363
+ end
362
364
 
363
- it "should find between two dates" do
364
- stub_time
365
- size(Date.today, Date.today + 5).should eql(3)
365
+ it "should find between two dates" do
366
+ stub_time
367
+ size(Date.today, Date.today + 5).should eql(3)
368
+ end
366
369
  end
367
- end
368
370
 
369
- describe "up to" do
370
- it "should be able to find posts up to 2 weeks from now" do
371
- stub_time
372
- Post.up_to_6_weeks_from_now.size.should eql(9)
373
- end
371
+ describe "up to" do
372
+ it "should be able to find posts up to 2 weeks from now" do
373
+ stub_time
374
+ Post.up_to_6_weeks_from_now.size.should eql(9)
375
+ end
374
376
 
375
- it "should be able to find posts up to 2 weeks from a given time" do
376
- stub_time
377
- Post.up_to_6_weeks_from_now(Time.zone.now - 1.month).size.should eql(14)
378
- end
377
+ it "should be able to find posts up to 2 weeks from a given time" do
378
+ stub_time
379
+ Post.up_to_6_weeks_from_now(Time.zone.now - 1.month).size.should eql(14)
380
+ end
379
381
 
380
- it "should error if given a date in the past" do
381
- lambda { Post.up_to_6_weeks_from_now(Time.zone.now + 2.months) }.should raise_error(ByStar::ParseError, "End time is before start time, searching like this will return no results.")
382
- end
382
+ it "should error if given a date in the past" do
383
+ lambda { Post.up_to_6_weeks_from_now(Time.zone.now + 2.months) }.should raise_error(ByStar::ParseError, "End time is before start time, searching like this will return no results.")
384
+ end
383
385
 
384
- it "should not do anything if given an invalid date" do
385
- lambda { Post.up_to_ryans_birthday }.should raise_error(ByStar::ParseError, "Chronic couldn't work out \"Ryans birthday\"; please be more precise.")
386
- end
386
+ it "should not do anything if given an invalid date" do
387
+ lambda { Post.up_to_ryans_birthday }.should raise_error(ByStar::ParseError, "Chronic couldn't work out \"Ryans birthday\"; please be more precise.")
388
+ end
387
389
 
388
- end
389
-
390
- # Because we override method_missing, we ensure that it still works as it should with this test.
391
- describe "method_missing" do
392
- it "should still work" do
393
- Post.find_by_text("Today's post").should_not be_nil
394
390
  end
391
+
392
+ # Because we override method_missing, we ensure that it still works as it should with this test.
393
+ describe "method_missing" do
394
+ it "should still work" do
395
+ Post.find_by_text("Today's post").should_not be_nil
396
+ end
395
397
 
396
- it "should raise a proper NoMethodError" do
397
- lambda { Post.idontexist }.should raise_error(NoMethodError, %r(^undefined method `idontexist'))
398
+ it "should raise a proper NoMethodError" do
399
+ lambda { Post.idontexist }.should raise_error(NoMethodError, %r(^undefined method `idontexist'))
400
+ end
398
401
  end
399
- end
400
402
 
401
- describe "named_scopes" do
402
- it "should be compatible" do
403
- Event.private.by_year(nil, :field => "start_time").size.should eql(1)
403
+ describe "named_scopes" do
404
+ it "should be compatible" do
405
+ Event.private.by_year(nil, :field => "start_time").size.should eql(1)
406
+ end
404
407
  end
405
- end
406
408
 
407
- describe "joins" do
408
- it "should not have ambiguous column names" do
409
- lambda { Post.by_month do
410
- { :joins => :tags }
411
- end }.should_not raise_error
409
+ describe "joins" do
410
+ it "should not have ambiguous column names" do
411
+ lambda { Post.by_month do
412
+ { :joins => :tags }
413
+ end }.should_not raise_error
414
+ end
412
415
  end
413
- end
414
416
 
415
417
 
416
- describe "nested find" do
417
-
418
- it "should be able to find posts after right now" do
419
- stub_time
420
- Post.by_current_work_week.size.should eql(2)
421
- Post.by_current_work_week do
422
- { :conditions => ["created_at > ?", Time.now] }
423
- end.size.should eql(0)
424
- end
418
+ describe "nested find" do
419
+
420
+ it "should be able to find posts after right now" do
421
+ stub_time
422
+ Post.by_current_work_week.size.should eql(2)
423
+ Post.by_current_work_week do
424
+ { :conditions => ["created_at > ?", Time.now] }
425
+ end.size.should eql(0)
426
+ end
425
427
 
426
- it "should be able to find a single post from last year with the tag 'ruby'" do
427
- Post.by_year(Time.zone.now.year - 1) do
428
- { :include => :tags, :conditions => ["tags.name = ?", 'ruby'] }
429
- end.size.should eql(1)
430
- end
428
+ it "should be able to find a single post from last year with the tag 'ruby'" do
429
+ Post.by_year(Time.zone.now.year - 1) do
430
+ { :include => :tags, :conditions => ["tags.name = ?", 'ruby'] }
431
+ end.size.should eql(1)
432
+ end
431
433
 
432
- it "should be able to find a single post from January last year with the tag 'ruby'" do
433
- Post.by_month("January", :year => Time.zone.now.year - 1) do
434
- { :include => :tags, :conditions => ["tags.name = ?", 'ruby'] }
435
- end.size.should eql(1)
436
- end
434
+ it "should be able to find a single post from January last year with the tag 'ruby'" do
435
+ Post.by_month("January", :year => Time.zone.now.year - 1) do
436
+ { :include => :tags, :conditions => ["tags.name = ?", 'ruby'] }
437
+ end.size.should eql(1)
438
+ end
437
439
 
438
- it "should be able to find a single post from the current fortnight with the tag 'may2'" do
439
- stub_time
440
- Post.by_fortnight do
441
- { :include => :tags, :conditions => ["tags.name = ?", 'may2'] }
442
- end.size.should eql(1)
443
- end
440
+ it "should be able to find a single post from the current fortnight with the tag 'may2'" do
441
+ stub_time
442
+ Post.by_fortnight do
443
+ { :include => :tags, :conditions => ["tags.name = ?", 'may2'] }
444
+ end.size.should eql(1)
445
+ end
444
446
 
445
- it "should be able to find a single post from the current week with the tag 'may2'" do
446
- stub_time
447
- Post.by_week do
448
- { :include => :tags, :conditions => ["tags.name = ?", 'may2'] }
449
- end.size.should eql(1)
450
- end
447
+ it "should be able to find a single post from the current week with the tag 'may2'" do
448
+ stub_time
449
+ Post.by_week do
450
+ { :include => :tags, :conditions => ["tags.name = ?", 'may2'] }
451
+ end.size.should eql(1)
452
+ end
451
453
 
452
- it "should be able to find a single post from the current weekend with the tag 'weekend'" do
453
- stub_time
454
- Post.by_weekend do
455
- { :include => :tags, :conditions => ["tags.name = ?", 'weekend'] }
456
- end.size.should eql(1)
457
- end
454
+ it "should be able to find a single post from the current weekend with the tag 'weekend'" do
455
+ stub_time
456
+ Post.by_weekend do
457
+ { :include => :tags, :conditions => ["tags.name = ?", 'weekend'] }
458
+ end.size.should eql(1)
459
+ end
458
460
 
459
- it "should be able to find a single post from the current day with the tag 'today'" do
460
- Post.by_day do
461
- { :include => :tags, :conditions => ["tags.name = ?", 'today'] }
462
- end.size.should eql(1)
463
- end
461
+ it "should be able to find a single post from the current day with the tag 'today'" do
462
+ Post.by_day do
463
+ { :include => :tags, :conditions => ["tags.name = ?", 'today'] }
464
+ end.size.should eql(1)
465
+ end
464
466
 
465
- it "should be able to find a single post from yesterday with the tag 'yesterday'" do
466
- Post.yesterday do
467
- { :include => :tags, :conditions => ["tags.name = ?", 'yesterday'] }
468
- end.size.should eql(1)
469
- end
467
+ it "should be able to find a single post from yesterday with the tag 'yesterday'" do
468
+ Post.yesterday do
469
+ { :include => :tags, :conditions => ["tags.name = ?", 'yesterday'] }
470
+ end.size.should eql(1)
471
+ end
470
472
 
471
473
 
472
- it "should be able to find a single post from tomorrow with the tag 'tomorrow'" do
473
- Post.tomorrow do
474
- { :include => :tags, :conditions => ["tags.name = ?", 'tomorrow'] }
475
- end.size.should eql(1)
476
- end
474
+ it "should be able to find a single post from tomorrow with the tag 'tomorrow'" do
475
+ Post.tomorrow do
476
+ { :include => :tags, :conditions => ["tags.name = ?", 'tomorrow'] }
477
+ end.size.should eql(1)
478
+ end
477
479
 
478
- it "should be able to find a single post from the past with the tag 'yesterday'" do
479
- Post.past do
480
- { :include => :tags, :conditions => ["tags.name = ?", 'yesterday'] }
481
- end.size.should eql(1)
482
- end
480
+ it "should be able to find a single post from the past with the tag 'yesterday'" do
481
+ Post.past do
482
+ { :include => :tags, :conditions => ["tags.name = ?", 'yesterday'] }
483
+ end.size.should eql(1)
484
+ end
483
485
 
484
- it "should be able to find a single post from the future with the tag 'tomorrow'" do
485
- Post.future do
486
- { :include => :tags, :conditions => ["tags.name = ?", 'tomorrow'] }
487
- end.size.should eql(1)
488
- end
486
+ it "should be able to find a single post from the future with the tag 'tomorrow'" do
487
+ Post.future do
488
+ { :include => :tags, :conditions => ["tags.name = ?", 'tomorrow'] }
489
+ end.size.should eql(1)
490
+ end
489
491
 
490
- end
492
+ end
491
493
 
492
- describe Time do
493
- it "should work out the beginning of a weekend (Friday 3pm)" do
494
- range_test do
495
- Time.now.beginning_of_weekend.strftime("%A %I:%M%p").should eql("Friday 03:00PM")
494
+ describe "Calculations" do
495
+ describe "Sum" do
496
+ describe "by year" do
497
+ it "current year" do
498
+ stub_time
499
+ Invoice.sum_by_year(:value).should eql(374000)
500
+ end
501
+ end
502
+
503
+ describe "by month" do
504
+ it "current month" do
505
+ stub_time
506
+ Invoice.sum_by_month(:value).should eql(15000)
507
+ end
508
+ end
496
509
  end
510
+
511
+ describe "Count" do
512
+ describe "by year" do
513
+ it "current year" do
514
+ Invoice.count_by_year.should eql(79)
515
+ end
516
+
517
+ it "using a field" do
518
+ Invoice.count_by_year(:number).should eql(Invoice.by_year.size-1)
519
+ end
520
+
521
+ it "different year" do
522
+ Invoice.count_by_year(:all, 2008)
523
+ end
524
+ end
525
+
526
+ describe "by month" do
527
+ it "current month" do
528
+ Invoice.count_by_month
529
+ end
530
+
531
+ it "using a field" do
532
+ Invoice.count_by_month(:number).should eql(Invoice.by_month.size-1)
533
+ end
534
+
535
+ it "different month" do
536
+ stub_time
537
+ Invoice.count_by_month(:all, 9).should eql(9)
538
+ end
539
+ end
540
+ end
541
+
497
542
  end
543
+
544
+ describe Time do
545
+ it "should work out the beginning of a weekend (Friday 3pm)" do
546
+ range_test do
547
+ Time.now.beginning_of_weekend.strftime("%A %I:%M%p").should eql("Friday 03:00PM")
548
+ end
549
+ end
498
550
 
499
- it "should work out the end of a weekend (Monday 3am)" do
500
- range_test do
501
- Time.now.end_of_weekend.strftime("%A %I:%M%p").should eql("Monday 03:00AM")
551
+ it "should work out the end of a weekend (Monday 3am)" do
552
+ range_test do
553
+ Time.now.end_of_weekend.strftime("%A %I:%M%p").should eql("Monday 03:00AM")
554
+ end
502
555
  end
503
556
  end
504
557
  end