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