Class: SimplesIdeias::Recurrence

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/recurrence/event.rb,
lib/recurrence/version.rb,
lib/recurrence/namespace.rb,
lib/recurrence/event/base.rb,
lib/recurrence/event/daily.rb,
lib/recurrence/event/weekly.rb,
lib/recurrence/event/yearly.rb,
lib/recurrence/event/monthly.rb

Direct Known Subclasses

Recurrence

Defined Under Namespace

Modules: Event, Version

Constant Summary collapse

FREQUENCY =

This is the available frequency options accepted by :every option.

%w(day week month year)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options) ⇒ Recurrence

Initialize a recurrence object. All options from shortcut methods (Recurrence.daily, Recurrence.monthly, and so on) and requires the :every option to be one of these options: :day, :week, :month, or :year.

Recurrence.new(:every => :day)
Recurrence.new(:every => :week, :on => :sunday)
Recurrence.new(:every => :month, :on => 14)
Recurrence.new(:every => :year, :on => [:jan, 14])

Raises:

  • (ArgumentError)


149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/recurrence/namespace.rb', line 149

def initialize(options)
  raise ArgumentError, ":every option is required" unless options.key?(:every)
  raise ArgumentError, "invalid :every option"     unless FREQUENCY.include?(options[:every].to_s)

  @options = options
  @_options = initialize_dates(options.dup)
  @_options[:interval] ||= 1

  @event = case @_options[:every].to_sym
    when :day
      Event::Daily.new(@_options)
    when :week
      Event::Weekly.new(@_options)
    when :month
      Event::Monthly.new(@_options)
    when :year
      Event::Yearly.new(@_options)
  end
end

Instance Attribute Details

#eventObject (readonly)

Returns the value of attribute event.



16
17
18
# File 'lib/recurrence/namespace.rb', line 16

def event
  @event
end

#optionsObject (readonly)

Returns the value of attribute options.



16
17
18
# File 'lib/recurrence/namespace.rb', line 16

def options
  @options
end

Class Method Details

.as_date(date) ⇒ Object

:nodoc:



18
19
20
21
22
23
24
25
# File 'lib/recurrence/namespace.rb', line 18

def self.as_date(date) # :nodoc:
  case date
  when String
    Date.parse(date)
  else
    date
  end
end

.daily(options = {}) ⇒ Object

Create a daily recurrence.

Recurrence.daily
Recurrence.daily(:interval => 2) #=> every 2 days
Recurrence.daily(:starts => 3.days.from_now)
Recurrence.daily(:until => 10.days.from_now)
Recurrence.daily(:repeat => 5)


83
84
85
86
# File 'lib/recurrence/namespace.rb', line 83

def self.daily(options = {})
  options[:every] = :day
  new(options)
end

.default_starts_dateObject

Return the default starting date.

Recurrence.default_starts_date
#=> <Date>


32
33
34
35
36
37
38
39
40
41
# File 'lib/recurrence/namespace.rb', line 32

def self.default_starts_date
  case @default_starts_date
  when String
    eval(@default_starts_date)
  when Proc
    @default_starts_date.call
  else
    Date.today
  end
end

.default_starts_date=(date) ⇒ Object

Set the default starting date globally. Can be a proc or a string.

Recurrence.default_starts_date = proc { Date.today }
Recurrence.default_starts_date = "Date.today"


49
50
51
52
53
54
55
# File 'lib/recurrence/namespace.rb', line 49

def self.default_starts_date=(date)
  unless date.respond_to?(:call) || date.kind_of?(String) || date == nil
    raise ArgumentError, 'default_starts_date must be a proc or an evaluatable string such as "Date.current"'
  end

  @default_starts_date = date
end

.default_until_dateObject

Return the default ending date. Defaults to 2037-12-31.

Recurrence.default_until_date


61
62
63
# File 'lib/recurrence/namespace.rb', line 61

def self.default_until_date
  @default_until_date ||= Date.new(2037, 12, 31)
end

.default_until_date=(date) ⇒ Object

Set the default ending date globally. Can be a date or a string recognized by Date#parse.

Recurrence.default_until_date = "2012-12-31"
Recurrence.default_until_date = Date.tomorrow


71
72
73
# File 'lib/recurrence/namespace.rb', line 71

def self.default_until_date=(date)
  @default_until_date = as_date(date)
end

.monthly(options = {}) ⇒ Object

Create a monthly recurrence.

Recurrence.monthly(:on => 15) #=> every 15th day
Recurrence.monthly(:on => :first, :weekday => :sunday)
Recurrence.monthly(:on => :second, :weekday => :sunday)
Recurrence.monthly(:on => :third, :weekday => :sunday)
Recurrence.monthly(:on => :fourth, :weekday => :sunday)
Recurrence.monthly(:on => :fifth, :weekday => :sunday)
Recurrence.monthly(:on => :last, :weekday => :sunday)
Recurrence.monthly(:on => 15, :interval => 2)
Recurrence.monthly(:on => 15, :interval => :monthly)
Recurrence.monthly(:on => 15, :interval => :bimonthly)
Recurrence.monthly(:on => 15, :interval => :quarterly)
Recurrence.monthly(:on => 15, :interval => :semesterly)
Recurrence.monthly(:on => 15, :repeat => 5)

The :on option can be one of the following:

* :sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday
* :sun, :mon, :tue, :wed, :thu, :fri, :sat


122
123
124
125
# File 'lib/recurrence/namespace.rb', line 122

def self.monthly(options = {})
  options[:every] = :month
  new(options)
end

.weekly(options = {}) ⇒ Object

Create a weekly recurrence.

Recurrence.weekly(:on => 5) #=> 0 = sunday, 1 = monday, ...
Recurrence.weekly(:on => :saturday)
Recurrence.weekly(:on => [sunday, :saturday])
Recurrence.weekly(:on => :saturday, :interval => 2)
Recurrence.weekly(:on => :saturday, :repeat => 5)


96
97
98
99
# File 'lib/recurrence/namespace.rb', line 96

def self.weekly(options = {})
  options[:every] = :week
  new(options)
end

.yearly(options = {}) ⇒ Object

Create a yearly recurrence.

Recurrence.yearly(:on => [7, 14]) #=> every Jul 14
Recurrence.yearly(:on => [7, 14], :interval => 2) #=> every 2 years on Jul 14
Recurrence.yearly(:on => [:jan, 14], :interval => 2)
Recurrence.yearly(:on => [:january, 14], :interval => 2)
Recurrence.yearly(:on => [:january, 14], :repeat => 5)


135
136
137
138
# File 'lib/recurrence/namespace.rb', line 135

def self.yearly(options = {})
  options[:every] = :year
  new(options)
end

Instance Method Details

#each(&block) ⇒ Object

Iterate in all events between :starts and :until options.

r = Recurrence.daily(:starts => "2010-11-15", :until => "2010-11-17")
r.each do |date|
  puts date
end

This will print

Sun, 15 Nov 2010
Sun, 16 Nov 2010
Sun, 17 Nov 2010

When called without a block, it will return a Enumerator.

r.each
#=> #<Enumerator: [Mon, 15 Nov 2010, Tue, 16 Nov 2010, Wed, 17 Nov 2010]:each>


280
281
282
# File 'lib/recurrence/namespace.rb', line 280

def each(&block)
  events.each(&block)
end

#each!(&block) ⇒ Object

Works like SimplesIdeias::Recurrence::Namespace#each, but removes the cache first.



285
286
287
288
# File 'lib/recurrence/namespace.rb', line 285

def each!(&block)
  reset!
  each(&block)
end

#events(options = {}) ⇒ Object

Return an array with all dates within a given recurrence, caching the result.

r = Recurrence.daily(:starts => "2010-11-15", :until => "2010-11-20")
r.events

The return will be

[
  [0] Mon, 15 Nov 2010,
  [1] Tue, 16 Nov 2010,
  [2] Wed, 17 Nov 2010,
  [3] Thu, 18 Nov 2010,
  [4] Fri, 19 Nov 2010,
  [5] Sat, 20 Nov 2010

]



231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/recurrence/namespace.rb', line 231

def events(options={})
  options[:starts] = as_date(options[:starts])
  options[:until]  = as_date(options[:until])
  options[:repeat] ||= @options[:repeat]

  reset! if options[:starts] || options[:until]

  @events ||= Array.new.tap do |list|
    loop do
      date = @event.next!

      break unless date

      valid_start = options[:starts].nil? || date >= options[:starts]
      valid_until = options[:until].nil?  || date <= options[:until]
      list << date if valid_start && valid_until

      stop_repeat = options[:repeat] && list.size == options[:repeat]
      stop_until = options[:until] && options[:until] <= date

      break if stop_until || stop_repeat
    end
  end
end

#events!(options = {}) ⇒ Object

Works like SimplesIdeias::Recurrence::Namespace#events, but removes the cache first.



257
258
259
260
# File 'lib/recurrence/namespace.rb', line 257

def events!(options={})
  reset!
  events(options)
end

#include?(required_date) ⇒ Boolean

Check if a given date can be retrieve from the current recurrence options.

r = Recurrence.weekly(:on => :sunday)
r.include?("2010-11-16")
#=> false, because "2010-11-16" is monday

Returns:

  • (Boolean)


181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/recurrence/namespace.rb', line 181

def include?(required_date)
  required_date = as_date(required_date)

  if required_date < @_options[:starts] || required_date > @_options[:until]
    false
  else
    each do |date|
      return true if date == required_date
    end
  end

  false
end

#nextObject

Return the next date in recurrence, without changing the internal date object.

r = Recurrence.weekly(:on => :sunday, :starts => "2010-11-15")
r.next #=> Sun, 21 Nov 2010
r.next #=> Sun, 21 Nov 2010


201
202
203
# File 'lib/recurrence/namespace.rb', line 201

def next
  @event.next
end

#next!Object

Return the next date in recurrence, and changes the internal date object.

r = Recurrence.weekly(:on => :sunday, :starts => "2010-11-15")
r.next! #=> Sun, 21 Nov 2010
r.next! #=> Sun, 28 Nov 2010


211
212
213
# File 'lib/recurrence/namespace.rb', line 211

def next!
  @event.next!
end

#reset!Object

Reset the recurrence cache, returning to the first available date.



170
171
172
173
# File 'lib/recurrence/namespace.rb', line 170

def reset!
  @event.reset!
  @events = nil
end