Class: Cyclical::Rule

Inherits:
Object
  • Object
show all
Defined in:
lib/cyclical/rule.rb

Overview

Rules describe the basic recurrence patterns (frequency and interval) and hold the set of rules (called filters) that a candidate date must match to be included into the recurrence set. Rules can align a date to a closest date (in the past or in the future) matching all the filters with respect to selected start date of the recurrence.

Direct Known Subclasses

DailyRule, MonthlyRule, WeeklyRule, YearlyRule

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(interval = 1) ⇒ Rule

Returns a new instance of Rule.



16
17
18
19
20
# File 'lib/cyclical/rule.rb', line 16

def initialize(interval = 1)
  @interval = interval
  @filters = []
  @filter_map = {}
end

Instance Attribute Details

#intervalObject (readonly)

Returns the value of attribute interval.



14
15
16
# File 'lib/cyclical/rule.rb', line 14

def interval
  @interval
end

Class Method Details

.daily(interval = 1) ⇒ Object



162
163
164
# File 'lib/cyclical/rule.rb', line 162

def daily(interval = 1)
  DailyRule.new(interval)
end

.from_hash(hash) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'lib/cyclical/rule.rb', line 178

def from_hash(hash)
  raise "Bad Hash format: '#{hash.inspect}'" unless hash[:freq] && hash[:interval]

  rule = self.send(hash[:freq].to_sym, hash[:interval].to_i)

  rule.count(hash[:count]) if hash.has_key?(:count)
  rule.stop(hash[:stop]) if hash.has_key?(:stop)

  rule.weekdays(*hash[:weekdays]) if hash.has_key?(:weekdays)
  rule.monthdays(*hash[:monthdays]) if hash.has_key?(:monthdays)
  rule.yeardays(*hash[:yeardays]) if hash.has_key?(:yeardays)
  rule.months(*hash[:months]) if hash.has_key?(:months)

  rule
end

.from_json(json) ⇒ Object



194
195
196
197
198
199
# File 'lib/cyclical/rule.rb', line 194

def from_json(json)
  h = JSON.parse(json)
  h['stop'] = Time.parse(h['stop']) if h['stop']

  from_hash(h.symbolize_keys)
end

.monthly(interval = 1) ⇒ Object



174
175
176
# File 'lib/cyclical/rule.rb', line 174

def monthly(interval = 1)
  MonthlyRule.new(interval)
end

.weekly(interval = 1) ⇒ Object



170
171
172
# File 'lib/cyclical/rule.rb', line 170

def weekly(interval = 1)
  WeeklyRule.new(interval)
end

.yearly(interval = 1) ⇒ Object



166
167
168
# File 'lib/cyclical/rule.rb', line 166

def yearly(interval = 1)
  YearlyRule.new(interval)
end

Instance Method Details

#aligned?(time, base) ⇒ Boolean

basic building blocks of the computations

Returns:

  • (Boolean)


133
134
135
# File 'lib/cyclical/rule.rb', line 133

def aligned?(time, base)
  # for subclass to override
end

#count(n = nil) ⇒ Object

rule specification DSL



24
25
26
27
28
29
# File 'lib/cyclical/rule.rb', line 24

def count(n = nil)
  return @count unless n

  @count = n
  self
end

#filters(kind = nil) ⇒ Object



84
85
86
87
88
# File 'lib/cyclical/rule.rb', line 84

def filters(kind = nil)
  return @filters if kind.nil?

  @filter_map[kind.to_sym]
end

#finite?Boolean

rule API

Returns:

  • (Boolean)


92
93
94
# File 'lib/cyclical/rule.rb', line 92

def finite?
  !infinite?
end

#infinite?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/cyclical/rule.rb', line 96

def infinite?
  @count.nil? && @stop.nil?
end

#match?(time, base) ⇒ Boolean

returns true if time is aligned to the recurrence pattern and matches all the filters

Returns:

  • (Boolean)


101
102
103
# File 'lib/cyclical/rule.rb', line 101

def match?(time, base)
  aligned?(time, base) && @filters.all? { |f| f.match?(time) }
end

#monthdays(*monthdays) ⇒ Object Also known as: monthday

Raises:

  • (RuntimeError)


61
62
63
64
65
66
67
68
69
# File 'lib/cyclical/rule.rb', line 61

def monthdays(*monthdays)
  raise RuntimeError, "monthdays filter already set" if @filter_map[:monthdays]

  f = MonthdaysFilter.new(*monthdays)
  @filters << f
  @filter_map[:monthdays] = f

  self
end

#months(*months) ⇒ Object Also known as: month

Raises:

  • (RuntimeError)


38
39
40
41
42
43
44
45
46
# File 'lib/cyclical/rule.rb', line 38

def months(*months)
  raise RuntimeError, "Months filter already set" if @filter_map[:month]

  f = MonthsFilter.new(*months)
  @filters << f
  @filter_map[:months] = f

  self
end

#next(time, base) ⇒ Object

get next date matching the rule (not checking limits). Returns next occurrence even if time matches the rule.



106
107
108
109
110
111
112
113
114
115
116
# File 'lib/cyclical/rule.rb', line 106

def next(time, base)
  current = time
  until match?(current, base) && current > time
    pot_next = align(potential_next(current, base), base)
    pot_next += min_step if pot_next == current

    current = pot_next
  end

  current
end

#previous(time, base) ⇒ Object

get previous date matching the rule (not checking limits). Returns next occurrence even if time matches the rule.



119
120
121
122
123
124
125
126
127
128
129
# File 'lib/cyclical/rule.rb', line 119

def previous(time, base)
  current = time
  until match?(current, base) && current < time
    pot_prev = align(potential_previous(current, base), base)
    pot_prev -= min_step if pot_prev == current

    current = pot_prev
  end

  current
end

#stepObject



137
138
139
# File 'lib/cyclical/rule.rb', line 137

def step
  # for subclass to override
end

#stop(t = nil) ⇒ Object



31
32
33
34
35
36
# File 'lib/cyclical/rule.rb', line 31

def stop(t = nil)
  return @stop unless t

  @stop = t
  self
end

#to_hashObject



141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/cyclical/rule.rb', line 141

def to_hash
  hash = { :freq => self.class.to_s.underscore.split('/').last.split('_').first, :interval => @interval }

  hash[:count] = @count if @count
  hash[:stop] = @stop if @stop

  hash[:weekdays] = (filters(:weekdays).weekdays + [filters(:weekdays).ordered_weekdays]) if filters(:weekdays)
  hash[:monthdays] = filters(:monthdays).monthdays if filters(:monthdays)
  hash[:yeardays] = filters(:yeardays).yeardays if filters(:yeardays)
  hash[:months] = filters(:months).months if filters(:months)

  hash
end

#to_jsonObject



155
156
157
# File 'lib/cyclical/rule.rb', line 155

def to_json
  to_hash.to_json
end

#weekdays(*weekdays) ⇒ Object Also known as: weekday

Raises:

  • (RuntimeError)


49
50
51
52
53
54
55
56
57
58
# File 'lib/cyclical/rule.rb', line 49

def weekdays(*weekdays)
  raise RuntimeError, "weekdays filter already set" if @filter_map[:weekdays]
  weekdays = [self] + weekdays

  f = WeekdaysFilter.new(*weekdays)
  @filters << f
  @filter_map[:weekdays] = f

  self
end

#yeardays(*yeardays) ⇒ Object Also known as: yearday

Raises:

  • (RuntimeError)


72
73
74
75
76
77
78
79
80
# File 'lib/cyclical/rule.rb', line 72

def yeardays(*yeardays)
  raise RuntimeError, "yeardays filter already set" if @filter_map[:yeardays]

  f = YeardaysFilter.new(*yeardays)
  @filters << f
  @filter_map[:yeardays] = f

  self
end