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 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.2.8
1
+ 0.3.1
@@ -22,7 +22,7 @@ class Timespan
22
22
  include Comparable
23
23
 
24
24
  def time_left time = nil
25
- time_compare = time || Time.now
25
+ time_compare = time || now
26
26
  diff = end_time - time_compare
27
27
  Timespan::TimeDuration.new(diff)
28
28
  end
@@ -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(timespan_hash)
19
- return if !timespan_hash
20
- ::Timespan.new(:from => timespan_hash[:from], :to => timespan_hash[:to])
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 = ::Timespan.new(value)
31
- {:from => timespan.start_time, :to => timespan.end_time, :duration => timespan.duration.total}
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 = Time.now unless start_time || (end_time && duration)
124
- self.end_time = Time.now unless end_time || (start_time && duration)
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 Timespan do
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 integer' do
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 (from now - default)' do
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.2.8"
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-29"
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.2.8
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-29 00:00:00.000000000 Z
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: 43834805566888461
259
+ hash: -4280308012345220837
259
260
  required_rubygems_version: !ruby/object:Gem::Requirement
260
261
  none: false
261
262
  requirements: