timespan 0.2.8 → 0.3.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.
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: