by_star 2.2.0 → 2.2.1

Sign up to get free protection for your applications and to get access to all the features.
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: