ice_cube 0.8.1 → 0.9.0

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/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