timespan 0.2.8 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +58 -0
- data/VERSION +1 -1
- data/lib/timespan/compare.rb +1 -1
- data/lib/timespan/mongoid.rb +60 -5
- data/lib/timespan.rb +6 -2
- data/spec/timespan/mongoid/account.rb +6 -2
- data/spec/timespan/mongoid/mongoid_search_spec.rb +40 -0
- data/spec/timespan/mongoid/mongoid_timespan_spec.rb +16 -4
- data/timespan.gemspec +3 -2
- metadata +4 -3
data/README.md
CHANGED
@@ -113,6 +113,43 @@ account.period.end_date
|
|
113
113
|
account.period.days
|
114
114
|
account.period.duration # => Duration
|
115
115
|
|
116
|
+
## Searching periods
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
Account.where(:'period.from'.lt => 6.days.ago.to_i)
|
120
|
+
Account.where(:'period.from'.gt => 3.days.ago.to_i)
|
121
|
+
|
122
|
+
# in range
|
123
|
+
Account.where(:'period.from'.gt => 3.days.ago.to_i, :'period.to'.lt => Time.now.utc.to_i)
|
124
|
+
```
|
125
|
+
|
126
|
+
Make it easier by introducing a class helper:
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
class Account
|
130
|
+
include Mongoid::Document
|
131
|
+
field :period, :type => TimeSpan
|
132
|
+
|
133
|
+
def self.between from, to
|
134
|
+
Account.where(:'period.from'.gt => from.to_i, :'period.to'.lte => to.to_i)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
```
|
138
|
+
|
139
|
+
`Account.between(6.days.ago, 1.day.ago)`
|
140
|
+
|
141
|
+
Alternatively auto-generate a `#between` helper for the field:
|
142
|
+
|
143
|
+
```ruby
|
144
|
+
class Account
|
145
|
+
include Mongoid::Document
|
146
|
+
field :period, :type => TimeSpan, :between => true
|
147
|
+
```
|
148
|
+
|
149
|
+
`Account.period_between(6.days.ago, 1.day.ago)`
|
150
|
+
|
151
|
+
See the `mongoid_search_spec.rb` for examples:
|
152
|
+
|
116
153
|
## Chronic duration
|
117
154
|
|
118
155
|
Is used to parse duration strings if Spanner can't be handle it
|
@@ -148,6 +185,27 @@ Currently it also uses Duration, which conflicts with the 'ruby-duration' gem.
|
|
148
185
|
1.week.each(10.hours) {|ten_hour_segment| ...} #=> Using a custom iterator of 10 hours. There would be 17 of them, but notice that the last iteration will only be 8 hours.
|
149
186
|
``
|
150
187
|
|
188
|
+
## Configuration and overrides
|
189
|
+
|
190
|
+
Timespan by default uses `Time.now.utc` to set the current time, fx used when either `end_date` or `start_date` otherwise would be nil. This is used in order to work with Mongoid (see [issue #400](https://github.com/mongoid/mongoid/issues/400))
|
191
|
+
|
192
|
+
You can customize `now` to return fx `Time.now`, `Date.today` or whatever suits you.
|
193
|
+
|
194
|
+
```ruby
|
195
|
+
class Timespan
|
196
|
+
def now
|
197
|
+
Time.now # or Date.today
|
198
|
+
end
|
199
|
+
end
|
200
|
+
```
|
201
|
+
|
202
|
+
By default the `TimeSpan` is stored using `:from` and `:to` for the start and end times. This can be customized as follows:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
TimeSpan.start_field = :start
|
206
|
+
TimeSpan.end_field = :end
|
207
|
+
```
|
208
|
+
|
151
209
|
## Contributing to Timespan
|
152
210
|
|
153
211
|
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.1
|
data/lib/timespan/compare.rb
CHANGED
data/lib/timespan/mongoid.rb
CHANGED
@@ -1,12 +1,40 @@
|
|
1
1
|
require "timespan"
|
2
2
|
require "mongoid/fields"
|
3
3
|
|
4
|
+
# http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
|
5
|
+
class Object
|
6
|
+
def meta_def name, &blk
|
7
|
+
(class << self; self; end).instance_eval { define_method name, &blk }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
Mongoid::Fields.option :between do |model, field, options|
|
12
|
+
name = field.name.to_sym
|
13
|
+
model.class_eval do
|
14
|
+
meta_def :"#{name}_between" do |from, to|
|
15
|
+
self.where(:"#{name}.#{TimeSpan.start_field}".gte => from.to_i, :"#{name}.#{TimeSpan.end_field}".lte => to.to_i)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
4
20
|
# Mongoid serialization support for Timespan type.
|
5
21
|
module Mongoid
|
6
22
|
module Fields
|
7
23
|
class Timespan
|
8
24
|
include Mongoid::Fields::Serializable
|
9
25
|
|
26
|
+
class << self
|
27
|
+
attr_writer :start_field, :end_field
|
28
|
+
|
29
|
+
def start_field
|
30
|
+
@start_field || :from
|
31
|
+
end
|
32
|
+
|
33
|
+
def end_field
|
34
|
+
@end_field || :to
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
10
38
|
def self.instantiate(name, options = {})
|
11
39
|
super
|
12
40
|
end
|
@@ -15,9 +43,9 @@ module Mongoid
|
|
15
43
|
#
|
16
44
|
# @param [Hash] Timespan as hash
|
17
45
|
# @return [Timespan] deserialized Timespan
|
18
|
-
def deserialize(
|
19
|
-
return if !
|
20
|
-
::Timespan.new
|
46
|
+
def deserialize(hash)
|
47
|
+
return if !hash
|
48
|
+
::Timespan.new :from => from(hash), :to => to(hash)
|
21
49
|
end
|
22
50
|
|
23
51
|
# Serialize a Timespan or a Hash (with Timespan units) or a Duration in some form to
|
@@ -27,8 +55,35 @@ module Mongoid
|
|
27
55
|
# @return [Hash] Timespan in seconds
|
28
56
|
def serialize(value)
|
29
57
|
return if value.blank?
|
30
|
-
timespan =
|
31
|
-
|
58
|
+
timespan = case value
|
59
|
+
when ::Timespan
|
60
|
+
value
|
61
|
+
else
|
62
|
+
::Timespan.new(value)
|
63
|
+
end
|
64
|
+
{:from => serialize_time(timespan.start_time), :to => serialize_time(timespan.end_time.to_i), :duration => timespan.duration.total }
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def from hash
|
70
|
+
from_value = hash['from'] || hash[:from]
|
71
|
+
raise ArgumentError, ":from is nil, #{hash.inspect}" if from_value.nil?
|
72
|
+
deserialize_time from_value
|
73
|
+
end
|
74
|
+
|
75
|
+
def to hash
|
76
|
+
to_value = hash['to'] || hash[:to]
|
77
|
+
raise ArgumentError, ":to is nil, #{hash.inspect}" if to_value.nil?
|
78
|
+
deserialize_time to_value
|
79
|
+
end
|
80
|
+
|
81
|
+
def serialize_time time
|
82
|
+
time.to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
def deserialize_time millisecs
|
86
|
+
Time.at millisecs
|
32
87
|
end
|
33
88
|
end
|
34
89
|
end
|
data/lib/timespan.rb
CHANGED
@@ -120,8 +120,12 @@ class Timespan
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def default_from_now!
|
123
|
-
self.start_time =
|
124
|
-
self.end_time =
|
123
|
+
self.start_time = now unless start_time || (end_time && duration)
|
124
|
+
self.end_time = now unless end_time || (start_time && duration)
|
125
|
+
end
|
126
|
+
|
127
|
+
def now
|
128
|
+
Time.now.utc
|
125
129
|
end
|
126
130
|
|
127
131
|
def validate!
|
@@ -1,10 +1,14 @@
|
|
1
1
|
class Account
|
2
|
-
include Mongoid::Document
|
3
|
-
field :period, :type => TimeSpan
|
2
|
+
include Mongoid::Document
|
3
|
+
field :period, :type => TimeSpan, :between => true
|
4
4
|
|
5
5
|
def self.create_it! duration
|
6
6
|
s = self.new
|
7
7
|
s.period = {duration: duration}
|
8
8
|
s
|
9
9
|
end
|
10
|
+
|
11
|
+
def self.between from, to
|
12
|
+
Account.where(:'period.from'.gt => from.to_i, :'period.to'.lte => to.to_i)
|
13
|
+
end
|
10
14
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'timespan/mongoid/spec_helper'
|
2
|
+
|
3
|
+
describe TimeSpan do
|
4
|
+
subject { account }
|
5
|
+
|
6
|
+
context '3 Accounts with periods serialized' do
|
7
|
+
before do
|
8
|
+
Account.delete_all
|
9
|
+
@acc1 = Account.create :period => Timespan.new(:start_date => 2.days.ago)
|
10
|
+
@acc2 = Account.create :period => Timespan.new(:start_date => 5.days.ago, :end_date => 2.days.ago)
|
11
|
+
@acc3 = Account.create :period => Timespan.new(:start_date => 10.days.ago)
|
12
|
+
|
13
|
+
# puts [@acc1._id, @acc2._id, @acc3._id]
|
14
|
+
end
|
15
|
+
|
16
|
+
describe 'find accounts within specific period' do
|
17
|
+
it 'should find a single period less than 6 days old' do
|
18
|
+
Account.where(:'period.from'.lt => 6.days.ago.to_i).first.should == @acc3
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should find a single period later than 3 days old' do
|
22
|
+
Account.where(:'period.from'.gt => 3.days.ago.to_i).first.should == @acc1
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'find a single period that is within period from 6 days ago to tomorrow' do
|
26
|
+
it 'should use Account.where' do
|
27
|
+
Account.where(:'period.from'.gt => 6.days.ago.to_i, :'period.to'.lte => 1.day.ago.to_i).first.should == @acc2
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should use Account class helper #between' do
|
31
|
+
Account.between(6.days.ago, 1.day.ago).first.should == @acc2
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should use Account class generated helper #period_between' do
|
35
|
+
Account.period_between(6.days.ago, 1.day.ago).first.should == @acc2
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'timespan/mongoid/spec_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe TimeSpan do
|
4
4
|
subject { account }
|
5
5
|
|
6
6
|
let(:from) { Chronic.parse("1 day ago") }
|
@@ -18,7 +18,19 @@ describe Timespan do
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
context '2 days duration using
|
21
|
+
context '2 days duration using Timespan' do
|
22
|
+
let(:account) do
|
23
|
+
Account.create :period => Timespan.new(:duration => 2.days)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.start_date' do
|
27
|
+
it 'should default to today' do
|
28
|
+
DateTime.parse(subject.period.start_date.to_s).strftime('%d %b %Y').should == Date.today.strftime('%d %b %Y')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context '2 days duration using :duration => integer via ActiveSupport::Duration' do
|
22
34
|
let(:account) do
|
23
35
|
Account.create :period => {:duration => 2.days }
|
24
36
|
end
|
@@ -30,7 +42,7 @@ describe Timespan do
|
|
30
42
|
end
|
31
43
|
end
|
32
44
|
|
33
|
-
context '2 days using integer' do
|
45
|
+
context '2 days using integer via ActiveSupport::Duration' do
|
34
46
|
let(:account) do
|
35
47
|
Account.create :period => 2.days
|
36
48
|
end
|
@@ -42,7 +54,7 @@ describe Timespan do
|
|
42
54
|
end
|
43
55
|
end
|
44
56
|
|
45
|
-
context '2 days duration
|
57
|
+
context '2 days duration using string' do
|
46
58
|
let(:account) do
|
47
59
|
Account.create :period => {:duration => '2 days'}
|
48
60
|
end
|
data/timespan.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "timespan"
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Kristian Mandrup"]
|
12
|
-
s.date = "2012-05-
|
12
|
+
s.date = "2012-05-30"
|
13
13
|
s.description = "Makes it easy to calculate time distance in different units"
|
14
14
|
s.email = "kmandrup@gmail.com"
|
15
15
|
s.extra_rdoc_files = [
|
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
|
|
38
38
|
"spec/timespan/duration_macros_spec.rb",
|
39
39
|
"spec/timespan/locales/duration_da.yml",
|
40
40
|
"spec/timespan/mongoid/account.rb",
|
41
|
+
"spec/timespan/mongoid/mongoid_search_spec.rb",
|
41
42
|
"spec/timespan/mongoid/mongoid_timespan_spec.rb",
|
42
43
|
"spec/timespan/mongoid/spec_helper.rb",
|
43
44
|
"spec/timespan/printer_spec.rb",
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: timespan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chronic
|
@@ -232,6 +232,7 @@ files:
|
|
232
232
|
- spec/timespan/duration_macros_spec.rb
|
233
233
|
- spec/timespan/locales/duration_da.yml
|
234
234
|
- spec/timespan/mongoid/account.rb
|
235
|
+
- spec/timespan/mongoid/mongoid_search_spec.rb
|
235
236
|
- spec/timespan/mongoid/mongoid_timespan_spec.rb
|
236
237
|
- spec/timespan/mongoid/spec_helper.rb
|
237
238
|
- spec/timespan/printer_spec.rb
|
@@ -255,7 +256,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
256
|
version: '0'
|
256
257
|
segments:
|
257
258
|
- 0
|
258
|
-
hash:
|
259
|
+
hash: -4280308012345220837
|
259
260
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
260
261
|
none: false
|
261
262
|
requirements:
|