timespan 0.4.6 → 0.4.9
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/Gemfile +4 -1
- data/Gemfile.lock +7 -2
- data/README.md +17 -0
- data/VERSION +1 -1
- data/lib/timespan/core_ext/hash.rb +12 -0
- data/lib/timespan/core_ext/range.rb +119 -0
- data/lib/timespan/core_ext.rb +1 -0
- data/lib/timespan/mongoid/mongoid_3x.rb +46 -5
- data/lib/timespan/mongoid.rb +6 -0
- data/lib/timespan.rb +110 -37
- data/spec/timespan/core_ext/duration_range_spec.rb +60 -0
- data/spec/timespan/core_ext/timespan_range_spec.rb +57 -0
- data/spec/timespan/mongoid/advanced_search_spec.rb +216 -0
- data/spec/timespan/mongoid/models/account_3x.rb +10 -1
- data/spec/timespan/mongoid/models/time_period.rb +2 -1
- data/timespan.gemspec +17 -5
- metadata +43 -5
data/Gemfile
CHANGED
@@ -4,6 +4,7 @@ gem 'chronic'
|
|
4
4
|
gem 'chronic_duration'
|
5
5
|
gem 'activesupport', '>= 3.0.0'
|
6
6
|
gem 'spanner'
|
7
|
+
gem 'sugar-high', '~> 0.7.2' # for range intersect
|
7
8
|
gem 'xduration', '~> 2.2'
|
8
9
|
|
9
10
|
group :test, :development do
|
@@ -12,10 +13,12 @@ group :test, :development do
|
|
12
13
|
# gem 'mongoid', '>= 2.4'
|
13
14
|
# gem 'bson', '>= 1.6'
|
14
15
|
|
15
|
-
gem 'mongoid', '~> 3.0
|
16
|
+
gem 'mongoid', '~> 3.0'
|
17
|
+
gem 'origin-selectable_ext', '~> 0.1.1'
|
16
18
|
# gem 'i18n'
|
17
19
|
end
|
18
20
|
|
21
|
+
|
19
22
|
group :development do
|
20
23
|
gem "rdoc", ">= 3.12"
|
21
24
|
gem "bundler", ">= 1.0.0"
|
data/Gemfile.lock
CHANGED
@@ -58,7 +58,9 @@ GEM
|
|
58
58
|
moped (1.2.0)
|
59
59
|
multi_json (1.3.6)
|
60
60
|
numerizer (0.1.1)
|
61
|
-
origin (1.0.
|
61
|
+
origin (1.0.9)
|
62
|
+
origin-selectable_ext (0.1.1)
|
63
|
+
origin
|
62
64
|
polyglot (0.3.3)
|
63
65
|
rack (1.4.1)
|
64
66
|
rack-cache (1.2)
|
@@ -102,6 +104,7 @@ GEM
|
|
102
104
|
hike (~> 1.2)
|
103
105
|
rack (~> 1.0)
|
104
106
|
tilt (~> 1.1, != 1.3.0)
|
107
|
+
sugar-high (0.7.2)
|
105
108
|
thor (0.15.4)
|
106
109
|
tilt (1.3.3)
|
107
110
|
treetop (1.4.10)
|
@@ -121,10 +124,12 @@ DEPENDENCIES
|
|
121
124
|
chronic
|
122
125
|
chronic_duration
|
123
126
|
jeweler (>= 1.8.3)
|
124
|
-
mongoid (~> 3.0
|
127
|
+
mongoid (~> 3.0)
|
128
|
+
origin-selectable_ext (~> 0.1.1)
|
125
129
|
rails (~> 3.2.7)
|
126
130
|
rdoc (>= 3.12)
|
127
131
|
rspec (>= 2.8.0)
|
128
132
|
simplecov (>= 0.5)
|
129
133
|
spanner
|
134
|
+
sugar-high (~> 0.7.2)
|
130
135
|
xduration (~> 2.2)
|
data/README.md
CHANGED
@@ -309,6 +309,23 @@ TimeSpan.start_field = :start
|
|
309
309
|
TimeSpan.end_field = :end
|
310
310
|
```
|
311
311
|
|
312
|
+
## Ranges
|
313
|
+
|
314
|
+
A Range can be converted into either a `Timespan` or a `DurationRange`
|
315
|
+
|
316
|
+
### DurationRange
|
317
|
+
|
318
|
+
```ruby
|
319
|
+
dr = (1..5).days # => DurationRange 1..5, :days
|
320
|
+
ts =(1..5).days(:timespan) # => Timespan start_date: 1.day.from_now, end_date: 5.days.from_now
|
321
|
+
|
322
|
+
dr.between?(4.days) # => true
|
323
|
+
```
|
324
|
+
|
325
|
+
You can also use Range#intersect from *sugar-high* gem to test intersection of time ranges ;)
|
326
|
+
|
327
|
+
### Timespan
|
328
|
+
|
312
329
|
## Contributing to Timespan
|
313
330
|
|
314
331
|
* 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.4.
|
1
|
+
0.4.9
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class Hash
|
2
|
+
def __evolve_to_timespan__
|
3
|
+
serializer = Mongoid::Fields::Timespan
|
4
|
+
object = self
|
5
|
+
::Timespan.new :from => serializer.from(object), :to => serializer.to(object), asap: serializer.asap(object)
|
6
|
+
end
|
7
|
+
|
8
|
+
def __evolve_to_duration_range__
|
9
|
+
range = Range.new self['from'], self['to']
|
10
|
+
::DurationRange.new range, :seconds
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
class TimespanRange < DelegateDecorator
|
2
|
+
attr_accessor :unit, :range
|
3
|
+
|
4
|
+
def initialize range, unit
|
5
|
+
super(range)
|
6
|
+
@range = Timespan.new between: range
|
7
|
+
@unit = unit.to_s.singularize.to_sym
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class DurationRange < DelegateDecorator
|
12
|
+
attr_accessor :unit, :range
|
13
|
+
|
14
|
+
def initialize range, unit
|
15
|
+
super(range)
|
16
|
+
@unit = unit.to_s.singularize.to_sym
|
17
|
+
@range = range
|
18
|
+
end
|
19
|
+
|
20
|
+
def __evolve_to_duration_range__
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
24
|
+
def mongoize
|
25
|
+
{:from => range.min.to_i, :to => range.max.to_i}
|
26
|
+
end
|
27
|
+
|
28
|
+
def between? duration
|
29
|
+
obj = case duration
|
30
|
+
when Duration
|
31
|
+
duration
|
32
|
+
else
|
33
|
+
Duration.new duration
|
34
|
+
end
|
35
|
+
obj.total >= min && obj.total <= max
|
36
|
+
end
|
37
|
+
|
38
|
+
class << self
|
39
|
+
# See http://mongoid.org/en/mongoid/docs/upgrading.html
|
40
|
+
|
41
|
+
# Serialize a Hash (with DurationRange keys) or a DurationRange to
|
42
|
+
# a BSON serializable type.
|
43
|
+
#
|
44
|
+
# @param [Timespan, Hash, Integer, String] value
|
45
|
+
# @return [Hash] Timespan in seconds
|
46
|
+
def mongoize object
|
47
|
+
mongoized = case object
|
48
|
+
when DurationRange then object.mongoize
|
49
|
+
when Hash
|
50
|
+
object
|
51
|
+
when Range
|
52
|
+
object.send(:seconds).mongoize
|
53
|
+
else
|
54
|
+
object
|
55
|
+
end
|
56
|
+
# puts "mongoized: #{mongoized} - Hash"
|
57
|
+
mongoized
|
58
|
+
end
|
59
|
+
|
60
|
+
# Deserialize a Timespan given the hash stored by Mongodb
|
61
|
+
#
|
62
|
+
# @param [Hash] Timespan as hash
|
63
|
+
# @return [Timespan] deserialized Timespan
|
64
|
+
def demongoize(object)
|
65
|
+
return if !object
|
66
|
+
|
67
|
+
demongoized = case object
|
68
|
+
when Hash
|
69
|
+
object.__evolve_to_duration_range__
|
70
|
+
else
|
71
|
+
raise "Unable to demongoize DurationRange from: #{object}"
|
72
|
+
end
|
73
|
+
# puts "demongoized: #{demongoized} - DurationRange"
|
74
|
+
demongoized
|
75
|
+
end
|
76
|
+
|
77
|
+
# Converts the object that was supplied to a criteria and converts it
|
78
|
+
# into a database friendly form.
|
79
|
+
def evolve(object)
|
80
|
+
object.__evolve_to_duration_range__.mongoize
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
|
85
|
+
def parse duration
|
86
|
+
if duration.kind_of? Numeric
|
87
|
+
return Duration.new duration
|
88
|
+
else
|
89
|
+
case duration
|
90
|
+
when Timespan
|
91
|
+
duration.duration
|
92
|
+
when Duration
|
93
|
+
duration
|
94
|
+
when Hash
|
95
|
+
Duration.new duration
|
96
|
+
when Time
|
97
|
+
duration.to_i
|
98
|
+
when DateTime, Date
|
99
|
+
duration.to_time.to_i
|
100
|
+
when String
|
101
|
+
Duration.new parse_duration(duration)
|
102
|
+
else
|
103
|
+
raise ArgumentError, "Unsupported duration type: #{duration.inspect} of class #{duration.class}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
class Range
|
113
|
+
[:seconds, :minutes, :hours, :days, :weeks, :months, :years].each do |unit|
|
114
|
+
define_method unit do |type = :duration|
|
115
|
+
timerange = Range.new self.min.send(unit), self.max.send(unit)
|
116
|
+
type == :timespan ? TimespanRange.new(timerange, unit) : DurationRange.new(timerange, unit)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'timespan/core_ext/range'
|
@@ -1,6 +1,14 @@
|
|
1
|
+
require 'origin-selectable_ext'
|
2
|
+
require 'timespan/core_ext/hash'
|
3
|
+
|
1
4
|
class Timespan
|
2
5
|
Serializer = Mongoid::Fields::Timespan
|
3
6
|
|
7
|
+
def __evolve_to_timespan__
|
8
|
+
self
|
9
|
+
end
|
10
|
+
|
11
|
+
|
4
12
|
# See http://mongoid.org/en/mongoid/docs/upgrading.html
|
5
13
|
|
6
14
|
# Serialize a Timespan or a Hash (with Timespan units) or a Duration in some form to
|
@@ -9,7 +17,7 @@ class Timespan
|
|
9
17
|
# @param [Timespan, Hash, Integer, String] value
|
10
18
|
# @return [Hash] Timespan in seconds
|
11
19
|
def mongoize
|
12
|
-
{:from => Serializer.serialize_time(start_time), :to => Serializer.serialize_time(end_time), :duration => duration.total }
|
20
|
+
{:from => Serializer.serialize_time(start_time), :to => Serializer.serialize_time(end_time), :duration => duration.total, :asap => asap? }
|
13
21
|
end
|
14
22
|
|
15
23
|
class << self
|
@@ -38,7 +46,7 @@ class Timespan
|
|
38
46
|
return if !object
|
39
47
|
case object
|
40
48
|
when Hash
|
41
|
-
|
49
|
+
object.__evolve_to_timespan__
|
42
50
|
else
|
43
51
|
::Timespan.new object
|
44
52
|
end
|
@@ -47,10 +55,43 @@ class Timespan
|
|
47
55
|
# Converts the object that was supplied to a criteria and converts it
|
48
56
|
# into a database friendly form.
|
49
57
|
def evolve(object)
|
50
|
-
|
51
|
-
|
52
|
-
|
58
|
+
object.__evolve_to_timespan__.mongoize
|
59
|
+
end
|
60
|
+
|
61
|
+
def custom_serialization?(operator)
|
62
|
+
return false unless operator
|
63
|
+
case operator
|
64
|
+
when '$gte', '$gt', '$lt', '$lte', '$eq', '$between', '$btw'
|
65
|
+
true
|
66
|
+
else
|
67
|
+
false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def custom_specify(name, operator, value, options = {})
|
72
|
+
puts "custom_specify: #{name}"
|
73
|
+
timespan = value.__evolve_to_timespan__
|
74
|
+
case operator
|
75
|
+
when '$gte', '$gt', '$lt', '$lte', '$eq', '$between', '$btw'
|
76
|
+
specify_with_asap(name, operator, timespan, options)
|
77
|
+
else
|
78
|
+
raise RuntimeError, "Unsupported operator"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def specify_with_asap(name, operator, timespan, options)
|
83
|
+
query = { 'from' => {}, 'to' => {} }
|
84
|
+
case operator
|
85
|
+
when '$gte', '$gt'
|
86
|
+
query['from'][operator] = Serializer.serialize_time(timespan.min)
|
87
|
+
when '$lte', '$lt', '$eq'
|
88
|
+
query['to'][operator] = Serializer.serialize_time(timespan.min)
|
89
|
+
when '$between', '$btw'
|
90
|
+
query['from']['$gte'] = Serializer.serialize_time(timespan.min)
|
91
|
+
query['to']['$lte'] = Serializer.serialize_time(timespan.max)
|
53
92
|
end
|
93
|
+
puts "query: #{query}"
|
94
|
+
query
|
54
95
|
end
|
55
96
|
end
|
56
97
|
end
|
data/lib/timespan/mongoid.rb
CHANGED
@@ -39,6 +39,12 @@ module Mongoid
|
|
39
39
|
deserialize_time to_value
|
40
40
|
end
|
41
41
|
|
42
|
+
def asap hash
|
43
|
+
asap_value = hash['asap'] || hash[:asap]
|
44
|
+
raise ArgumentError, ":asap is nil, #{hash.inspect}" if ![true, false, nil].include? asap_value
|
45
|
+
asap_value
|
46
|
+
end
|
47
|
+
|
42
48
|
def serialize_time time
|
43
49
|
raise ArgumentError, "Can't serialize time from nil" if time.nil?
|
44
50
|
time.to_i
|
data/lib/timespan.rb
CHANGED
@@ -3,6 +3,13 @@ require 'chronic'
|
|
3
3
|
require 'chronic_duration'
|
4
4
|
require 'spanner'
|
5
5
|
|
6
|
+
# Range intersection that works with dates!
|
7
|
+
require 'sugar-high/range'
|
8
|
+
require 'sugar-high/delegate'
|
9
|
+
require 'sugar-high/kind_of'
|
10
|
+
|
11
|
+
require 'timespan/core_ext'
|
12
|
+
|
6
13
|
require 'timespan/units'
|
7
14
|
require 'timespan/compare'
|
8
15
|
require 'timespan/printer'
|
@@ -44,7 +51,6 @@ class Timespan
|
|
44
51
|
|
45
52
|
def initialize options = {}
|
46
53
|
@is_new = true
|
47
|
-
|
48
54
|
@init_options = options
|
49
55
|
validate! if options == {}
|
50
56
|
|
@@ -60,41 +66,70 @@ class Timespan
|
|
60
66
|
@is_new = false
|
61
67
|
end
|
62
68
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
Time.now
|
67
|
-
when :today
|
68
|
-
Date.today
|
69
|
-
when :tomorrow
|
70
|
-
Date.today + 1.day
|
71
|
-
when :next_week # requires active_support
|
72
|
-
date = Date.today.next_week
|
73
|
-
options[:start] ? date.beginning_of_week : date
|
74
|
-
when :next_month
|
75
|
-
date = Date.today.next_month
|
76
|
-
options[:start] ? date.at_beginning_of_month.next_month : date
|
77
|
-
else
|
78
|
-
start
|
69
|
+
class << self
|
70
|
+
def max_date
|
71
|
+
@max_date ||= Time.now + 10.years
|
79
72
|
end
|
80
73
|
|
81
|
-
|
82
|
-
|
74
|
+
def min_date
|
75
|
+
@min_date ||= Time.now
|
76
|
+
end
|
83
77
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
options
|
94
|
-
|
95
|
-
|
78
|
+
def max_date= date
|
79
|
+
@max_date = date if valid_date?(date)
|
80
|
+
end
|
81
|
+
|
82
|
+
def min_date= date
|
83
|
+
@max_date = date if valid_date?(date)
|
84
|
+
end
|
85
|
+
|
86
|
+
def asap options = {}
|
87
|
+
self.new options.merge(asap: true)
|
88
|
+
end
|
89
|
+
|
90
|
+
def from start, duration, options = {}
|
91
|
+
start = case start.to_sym
|
92
|
+
when :now, :asap
|
93
|
+
Time.now
|
94
|
+
when :today
|
95
|
+
Date.today
|
96
|
+
when :tomorrow
|
97
|
+
Date.today + 1.day
|
98
|
+
when :next_week # requires active_support
|
99
|
+
date = Date.today.next_week
|
100
|
+
options[:start] ? date.beginning_of_week : date
|
101
|
+
when :next_month
|
102
|
+
date = Date.today.next_month
|
103
|
+
options[:start] ? date.at_beginning_of_month.next_month : date
|
104
|
+
else
|
105
|
+
start
|
106
|
+
end
|
107
|
+
|
108
|
+
self.new start_date: start, duration: duration
|
109
|
+
end
|
110
|
+
|
111
|
+
def untill ending
|
112
|
+
ending = case ending.to_sym
|
113
|
+
when :tomorrow
|
114
|
+
Date.today + 1.day
|
115
|
+
when :next_week # requires active_support
|
116
|
+
date = Date.today.next_week
|
117
|
+
options[:start] ? date.beginning_of_week : date
|
118
|
+
when :next_month
|
119
|
+
date = Date.today.next_month
|
120
|
+
options[:start] ? date.at_beginning_of_month.next_month : date
|
121
|
+
else
|
122
|
+
ending
|
123
|
+
end
|
124
|
+
self.new start_date: Date.now, end_date: ending
|
125
|
+
end
|
126
|
+
alias_method :until, :untill
|
127
|
+
|
128
|
+
protected
|
129
|
+
|
130
|
+
def valid_date? date
|
131
|
+
date.any_kind_of?(Date, Time, DateTime)
|
96
132
|
end
|
97
|
-
self.new start_date: Date.now, end_date: ending
|
98
133
|
end
|
99
134
|
|
100
135
|
def start_time= time
|
@@ -122,21 +157,37 @@ class Timespan
|
|
122
157
|
end
|
123
158
|
alias_method :end_date=, :end_time=
|
124
159
|
|
125
|
-
def
|
160
|
+
def asap?
|
161
|
+
@asap
|
162
|
+
end
|
163
|
+
|
164
|
+
def min
|
165
|
+
asap ? Time.now : start_time
|
166
|
+
end
|
167
|
+
|
168
|
+
def max
|
169
|
+
end_time
|
170
|
+
end
|
171
|
+
|
172
|
+
def untill time
|
126
173
|
self.end_time = time
|
127
174
|
self
|
128
175
|
end
|
176
|
+
alias_method :until, :untill
|
129
177
|
|
130
178
|
def convert_to_time time
|
179
|
+
time = Duration.new time if time.kind_of? Numeric
|
131
180
|
case time
|
132
181
|
when String
|
133
182
|
Chronic.parse(time)
|
134
183
|
when Date, DateTime
|
135
184
|
time.to_time
|
185
|
+
when Duration
|
186
|
+
(Time.now + time).to_time
|
136
187
|
when Time
|
137
188
|
time
|
138
189
|
else
|
139
|
-
raise ArgumentError, "A valid time must be either a String, Date, Time or DateTime, was: #{time.inspect}"
|
190
|
+
raise ArgumentError, "A valid time must be either a String, Duration, Date, Time or DateTime, was: #{time.inspect} (#{time.class})"
|
140
191
|
end
|
141
192
|
end
|
142
193
|
|
@@ -153,18 +204,40 @@ class Timespan
|
|
153
204
|
from = options[first_from(START_KEYS, options)]
|
154
205
|
to = options[first_from(END_KEYS, options)]
|
155
206
|
dur = options[first_from(DURATION_KEYS, options)]
|
207
|
+
asap = options[:asap]
|
208
|
+
|
209
|
+
if options[:at_least]
|
210
|
+
to = Timespan.max_date
|
211
|
+
from = Time.now + options[:at_least]
|
212
|
+
end
|
213
|
+
|
214
|
+
if options[:at_most]
|
215
|
+
to = Time.now + options[:at_most]
|
216
|
+
from = Time.now
|
217
|
+
end
|
218
|
+
|
219
|
+
if options[:between]
|
220
|
+
from = Time.now + options[:between].min
|
221
|
+
to = Time.now + options[:between].max
|
222
|
+
end
|
223
|
+
|
224
|
+
# puts "configure: to:#{to}, from:#{from}, dur:#{dur}, asap:#{asap}"
|
156
225
|
|
226
|
+
@asap = asap if asap
|
157
227
|
self.duration = dur if dur
|
158
228
|
self.start_time = from if from
|
159
229
|
self.end_time = to if to
|
160
230
|
|
231
|
+
# puts "configured: start:#{self.start_time}, end:#{self.end_time}, duration:#{self.duration}, asap:#{self.asap?}"
|
232
|
+
|
161
233
|
default_from_now!
|
162
234
|
calculate_miss!
|
163
235
|
rescue ArgumentError => e
|
164
236
|
raise TimeParseError, e.message
|
165
|
-
rescue Exception => e
|
166
|
-
|
167
|
-
|
237
|
+
# rescue Exception => e
|
238
|
+
# puts "Exception: #{e}"
|
239
|
+
# calculate_miss!
|
240
|
+
# validate!
|
168
241
|
end
|
169
242
|
|
170
243
|
def default_from_now!
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'timespan/mongoid/spec_helper'
|
2
|
+
|
3
|
+
describe Range do
|
4
|
+
subject { timerange }
|
5
|
+
|
6
|
+
describe 'create DurationRange' do
|
7
|
+
let(:range) { (1..5) }
|
8
|
+
let (:timerange) { range.days }
|
9
|
+
|
10
|
+
specify { subject.should be_a DurationRange }
|
11
|
+
|
12
|
+
its(:min) { should be_a Fixnum }
|
13
|
+
its(:max) { should be_a Fixnum }
|
14
|
+
|
15
|
+
specify { subject.min.should == 1.day }
|
16
|
+
specify { subject.max.should == 5.days }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe DurationRange do
|
21
|
+
subject { timerange }
|
22
|
+
|
23
|
+
let(:range) { (1..5) }
|
24
|
+
|
25
|
+
context 'day range' do
|
26
|
+
let (:timerange) { range.days }
|
27
|
+
|
28
|
+
its(:range) { should be_a Range }
|
29
|
+
its(:min) { should == 1.day }
|
30
|
+
its(:max) { should == 5.days }
|
31
|
+
its(:unit) { should == :day }
|
32
|
+
|
33
|
+
specify { subject.between?(4.days).should be_true }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'week range' do
|
37
|
+
let (:timerange) { range.weeks }
|
38
|
+
|
39
|
+
its(:range) { should be_a Range }
|
40
|
+
its(:min) { should == 1.week }
|
41
|
+
its(:max) { should == 5.weeks }
|
42
|
+
its(:unit) { should == :week }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'month range' do
|
46
|
+
let (:timerange) { range.months }
|
47
|
+
|
48
|
+
its(:min) { should == 1.month }
|
49
|
+
its(:max) { should == 5.months }
|
50
|
+
its(:unit) { should == :month }
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'year range' do
|
54
|
+
let (:timerange) { range.years }
|
55
|
+
|
56
|
+
its(:min) { should == 1.year }
|
57
|
+
its(:max) { should == 5.years }
|
58
|
+
its(:unit) { should == :year }
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'timespan/mongoid/spec_helper'
|
2
|
+
|
3
|
+
describe Range do
|
4
|
+
subject { timerange }
|
5
|
+
|
6
|
+
let(:range) { (1..5) }
|
7
|
+
|
8
|
+
describe 'create TimespanRange' do
|
9
|
+
|
10
|
+
let (:timerange) { range.months(:timespan) }
|
11
|
+
|
12
|
+
specify { subject.should be_a TimespanRange }
|
13
|
+
its(:range) { should be_a Timespan }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe TimespanRange do
|
18
|
+
subject { timerange }
|
19
|
+
|
20
|
+
let(:range) { (1..5) }
|
21
|
+
|
22
|
+
context 'day range' do
|
23
|
+
let (:timerange) { range.days(:timespan) }
|
24
|
+
|
25
|
+
its(:range) { should be_a Timespan }
|
26
|
+
its(:min) { should == 1.day }
|
27
|
+
its(:max) { should == 5.days }
|
28
|
+
its(:unit) { should == :day }
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'week range' do
|
32
|
+
let (:timerange) { range.weeks(:timespan) }
|
33
|
+
|
34
|
+
its(:range) { should be_a Timespan }
|
35
|
+
its(:min) { should == 1.week }
|
36
|
+
its(:max) { should == 5.weeks }
|
37
|
+
its(:unit) { should == :week }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'month range' do
|
41
|
+
let (:timerange) { range.months(:timespan) }
|
42
|
+
|
43
|
+
its(:range) { should be_a Timespan }
|
44
|
+
its(:min) { should == 1.month }
|
45
|
+
its(:max) { should == 5.months }
|
46
|
+
its(:unit) { should == :month }
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'year range' do
|
50
|
+
let (:timerange) { range.years(:timespan) }
|
51
|
+
|
52
|
+
its(:range) { should be_a Timespan }
|
53
|
+
its(:min) { should == 1.year }
|
54
|
+
its(:max) { should == 5.years }
|
55
|
+
its(:unit) { should == :year }
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,216 @@
|
|
1
|
+
require 'timespan/mongoid/spec_helper'
|
2
|
+
|
3
|
+
describe TimeSpan do
|
4
|
+
subject { account }
|
5
|
+
|
6
|
+
before :all do
|
7
|
+
# Mongoid.logger.level = Logger::DEBUG
|
8
|
+
# Moped.logger.level = Logger::DEBUG
|
9
|
+
# Mongoid.logger = Logger.new($stdout)
|
10
|
+
# Moped.logger = Logger.new($stdout)
|
11
|
+
end
|
12
|
+
|
13
|
+
def max_asap
|
14
|
+
10.days.from_now.to_i
|
15
|
+
end
|
16
|
+
|
17
|
+
context '10 Accounts with period and duration-range' do
|
18
|
+
|
19
|
+
# TODO:
|
20
|
+
# Doesn't handle dynamic ASAP as attempted
|
21
|
+
# implemented via custom_specify
|
22
|
+
|
23
|
+
before do
|
24
|
+
Account.delete_all
|
25
|
+
|
26
|
+
@acc1 = Account.create name: '1', period: Timespan.from(:today, 5.days),
|
27
|
+
time_period: TimePeriod.new(flex: (2..5).minutes)
|
28
|
+
|
29
|
+
@acc2 = Account.create name: '2', period: Timespan.from(:today, 5.days),
|
30
|
+
time_period: TimePeriod.new(flex: (2..4).minutes)
|
31
|
+
|
32
|
+
@acc3 = Account.create name: '3', period: Timespan.from(:today, 5.days),
|
33
|
+
time_period: TimePeriod.new(flex: (0..4).minutes)
|
34
|
+
|
35
|
+
@acc4 = Account.create name: '4', period: Timespan.from(:today, 5.days),
|
36
|
+
time_period: TimePeriod.new(flex: (0..3).minutes)
|
37
|
+
|
38
|
+
@acc5 = Account.create name: '5', period: Timespan.from(:today, 5.days),
|
39
|
+
time_period: TimePeriod.new(flex: (0..2).minutes)
|
40
|
+
|
41
|
+
@acc6 = Account.create name: '6', period: Timespan.from(:next_month, 100.days),
|
42
|
+
time_period: TimePeriod.new(flex: (0..2).minutes)
|
43
|
+
|
44
|
+
@acc7 = Account.create name: '7', period: Timespan.from(:next_week, 100.days),
|
45
|
+
time_period: TimePeriod.new(flex: (0..2).minutes)
|
46
|
+
|
47
|
+
@acc8 = Account.create name: '8', period: Timespan.new(start_date: 9.days.from_now, duration: 100.days),
|
48
|
+
time_period: TimePeriod.new(flex: (5..10).minutes)
|
49
|
+
|
50
|
+
@acc9 = Account.create name: '9', period: Timespan.new(start_date: 40.days.from_now, duration: 100.days),
|
51
|
+
time_period: TimePeriod.new(flex: (0..3).minutes)
|
52
|
+
|
53
|
+
@acc8 = Account.create name: '10', period: Timespan.new(start_date: 1.week.from_now, duration: 100.days),
|
54
|
+
time_period: TimePeriod.new(flex: (3..6).minutes)
|
55
|
+
end
|
56
|
+
|
57
|
+
def yesterday
|
58
|
+
1.day.ago.to_i
|
59
|
+
end
|
60
|
+
|
61
|
+
def where_hash
|
62
|
+
{:'period.from'.gte => yesterday, :'period.from'.lte => max_asap}
|
63
|
+
end
|
64
|
+
|
65
|
+
def exactly
|
66
|
+
[{:'time_period.flex.from' => period}, {:'time_period.flex.to' => period}]
|
67
|
+
end
|
68
|
+
|
69
|
+
def in_between
|
70
|
+
[{:'time_period.flex.from' => min_period}, {:'time_period.flex.to' => max_period}]
|
71
|
+
end
|
72
|
+
|
73
|
+
def at_least type = :min
|
74
|
+
{:'time_period.flex.to'.gte => send("#{type}_period") }
|
75
|
+
end
|
76
|
+
|
77
|
+
def at_most type = :max
|
78
|
+
{:'time_period.flex.to'.lte => send("#{type}_period") }
|
79
|
+
end
|
80
|
+
|
81
|
+
describe 'ASAP 2 minutes' do
|
82
|
+
let(:period) { 2.minutes.to_i }
|
83
|
+
|
84
|
+
let(:criteria) do
|
85
|
+
Account.where(where_hash).or(exactly)
|
86
|
+
end
|
87
|
+
|
88
|
+
# it 'should have a nice criteria' do
|
89
|
+
# criteria.selector['$or'].should == [{"time_period.flex.from"=>120}, {"time_period.flex.to"=>120}]
|
90
|
+
# criteria.selector["period.from"].should be_a Hash
|
91
|
+
# end
|
92
|
+
|
93
|
+
it 'should find #1, #2, #3, #4, #5' do
|
94
|
+
criteria.to_a.map(&:name).should include '1', '2', '5', '7'
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:time_period) { criteria.first.time_period }
|
98
|
+
|
99
|
+
specify do
|
100
|
+
time_period.flex.should be_a DurationRange
|
101
|
+
time_period.flex.min.should == 2.minutes
|
102
|
+
time_period.flex.max.should == 5.minutes
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe 'ASAP 3 minutes' do
|
107
|
+
let(:period) { 3.minutes.to_i }
|
108
|
+
|
109
|
+
let(:criteria) do
|
110
|
+
Account.where(where_hash).or(exactly)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'should find #4, #10' do
|
114
|
+
# puts criteria.to_a.map(&:name)
|
115
|
+
criteria.to_a.map(&:name).should include '4', '10'
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe 'ASAP 4 minutes' do
|
120
|
+
let(:period) { 4.minutes.to_i }
|
121
|
+
|
122
|
+
let(:criteria) do
|
123
|
+
Account.where(where_hash).or(exactly)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should find #2, #3' do
|
127
|
+
criteria.to_a.should include(@acc2, @acc3)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'ASAP 1-4 minutes' do
|
132
|
+
let(:min_period) { 1.minute }
|
133
|
+
let(:max_period) { 4.minutes }
|
134
|
+
|
135
|
+
let(:criteria) do
|
136
|
+
Account.where(where_hash).or(in_between)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should find #2, #3' do
|
140
|
+
# puts "ASAP 1-4 minutes"
|
141
|
+
# puts criteria.selector
|
142
|
+
# puts criteria.to_a.map(&:name)
|
143
|
+
criteria.to_a.map(&:name).should_not include('8', '9')
|
144
|
+
criteria.to_a.map(&:name).should include('2', '3')
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'ASAP 3-5 minutes' do
|
149
|
+
let(:min_period) { 3.minutes }
|
150
|
+
let(:max_period) { 5.minutes }
|
151
|
+
|
152
|
+
it 'should have a nice criteria' do
|
153
|
+
# puts "ASAP 3-5 minutes"
|
154
|
+
# puts criteria.selector
|
155
|
+
criteria.selector["time_period.flex.from"] = 180
|
156
|
+
criteria.selector["time_period.flex.to"] = 300
|
157
|
+
criteria.selector["period.from"].should be_a Hash
|
158
|
+
end
|
159
|
+
|
160
|
+
let(:criteria) do
|
161
|
+
Account.where(where_hash).or(in_between)
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should find #2, #3' do
|
165
|
+
# puts criteria.to_a.map(&:name)
|
166
|
+
criteria.to_a.map(&:name).should_not include('8', '9')
|
167
|
+
criteria.to_a.map(&:name).should include('10')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe 'ASAP 5-7 minutes' do
|
172
|
+
let(:min_period) { 5.minutes }
|
173
|
+
let(:max_period) { 7.minutes }
|
174
|
+
|
175
|
+
let(:criteria) do
|
176
|
+
Account.where(where_hash).or(in_between)
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should find #2, #3' do
|
180
|
+
# puts criteria.to_a.map(&:name)
|
181
|
+
criteria.to_a.map(&:name).should_not include('6', '9', '10')
|
182
|
+
criteria.to_a.map(&:name).should include('8')
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe 'ASAP at least 4 minutes' do
|
187
|
+
let(:min_period) { 4.minutes }
|
188
|
+
|
189
|
+
let(:criteria) do
|
190
|
+
Account.where where_hash.merge(at_least)
|
191
|
+
end
|
192
|
+
|
193
|
+
it 'should find #2, #3' do
|
194
|
+
# puts criteria.selector
|
195
|
+
# puts criteria.to_a.map(&:name)
|
196
|
+
criteria.to_a.map(&:name).should_not include '9'
|
197
|
+
criteria.to_a.map(&:name).should include '1', '2', '3', '8', '10'
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
describe 'ASAP at most 3 minutes' do
|
202
|
+
let(:max_period) { 3.minutes }
|
203
|
+
|
204
|
+
let(:criteria) do
|
205
|
+
Account.where where_hash.merge(at_most)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should find #2, #3' do
|
209
|
+
# puts criteria.selector
|
210
|
+
# puts criteria.to_a.map(&:name)
|
211
|
+
criteria.to_a.map(&:name).should_not include '8', '9', '10'
|
212
|
+
criteria.to_a.map(&:name).should include '4', '5', '7'
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
end
|
@@ -4,12 +4,15 @@ class Account
|
|
4
4
|
include Mongoid::Document
|
5
5
|
include Mongoid::Timespanned
|
6
6
|
|
7
|
+
field :name
|
7
8
|
field :period, :type => ::Timespan, :between => true
|
8
9
|
|
9
10
|
timespan_methods :period
|
10
11
|
|
11
12
|
embeds_one :time_period
|
12
|
-
|
13
|
+
|
14
|
+
timespan_container_delegates :time_period, :dates, :all
|
15
|
+
timespan_container_delegates :time_period, :flex, :all
|
13
16
|
|
14
17
|
def self.create_it! duration
|
15
18
|
acc = self.new period: ::Timespan.new(duration: duration), time_period: ::TimePeriod.new
|
@@ -17,6 +20,12 @@ class Account
|
|
17
20
|
acc
|
18
21
|
end
|
19
22
|
|
23
|
+
# def to_s
|
24
|
+
# %Q{
|
25
|
+
# name: #{name}
|
26
|
+
# }
|
27
|
+
# end
|
28
|
+
|
20
29
|
def self.between from, to
|
21
30
|
Account.where(:'period.from'.gt => from.to_i, :'period.to'.lte => to.to_i)
|
22
31
|
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.4.
|
8
|
+
s.version = "0.4.9"
|
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-09-
|
12
|
+
s.date = "2012-09-25"
|
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 = [
|
@@ -28,6 +28,9 @@ Gem::Specification.new do |s|
|
|
28
28
|
"config/locales/timespan/da.yml",
|
29
29
|
"lib/timespan.rb",
|
30
30
|
"lib/timespan/compare.rb",
|
31
|
+
"lib/timespan/core_ext.rb",
|
32
|
+
"lib/timespan/core_ext/hash.rb",
|
33
|
+
"lib/timespan/core_ext/range.rb",
|
31
34
|
"lib/timespan/mongoid.rb",
|
32
35
|
"lib/timespan/mongoid/mongoid_2x.rb",
|
33
36
|
"lib/timespan/mongoid/mongoid_3x.rb",
|
@@ -38,8 +41,11 @@ Gem::Specification.new do |s|
|
|
38
41
|
"lib/timespan/units.rb",
|
39
42
|
"spec/spec_helper.rb",
|
40
43
|
"spec/timespan/compare_spec.rb",
|
44
|
+
"spec/timespan/core_ext/duration_range_spec.rb",
|
45
|
+
"spec/timespan/core_ext/timespan_range_spec.rb",
|
41
46
|
"spec/timespan/duration_macros_spec.rb",
|
42
47
|
"spec/timespan/locales/duration_da.yml",
|
48
|
+
"spec/timespan/mongoid/advanced_search_spec.rb",
|
43
49
|
"spec/timespan/mongoid/models/account_2x.rb",
|
44
50
|
"spec/timespan/mongoid/models/account_3x.rb",
|
45
51
|
"spec/timespan/mongoid/models/time_period.rb",
|
@@ -70,10 +76,12 @@ Gem::Specification.new do |s|
|
|
70
76
|
s.add_runtime_dependency(%q<chronic_duration>, [">= 0"])
|
71
77
|
s.add_runtime_dependency(%q<activesupport>, [">= 3.0.0"])
|
72
78
|
s.add_runtime_dependency(%q<spanner>, [">= 0"])
|
79
|
+
s.add_runtime_dependency(%q<sugar-high>, ["~> 0.7.2"])
|
73
80
|
s.add_runtime_dependency(%q<xduration>, ["~> 2.2"])
|
74
81
|
s.add_development_dependency(%q<rspec>, [">= 2.8.0"])
|
75
82
|
s.add_development_dependency(%q<rails>, ["~> 3.2.7"])
|
76
|
-
s.add_development_dependency(%q<mongoid>, ["~> 3.0
|
83
|
+
s.add_development_dependency(%q<mongoid>, ["~> 3.0"])
|
84
|
+
s.add_development_dependency(%q<origin-selectable_ext>, ["~> 0.1.1"])
|
77
85
|
s.add_development_dependency(%q<rdoc>, [">= 3.12"])
|
78
86
|
s.add_development_dependency(%q<bundler>, [">= 1.0.0"])
|
79
87
|
s.add_development_dependency(%q<jeweler>, [">= 1.8.3"])
|
@@ -83,10 +91,12 @@ Gem::Specification.new do |s|
|
|
83
91
|
s.add_dependency(%q<chronic_duration>, [">= 0"])
|
84
92
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
85
93
|
s.add_dependency(%q<spanner>, [">= 0"])
|
94
|
+
s.add_dependency(%q<sugar-high>, ["~> 0.7.2"])
|
86
95
|
s.add_dependency(%q<xduration>, ["~> 2.2"])
|
87
96
|
s.add_dependency(%q<rspec>, [">= 2.8.0"])
|
88
97
|
s.add_dependency(%q<rails>, ["~> 3.2.7"])
|
89
|
-
s.add_dependency(%q<mongoid>, ["~> 3.0
|
98
|
+
s.add_dependency(%q<mongoid>, ["~> 3.0"])
|
99
|
+
s.add_dependency(%q<origin-selectable_ext>, ["~> 0.1.1"])
|
90
100
|
s.add_dependency(%q<rdoc>, [">= 3.12"])
|
91
101
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
92
102
|
s.add_dependency(%q<jeweler>, [">= 1.8.3"])
|
@@ -97,10 +107,12 @@ Gem::Specification.new do |s|
|
|
97
107
|
s.add_dependency(%q<chronic_duration>, [">= 0"])
|
98
108
|
s.add_dependency(%q<activesupport>, [">= 3.0.0"])
|
99
109
|
s.add_dependency(%q<spanner>, [">= 0"])
|
110
|
+
s.add_dependency(%q<sugar-high>, ["~> 0.7.2"])
|
100
111
|
s.add_dependency(%q<xduration>, ["~> 2.2"])
|
101
112
|
s.add_dependency(%q<rspec>, [">= 2.8.0"])
|
102
113
|
s.add_dependency(%q<rails>, ["~> 3.2.7"])
|
103
|
-
s.add_dependency(%q<mongoid>, ["~> 3.0
|
114
|
+
s.add_dependency(%q<mongoid>, ["~> 3.0"])
|
115
|
+
s.add_dependency(%q<origin-selectable_ext>, ["~> 0.1.1"])
|
104
116
|
s.add_dependency(%q<rdoc>, [">= 3.12"])
|
105
117
|
s.add_dependency(%q<bundler>, [">= 1.0.0"])
|
106
118
|
s.add_dependency(%q<jeweler>, [">= 1.8.3"])
|
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.
|
4
|
+
version: 0.4.9
|
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-09-
|
12
|
+
date: 2012-09-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chronic
|
@@ -75,6 +75,22 @@ dependencies:
|
|
75
75
|
- - ! '>='
|
76
76
|
- !ruby/object:Gem::Version
|
77
77
|
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: sugar-high
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.7.2
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.7.2
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
95
|
name: xduration
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
@@ -130,7 +146,7 @@ dependencies:
|
|
130
146
|
requirements:
|
131
147
|
- - ~>
|
132
148
|
- !ruby/object:Gem::Version
|
133
|
-
version: 3.0
|
149
|
+
version: '3.0'
|
134
150
|
type: :development
|
135
151
|
prerelease: false
|
136
152
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -138,7 +154,23 @@ dependencies:
|
|
138
154
|
requirements:
|
139
155
|
- - ~>
|
140
156
|
- !ruby/object:Gem::Version
|
141
|
-
version: 3.0
|
157
|
+
version: '3.0'
|
158
|
+
- !ruby/object:Gem::Dependency
|
159
|
+
name: origin-selectable_ext
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
161
|
+
none: false
|
162
|
+
requirements:
|
163
|
+
- - ~>
|
164
|
+
- !ruby/object:Gem::Version
|
165
|
+
version: 0.1.1
|
166
|
+
type: :development
|
167
|
+
prerelease: false
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - ~>
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 0.1.1
|
142
174
|
- !ruby/object:Gem::Dependency
|
143
175
|
name: rdoc
|
144
176
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,6 +254,9 @@ files:
|
|
222
254
|
- config/locales/timespan/da.yml
|
223
255
|
- lib/timespan.rb
|
224
256
|
- lib/timespan/compare.rb
|
257
|
+
- lib/timespan/core_ext.rb
|
258
|
+
- lib/timespan/core_ext/hash.rb
|
259
|
+
- lib/timespan/core_ext/range.rb
|
225
260
|
- lib/timespan/mongoid.rb
|
226
261
|
- lib/timespan/mongoid/mongoid_2x.rb
|
227
262
|
- lib/timespan/mongoid/mongoid_3x.rb
|
@@ -232,8 +267,11 @@ files:
|
|
232
267
|
- lib/timespan/units.rb
|
233
268
|
- spec/spec_helper.rb
|
234
269
|
- spec/timespan/compare_spec.rb
|
270
|
+
- spec/timespan/core_ext/duration_range_spec.rb
|
271
|
+
- spec/timespan/core_ext/timespan_range_spec.rb
|
235
272
|
- spec/timespan/duration_macros_spec.rb
|
236
273
|
- spec/timespan/locales/duration_da.yml
|
274
|
+
- spec/timespan/mongoid/advanced_search_spec.rb
|
237
275
|
- spec/timespan/mongoid/models/account_2x.rb
|
238
276
|
- spec/timespan/mongoid/models/account_3x.rb
|
239
277
|
- spec/timespan/mongoid/models/time_period.rb
|
@@ -264,7 +302,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
264
302
|
version: '0'
|
265
303
|
segments:
|
266
304
|
- 0
|
267
|
-
hash: -
|
305
|
+
hash: -4405468294374256560
|
268
306
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
269
307
|
none: false
|
270
308
|
requirements:
|