by_star 2.2.1 → 3.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.
Files changed (55) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +5 -5
  3. data/.travis.yml +61 -35
  4. data/CHANGELOG.md +44 -35
  5. data/Gemfile +18 -25
  6. data/MIT-LICENSE +20 -20
  7. data/README.md +577 -540
  8. data/Rakefile +18 -18
  9. data/UPGRADING +6 -12
  10. data/by_star.gemspec +34 -32
  11. data/cleaner.rb +24 -24
  12. data/lib/by_star.rb +17 -16
  13. data/lib/by_star/base.rb +68 -70
  14. data/lib/by_star/between.rb +156 -120
  15. data/lib/by_star/directional.rb +37 -33
  16. data/lib/by_star/kernel/date.rb +50 -19
  17. data/lib/by_star/kernel/time.rb +41 -41
  18. data/lib/by_star/normalization.rb +127 -118
  19. data/lib/by_star/orm/active_record/by_star.rb +61 -69
  20. data/lib/by_star/orm/mongoid/by_star.rb +76 -73
  21. data/lib/by_star/orm/mongoid/reorder.rb +23 -0
  22. data/lib/by_star/version.rb +3 -3
  23. data/spec/database.yml +15 -15
  24. data/spec/fixtures/active_record/models.rb +12 -10
  25. data/spec/fixtures/active_record/schema.rb +19 -19
  26. data/spec/fixtures/mongoid/models.rb +31 -29
  27. data/spec/fixtures/shared/seeds.rb +26 -26
  28. data/spec/gemfiles/Gemfile.master +6 -0
  29. data/spec/gemfiles/Gemfile.rails40 +7 -0
  30. data/spec/gemfiles/Gemfile.rails41 +7 -0
  31. data/spec/gemfiles/Gemfile.rails42 +7 -0
  32. data/spec/gemfiles/Gemfile.rails50 +10 -0
  33. data/spec/gemfiles/Gemfile.rails51 +10 -0
  34. data/spec/integration/active_record/active_record_spec.rb +38 -53
  35. data/spec/integration/mongoid/mongoid_spec.rb +37 -46
  36. data/spec/integration/shared/between_times.rb +82 -0
  37. data/spec/integration/shared/by_calendar_month.rb +55 -55
  38. data/spec/integration/shared/by_cweek.rb +54 -0
  39. data/spec/integration/shared/by_day.rb +96 -108
  40. data/spec/integration/shared/by_direction.rb +172 -153
  41. data/spec/integration/shared/by_fortnight.rb +48 -48
  42. data/spec/integration/shared/by_month.rb +50 -50
  43. data/spec/integration/shared/by_quarter.rb +49 -49
  44. data/spec/integration/shared/by_week.rb +54 -54
  45. data/spec/integration/shared/by_weekend.rb +49 -49
  46. data/spec/integration/shared/by_year.rb +48 -48
  47. data/spec/integration/shared/offset_parameter.rb +32 -31
  48. data/spec/integration/shared/order_parameter.rb +36 -0
  49. data/spec/integration/shared/relative.rb +174 -174
  50. data/spec/integration/shared/scope_parameter.rb +73 -72
  51. data/spec/spec_helper.rb +29 -29
  52. data/spec/unit/kernel_date_spec.rb +113 -60
  53. data/spec/unit/kernel_time_spec.rb +57 -57
  54. data/spec/unit/normalization_spec.rb +305 -255
  55. metadata +61 -62
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MWNiZTk1NWIxMjM1ZTY5ZDk1NWMzZjY5MWQ0ODM1NTU2MGU3YzRmZA==
5
- data.tar.gz: !binary |-
6
- ZGI4N2RhZmViNWU3NzdjNTc5M2ZjYmU2ZDZlYTA1MzU0YjZmYzE4ZQ==
2
+ SHA256:
3
+ metadata.gz: b215af1453a6bb5552109578699e5bc4e5e18aa4df583461b3eb9544dfba72e7
4
+ data.tar.gz: 43918eb7759cd1539fe52f3c9d33f087029e302dc25d28842b73485cc446ec67
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZDYyMDZmNTFmYWYzMDg3OWNjZTU1YzNmMmRmNDYyNWRmOGYxNjJjOWE1ZTk5
10
- OWExODkxZDA2ZGNjMDBlNDUwOTA0ZDZkMDMzMTE5MTMzYWYxMjkzYzE0NjFk
11
- NjBhOThhMWMwNDMzYWU1NmYwOTlkMTI4ZDExZGU2YmRiOTUyY2U=
12
- data.tar.gz: !binary |-
13
- ZTZiYzg5YWFmNzNkNmI2OTg4NTcwN2RkMDU3YjgwNDAyNTg0NzZmZTk5ZjNl
14
- ZDIyYzM0YzgwZWM0Y2NiMzQzYTA1YjQ2ODliMzQ5NTNjZDhlZjAwYjJjOTEy
15
- Y2QxYzY2NDVjMzUyZmVjYzczODNkMzMzM2E2MDM0ZDZiNzIyOGI=
6
+ metadata.gz: f15335c52f3dea9f54dfbf054d8b1e532535cc7cd1c9616bd7b5bf1d1a4274fb0df3d4c2619025ab1f6db975b46a93a74f77458e3533fa3867c0aaaa39a48b6a
7
+ data.tar.gz: eba9a69f7a83a0b8c65e4c1bee16451f6f4beeec1eb65d836e8b22841bfa70e02b4136b8f495577b91e023ed5f709221547ea9cc067d816a66c28e3f6ded0e27
data/.gitignore CHANGED
@@ -1,5 +1,5 @@
1
- tmp
2
- spec/fixtures/database.yml
3
- pkg
4
- by_star.sqlite3
5
- Gemfile.lock
1
+ tmp
2
+ spec/fixtures/database.yml
3
+ pkg
4
+ by_star.sqlite3
5
+ Gemfile.lock
@@ -1,35 +1,61 @@
1
- before_script:
2
- - "mysql -e 'create database by_star_test;'"
3
- - "psql -c 'create database by_star_test;' -U postgres"
4
-
5
- env:
6
- - DB=sqlite
7
- - DB=mysql
8
- - DB=postgres
9
- - DB=mongodb
10
- - ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master DB=sqlite
11
- - ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master DB=mysql
12
- - ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master DB=postgres
13
- - ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master DB=mongodb
14
-
15
- notifications:
16
- email:
17
- - radarlistener@gmail.com
18
-
19
- branches:
20
- only:
21
- - master
22
-
23
- rvm:
24
- - 1.9.3
25
- - 2.0.0
26
- - 2.1.0
27
- - rbx
28
- - jruby
29
-
30
- matrix:
31
- allow_failures:
32
- - rvm: rbx
33
- - rvm: jruby
34
-
35
- services: mongodb
1
+ before_install:
2
+ - gem update --system
3
+ - gem update bundler
4
+
5
+ before_script:
6
+ - "mysql -e 'create database by_star_test;'"
7
+ - "psql -c 'create database by_star_test;' -U postgres"
8
+
9
+ env:
10
+ - DB=sqlite
11
+ - DB=mysql
12
+ - DB=postgres
13
+ - DB=mongodb
14
+
15
+ gemfile:
16
+ - spec/gemfiles/Gemfile.rails40
17
+ - spec/gemfiles/Gemfile.rails41
18
+ - spec/gemfiles/Gemfile.rails42
19
+ - spec/gemfiles/Gemfile.rails50
20
+ - spec/gemfiles/Gemfile.rails51
21
+ - spec/gemfiles/Gemfile.master
22
+
23
+ notifications:
24
+ email:
25
+ - radarlistener@gmail.com
26
+
27
+ branches:
28
+ only:
29
+ - master
30
+
31
+ rvm:
32
+ - 2.0.0
33
+ - 2.1.9
34
+ - 2.2.5
35
+ - 2.3.1
36
+ - 2.4.2
37
+ - 2.5.0
38
+
39
+ matrix:
40
+ exclude:
41
+ - rvm: 2.0.0
42
+ gemfile: "spec/gemfiles/Gemfile.rails50"
43
+ - rvm: 2.0.0
44
+ gemfile: "spec/gemfiles/Gemfile.rails51"
45
+ - rvm: 2.1.9
46
+ gemfile: "spec/gemfiles/Gemfile.rails50"
47
+ - rvm: 2.1.9
48
+ gemfile: "spec/gemfiles/Gemfile.rails51"
49
+ - rvm: 2.4.2
50
+ gemfile: "spec/gemfiles/Gemfile.rails40"
51
+ - rvm: 2.5.0
52
+ gemfile: "spec/gemfiles/Gemfile.rails40"
53
+ - rvm: 2.4.2
54
+ gemfile: "spec/gemfiles/Gemfile.rails41"
55
+ - rvm: 2.5.0
56
+ gemfile: "spec/gemfiles/Gemfile.rails41"
57
+ allow_failures:
58
+ - gemfile: spec/gemfiles/Gemfile.master
59
+
60
+
61
+ services: mongodb
@@ -1,35 +1,44 @@
1
- # CHANGELOG
2
-
3
- ## v2.2.1 - 2014-04-21
4
-
5
- * Allow `previous` and `next` to take the current record in their scope - @pnomolos / @johnnyshields
6
- * Alias `Date#in_time_zone` to `#to_time_in_current_zone` if not already defined (e.g. for Rails <= 3) - @jcypret / @johnnyshields
7
- * Add `oldest` and `newest` methods
8
-
9
- ## v2.2.0 - 2014-04-01
10
-
11
- * Add `:scope` parameter support on all finders - @pnomolos / @johnnyshields
12
- * Feature: Add `past_*` and `next_*` finders - @davegudge
13
- * Bug Fix: `:field`, `:start_field`, and `:end_field` options were being ignored on finder - @johnnyshields / @gamov
14
- * Bug Fix: `by_star_field` should accept options without start/end_time args - @johnnyshields
15
- * Improve readme documentation - @johnnyshields
16
-
17
- ## v2.2.0.rc1 - 2014-01-14
18
-
19
- * Begin tracking CHANGELOG
20
- * Drop official support for Ruby <= 1.9.2
21
- * Add Ruby 2.1.0, Rubinius, and JRuby to Travis
22
- * Decouple gem from ActiveRecord, and put ActiveRecord and Mongoid specific methods in ORM modules.
23
- * Consolidate all normalization/parsing functions into new Normalization module
24
- * Remove meta-programming methods, e.g. `send("by_week_#{time_klass}")`
25
- * Support matching timespan-type objects with distinct start and end times (previously only point-in-time matching was supported)
26
- * Make Chronic gem optional; use it only if user has included it externally
27
- * `by_week` always returns a calendar week (i.e. beginning Monday or as specified by Rails setting), regardless of whether Date or Fixnum is given as a parameter.
28
- * `by_week` and `by_calendar_month` now supports optional `:start_day` option (:monday, :tuesday, etc)
29
- * Separate `by_calendar_month` into it's own class
30
- * Rename `between` method to `between_times` internally, as Mongoid already defines `between`. ActiveRecord has an alias of `between` so interface stays consistent.
31
- * Add `:offset` option to all query methods, in order to offset the time the day begins/ends (for example supposing business cycle begins at 8:00 each day until 7:59:59 the next day)
32
- * `by_weekend` can now take a fixnum (parsing logic is same as by_week)
33
- * Two-digit year now considers 70 to be 1970, and 69 to be 2069 (was previously 40 -> 1940)
34
- * Add Time kernel extensions for fortnight and calendar_month
35
- * Add Johnny Shields as a gem co-author
1
+ # CHANGELOG
2
+
3
+ ## v3.0.0
4
+
5
+ * Upgrade Travis for broader coverage of Ruby, ActiveRecord, and Mongoid versions - @johnnyshields
6
+ * Removed support for Ruby < 2.0 and Rails < 4.0. They are over 5 years old, and so it's time to upgrade. - @radar
7
+ * Removed references to deprecated Fixnum constant - @rgioia - #78
8
+ * Mongoid `newest`, `oldest`, `previous`, and `next` now use `reorder` to ignore any default scope, consistent with ActiveRecord - @johnnyshields
9
+ * Mongoid 3.x: Add support for `Criteria#reorder` method from version 4+ - @johnnyshields
10
+ * Upgrade Rspec tests to version 3.1 - @nhocki
11
+
12
+ ## v2.2.1 - 2014-04-21
13
+
14
+ * Allow `previous` and `next` to take the current record in their scope - @pnomolos / @johnnyshields
15
+ * Alias `Date#in_time_zone` to `#to_time_in_current_zone` if not already defined (e.g. for Rails <= 3) - @jcypret / @johnnyshields
16
+ * Add `oldest` and `newest` methods
17
+
18
+ ## v2.2.0 - 2014-04-01
19
+
20
+ * Add `:scope` parameter support on all finders - @pnomolos / @johnnyshields
21
+ * Feature: Add `past_*` and `next_*` finders - @davegudge
22
+ * Bug Fix: `:field`, `:start_field`, and `:end_field` options were being ignored on finder - @johnnyshields / @gamov
23
+ * Bug Fix: `by_star_field` should accept options without start/end_time args - @johnnyshields
24
+ * Improve readme documentation - @johnnyshields
25
+
26
+ ## v2.2.0.rc1 - 2014-01-14
27
+
28
+ * Begin tracking CHANGELOG
29
+ * Drop official support for Ruby <= 1.9.2
30
+ * Add Ruby 2.1.0, Rubinius, and JRuby to Travis
31
+ * Decouple gem from ActiveRecord, and put ActiveRecord and Mongoid specific methods in ORM modules.
32
+ * Consolidate all normalization/parsing functions into new Normalization module
33
+ * Remove meta-programming methods, e.g. `send("by_week_#{time_klass}")`
34
+ * Support matching timespan-type objects with distinct start and end times (previously only point-in-time matching was supported)
35
+ * Make Chronic gem optional; use it only if user has included it externally
36
+ * `by_week` always returns a calendar week (i.e. beginning Monday or as specified by Rails setting), regardless of whether Date or Fixnum is given as a parameter.
37
+ * `by_week` and `by_calendar_month` now supports optional `:start_day` option (:monday, :tuesday, etc)
38
+ * Separate `by_calendar_month` into it's own class
39
+ * Rename `between` method to `between_times` internally, as Mongoid already defines `between`. ActiveRecord has an alias of `between` so interface stays consistent.
40
+ * Add `:offset` option to all query methods, in order to offset the time the day begins/ends (for example supposing business cycle begins at 8:00 each day until 7:59:59 the next day)
41
+ * `by_weekend` can now take a fixnum (parsing logic is same as by_week)
42
+ * Two-digit year now considers 70 to be 1970, and 69 to be 2069 (was previously 40 -> 1940)
43
+ * Add Time kernel extensions for fortnight and calendar_month
44
+ * Add Johnny Shields as a gem co-author
data/Gemfile CHANGED
@@ -1,25 +1,18 @@
1
- source 'http://rubygems.org'
2
-
3
- # Specify your gem's dependencies in by_star.gemspec
4
- gemspec
5
-
6
- active_record_version = ENV['ACTIVE_RECORD_VERSION'] || 'default'
7
-
8
- active_record_opts =
9
- case active_record_version
10
- when 'master' then {github: 'rails/rails'}
11
- when 'default' then '~> 3.0'
12
- else "~> #{active_record_version}"
13
- end
14
-
15
- mongoid_version = ENV['MONGOID_VERSION'] || 'default'
16
-
17
- mongoid_opts =
18
- case mongoid_version
19
- when 'master' then {github: 'mongoid/mongoid'}
20
- when 'default' then '~> 3.0'
21
- else "~> #{mongoid_version}"
22
- end
23
-
24
- gem 'activerecord', active_record_opts
25
- gem 'mongoid', mongoid_opts
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ ar_version = ENV['ACTIVE_RECORD_VERSION']
6
+ ar_version = case ar_version
7
+ when 'master' then {github: 'rails'}
8
+ when String then "~> #{ar_version}"
9
+ end
10
+
11
+ mo_version = ENV['MONGOID_VERSION']
12
+ mo_version = case mo_version
13
+ when 'master' then {github: 'mongoid'}
14
+ when String then "~> #{mo_version}"
15
+ end
16
+
17
+ gem 'activerecord', ar_version if ar_version
18
+ gem 'mongoid', mo_version if mo_version
@@ -1,20 +1,20 @@
1
- Copyright (c) 2008 Ryan Bigg
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2008 Ryan Bigg
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,540 +1,577 @@
1
- # ByStar
2
-
3
- [![Build Status](https://travis-ci.org/radar/by_star.png)](https://travis-ci.org/radar/by_star)
4
- [![Code Climate](https://codeclimate.com/github/radar/by_star.png)](https://codeclimate.com/github/radar/by_star)
5
-
6
- ByStar (by_*) allows you easily and reliably query ActiveRecord and Mongoid objects based on time.
7
-
8
- ### Examples
9
-
10
- ```ruby
11
- Post.by_year(2013) # all posts in 2013
12
- Post.before(Date.today) # all posts for before today
13
- Post.yesterday # all posts in 2013
14
- Post.between_times(Time.zone.now - 3.hours, # all posts in last 3 hours
15
- Time.zone.now)
16
- @post.next # next post after a given post
17
- ```
18
-
19
- ## Installation
20
-
21
- Install this gem by adding this to your Gemfile:
22
-
23
- ```ruby
24
- gem 'by_star', :git => "git://github.com/radar/by_star"
25
- ```
26
-
27
- Then run `bundle install`
28
-
29
- If you are using ActiveRecord, you're done!
30
-
31
- Mongoid users, please include the Mongoid::ByStar module for each model you wish to use the functionality.
32
- This is the convention among Mongoid plugins.
33
-
34
- ```ruby
35
- class MyModel
36
- include Mongoid::Document
37
- include Mongoid::ByStar
38
- ```
39
-
40
- ## Finder Methods
41
-
42
- ### Base Scopes
43
-
44
- ByStar adds the following finder scopes (class methods) to your model to query time ranges.
45
- These accept a `Date`, `Time`, or `DateTime` object as an argument, which defaults to `Time.zone.now` if not specified:
46
-
47
- * `between_times(start_time, end_time)` Finds all records occurring between the two given times
48
- * `before(end_time)` Finds all records occurring before the given time
49
- * `after(start_time)` Finds all records occurring after the given time
50
-
51
- ### Time Range Scopes
52
-
53
- ByStar adds additional shortcut scopes based on commonly used time ranges.
54
- See sections below for detailed argument usage of each:
55
-
56
- * `by_day`
57
- * `by_week`
58
- * `by_weekend` 60-hour period from 15:00 Friday to 03:00 Monday
59
- * `by_fortnight` A two-week period, with the first fortnight of the year beginning on 1st January
60
- * `by_month`
61
- * `by_calendar_month` Month as it appears on a calendar; days form previous/following months which are part of the first/last weeks of the given month
62
- * `by_quarter` 3-month intervals of the year
63
- * `by_year`
64
-
65
- ### Relative Scopes
66
-
67
- ByStar also adds scopes which are relative to the current time.
68
- Note the `past_*` and `next_*` methods represent a time distance from current time (`Time.zone.now`),
69
- and do not strictly end/begin evenly on a calendar week/month/year (unlike `by_*` methods which do.)
70
-
71
- * `today` Finds all occurrences on today's date
72
- * `yesterday` Finds all occurrences on yesterday's date
73
- * `tomorrow` Finds all occurrences on tomorrow's date
74
- * `past_day` Prior 24-hour period from current time
75
- * `past_week` Prior 7-day period from current time
76
- * `past_fortnight` Prior 14-day period from current time
77
- * `past_month` Prior 30-day period from current time
78
- * `past_year` Prior 365-day period from current time
79
- * `next_day` Subsequent 24-hour period from current time
80
- * `next_week` Subsequent 7-day period from current time
81
- * `next_fortnight` Subsequent 14-day period from current time
82
- * `next_month` Subsequent 30-day period from current time
83
- * `next_year` Subsequent 365-day period from current time
84
-
85
- ### Superlative Finders
86
-
87
- Find the oldest or newest records. Returns an object instance (not a relation):
88
-
89
- * `newest`
90
- * `oldest`
91
-
92
- ### Instance Methods
93
-
94
- In addition, ByStar adds instance methods to return the next / previous record in the timewise sequence.
95
- Returns an object instance (not a relation):
96
-
97
- * `object.next`
98
- * `object.previous`
99
-
100
- ### Kernel Extensions
101
-
102
- ByStar extends the kernel `Date`, `Time`, and `DateTime` objects with the following instance methods,
103
- which mirror the ActiveSupport methods `beginning_of_day`, `end_of_week`, etc:
104
-
105
- * `beginning_of_weekend`
106
- * `end_of_weekend`
107
- * `beginning_of_fortnight`
108
- * `end_of_fortnight`
109
- * `beginning_of_calendar_month`
110
- * `end_of_calendar_month`
111
-
112
- Lastly, ByStar aliases Rails 3 `Date#to_time_in_current_zone` to the Rails 4 syntax `#in_time_zone`, if it has not already been defined.
113
-
114
- ## Usage
115
-
116
- ### Setting the Query Field
117
-
118
- By default, ByStar assumes you will use the `created_at` field to query objects by time.
119
- You may specify an alternate field on all query methods as follows:
120
-
121
- ```ruby
122
- Post.by_month("January", field: :updated_at)
123
- ```
124
-
125
- Alternatively, you may set a default in your model using the `by_star_field` macro:
126
-
127
- ```ruby
128
- class Post < ActiveRecord::Base
129
- by_star_field :updated_at
130
- end
131
- ```
132
-
133
- ### Scoping the Find
134
-
135
- All ByStar methods (except `oldest`, `newest`, `previous`, `next`) return `ActiveRecord::Relation` and/or
136
- `Mongoid::Criteria` objects, which can be daisy-chained with other scopes/finder methods:
137
-
138
- ```ruby
139
- Post.by_month.your_scope
140
- Post.by_month(1).include(:tags).where("tags.name" => "ruby")
141
- ```
142
-
143
- Want to count records? Simple:
144
-
145
- ```ruby
146
- Post.by_month.count
147
- ```
148
-
149
- ### :scope Option
150
-
151
- You may pass a `:scope` option as a Relation or Proc to all ByStar methods like so:
152
-
153
- ```ruby
154
- @post.next(scope: Post.where(category: @post.category))
155
- @post.next(scope: ->{ where(category: 'blog') })
156
- ```
157
-
158
- This is particularly useful for `oldest`, `newest`, `previous`, `next` which return a model instance rather than
159
- a Relation and hence cannot be daisy-chained with other scopes.
160
-
161
- `previous` and `next` support a special feature that the `:scope` option may take the subject record as an argument:
162
-
163
- ```ruby
164
- @post.next(scope: ->(record){ where(category: record.category) })
165
- ```
166
-
167
- You may also set a default scope in the `by_star_field` macro. (It is recommended this be a Proc):
168
-
169
- ```ruby
170
- class Post < ActiveRecord::Base
171
- by_star_field scope: ->{ where(category: 'blog') }
172
- end
173
- ```
174
-
175
- ### :offset Option
176
-
177
- All ByStar finders support an `:offset` option which offsets the time period for which the query is performed.
178
- This is useful in cases where the daily cycle occurs at a time other than midnight.
179
-
180
- Post.by_day('2014-03-05', offset: 9.hours)
181
-
182
- You may also set a offset scope in the `by_star_field` macro:
183
-
184
- ```ruby
185
- class Post < ActiveRecord::Base
186
- by_star_field offset: offset: 9.hours
187
- end
188
- ```
189
-
190
- ### Time-Range Type Objects
191
-
192
- If your object has both a start and end time, you may pass both params to `by_star_field`:
193
-
194
- ```ruby
195
- by_star_field :start_time, :end_time
196
- ```
197
-
198
- By default, ByStar queries will return all objects whose range has any overlap within the desired period (permissive):
199
-
200
- ```ruby
201
- MultiDayEvent.by_month("January") #=> returns MultiDayEvents that overlap in January,
202
- even if they start in December and/or end in February
203
- ```
204
-
205
- If you'd like to confine results to starting and ending within the given range, use the `:strict` option:
206
-
207
- ```ruby
208
- MultiDayEvent.by_month("January", strict => true) #=> returns MultiDayEvents that both start AND end in January
209
- ```
210
-
211
- ### Chronic Support
212
-
213
- If [Chronic](https://github.com/mojombo/chronic) gem is present, it will be used to parse natural-language date/time
214
- strings in all ByStar finder methods. Otherwise, the Ruby `Time.parse` kernel method will be used as a fallback.
215
-
216
- As of ByStar 2.2.0, you must explicitly include `gem chronic` into your Gemfile in order to use Chronic.
217
-
218
-
219
- ## Advanced Usage
220
-
221
- ### between_times
222
-
223
- To find records between two times:
224
-
225
- ```ruby
226
- Post.between_times(time1, time2)
227
- ```
228
-
229
- Also works with dates:
230
-
231
- ```ruby
232
- Post.between_times(date1, date2)
233
- ```
234
-
235
- ActiveRecord only: `between` is an alias for `between_times`:
236
-
237
- ```ruby
238
- Post.between(time1, time2) #=> results identical to between_times above
239
- ```
240
-
241
- ### before and after
242
-
243
- To find all posts before / after the current time:
244
-
245
- ```ruby
246
- Post.before
247
- Post.after
248
- ```
249
-
250
- To find all posts before certain time or date:
251
-
252
- ```ruby
253
- Post.before(Date.today + 2)
254
- Post.after(Time.now + 5.days)
255
- ```
256
-
257
- You can also pass a string:
258
-
259
- ```ruby
260
- Post.before("next tuesday")
261
- ```
262
-
263
- For Time-Range type objects, only the start time is considered for `before` and `after`.
264
-
265
- ### previous and next
266
-
267
- To find the prior/subsequent record to a model instance, `previous`/`next` on it:
268
-
269
- ```ruby
270
- Post.last.previous
271
- Post.first.next
272
- ```
273
-
274
- You can specify a field also:
275
-
276
- ```ruby
277
- Post.last.previous(field: "published_at")
278
- Post.first.next(field: "published_at")
279
- ```
280
-
281
- For Time-Range type objects, only the start time is considered for `previous` and `next`.
282
-
283
- ### by_year
284
-
285
- To find records from the current year, simply call the method without any arguments:
286
-
287
- ```ruby
288
- Post.by_year
289
- ```
290
-
291
- To find records based on a year you can pass it a two or four digit number:
292
-
293
- ```ruby
294
- Post.by_year(09)
295
- ```
296
-
297
- This will return all posts in 2009, whereas:
298
-
299
- ```ruby
300
- Post.by_year(99)
301
- ```
302
-
303
- will return all the posts in the year 1999.
304
-
305
- You can also specify the full year:
306
-
307
- ```ruby
308
- Post.by_year(2009)
309
- Post.by_year(1999)
310
- ```
311
-
312
- ### by_month
313
-
314
- If you know the number of the month you want:
315
-
316
- ```ruby
317
- Post.by_month(1)
318
- ```
319
-
320
- This will return all posts in the first month (January) of the current year.
321
-
322
- If you like being verbose:
323
-
324
- ```ruby
325
- Post.by_month("January")
326
- ```
327
-
328
- This will return all posts created in January of the current year.
329
-
330
- If you want to find all posts in January of last year just do
331
-
332
- ```ruby
333
- Post.by_month(1, :year => 2007)
334
- ```
335
-
336
- or
337
-
338
- ```ruby
339
- Post.by_month("January", :year => 2007)
340
-
341
- This will perform a find using the column you've specified.
342
-
343
- If you have a Time object you can use it to find the posts:
344
-
345
- ```ruby
346
- Post.by_month(Time.local(2012, 11, 24))
347
- ```
348
-
349
- This will find all the posts in November 2012.
350
-
351
- ### by_calendar_month
352
-
353
- Finds records for a given month as shown on a calendar. Includes all the results of `by_month`, plus any results which fall in the same week as the first and last of the month. Useful for working with UI calendars which show rows of weeks.
354
-
355
- ```ruby
356
- Post.by_calendar_month
357
- ```
358
-
359
- Parameter behavior is otherwise the same as `by_month`. Also, `:start_day` option is supported to specify the start day of the week (`:monday`, `:tuesday`, etc.)
360
-
361
- ### by_fortnight
362
-
363
- Fortnight numbering starts at 0. The beginning of a fortnight is Monday, 12am.
364
-
365
- To find records from the current fortnight:
366
-
367
- ```ruby
368
- Post.by_fortnight
369
- ```
370
-
371
- To find records based on a fortnight, you can pass in a number (representing the fortnight number) or a time object:
372
-
373
- ```ruby
374
- Post.by_fortnight(18)
375
- ```
376
-
377
- This will return all posts in the 18th fortnight of the current year.
378
-
379
- ```ruby
380
- Post.by_fortnight(18, :year => 2012)
381
- ```
382
-
383
- This will return all posts in the 18th fortnight week of 2012.
384
-
385
- ```ruby
386
- Post.by_fortnight(Time.local(2012,1,1))
387
- ```
388
-
389
- This will return all posts from the first fortnight of 2012.
390
-
391
- ### by_week
392
-
393
- Week numbering starts at 0. The beginning of a week is Monday, 12am.
394
-
395
- To find records from the current week:
396
-
397
- ```ruby
398
- Post.by_week
399
- ```
400
-
401
- To find records based on a week, you can pass in a number (representing the week number) or a time object:
402
-
403
- ```ruby
404
- Post.by_week(36)
405
- ```
406
-
407
- This will return all posts in the 37th week of the current year (remember week numbering starts at 0).
408
-
409
- ```ruby
410
- Post.by_week(36, :year => 2012)
411
- ```
412
-
413
- This will return all posts in the 37th week of 2012.
414
-
415
- ```ruby
416
- Post.by_week(Time.local(2012,1,1))
417
- ```
418
-
419
- This will return all posts from the first week of 2012.
420
-
421
- You may pass in a `:start_day` option (`:monday`, `:tuesday`, etc.) to specify the starting day of the week. This may also be configured in Rails.
422
-
423
- ### by_weekend
424
-
425
- If the time passed in (or the time now is a weekend) it will return posts from 12am Saturday to 11:59:59PM Sunday. If the time is a week day, it will show all posts for the coming weekend.
426
-
427
- ```ruby
428
- Post.by_weekend(Time.now)
429
- ```
430
-
431
- ### by_day and today
432
-
433
- To find records for today:
434
-
435
- ```ruby
436
- Post.by_day
437
- Post.today
438
- ```
439
-
440
- To find records for a certain day:
441
-
442
- ```ruby
443
- Post.by_day(Time.local(2012, 1, 1))
444
- ```
445
-
446
- You can also pass a string:
447
-
448
- ```ruby
449
- Post.by_day("next tuesday")
450
- ```
451
-
452
- This will return all posts for the given day.
453
-
454
- ### by_quarter
455
-
456
- Finds records by 3-month quarterly period of year. Quarter numbering starts at 1. The four quarters of the year begin on Jan 1, Apr 1, Jul 1, and Oct 1 respectively.
457
-
458
- To find records from the current quarter:
459
-
460
- ```ruby
461
- Post.by_quarter
462
- ```
463
-
464
- To find records based on a quarter, you can pass in a number (representing the quarter number) or a time object:
465
-
466
- ```ruby
467
- Post.by_quarter(4)
468
- ```
469
-
470
- This will return all posts in the 4th quarter of the current year.
471
-
472
- ```ruby
473
- Post.by_quarter(2, :year => 2012)
474
- ```
475
-
476
- This will return all posts in the 2nd quarter of 2012.
477
-
478
- ```ruby
479
- Post.by_week(Time.local(2012,1,1))
480
- ```
481
-
482
- This will return all posts from the first quarter of 2012.
483
-
484
-
485
- ## Version Support
486
-
487
- ByStar is tested against the following versions:
488
-
489
- * Ruby 1.9.3+
490
- * Rails/ActiveRecord 3.0+
491
- * Mongoid 3.0+
492
-
493
-
494
- ## Testing
495
-
496
- ### Test Setup
497
-
498
- Specify a database by supplying a `DB` environmental variable:
499
-
500
- `bundle exec rake spec DB=sqlite`
501
-
502
- You can also take an ORM-specific test task for a ride:
503
-
504
- `bundle exec rake spec:active_record`
505
-
506
- Have an Active Record or Mongoid version in mind? Set the environment variables
507
- `ACTIVE_RECORD_VERSION` and `MONGOID_VERSION` to a version of your choice. A
508
- version number provided will translate to `~> VERSION`, and the string `master`
509
- will grab the latest from Github.
510
-
511
- ```bash
512
- # Update your bundle appropriately...
513
- ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle update
514
-
515
- # ...then run the specs
516
- ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle exec rpsec spec
517
- ```
518
-
519
- ### Test Implementation
520
-
521
- ByStar tests use TimeCop to lock the system `Time.now` at Jan 01, 2014, and seed
522
- objects with fixed dates according to `spec/fixtures/shared/seeds.rb`.
523
- Note that the timezone is randomized on each run to shake-out timezone related quirks.
524
-
525
-
526
- ## Collaborators
527
-
528
- ByStar is actively maintained by Ryan Biggs (radar) and Johnny Shields (johnnyshields)
529
-
530
- Thank you to the following people:
531
-
532
- * Thomas Sinclair for the original bump for implementing ByStar
533
- * [Ruby on Rails](http://rubyonrails.org/) for their support
534
- * Mislav Marohnic
535
- * August Lilleas (leethal)
536
- * gte351s
537
- * Sam Elliott (lenary)
538
- * The creators of the [Chronic](https://github.com/mojombo/chronic) gem
539
- * Erik Fonselius
540
- * Johnny Shields (johnnyshields)
1
+ # ByStar
2
+
3
+ [![Build Status](https://travis-ci.org/radar/by_star.svg)](https://travis-ci.org/radar/by_star)
4
+ [![Code Climate](https://codeclimate.com/github/radar/by_star.svg)](https://codeclimate.com/github/radar/by_star)
5
+
6
+ ByStar (by_*) allows you easily and reliably query ActiveRecord and Mongoid objects based on time.
7
+
8
+ ### Examples
9
+
10
+ ```ruby
11
+ Post.by_year(2013) # all posts in 2013
12
+ Post.before(Date.today) # all posts for before today
13
+ Post.yesterday # all posts for yesterday
14
+ Post.between_times(Time.zone.now - 3.hours, # all posts in last 3 hours
15
+ Time.zone.now)
16
+ @post.next # next post after a given post
17
+ ```
18
+
19
+ ## Installation
20
+
21
+ Install this gem by adding this to your Gemfile:
22
+
23
+ ```ruby
24
+ gem 'by_star', git: "git://github.com/radar/by_star"
25
+ ```
26
+
27
+ Then run `bundle install`
28
+
29
+ If you are using ActiveRecord, you're done!
30
+
31
+ Mongoid users, please include the Mongoid::ByStar module for each model you wish to use the functionality.
32
+ This is the convention among Mongoid plugins.
33
+
34
+ ```ruby
35
+ class MyModel
36
+ include Mongoid::Document
37
+ include Mongoid::ByStar
38
+ ```
39
+
40
+ ## Finder Methods
41
+
42
+ ### Base Scopes
43
+
44
+ ByStar adds the following finder scopes (class methods) to your model to query time ranges.
45
+ These accept a `Date`, `Time`, or `DateTime` object as an argument, which defaults to `Time.zone.now` if not specified:
46
+
47
+ * `between_times(start_time, end_time)` - Finds all records occurring between the two given times.
48
+ * `before(end_time)` - Finds all records occurring before the given time
49
+ * `after(start_time)` - Finds all records occurring after the given time
50
+
51
+ `between_times` supports alternate argument forms:
52
+ * `between_times(Range)`
53
+ * `between_times(Array)`
54
+ * `between_times(start_time, nil)` - same as `after(start_time)`
55
+ * `between_times(nil, end_time)` - same as `before(end_time)`
56
+
57
+ ### Time Range Scopes
58
+
59
+ ByStar adds additional shortcut scopes based on commonly used time ranges.
60
+ See sections below for detailed argument usage of each:
61
+
62
+ * `by_day`
63
+ * `by_week` Allows zero-based week value from 0 to 52
64
+ * `by_cweek` Allows one-based week value from 1 to 53
65
+ * `by_weekend` Saturday and Sunday only of the given week
66
+ * `by_fortnight` A two-week period, with the first fortnight of the year beginning on 1st January
67
+ * `by_month`
68
+ * `by_calendar_month` Month as it appears on a calendar; days form previous/following months which are part of the first/last weeks of the given month
69
+ * `by_quarter` 3-month intervals of the year
70
+ * `by_year`
71
+
72
+ ### Relative Scopes
73
+
74
+ ByStar also adds scopes which are relative to the current time.
75
+ Note the `past_*` and `next_*` methods represent a time distance from current time (`Time.zone.now`),
76
+ and do not strictly end/begin evenly on a calendar week/month/year (unlike `by_*` methods which do.)
77
+
78
+ * `today` Finds all occurrences on today's date
79
+ * `yesterday` Finds all occurrences on yesterday's date
80
+ * `tomorrow` Finds all occurrences on tomorrow's date
81
+ * `past_day` Prior 24-hour period from current time
82
+ * `past_week` Prior 7-day period from current time
83
+ * `past_fortnight` Prior 14-day period from current time
84
+ * `past_month` Prior 30-day period from current time
85
+ * `past_year` Prior 365-day period from current time
86
+ * `next_day` Subsequent 24-hour period from current time
87
+ * `next_week` Subsequent 7-day period from current time
88
+ * `next_fortnight` Subsequent 14-day period from current time
89
+ * `next_month` Subsequent 30-day period from current time
90
+ * `next_year` Subsequent 365-day period from current time
91
+
92
+ ### Superlative Finders
93
+
94
+ Find the oldest or newest records. Returns an object instance (not a relation):
95
+
96
+ * `newest`
97
+ * `oldest`
98
+
99
+ ### Instance Methods
100
+
101
+ In addition, ByStar adds instance methods to return the next / previous record in the timewise sequence.
102
+ Returns an object instance (not a relation):
103
+
104
+ * `object.next`
105
+ * `object.previous`
106
+
107
+ ### Kernel Extensions
108
+
109
+ ByStar extends the kernel `Date`, `Time`, and `DateTime` objects with the following instance methods,
110
+ which mirror the ActiveSupport methods `beginning_of_day`, `end_of_week`, etc:
111
+
112
+ * `beginning_of_weekend`
113
+ * `end_of_weekend`
114
+ * `beginning_of_fortnight`
115
+ * `end_of_fortnight`
116
+ * `beginning_of_calendar_month`
117
+ * `end_of_calendar_month`
118
+
119
+ Lastly, ByStar aliases Rails 3 `Date#to_time_in_current_zone` to the Rails 4 syntax `#in_time_zone`, if it has not already been defined.
120
+
121
+ ## Usage
122
+
123
+ ### Setting the Query Field
124
+
125
+ By default, ByStar assumes you will use the `created_at` field to query objects by time.
126
+ You may specify an alternate field on all query methods as follows:
127
+
128
+ ```ruby
129
+ Post.by_month("January", field: :updated_at)
130
+ ```
131
+
132
+ Alternatively, you may set a default in your model using the `by_star_field` macro:
133
+
134
+ ```ruby
135
+ class Post < ActiveRecord::Base
136
+ by_star_field :updated_at
137
+ end
138
+ ```
139
+
140
+ ### Scoping the Query
141
+
142
+ All ByStar methods (except `oldest`, `newest`, `previous`, `next`) return `ActiveRecord::Relation` and/or
143
+ `Mongoid::Criteria` objects, which can be daisy-chained with other scopes/finder methods:
144
+
145
+ ```ruby
146
+ Post.by_month.your_scope
147
+ Post.by_month(1).include(:tags).where("tags.name" => "ruby")
148
+ ```
149
+
150
+ Want to count records? Simple:
151
+
152
+ ```ruby
153
+ Post.by_month.count
154
+ ```
155
+
156
+ ### :scope Option
157
+
158
+ You may pass a `:scope` option as a Relation or Proc to all ByStar methods like so:
159
+
160
+ ```ruby
161
+ @post.next(scope: Post.where(category: @post.category))
162
+ @post.next(scope: ->{ where(category: 'blog') })
163
+ ```
164
+
165
+ This is particularly useful for `oldest`, `newest`, `previous`, `next` which return a model instance rather than
166
+ a Relation and hence cannot be daisy-chained with other scopes.
167
+
168
+ `previous` and `next` support a special feature that the `:scope` option may take the subject record as an argument:
169
+
170
+ ```ruby
171
+ @post.next(scope: ->(record){ where(category: record.category) })
172
+ ```
173
+
174
+ You may also set a default scope in the `by_star_field` macro. (It is recommended this be a Proc):
175
+
176
+ ```ruby
177
+ class Post < ActiveRecord::Base
178
+ by_star_field scope: ->{ where(category: 'blog') }
179
+ end
180
+ ```
181
+
182
+ ### `:offset` Option
183
+
184
+ All ByStar finders support an `:offset` option which is applied to time period of the query condition.
185
+ This is useful in cases where the daily cycle occurs at a time other than midnight.
186
+
187
+ For example, if you'd like to find all Posts from 9:00 on 2014-03-05 until 8:59:59.999 on 2014-03-06, you can do:
188
+
189
+ Post.by_day('2014-03-05', offset: 9.hours)
190
+
191
+ You may also set a offset scope in the `by_star_field` macro:
192
+
193
+ ```ruby
194
+ class Post < ActiveRecord::Base
195
+ by_star_field offset: 9.hours
196
+ end
197
+ ```
198
+
199
+ ### Timespan Objects
200
+
201
+ If your object has both a start and end time, you may pass both params to `by_star_field`:
202
+
203
+ ```ruby
204
+ by_star_field :start_time, :end_time
205
+ ```
206
+
207
+ By default, ByStar queries will return all objects whose range has any overlap within the desired period (permissive):
208
+
209
+ ```ruby
210
+ MultiDayEvent.by_month("January") #=> returns MultiDayEvents that overlap in January,
211
+ even if they start in December and/or end in February
212
+ ```
213
+
214
+ ### Timespan Objects: `:strict` Option
215
+
216
+ If you'd like to confine results to only those both starting and ending within the given range, use the `:strict` option:
217
+
218
+ ```ruby
219
+ MultiDayEvent.by_month("January", :strict => true) #=> returns MultiDayEvents that both start AND end in January
220
+ ```
221
+
222
+ ### Timespan Objects: Database Indexing and `:index_start` Option
223
+
224
+ In order to ensure query performance on large dataset, you must add an index to the query field (e.g. "created_at") be indexed. ByStar does **not** define indexes automatically.
225
+
226
+ Database indexes require querying a range query on a single field, i.e. `start_time >= X and start_time <= Y`.
227
+ If we use a single-sided query, the database will iterate through all items either from the beginning or until the end of time.
228
+ This poses a challenge for timespan-type objects which have two fields, i.e. `start_time` and `end_time`.
229
+ There are two cases to consider:
230
+
231
+ 1) Timespan with `:strict` option, e.g. "start_time >= X and end_time <= Y".
232
+
233
+ Given that this gem requires start_time >= end_time, we add the converse constraint "start_time <= Y and end_time >= X" to ensure both fields are double-sided, i.e. an index can be used on either field.
234
+
235
+ 2) Timespan without `:strict` option, e.g. "start_time < Y and end_time > X".
236
+
237
+ This is not yet supported but will be soon.
238
+
239
+
240
+ ### Chronic Support
241
+
242
+ If [Chronic](https://github.com/mojombo/chronic) gem is present, it will be used to parse natural-language date/time
243
+ strings in all ByStar finder methods. Otherwise, the Ruby `Time.parse` kernel method will be used as a fallback.
244
+
245
+ As of ByStar 2.2.0, you must explicitly include `gem 'chronic'` into your Gemfile in order to use Chronic.
246
+
247
+
248
+ ## Advanced Usage
249
+
250
+ ### between_times
251
+
252
+ To find records between two times:
253
+
254
+ ```ruby
255
+ Post.between_times(time1, time2)
256
+ ```
257
+
258
+ You use a Range like so:
259
+
260
+ ```ruby
261
+ Post.between_times(time1..time2)
262
+ ```
263
+
264
+ Also works with dates - WARNING: there are currently some caveats see [Issue #49](https://github.com/radar/by_star/issues/49):
265
+
266
+ ```ruby
267
+ Post.between_times(date1, date2)
268
+ ```
269
+
270
+ ### before and after
271
+
272
+ To find all posts before / after the current time:
273
+
274
+ ```ruby
275
+ Post.before
276
+ Post.after
277
+ ```
278
+
279
+ To find all posts before certain time or date:
280
+
281
+ ```ruby
282
+ Post.before(Date.today + 2)
283
+ Post.after(Time.now + 5.days)
284
+ ```
285
+
286
+ You can also pass a string:
287
+
288
+ ```ruby
289
+ Post.before("next tuesday")
290
+ ```
291
+
292
+ For Time-Range type objects, only the start time is considered for `before` and `after`.
293
+
294
+ ### previous and next
295
+
296
+ To find the prior/subsequent record to a model instance, `previous`/`next` on it:
297
+
298
+ ```ruby
299
+ Post.last.previous
300
+ Post.first.next
301
+ ```
302
+
303
+ You can specify a field also:
304
+
305
+ ```ruby
306
+ Post.last.previous(field: "published_at")
307
+ Post.first.next(field: "published_at")
308
+ ```
309
+
310
+ For Time-Range type objects, only the start time is considered for `previous` and `next`.
311
+
312
+ ### by_year
313
+
314
+ To find records from the current year, simply call the method without any arguments:
315
+
316
+ ```ruby
317
+ Post.by_year
318
+ ```
319
+
320
+ To find records based on a year you can pass it a two or four digit number:
321
+
322
+ ```ruby
323
+ Post.by_year(09)
324
+ ```
325
+
326
+ This will return all posts in 2009, whereas:
327
+
328
+ ```ruby
329
+ Post.by_year(99)
330
+ ```
331
+
332
+ will return all the posts in the year 1999.
333
+
334
+ You can also specify the full year:
335
+
336
+ ```ruby
337
+ Post.by_year(2009)
338
+ Post.by_year(1999)
339
+ ```
340
+
341
+ ### by_month
342
+
343
+ If you know the number of the month you want:
344
+
345
+ ```ruby
346
+ Post.by_month(1)
347
+ ```
348
+
349
+ This will return all posts in the first month (January) of the current year.
350
+
351
+ If you like being verbose:
352
+
353
+ ```ruby
354
+ Post.by_month("January")
355
+ ```
356
+
357
+ This will return all posts created in January of the current year.
358
+
359
+ If you want to find all posts in January of last year just do
360
+
361
+ ```ruby
362
+ Post.by_month(1, year: 2007)
363
+ ```
364
+
365
+ or
366
+
367
+ ```ruby
368
+ Post.by_month("January", year: 2007)
369
+ ```
370
+
371
+ This will perform a find using the column you've specified.
372
+
373
+ If you have a Time object you can use it to find the posts:
374
+
375
+ ```ruby
376
+ Post.by_month(Time.local(2012, 11, 24))
377
+ ```
378
+
379
+ This will find all the posts in November 2012.
380
+
381
+ ### by_calendar_month
382
+
383
+ Finds records for a given month as shown on a calendar. Includes all the results of `by_month`, plus any results which fall in the same week as the first and last of the month. Useful for working with UI calendars which show rows of weeks.
384
+
385
+ ```ruby
386
+ Post.by_calendar_month
387
+ ```
388
+
389
+ Parameter behavior is otherwise the same as `by_month`. Also, `:start_day` option is supported to specify the start day of the week (`:monday`, `:tuesday`, etc.)
390
+
391
+ ### by_fortnight
392
+
393
+ Fortnight numbering starts at 0. The beginning of a fortnight is Monday, 12am.
394
+
395
+ To find records from the current fortnight:
396
+
397
+ ```ruby
398
+ Post.by_fortnight
399
+ ```
400
+
401
+ To find records based on a fortnight, you can pass in a number (representing the fortnight number) or a time object:
402
+
403
+ ```ruby
404
+ Post.by_fortnight(18)
405
+ ```
406
+
407
+ This will return all posts in the 18th fortnight of the current year.
408
+
409
+ ```ruby
410
+ Post.by_fortnight(18, year: 2012)
411
+ ```
412
+
413
+ This will return all posts in the 18th fortnight week of 2012.
414
+
415
+ ```ruby
416
+ Post.by_fortnight(Time.local(2012,1,1))
417
+ ```
418
+
419
+ This will return all posts from the first fortnight of 2012.
420
+
421
+ ### by_week and by_cweek
422
+
423
+ Week numbering starts at 0, and cweek numbering starts at 1 (same as `Date#cweek`). The beginning of a week is as defined in `ActiveSupport#beginning_of_week`, which can be configured.
424
+
425
+ To find records from the current week:
426
+
427
+ ```ruby
428
+ Post.by_week
429
+ Post.by_cweek # same result
430
+ ```
431
+
432
+ This will return all posts in the 37th week of the current year (remember week numbering starts at 0):
433
+
434
+ ```ruby
435
+ Post.by_week(36)
436
+ Post.by_cweek(37) # same result
437
+ ```
438
+
439
+ This will return all posts in the 37th week of 2012:
440
+
441
+ ```ruby
442
+ Post.by_week(36, year: 2012)
443
+ Post.by_cweek(37, year: 2012) # same result
444
+ ```
445
+
446
+ This will return all posts in the week which contains Jan 1, 2012:
447
+
448
+ ```ruby
449
+ Post.by_week(Time.local(2012,1,1))
450
+ Post.by_cweek(Time.local(2012,1,1)) # same result
451
+ ```
452
+
453
+ You may pass in a `:start_day` option (`:monday`, `:tuesday`, etc.) to specify the starting day of the week. This may also be configured in Rails.
454
+
455
+ ### by_weekend
456
+
457
+ If the time passed in (or the time now is a weekend) it will return posts from 0:00 Saturday to 23:59:59 Sunday. If the time is a week day, it will show all posts for the coming weekend.
458
+
459
+ ```ruby
460
+ Post.by_weekend(Time.now)
461
+ ```
462
+
463
+ ### by_day and today
464
+
465
+ To find records for today:
466
+
467
+ ```ruby
468
+ Post.by_day
469
+ Post.today
470
+ ```
471
+
472
+ To find records for a certain day:
473
+
474
+ ```ruby
475
+ Post.by_day(Time.local(2012, 1, 1))
476
+ ```
477
+
478
+ You can also pass a string:
479
+
480
+ ```ruby
481
+ Post.by_day("next tuesday")
482
+ ```
483
+
484
+ This will return all posts for the given day.
485
+
486
+ ### by_quarter
487
+
488
+ Finds records by 3-month quarterly period of year. Quarter numbering starts at 1. The four quarters of the year begin on Jan 1, Apr 1, Jul 1, and Oct 1 respectively.
489
+
490
+ To find records from the current quarter:
491
+
492
+ ```ruby
493
+ Post.by_quarter
494
+ ```
495
+
496
+ To find records based on a quarter, you can pass in a number (representing the quarter number) or a time object:
497
+
498
+ ```ruby
499
+ Post.by_quarter(4)
500
+ ```
501
+
502
+ This will return all posts in the 4th quarter of the current year.
503
+
504
+ ```ruby
505
+ Post.by_quarter(2, year: 2012)
506
+ ```
507
+
508
+ This will return all posts in the 2nd quarter of 2012.
509
+
510
+ ```ruby
511
+ Post.by_week(Time.local(2012,1,1))
512
+ ```
513
+
514
+ This will return all posts from the first quarter of 2012.
515
+
516
+
517
+ ## Version Support
518
+
519
+ ByStar is tested against the following versions:
520
+
521
+ * Ruby 1.9.3+
522
+ * Rails/ActiveRecord 3.0+
523
+ * Mongoid 3.0+
524
+
525
+ Note that ByStar automatically adds the following version compatibility shims:
526
+
527
+ * ActiveSupport 3.x: `Date#to_time_in_current_zone` is aliased to `Date#in_time_zone` from version 4+
528
+ * Mongoid 3.x: Adds support for `Criteria#reorder` method from version 4+
529
+
530
+
531
+ ## Testing
532
+
533
+ ### Test Setup
534
+
535
+ Specify a database by supplying a `DB` environmental variable:
536
+
537
+ `bundle exec rake spec DB=sqlite`
538
+
539
+ You can also take an ORM-specific test task for a ride:
540
+
541
+ `bundle exec rake spec:active_record`
542
+
543
+ Have an Active Record or Mongoid version in mind? Set the environment variables
544
+ `ACTIVE_RECORD_VERSION` and `MONGOID_VERSION` to a version of your choice. A
545
+ version number provided will translate to `~> VERSION`, and the string `master`
546
+ will grab the latest from Github.
547
+
548
+ ```bash
549
+ # Update your bundle appropriately...
550
+ ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle update
551
+
552
+ # ...then run the specs
553
+ ACTIVE_RECORD_VERSION=4.0.0 MONGOID_VERSION=master bundle exec rpsec spec
554
+ ```
555
+
556
+ ### Test Implementation
557
+
558
+ ByStar tests use TimeCop to lock the system `Time.now` at Jan 01, 2014, and seed
559
+ objects with fixed dates according to `spec/fixtures/shared/seeds.rb`.
560
+ Note that the timezone is randomized on each run to shake-out timezone related quirks.
561
+
562
+
563
+ ## Collaborators
564
+
565
+ ByStar is actively maintained by Ryan Bigg (radar) and Johnny Shields (johnnyshields)
566
+
567
+ Thank you to the following people:
568
+
569
+ * Thomas Sinclair for the original bump for implementing ByStar
570
+ * [Ruby on Rails](http://rubyonrails.org/) for their support
571
+ * Mislav Marohnic
572
+ * August Lilleas (leethal)
573
+ * gte351s
574
+ * Sam Elliott (lenary)
575
+ * The creators of the [Chronic](https://github.com/mojombo/chronic) gem
576
+ * Erik Fonselius
577
+ * Johnny Shields (johnnyshields)