by_star 1.0.1 → 2.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+ describe Time do
3
+ it "should work out the beginning of a weekend (Friday 3pm)" do
4
+ Time.now.beginning_of_weekend.strftime("%A %I:%M%p").should eql("Friday 03:00PM")
5
+ end
6
+
7
+ it "should work out the end of a weekend (Monday 3am)" do
8
+ Time.now.end_of_weekend.strftime("%A %I:%M%p").should eql("Monday 03:00AM")
9
+ end
10
+ end
metadata CHANGED
@@ -1,61 +1,113 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: by_star
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 1.0.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0.beta1
5
+ prerelease: 6
6
6
  platform: ruby
7
- authors:
7
+ authors:
8
8
  - Ryan Bigg
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
-
13
- date: 2011-08-29 00:00:00 Z
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
12
+ date: 2012-02-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
16
15
  name: bundler
17
- prerelease: false
18
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &70234733397300 !ruby/object:Gem::Requirement
19
17
  none: false
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
23
21
  version: 1.0.0
24
22
  type: :development
25
- version_requirements: *id001
26
- - !ruby/object:Gem::Dependency
27
- name: activerecord
28
23
  prerelease: false
29
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *70234733397300
25
+ - !ruby/object:Gem::Dependency
26
+ name: sqlite3
27
+ requirement: &70234733396920 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70234733396920
36
+ - !ruby/object:Gem::Dependency
37
+ name: pg
38
+ requirement: &70234733396460 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70234733396460
47
+ - !ruby/object:Gem::Dependency
48
+ name: mysql2
49
+ requirement: &70234733396040 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70234733396040
58
+ - !ruby/object:Gem::Dependency
59
+ name: rspec-rails
60
+ requirement: &70234733395540 !ruby/object:Gem::Requirement
30
61
  none: false
31
- requirements:
32
- - - ">="
33
- - !ruby/object:Gem::Version
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: '2.8'
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70234733395540
69
+ - !ruby/object:Gem::Dependency
70
+ name: timecop
71
+ requirement: &70234733395040 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ version: '0.3'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: *70234733395040
80
+ - !ruby/object:Gem::Dependency
81
+ name: activerecord
82
+ requirement: &70234733394580 !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
34
87
  version: 2.0.0
35
88
  type: :runtime
36
- version_requirements: *id002
37
- - !ruby/object:Gem::Dependency
38
- name: chronic
39
89
  prerelease: false
40
- requirement: &id003 !ruby/object:Gem::Requirement
90
+ version_requirements: *70234733394580
91
+ - !ruby/object:Gem::Dependency
92
+ name: chronic
93
+ requirement: &70234733394200 !ruby/object:Gem::Requirement
41
94
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- version: "0"
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
46
99
  type: :runtime
47
- version_requirements: *id003
100
+ prerelease: false
101
+ version_requirements: *70234733394200
48
102
  description: ActiveRecord extension for easier date scopes and time ranges
49
- email:
103
+ email:
50
104
  - radarlistener@gmail.com
51
105
  executables: []
52
-
53
106
  extensions: []
54
-
55
107
  extra_rdoc_files: []
56
-
57
- files:
108
+ files:
58
109
  - .gitignore
110
+ - .travis.yml
59
111
  - Gemfile
60
112
  - Gemfile.lock
61
113
  - MIT-LICENSE
@@ -63,49 +115,52 @@ files:
63
115
  - Rakefile
64
116
  - by_star.gemspec
65
117
  - cleaner.rb
66
- - init.rb
67
118
  - lib/by_star.rb
68
- - lib/by_star/calculations.rb
69
- - lib/by_star/calculations/count.rb
70
- - lib/by_star/calculations/sum.rb
71
- - lib/by_star/neighbours.rb
72
- - lib/by_star/range_calculations.rb
73
- - lib/by_star/shared.rb
119
+ - lib/by_star/by_day.rb
120
+ - lib/by_star/by_direction.rb
121
+ - lib/by_star/by_fortnight.rb
122
+ - lib/by_star/by_month.rb
123
+ - lib/by_star/by_week.rb
124
+ - lib/by_star/by_weekend.rb
125
+ - lib/by_star/by_year.rb
126
+ - lib/by_star/instance_methods.rb
74
127
  - lib/by_star/time_ext.rb
75
- - lib/by_star/vanilla.rb
76
128
  - lib/by_star/version.rb
77
- - spec/by_star_spec.rb
129
+ - spec/by_star/by_day_spec.rb
130
+ - spec/by_star/by_direction_spec.rb
131
+ - spec/by_star/by_fortnight_spec.rb
132
+ - spec/by_star/by_month_spec.rb
133
+ - spec/by_star/by_week_spec.rb
134
+ - spec/by_star/by_weekend_spec.rb
135
+ - spec/by_star/by_year_spec.rb
78
136
  - spec/database.yml
79
137
  - spec/fixtures/models.rb
80
138
  - spec/fixtures/schema.rb
81
139
  - spec/spec_helper.rb
140
+ - spec/time_ext_spec.rb
82
141
  - tmp/.gitignore
83
142
  homepage: http://rubygems.org/gems/by_star
84
143
  licenses: []
85
-
86
144
  post_install_message:
87
145
  rdoc_options: []
88
-
89
- require_paths:
146
+ require_paths:
90
147
  - lib
91
- required_ruby_version: !ruby/object:Gem::Requirement
148
+ required_ruby_version: !ruby/object:Gem::Requirement
92
149
  none: false
93
- requirements:
94
- - - ">="
95
- - !ruby/object:Gem::Version
96
- version: "0"
97
- required_rubygems_version: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ! '>='
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
155
  none: false
99
- requirements:
100
- - - ">="
101
- - !ruby/object:Gem::Version
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
102
159
  version: 1.3.6
103
160
  requirements: []
104
-
105
161
  rubyforge_project: by_star
106
- rubygems_version: 1.8.8
162
+ rubygems_version: 1.8.15
107
163
  signing_key:
108
164
  specification_version: 3
109
165
  summary: ActiveRecord extension for easier date scopes and time ranges
110
166
  test_files: []
111
-
data/init.rb DELETED
@@ -1,2 +0,0 @@
1
- require 'by_star'
2
- ActiveRecord::Base.send :include, ByStar
@@ -1,23 +0,0 @@
1
- module ByStar
2
- module Calculations
3
- include Count
4
- include Sum
5
-
6
- private
7
- def work_out_month(time, year=Time.zone.now.year)
8
- 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
@@ -1,20 +0,0 @@
1
- module ByStar
2
- module Calculations
3
- module Count
4
- def count_by_year(field=nil, year=Time.zone.now.year, options={}, &block)
5
- db_field = options.delete(:field)
6
- scoped_by(block) do
7
- count(field, { :conditions => conditions_for_range(start_of_year(year), end_of_year(year), db_field) }.reverse_merge!(options))
8
- end
9
- end
10
-
11
- def count_by_month(field=nil, month=Time.now.month, options={}, &block)
12
- db_field = options.delete(:field)
13
- year, month = work_out_month(month, options.delete(:year))
14
- scoped_by(block) do
15
- count(field, { :conditions => conditions_for_range(start_of_month(month, year), end_of_month(month, year), db_field) }.reverse_merge!(options))
16
- end
17
- end
18
- end
19
- end
20
- end
@@ -1,25 +0,0 @@
1
- module ByStar
2
- module Calculations
3
- module Sum
4
- def sum_by_year(field, year=Time.zone.now.year, options={}, &block)
5
- scoped_by(block) do
6
- sum(field, { :conditions => conditions_for_range(start_of_year(year), end_of_year(year), options.delete(:field)) }.reverse_merge!(options))
7
- end
8
- end
9
-
10
- def sum_by_month(field, month=Time.zone.now.month, options={}, &block)
11
- year, month = work_out_month(month, options.delete(:year))
12
- scoped_by(block) do
13
- sum(field, { :conditions => conditions_for_range(start_of_month(month, year), end_of_month(month, year), options.delete(:field)) }.reverse_merge!(options))
14
- end
15
- end
16
-
17
- def sum_by_day(field, day=Time.zone.now, options={}, &block)
18
- scoped_by(block) do
19
- day = parse(day)
20
- sum(field, { :conditions => conditions_for_range(day.beginning_of_day, day.end_of_day, options.delete(:field)) }.reverse_merge!(options))
21
- end
22
- end
23
- end
24
- end
25
- end
@@ -1,15 +0,0 @@
1
- module ByStar
2
- module Neighbours
3
- # Find the previous record to this.
4
- def previous(field=nil)
5
- field = field || self.class.by_star_field
6
- self.class.past(self.send(field.to_s.split(".").last)) { { :order => "#{field} DESC" }}.first
7
- end
8
-
9
- # Find the next record to this.
10
- def next(field=nil)
11
- field = field || self.class.by_star_field
12
- self.class.future(self.send(field.to_s.split(".").last)) { { :order => "#{field} ASC" }}.first
13
- end
14
- end
15
- end
@@ -1,23 +0,0 @@
1
- module ByStar
2
- module RangeCalculations
3
-
4
- private
5
-
6
- def start_of_year(year=Time.zone.now.year)
7
- Time.utc(year, 1, 1)
8
- end
9
-
10
- def end_of_year(year=Time.zone.now.year)
11
- start_of_year(year).end_of_year
12
- end
13
-
14
- def start_of_month(month, year=Timeow.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
@@ -1,18 +0,0 @@
1
- module Shared
2
- def conditions_for_range(start_time, end_time, field=nil)
3
- field = "#{table_name}.#{field}" if field
4
- field ||= by_star_field
5
- ["#{field} >= ? AND #{field} <= ?", start_time.utc, end_time.utc]
6
- end
7
-
8
- private
9
- def scoped_by(options=nil, &block)
10
- if options && scope = options.call
11
- with_scope(:find => scope) do
12
- block.call
13
- end
14
- else
15
- block.call
16
- end
17
- end
18
- end
@@ -1,276 +0,0 @@
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.delete(:year))
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.delete(: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.zone.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.zone.now.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
- # Make the start of the week predictably Sunday.
92
- start_time.strftime("%w").to_i != 0 ? start_time - (7 - start_time.strftime("%w").to_i).days : start_time
93
- start_time += weeks.weeks
94
- end_time = start_time + 1.week
95
- by_star(start_time, end_time, options, &block)
96
- end
97
-
98
-
99
- # Examples:
100
- # Post.by_weekend
101
- # Post.by_weekend(Time.now + 5.days)
102
- # Post.by_weekend(Date.today + 5)
103
- # Post.by_weekend("next tuesday")
104
- def by_weekend(time=Time.now, options = {}, &block)
105
- time = parse(time)
106
- start_time = time.beginning_of_weekend
107
- end_time = (start_time + 1.day).end_of_day
108
- by_star(start_time, end_time, options, &block)
109
- end
110
-
111
-
112
- # Examples:
113
- # Post.by_current_weekend
114
- def by_current_weekend(options = {}, &block)
115
- time = Time.zone.now
116
- # Friday, 3pm
117
- start_time = time.beginning_of_weekend
118
- # Monday, 3am
119
- end_time = time.end_of_weekend
120
- by_star(start_time, end_time, options, &block)
121
- end
122
-
123
- # Examples:
124
- # Post.by_current_work_week
125
- def by_current_work_week(options = {}, &block)
126
- time = Time.zone.now
127
- # Monday, 3am
128
- time = time + 1.week if time.wday == 6 || time.wday == 0
129
- start_time = time.beginning_of_week + 3.hours
130
- # Friday, 3pm
131
- end_time = time.beginning_of_weekend
132
- by_star(start_time, end_time, options, &block)
133
- end
134
-
135
-
136
- # Examples:
137
- # Post.by_day
138
- # Post.by_day(Time.yesterday)
139
- # Post.by_day("next tuesday")
140
- def by_day(time = Time.zone.now, options = {}, &block)
141
- time = parse(time)
142
- by_star(time.beginning_of_day, time.end_of_day, options, &block)
143
- end
144
- alias_method :today, :by_day
145
-
146
- # Examples:
147
- # Post.yesterday
148
- # # 2 days ago:
149
- # Post.yesterday(Time.yesterday)
150
- # # day before next tuesday
151
- # Post.yesterday("next tuesday")
152
- def yesterday(time = Time.zone.now, options = {}, &block)
153
- time = parse(time)
154
- by_day(time.advance(:days => -1), options, &block)
155
- end
156
-
157
- # Examples:
158
- # Post.tomorrow
159
- # # 2 days from now:
160
- # Post.tomorrow(Time.tomorrow)
161
- # # day after next tuesday
162
- # Post.tomorrow("next tuesday")
163
- def tomorrow(time = Time.zone.now, options = {}, &block)
164
- time = parse(time)
165
- by_day(time.advance(:days => 1), options, &block)
166
- end
167
-
168
- # Scopes to records older than current or given time
169
- # Post.past
170
- # Post.past()
171
- def past(time = Time.zone.now, options = {}, &block)
172
- time = parse(time)
173
- by_direction("<", time, options, &block)
174
- end
175
-
176
- # Scopes to records newer than current or given time
177
- def future(time = Time.zone.now, options = {}, &block)
178
- time = parse(time)
179
- by_direction(">", time, options, &block)
180
- end
181
-
182
- private
183
-
184
- def by_direction(condition, time, options = {}, &block)
185
- field = options.delete(:field) || by_star_field
186
- ensure_valid_options(options)
187
- result = scoped({ :conditions => ["#{field} #{condition} ?", time.utc] }.merge(options))
188
- result = result.scoped(block.call) if block_given?
189
- result
190
- end
191
-
192
- # scopes results between start_time and end_time
193
- def by_star(start_time, end_time, options = {}, &block)
194
- start_time = parse(start_time)
195
- end_time = parse(end_time)
196
-
197
-
198
- raise ParseError, "End time is before start time, searching like this will return no results." if end_time < start_time
199
- field = options.delete(:field)
200
- ensure_valid_options(options)
201
-
202
- scoping = { :conditions => conditions_for_range(start_time, end_time, field) }.merge(options)
203
- result = scoped(scoping)
204
- result = result.scoped(block.call) if block_given?
205
- result
206
- end
207
-
208
- def ensure_valid_options(options)
209
- if respond_to?(:validate_find_options)
210
- validate_find_options(options)
211
- else
212
- options.assert_valid_keys(ActiveRecord::SpawnMethods::VALID_FIND_OPTIONS)
213
- end
214
- end
215
-
216
- alias :between :by_star
217
- public :between
218
-
219
- # This will work for the next 30 years (written in 2009)
220
- def work_out_year(value)
221
- case value
222
- when 0..39
223
- 2000 + value
224
- when 40..99
225
- 1900 + value
226
- when nil
227
- Time.zone.now.year
228
- else
229
- # We may be passed something that's not a straight out integer
230
- # These things include: BigDecimals, Floats and Strings.
231
- value.to_i
232
- end
233
- end
234
-
235
- # Checks if the object is a Time, Date or TimeWithZone object.
236
- def valid_time_or_date?(value)
237
- value.is_a?(Time) || value.is_a?(Date) || value.is_a?(ActiveSupport::TimeWithZone)
238
- end
239
-
240
- def parse(object)
241
- object = case object.class.to_s
242
- when "NilClass"
243
- o = Time.zone.now
244
- when "String"
245
- o = object
246
- Chronic.parse(object, :now => Time.zone.now)
247
- when "Date"
248
- object.to_time(:utc)
249
- else
250
- object
251
- end
252
- raise ParseError, "Chronic couldn't work out #{o.inspect}; please be more precise." if object.nil?
253
- object
254
- end
255
-
256
- def method_missing(method, *args)
257
- if method.to_s =~ /^(as_of|up_to)_(.+)$/
258
- method = $1
259
- expr = $2.humanize
260
- unless time = parse(expr)
261
- raise ParseError, "Chronic couldn't work out #{expr.inspect}; please be more precise."
262
- end
263
-
264
- reference = args.first || Time.now
265
-
266
- if "as_of" == method
267
- between(time, reference)
268
- else
269
- between(reference, time)
270
- end
271
- else
272
- super
273
- end
274
- end
275
- end
276
- end