ice_cube 0.8.1 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/ice_cube.rb CHANGED
@@ -13,6 +13,7 @@ module IceCube
13
13
  autoload :VERSION, 'ice_cube/version'
14
14
 
15
15
  autoload :TimeUtil, 'ice_cube/time_util'
16
+ autoload :FlexibleHash, 'ice_cube/flexible_hash'
16
17
 
17
18
  autoload :Rule, 'ice_cube/rule'
18
19
  autoload :Schedule, 'ice_cube/schedule'
@@ -0,0 +1,24 @@
1
+ require 'delegate'
2
+
3
+ module IceCube
4
+
5
+ # A way to symbolize what's necessary on the fly
6
+ # Due to the serialization format of ice_cube, this limited implementation
7
+ # is entirely sufficient
8
+
9
+ class FlexibleHash < SimpleDelegator
10
+
11
+ def initialize(hash)
12
+ @underlying = hash
13
+ end
14
+
15
+ def [](key)
16
+ case key
17
+ when String then @underlying[key] || @underlying[key.to_sym]
18
+ else @underlying[key] || @underlying[key.to_s]
19
+ end
20
+ end
21
+
22
+ end
23
+
24
+ end
data/lib/ice_cube/rule.rb CHANGED
@@ -44,7 +44,8 @@ module IceCube
44
44
  end
45
45
 
46
46
  # Convert from a hash and create a rule
47
- def self.from_hash(hash)
47
+ def self.from_hash(original_hash)
48
+ hash = IceCube::FlexibleHash.new original_hash
48
49
  return nil unless match = hash[:rule_type].match(/\:\:(.+?)Rule/)
49
50
  rule = IceCube::Rule.send(match[1].downcase.to_sym, hash[:interval] || 1)
50
51
  rule.until(TimeUtil.deserialize_time(hash[:until])) if hash[:until]
@@ -70,7 +71,7 @@ module IceCube
70
71
 
71
72
  # Whether this rule requires a full run
72
73
  def full_required?
73
- !@count.nil?
74
+ !@count.nil? || (!@interval.nil? && @interval > 1)
74
75
  end
75
76
 
76
77
  # Convenience methods for creating Rules
@@ -21,7 +21,7 @@ module IceCube
21
21
 
22
22
  # Create a new schedule
23
23
  def initialize(start_time = nil, options = {})
24
- @start_time = start_time || Time.now
24
+ @start_time = start_time || TimeUtil.now
25
25
  @end_time = options[:end_time]
26
26
  @duration = options[:duration]
27
27
  @all_recurrence_rules = []
@@ -145,17 +145,17 @@ module IceCube
145
145
  end
146
146
 
147
147
  # The next n occurrences after now
148
- def next_occurrences(num, from = Time.now)
148
+ def next_occurrences(num, from = TimeUtil.now)
149
149
  find_occurrences(from + 1, nil, num)
150
150
  end
151
151
 
152
152
  # The next occurrence after now (overridable)
153
- def next_occurrence(from = Time.now)
153
+ def next_occurrence(from = TimeUtil.now)
154
154
  find_occurrences(from + 1, nil, 1).first
155
155
  end
156
156
 
157
157
  # The remaining occurrences (same requirements as all_occurrences)
158
- def remaining_occurrences(from = Time.now)
158
+ def remaining_occurrences(from = TimeUtil.now)
159
159
  find_occurrences(from)
160
160
  end
161
161
 
@@ -170,6 +170,13 @@ module IceCube
170
170
  !find_occurrences(begin_time, closing_time, 1).empty?
171
171
  end
172
172
 
173
+ # Return a boolean indicating if an occurrence is occurring between
174
+ # two times, inclusive
175
+ def occurring_between?(begin_time, closing_time)
176
+ dur = duration || 0
177
+ occurs_between?(begin_time - dur + 1, closing_time + dur - 1)
178
+ end
179
+
173
180
  # Return a boolean indicating if an occurrence falls on a certain date
174
181
  def occurs_on?(date)
175
182
  begin_time = TimeUtil.beginning_of_date(date)
@@ -215,6 +222,7 @@ module IceCube
215
222
  # Due to durations, we need to walk up to the end time, and verify in the
216
223
  # other direction
217
224
  if last_time
225
+ last_time = terminating_schedule.duration ? last_time + terminating_schedule.duration : last_time
218
226
  other_schedule.each_occurrence do |time|
219
227
  break if time > last_time
220
228
  return true if terminating_schedule.occurring_at?(time)
@@ -243,7 +251,6 @@ module IceCube
243
251
  pieces.concat rrules.map { |t| t.to_s }
244
252
  pieces.concat exrules.map { |t| "not #{t.to_s}" }
245
253
  pieces.concat ed.sort.map { |t| "not on #{t.strftime(IceCube.to_s_time_format)}" }
246
- pieces << "until #{end_time.strftime(IceCube.to_s_time_format)}" if end_time
247
254
  pieces.join(' / ')
248
255
  end
249
256
 
@@ -274,7 +281,7 @@ module IceCube
274
281
  def to_hash
275
282
  data = {}
276
283
  data[:start_date] = TimeUtil.serialize_time(start_time)
277
- data[:end_time] = end_time if end_time
284
+ data[:end_time] = TimeUtil.serialize_time(end_time) if end_time
278
285
  data[:duration] = duration if duration
279
286
  data[:rrules] = recurrence_rules.map(&:to_hash)
280
287
  data[:exrules] = exception_rules.map(&:to_hash)
@@ -288,9 +295,10 @@ module IceCube
288
295
  end
289
296
 
290
297
  # Load the schedule from a hash
291
- def self.from_hash(data, options = {})
292
- data[:start_date] = options[:start_date_override] if options[:start_date_override]
298
+ def self.from_hash(original_hash, options = {})
299
+ original_hash[:start_date] = options[:start_date_override] if options[:start_date_override]
293
300
  # And then deserialize
301
+ data = IceCube::FlexibleHash.new(original_hash)
294
302
  schedule = IceCube::Schedule.new TimeUtil.deserialize_time(data[:start_date])
295
303
  schedule.duration = data[:duration] if data[:duration]
296
304
  schedule.end_time = TimeUtil.deserialize_time(data[:end_time]) if data[:end_time]
@@ -315,7 +323,7 @@ module IceCube
315
323
  # Determine if the schedule will end
316
324
  # @return [Boolean] true if ending, false if repeating forever
317
325
  def terminating?
318
- end_time || recurrence_rules.all?(&:terminating?)
326
+ recurrence_rules.empty? || recurrence_rules.all?(&:terminating?)
319
327
  end
320
328
 
321
329
  def self.dump(schedule)
@@ -339,10 +347,6 @@ module IceCube
339
347
  def find_occurrences(opening_time, closing_time = nil, limit = nil, &block)
340
348
  reset
341
349
  answers = []
342
- # ensure the bounds are proper
343
- if end_time
344
- closing_time = end_time unless closing_time && closing_time < end_time
345
- end
346
350
  opening_time = start_time if opening_time < start_time
347
351
  # walk up to the opening time - and off we go
348
352
  # If we have rules with counts, we need to walk from the beginning of time,
@@ -18,6 +18,11 @@ module IceCube
18
18
  :november => 11, :december => 12
19
19
  }
20
20
 
21
+ # Provides a Time.now without the usec
22
+ def self.now
23
+ Time.at Time.now.to_i
24
+ end
25
+
21
26
  # Serialize a time appropriate for storing
22
27
  def self.serialize_time(time)
23
28
  if defined?(:ActiveSupport) && const_defined?(:ActiveSupport) && time.is_a?(ActiveSupport::TimeWithZone)
@@ -39,6 +39,9 @@ module IceCube
39
39
  wrapper = TimeUtil::TimeWrapper.new(time, dst_adjust)
40
40
  wrapper.add(type, fwd)
41
41
  wrapper.clear_below(type)
42
+ if wrapper.to_time == time
43
+ wrapper.add(:sec, wrapper.to_time.utc_offset * 2)
44
+ end
42
45
  time = wrapper.to_time
43
46
  end
44
47
  false
@@ -93,7 +96,11 @@ module IceCube
93
96
 
94
97
  # Fully replace validations
95
98
  def replace_validations_for(key, arr)
96
- @validations[key] = arr
99
+ if arr.nil?
100
+ @validations.delete(key)
101
+ else
102
+ @validations[key] = arr
103
+ end
97
104
  end
98
105
 
99
106
  # Remove the specified base validations
@@ -4,6 +4,7 @@ module IceCube
4
4
 
5
5
  # Add a new interval validation
6
6
  def interval(interval)
7
+ @interval = interval
7
8
  validations_for(:interval) << Validation.new(interval)
8
9
  clobber_base_validations(:wday, :day)
9
10
  self
@@ -3,6 +3,7 @@ module IceCube
3
3
  module Validations::HourlyInterval
4
4
 
5
5
  def interval(interval)
6
+ @interval = interval
6
7
  validations_for(:interval) << Validation.new(interval)
7
8
  clobber_base_validations(:hour)
8
9
  self
@@ -3,6 +3,7 @@ module IceCube
3
3
  module Validations::MinutelyInterval
4
4
 
5
5
  def interval(interval)
6
+ @interval = interval
6
7
  validations_for(:interval) << Validation.new(interval)
7
8
  clobber_base_validations(:min)
8
9
  self
@@ -3,6 +3,7 @@ module IceCube
3
3
  module Validations::MonthlyInterval
4
4
 
5
5
  def interval(interval = 1)
6
+ @interval = interval
6
7
  validations_for(:interval) << Validation.new(interval)
7
8
  clobber_base_validations(:month)
8
9
  self
@@ -3,6 +3,7 @@ module IceCube
3
3
  module Validations::SecondlyInterval
4
4
 
5
5
  def interval(interval)
6
+ @interval = interval
6
7
  validations_for(:interval) << Validation.new(interval)
7
8
  clobber_base_validations(:sec)
8
9
  self
@@ -41,11 +41,11 @@ module IceCube
41
41
  end
42
42
 
43
43
  def validate(t, schedule)
44
- raise UntilExceeded if t > time
44
+ raise UntilExceeded if t > time
45
45
  end
46
46
 
47
47
  end
48
-
48
+
49
49
  end
50
50
 
51
51
  end
@@ -5,6 +5,7 @@ module IceCube
5
5
  module Validations::WeeklyInterval
6
6
 
7
7
  def interval(interval, week_start = :sunday)
8
+ @interval = interval
8
9
  validations_for(:interval) << Validation.new(interval, week_start)
9
10
  clobber_base_validations(:day)
10
11
  self
@@ -3,6 +3,7 @@ module IceCube
3
3
  module Validations::YearlyInterval
4
4
 
5
5
  def interval(interval = 1)
6
+ @interval = interval
6
7
  validations_for(:interval) << Validation.new(interval)
7
8
  clobber_base_validations(:year)
8
9
  end
@@ -1,5 +1,5 @@
1
1
  module IceCube
2
2
 
3
- VERSION = '0.8.1'
3
+ VERSION = '0.9.0'
4
4
 
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ice_cube
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 0.9.0
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-28 00:00:00.000000000 Z
12
+ date: 2012-10-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -72,6 +72,7 @@ files:
72
72
  - lib/ice_cube/deprecated.rb
73
73
  - lib/ice_cube/errors/count_exceeded.rb
74
74
  - lib/ice_cube/errors/until_exceeded.rb
75
+ - lib/ice_cube/flexible_hash.rb
75
76
  - lib/ice_cube/rule.rb
76
77
  - lib/ice_cube/rules/daily_rule.rb
77
78
  - lib/ice_cube/rules/hourly_rule.rb