Class: IceCube::Schedule

Inherits:
Object
  • Object
show all
Defined in:
lib/ice_cube/schedule.rb

Constant Summary collapse

TIME_FORMAT =
'%B %e, %Y'
SEPARATOR =
' / '
NEWLINE =
"\n"

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(start_date, options = {}) ⇒ Schedule

Returns a new instance of Schedule.

Raises:

  • (ArgumentError)


8
9
10
11
12
13
14
15
16
17
18
# File 'lib/ice_cube/schedule.rb', line 8

def initialize(start_date, options = {})
  @rrule_occurrence_heads = []
  @exrule_occurrence_heads = []
  @rdates = []
  @exdates = []
  @start_date = start_date
  raise ArgumentError.new('Duration cannot be negative') if options[:duration] && options[:duration] < 0
  @duration = options[:duration]
  raise ArgumentError.new('Start time must be before end time') if options[:end_time] && options[:end_time] < @start_date
  @end_time = options[:end_time]
end

Instance Attribute Details

#durationObject (readonly)

Returns the value of attribute duration.



5
6
7
# File 'lib/ice_cube/schedule.rb', line 5

def duration
  @duration
end

#end_timeObject (readonly)

Returns the value of attribute end_time.



5
6
7
# File 'lib/ice_cube/schedule.rb', line 5

def end_time
  @end_time
end

#exdatesObject (readonly)

Returns the value of attribute exdates.



5
6
7
# File 'lib/ice_cube/schedule.rb', line 5

def exdates
  @exdates
end

#rdatesObject (readonly)

Returns the value of attribute rdates.



5
6
7
# File 'lib/ice_cube/schedule.rb', line 5

def rdates
  @rdates
end

#start_dateObject (readonly) Also known as: start_time

Returns the value of attribute start_date.



5
6
7
# File 'lib/ice_cube/schedule.rb', line 5

def start_date
  @start_date
end

Class Method Details

.from_hash(hash) ⇒ Object

Create a schedule from a hash created by instance.to_hash



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/ice_cube/schedule.rb', line 44

def self.from_hash(hash)
  options = {}
  options[:duration] = hash[:duration] if hash.has_key?(:duration)
  options[:end_time] = hash[:end_time] if hash.has_key?(:end_time)
  schedule = Schedule.new(hash[:start_date], options)
  hash[:rrules].each { |rr| schedule.add_recurrence_rule Rule.from_hash(rr) }
  hash[:exrules].each { |ex| schedule.add_exception_rule Rule.from_hash(ex) }
  hash[:rdates].each { |rd| schedule.add_recurrence_date rd }
  hash[:exdates].each { |ed| schedule.add_exception_date ed }
  schedule
end

.from_yaml(str) ⇒ Object

Create a schedule from a yaml string created by instance.to_yaml



57
58
59
# File 'lib/ice_cube/schedule.rb', line 57

def self.from_yaml(str)
  from_hash(YAML::load(str))
end

Instance Method Details

#add_exception_date(date) ⇒ Object

Add an individual date exception to this schedule



159
160
161
# File 'lib/ice_cube/schedule.rb', line 159

def add_exception_date(date)
  @exdates << date unless date.nil?
end

#add_exception_rule(rule) ⇒ Object

Add a rule of any type as an exception to this schedule

Raises:

  • (ArgumentError)


144
145
146
147
# File 'lib/ice_cube/schedule.rb', line 144

def add_exception_rule(rule)
  raise ArgumentError.new('Argument must be a valid rule') unless rule.class < Rule
  @exrule_occurrence_heads << RuleOccurrence.new(rule, @start_date, @end_time)
end

#add_recurrence_date(date) ⇒ Object

Add an individual date to this schedule



154
155
156
# File 'lib/ice_cube/schedule.rb', line 154

def add_recurrence_date(date)
  @rdates << date unless date.nil?
end

#add_recurrence_rule(rule) ⇒ Object

Add a rule of any type as an recurrence in this schedule

Raises:

  • (ArgumentError)


134
135
136
137
# File 'lib/ice_cube/schedule.rb', line 134

def add_recurrence_rule(rule)
  raise ArgumentError.new('Argument must be a valid rule') unless rule.class < Rule
  @rrule_occurrence_heads << RuleOccurrence.new(rule, @start_date, @end_time)
end

#all_occurrencesObject

Return all possible occurrences In order to make this call, all rules in the schedule must have either an until date or an occurrence count



116
117
118
# File 'lib/ice_cube/schedule.rb', line 116

def all_occurrences
  find_occurrences { |head| head.all_occurrences }
end

#exrulesObject



149
150
151
# File 'lib/ice_cube/schedule.rb', line 149

def exrules 
  @exrule_occurrence_heads.map { |h| h.rule }
end

#first(n = 1) ⇒ Object

Retrieve the first (n) occurrences of the schedule. May return less than n results, if the rules end before n results are reached.



128
129
130
131
# File 'lib/ice_cube/schedule.rb', line 128

def first(n = 1)
  dates = find_occurrences { |head| head.first(n) }
  dates.slice(0, n)
end

#occurrences(end_date) ⇒ Object

Find all occurrences until a certain date



121
122
123
124
# File 'lib/ice_cube/schedule.rb', line 121

def occurrences(end_date)
  end_date = @end_time if @end_time && @end_time < end_date
  find_occurrences { |head| head.upto(end_date) }
end

#occurrences_between(begin_time, end_time) ⇒ Object



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/ice_cube/schedule.rb', line 163

def occurrences_between(begin_time, end_time)
  # adjust to the propert end date
  end_time = @end_time if @end_time && @end_time < end_time
  # collect the occurrences
  exclude_dates, include_dates = Set.new(@exdates), SortedSet.new(@rdates)
  @rrule_occurrence_heads.each do |rrule_occurrence_head|
    include_dates.merge(rrule_occurrence_head.between(begin_time, end_time))
  end
  @exrule_occurrence_heads.each do |exrule_occurrence_head|
    exclude_dates.merge(exrule_occurrence_head.between(begin_time, end_time))
  end
  # reject all of the ones outside of the range
  include_dates.reject! { |date| exclude_dates.include?(date) || date < begin_time || date > end_time }
  include_dates.to_a
end

#occurring_at?(time) ⇒ Boolean

Returns:

  • (Boolean)


91
92
93
94
95
96
# File 'lib/ice_cube/schedule.rb', line 91

def occurring_at?(time)
  return false if @exdates.include?(time)
  return true if @rdates.include?(time)
  return false if any_occurring_at?(@exrule_occurrence_heads, time)
  any_occurring_at?(@rrule_occurrence_heads, time)
end

#occurs_at?(date) ⇒ Boolean

Determine whether a given time adheres to the ruleset of this schedule.

Returns:

  • (Boolean)


99
100
101
102
103
# File 'lib/ice_cube/schedule.rb', line 99

def occurs_at?(date)
  return false if @end_time && date > @end_time
  dates = occurrences(date)
  dates.last == date
end

#occurs_on?(date) ⇒ Boolean

Determine whether a given date appears in the times returned by the schedule Required activeSupport

Returns:

  • (Boolean)


107
108
109
110
111
# File 'lib/ice_cube/schedule.rb', line 107

def occurs_on?(date)      
  time = date.to_time
  return false if @end_time && time > @end_time
  occurrences_between(time.beginning_of_day, time.end_of_day).any?
end

#rrulesObject



139
140
141
# File 'lib/ice_cube/schedule.rb', line 139

def rrules
  @rrule_occurrence_heads.map { |h| h.rule }
end

#to_hashObject

Convert the schedule to a hash, reverse of Schedule.from_hash



21
22
23
24
25
26
27
28
29
30
31
# File 'lib/ice_cube/schedule.rb', line 21

def to_hash
  hash = Hash.new
  hash[:start_date] = @start_date
  hash[:rrules] = @rrule_occurrence_heads.map { |rr| rr.rule.to_hash }
  hash[:exrules] = @exrule_occurrence_heads.map { |ex| ex.rule.to_hash }
  hash[:rdates] = @rdates
  hash[:exdates] = @exdates
  hash[:duration] = @duration
  hash[:end_time] = @end_time
  hash
end

#to_icalObject



79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ice_cube/schedule.rb', line 79

def to_ical
  representation_pieces = ["DTSTART#{TimeUtil.ical_format(@start_date)}"]
  representation_pieces << "DURATION:#{TimeUtil.ical_duration(@duration)}" if @duration
  inc_dates = (@rdates - @exdates).uniq
  representation_pieces.concat inc_dates.sort.map { |d| "RDATE#{TimeUtil.ical_format(d)}" } if inc_dates.any?
  representation_pieces.concat @exdates.uniq.sort.map { |d| "EXDATE#{TimeUtil.ical_format(d)}" } if @exdates
  representation_pieces.concat @rrule_occurrence_heads.map { |r| "RRULE:#{r.rule.to_ical}" } if @rrule_occurrence_heads
  representation_pieces.concat @exrule_occurrence_heads.map { |r| "EXRULE:#{r.rule.to_ical}" } if @exrule_occurrence_heads
  representation_pieces << "DTEND#{TimeUtil.ical_format(@end_time)}" if @end_time
  representation_pieces.join(NEWLINE)      
end

#to_sObject

use with caution incomplete and not entirely tested - no time representation in dates there’s a lot that can happen here



68
69
70
71
72
73
74
75
76
77
# File 'lib/ice_cube/schedule.rb', line 68

def to_s
  representation_pieces = []
  inc_dates = (@rdates - @exdates).uniq
  representation_pieces.concat inc_dates.sort.map { |d| d.strftime(TIME_FORMAT) } unless inc_dates.empty?
  representation_pieces.concat @rrule_occurrence_heads.map{ |r| r.rule.to_s } if @rrule_occurrence_heads
  representation_pieces.concat @exrule_occurrence_heads.map { |r| 'not ' << r.rule.to_s } if @exrule_occurrence_heads
  representation_pieces.concat @exdates.uniq.sort.map { |d| 'not on ' << d.strftime(TIME_FORMAT) } if @exdates
  representation_pieces << "until #{end_time.strftime(TIME_FORMAT)}" if @end_time
  representation_pieces.join(SEPARATOR)
end

#to_yamlObject

Convert the schedule to yaml, reverse of Schedule.from_yaml



34
35
36
37
38
39
40
41
# File 'lib/ice_cube/schedule.rb', line 34

def to_yaml
  hash = to_hash
  hash[:start_date] = TimeUtil.serializable_time(hash[:start_date])
  hash[:rdates] = hash[:rdates].map { |t| TimeUtil.serializable_time(t) }
  hash[:exdates] = hash[:exdates].map { |t| TimeUtil.serializable_time(t) }
  hash[:end_time] = TimeUtil.serializable_time(hash[:end_time])
  hash.to_yaml
end