by_star 2.2.0 → 2.2.1

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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MTIzYTk4N2IwY2ExNjIwNGNhNGRmODNiNjA3NGQ5YmQyYWI1ODkyZQ==
4
+ MWNiZTk1NWIxMjM1ZTY5ZDk1NWMzZjY5MWQ0ODM1NTU2MGU3YzRmZA==
5
5
  data.tar.gz: !binary |-
6
- Zjg5MDgwZDMzMTcyOThlZGE4N2M4OTg5MmMzNDMxNzE0MGUyYjhlMg==
6
+ ZGI4N2RhZmViNWU3NzdjNTc5M2ZjYmU2ZDZlYTA1MzU0YjZmYzE4ZQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmU1OTgwYWY3YTBmMjQwMzgyYmI0YWNkMTkxM2I5NGMxZTQzYTI2MmEyYTIw
10
- OTZjMmJiZmNkZjk4YTUyMmNkOTcxN2IyYjZjZjc4ZGFkMjE5YmNmNjUwNzhj
11
- MzEyYTdlZTcyN2QwMjE1YzFjODIyYTA4ZTFkOTQ2ODVjMjJkZTI=
9
+ ZDYyMDZmNTFmYWYzMDg3OWNjZTU1YzNmMmRmNDYyNWRmOGYxNjJjOWE1ZTk5
10
+ OWExODkxZDA2ZGNjMDBlNDUwOTA0ZDZkMDMzMTE5MTMzYWYxMjkzYzE0NjFk
11
+ NjBhOThhMWMwNDMzYWU1NmYwOTlkMTI4ZDExZGU2YmRiOTUyY2U=
12
12
  data.tar.gz: !binary |-
13
- YzVhM2U3YzRlZTE5ZWY4ZTdjZDc2MDc3MDI4YTVlMWU4OWY4MjNiM2Q3Y2Fk
14
- N2JmNTdmN2M2YmNjYjY1MjJkZGUxMGVmNTdlNzA0OTBiNjJlZWRjN2RhOTcy
15
- YWVhMzIwZmUxMjdjNWEwNmI2NjdiYWNiNGE4NjZhMjdjMmE1NDM=
13
+ ZTZiYzg5YWFmNzNkNmI2OTg4NTcwN2RkMDU3YjgwNDAyNTg0NzZmZTk5ZjNl
14
+ ZDIyYzM0YzgwZWM0Y2NiMzQzYTA1YjQ2ODliMzQ5NTNjZDhlZjAwYjJjOTEy
15
+ Y2QxYzY2NDVjMzUyZmVjYzczODNkMzMzM2E2MDM0ZDZiNzIyOGI=
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # CHANGELOG
2
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
+
3
9
  ## v2.2.0 - 2014-04-01
4
10
 
5
11
  * Add `:scope` parameter support on all finders - @pnomolos / @johnnyshields
data/README.md CHANGED
@@ -82,16 +82,24 @@ and do not strictly end/begin evenly on a calendar week/month/year (unlike `by_*
82
82
  * `next_month` Subsequent 30-day period from current time
83
83
  * `next_year` Subsequent 365-day period from current time
84
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
+
85
92
  ### Instance Methods
86
93
 
87
- In addition, ByStar adds instance methods to return the next / previous record in the timewise sequence:
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):
88
96
 
89
97
  * `object.next`
90
98
  * `object.previous`
91
99
 
92
100
  ### Kernel Extensions
93
101
 
94
- Lastly, ByStar extends the kernel `Date`, `Time`, and `DateTime` objects with the following instance methods,
102
+ ByStar extends the kernel `Date`, `Time`, and `DateTime` objects with the following instance methods,
95
103
  which mirror the ActiveSupport methods `beginning_of_day`, `end_of_week`, etc:
96
104
 
97
105
  * `beginning_of_weekend`
@@ -101,6 +109,8 @@ which mirror the ActiveSupport methods `beginning_of_day`, `end_of_week`, etc:
101
109
  * `beginning_of_calendar_month`
102
110
  * `end_of_calendar_month`
103
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
+
104
114
  ## Usage
105
115
 
106
116
  ### Setting the Query Field
@@ -122,7 +132,8 @@ Alternatively, you may set a default in your model using the `by_star_field` mac
122
132
 
123
133
  ### Scoping the Find
124
134
 
125
- All ByStar methods (except `previous` and `next`) return `ActiveRecord::Relation` and/or `Mongoid::Criteria` objects, which can be daisy-chained with other scopes/finder methods:
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:
126
137
 
127
138
  ```ruby
128
139
  Post.by_month.your_scope
@@ -144,9 +155,15 @@ You may pass a `:scope` option as a Relation or Proc to all ByStar methods like
144
155
  @post.next(scope: ->{ where(category: 'blog') })
145
156
  ```
146
157
 
147
- This is particularly useful for `previous` and `next`, which return a model instance rather than
158
+ This is particularly useful for `oldest`, `newest`, `previous`, `next` which return a model instance rather than
148
159
  a Relation and hence cannot be daisy-chained with other scopes.
149
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
+
150
167
  You may also set a default scope in the `by_star_field` macro. (It is recommended this be a Proc):
151
168
 
152
169
  ```ruby
data/UPGRADING CHANGED
@@ -1,7 +1,7 @@
1
- Upgrading to ByStar 2.2.0
2
- -------------------------
1
+ Upgrading ByStar
2
+ ----------------
3
3
 
4
- * ActiveRecord: the `between` method has been deprecated as of version 2.2.0, and will be removed in version 3.3.0.
4
+ * ActiveRecord: the `between` method has been deprecated as of version 2.2.0, and will be removed in version 3.0.0.
5
5
  Please use `between_times` instead.
6
6
 
7
7
  * Mongoid: the `between` method has been removed as of version 2.2.0, as it conflicts with the native Mongoid `between`
data/lib/by_star.rb CHANGED
@@ -1,4 +1,5 @@
1
- require 'by_star/kernel'
1
+ require 'by_star/kernel/time'
2
+ require 'by_star/kernel/date'
2
3
  require 'by_star/normalization'
3
4
  require 'by_star/between'
4
5
  require 'by_star/directional'
data/lib/by_star/base.rb CHANGED
@@ -38,8 +38,10 @@ module ByStar
38
38
  if scope.is_a?(Proc)
39
39
  if scope.arity == 0
40
40
  return instance_exec(&scope)
41
+ elsif options[:scope_args]
42
+ return instance_exec(*Array(options[:scope_args]), &scope)
41
43
  else
42
- return instance_exec(self, &scope)
44
+ raise 'ByStar :scope does not accept arguments'
43
45
  end
44
46
  else
45
47
  return scope
@@ -17,5 +17,17 @@ module ByStar
17
17
  end
18
18
  end
19
19
  alias_method :after_now, :after
20
+
21
+ def oldest(*args)
22
+ with_by_star_options(*args) do |time, options|
23
+ oldest_query(options)
24
+ end
25
+ end
26
+
27
+ def newest(*args)
28
+ with_by_star_options(*args) do |time, options|
29
+ newest_query(options)
30
+ end
31
+ end
20
32
  end
21
33
  end
@@ -0,0 +1,19 @@
1
+ module ByStar
2
+
3
+ module Kernel
4
+
5
+ module Date
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+
10
+ # Shim to alias Rails 3 #to_time_in_current_zone to Rails 4 name #in_time_zone
11
+ if method_defined?(:to_time_in_current_zone) && !method_defined?(:in_time_zone)
12
+ alias_method :in_time_zone, :to_time_in_current_zone
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ ::Date.__send__(:include, ByStar::Kernel::Date)
File without changes
@@ -8,9 +8,9 @@ module ByStar
8
8
 
9
9
  def time(value)
10
10
  case value
11
- when String then time_string(value)
11
+ when String then time_string(value)
12
12
  when DateTime then value.to_time
13
- when Date then value.to_time_in_current_zone
13
+ when Date then value.in_time_zone
14
14
  else value
15
15
  end
16
16
  end
@@ -42,18 +42,28 @@ module ByStar
42
42
  field = by_star_start_field(options)
43
43
  by_star_scope(options).where("#{field} >= ?", time)
44
44
  end
45
+
46
+ def oldest_query(options={})
47
+ field = by_star_start_field(options)
48
+ by_star_scope(options).reorder("#{field} ASC").first
49
+ end
50
+
51
+ def newest_query(options={})
52
+ field = by_star_start_field(options)
53
+ by_star_scope(options).reorder("#{field} DESC").first
54
+ end
45
55
  end
46
56
 
47
57
  def previous(options={})
48
58
  field = self.class.by_star_start_field
49
59
  value = self.send(field.split(".").last)
50
- self.class.by_star_scope(options).where("#{field} < ?", value).reorder("#{field} DESC").first
60
+ self.class.by_star_scope(options.merge(scope_args: self)).where("#{field} < ?", value).reorder("#{field} DESC").first
51
61
  end
52
62
 
53
63
  def next(options={})
54
64
  field = self.class.by_star_start_field
55
65
  value = self.send(field.split(".").last)
56
- self.class.by_star_scope(options).where("#{field} > ?", value).reorder("#{field} ASC").first
66
+ self.class.by_star_scope(options.merge(scope_args: self)).where("#{field} > ?", value).reorder("#{field} ASC").first
57
67
  end
58
68
  end
59
69
  end
@@ -48,16 +48,26 @@ module Mongoid
48
48
  field = by_star_start_field(options)
49
49
  by_star_scope(options).gte(field => time)
50
50
  end
51
+
52
+ def oldest_query(options={})
53
+ field = by_star_start_field(options)
54
+ by_star_scope(options).order_by(field => :asc).first
55
+ end
56
+
57
+ def newest_query(options={})
58
+ field = by_star_start_field(options)
59
+ by_star_scope(options).order_by(field => :desc).first
60
+ end
51
61
  end
52
62
 
53
63
  def previous(options={})
54
64
  field = self.class.by_star_start_field
55
- self.class.by_star_scope(options).lt(field => self.send(field)).desc(field).first
65
+ self.class.by_star_scope(options.merge(scope_args: self)).lt(field => self.send(field)).desc(field).first
56
66
  end
57
67
 
58
68
  def next(options={})
59
69
  field = self.class.by_star_start_field
60
- self.class.by_star_scope(options).gt(field => self.send(field)).asc(field).first
70
+ self.class.by_star_scope(options.merge(scope_args: self)).gt(field => self.send(field)).asc(field).first
61
71
  end
62
72
  end
63
73
  end
@@ -1,3 +1,3 @@
1
1
  module ByStar
2
- VERSION = '2.2.0'
2
+ VERSION = '2.2.1'
3
3
  end
@@ -78,6 +78,44 @@ shared_examples_for 'by direction' do
78
78
  end
79
79
  end
80
80
 
81
+ describe '#oldest and #newest' do
82
+
83
+ context 'point-in-time' do
84
+ it { Post.newest.created_at.should eq Time.zone.parse('2014-04-15 17:00:00') }
85
+ it { Post.oldest.created_at.should eq Time.zone.parse('2013-11-01 17:00:00') }
86
+ end
87
+
88
+ context 'timespan' do
89
+ it { Event.newest.created_at.should eq Time.zone.parse('2014-04-15 17:00:00') }
90
+ it { Event.oldest.created_at.should eq Time.zone.parse('2013-11-01 17:00:00') }
91
+ end
92
+
93
+ context 'timespan strict' do
94
+ it { Event.newest(strict: true).created_at.should eq Time.zone.parse('2014-04-15 17:00:00') }
95
+ it { Event.oldest(strict: true).created_at.should eq Time.zone.parse('2013-11-01 17:00:00') }
96
+ end
97
+
98
+ context 'alternative field' do
99
+ it { Event.newest(field: 'created_at').created_at.should eq Time.zone.parse('2014-04-15 17:00:00') }
100
+ it { Event.oldest(field: 'created_at').created_at.should eq Time.zone.parse('2013-11-01 17:00:00') }
101
+ end
102
+
103
+ context 'with default scope' do
104
+ it { Appointment.newest(field: 'created_at').created_at.should eq Time.zone.parse('2014-04-01 17:00:00') }
105
+ it { Appointment.oldest(field: 'created_at').created_at.should eq Time.zone.parse('2013-11-01 17:00:00') }
106
+ end
107
+
108
+ context 'with scope as a query criteria' do
109
+ it { Post.newest(field: 'created_at', scope: Post.where(day_of_month: 5)).created_at.should eq Time.zone.parse('2014-01-05 17:00:00') }
110
+ it { Post.oldest(field: 'created_at', scope: Post.where(day_of_month: 5)).created_at.should eq Time.zone.parse('2013-12-05 17:00:00') }
111
+ end
112
+
113
+ context 'with scope as a proc' do
114
+ it { Post.newest(field: 'created_at', scope: ->{ where(day_of_month: 5) }).created_at.should eq Time.zone.parse('2014-01-05 17:00:00') }
115
+ it { Post.oldest(field: 'created_at', scope: ->{ where(day_of_month: 5) }).created_at.should eq Time.zone.parse('2013-12-05 17:00:00') }
116
+ end
117
+ end
118
+
81
119
  describe '#previous and #next' do
82
120
 
83
121
  context 'point-in-time' do
@@ -107,8 +145,9 @@ shared_examples_for 'by direction' do
107
145
  context 'with scope as a proc' do
108
146
  subject { Post.where(created_at: Time.zone.parse('2014-01-05 17:00:00')).first }
109
147
  it{ subject.previous({ scope: Proc.new{ where(day_of_month: 5) } }).created_at.should eq Time.zone.parse('2013-12-05 17:00:00') }
148
+ it{ subject.previous({ scope: Proc.new{|record| where(day_of_month: record.day_of_month) } }).created_at.should eq Time.zone.parse('2013-12-05 17:00:00') }
110
149
  it{ subject.next({ scope: ->{ where(day_of_month: 1) } }).created_at.should eq Time.zone.parse('2014-02-01 17:00:00') }
111
- it{ subject.next({ scope: ->(klass){ klass.where(day_of_month: 1) } }).created_at.should eq Time.zone.parse('2014-02-01 17:00:00') }
150
+ it{ subject.next({ scope: ->(record){ where(day_of_month: record.day_of_month - 4) } }).created_at.should eq Time.zone.parse('2014-02-01 17:00:00') }
112
151
  end
113
152
  end
114
153
  end
@@ -19,11 +19,26 @@ shared_examples_for 'scope parameter' do
19
19
  its(:count) { should eq 14 }
20
20
  end
21
21
 
22
- context 'between_times with scope override as a Proc' do
22
+ context 'between_times with scope override as a Lambda' do
23
23
  subject { Appointment.between_times(Date.parse('2013-12-01'), Date.parse('2014-02-01'), scope: ->{ unscoped }) }
24
24
  its(:count) { should eq 14 }
25
25
  end
26
26
 
27
+ context 'between_times with scope override as a Lambda' do
28
+ subject { Appointment.between_times(Date.parse('2013-12-01'), Date.parse('2014-02-01'), scope: ->(x){ unscoped }) }
29
+ it{ ->{subject}.should raise_error }
30
+ end
31
+
32
+ context 'between_times with scope override as a Proc with arguments' do
33
+ subject { Appointment.between_times(Date.parse('2013-12-01'), Date.parse('2014-02-01'), scope: Proc.new{ unscoped }) }
34
+ its(:count) { should eq 14 }
35
+ end
36
+
37
+ context 'between_times with scope override as a Proc with arguments' do
38
+ subject { Appointment.between_times(Date.parse('2013-12-01'), Date.parse('2014-02-01'), scope: Proc.new{|x,y| unscoped }) }
39
+ it{ ->{subject}.should raise_error }
40
+ end
41
+
27
42
  context 'by_month with default scope' do
28
43
  subject { Appointment.by_month(Date.parse('2014-01-01')) }
29
44
  its(:count) { should eq 2 }
@@ -34,9 +49,24 @@ shared_examples_for 'scope parameter' do
34
49
  its(:count) { should eq 6 }
35
50
  end
36
51
 
37
- context 'by_month with scope override as a Proc' do
52
+ context 'by_month with scope override as a Lambda' do
38
53
  subject { Appointment.by_month(Date.parse('2014-01-01'), scope: ->{ unscoped }) }
39
54
  its(:count) { should eq 6 }
40
55
  end
56
+
57
+ context 'by_month with scope override as a Lambda with arguments' do
58
+ subject { Appointment.by_month(Date.parse('2014-01-01'), scope: ->(x){ unscoped }) }
59
+ it{ ->{subject}.should raise_error }
60
+ end
61
+
62
+ context 'by_month with scope override as a Proc' do
63
+ subject { Appointment.by_month(Date.parse('2014-01-01'), scope: Proc.new{ unscoped }) }
64
+ its(:count) { should eq 6 }
65
+ end
66
+
67
+ context 'by_month with scope override as a Proc with arguments' do
68
+ subject { Appointment.by_month(Date.parse('2014-01-01'), scope: Proc.new{|x| unscoped }) }
69
+ it{ ->{subject}.should raise_error }
70
+ end
41
71
  end
42
72
  end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Date do
4
+
5
+ describe '#in_time_zone' do
6
+
7
+ subject { Date.new }
8
+
9
+ before do
10
+ stub_const('Date', Class.new)
11
+ Date.any_instance.stub(:to_time_in_current_zone)
12
+ end
13
+
14
+ context 'when #in_time_zone is already defined' do
15
+ before do
16
+ Date.any_instance.should_receive(:in_time_zone)
17
+ end
18
+
19
+ context 'when ByStar::Kernel::Date included' do
20
+ before do
21
+ ::Date.__send__(:include, ByStar::Kernel::Date)
22
+ end
23
+
24
+ it 'should not be aliased to #to_time_in_current_zone' do
25
+ subject.should_not_receive(:to_time_in_current_zone)
26
+ subject.in_time_zone
27
+ end
28
+ end
29
+
30
+ context 'when ByStar::Kernel::Date not included' do
31
+
32
+ it 'should not be aliased to #to_time_in_current_zone' do
33
+ subject.should_not_receive(:to_time_in_current_zone)
34
+ subject.in_time_zone
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'when #in_time_zone is not defined' do
40
+
41
+ context 'when ByStar::Kernel::Date included' do
42
+ before do
43
+ ::Date.__send__(:include, ByStar::Kernel::Date)
44
+ end
45
+
46
+ it 'should be aliased to #to_time_in_current_zone' do
47
+ subject.should_receive(:to_time_in_current_zone)
48
+ subject.in_time_zone
49
+ end
50
+ end
51
+
52
+ context 'when ByStar::Kernel::Date not included' do
53
+
54
+ it 'should raise NoMethodError' do
55
+ ->{ subject.in_time_zone }.should raise_error(NoMethodError)
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: by_star
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.0
4
+ version: 2.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Bigg
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-04-01 00:00:00.000000000 Z
12
+ date: 2014-04-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -186,7 +186,8 @@ files:
186
186
  - lib/by_star/base.rb
187
187
  - lib/by_star/between.rb
188
188
  - lib/by_star/directional.rb
189
- - lib/by_star/kernel.rb
189
+ - lib/by_star/kernel/date.rb
190
+ - lib/by_star/kernel/time.rb
190
191
  - lib/by_star/normalization.rb
191
192
  - lib/by_star/orm/active_record/by_star.rb
192
193
  - lib/by_star/orm/mongoid/by_star.rb
@@ -211,19 +212,20 @@ files:
211
212
  - spec/integration/shared/relative.rb
212
213
  - spec/integration/shared/scope_parameter.rb
213
214
  - spec/spec_helper.rb
215
+ - spec/unit/kernel_date_spec.rb
214
216
  - spec/unit/kernel_time_spec.rb
215
217
  - spec/unit/normalization_spec.rb
216
218
  - tmp/.gitignore
217
219
  homepage: http://github.com/radar/by_star
218
220
  licenses: []
219
221
  metadata: {}
220
- post_install_message: ! 'Upgrading to ByStar 2.2.0
222
+ post_install_message: ! 'Upgrading ByStar
221
223
 
222
- -------------------------
224
+ ----------------
223
225
 
224
226
 
225
227
  * ActiveRecord: the `between` method has been deprecated as of version 2.2.0, and
226
- will be removed in version 3.3.0.
228
+ will be removed in version 3.0.0.
227
229
 
228
230
  Please use `between_times` instead.
229
231
 
@@ -283,6 +285,7 @@ test_files:
283
285
  - spec/integration/shared/relative.rb
284
286
  - spec/integration/shared/scope_parameter.rb
285
287
  - spec/spec_helper.rb
288
+ - spec/unit/kernel_date_spec.rb
286
289
  - spec/unit/kernel_time_spec.rb
287
290
  - spec/unit/normalization_spec.rb
288
291
  has_rdoc: