Class: SimplesIdeias::Recurrence

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/recurrence/event.rb,
lib/recurrence/handler.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,
lib/recurrence/handler/fall_back.rb

Direct Known Subclasses

Recurrence

Defined Under Namespace

Modules: Event, Handler, 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])


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

def initialize(options)
  validate_initialize_options(options)

  options[:except] = [options[:except]].flatten.map {|d| as_date(d)} if options[:except]

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

  @event = initialize_event(@_options[:every])
end

Instance Attribute Details

#eventObject (readonly)

Returns the value of attribute event.



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

def event
  @event
end

#optionsObject (readonly)

Returns the value of attribute options.



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

def options
  @options
end

Class Method Details

.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)
Recurrence.daily(:except => Date.tomorrow)


76
77
78
79
# File 'lib/recurrence/namespace.rb', line 76

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

.default_starts_dateObject

Return the default starting date.

Recurrence.default_starts_date
#=> <Date>


24
25
26
27
28
29
30
31
32
33
# File 'lib/recurrence/namespace.rb', line 24

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"


41
42
43
44
45
46
47
# File 'lib/recurrence/namespace.rb', line 41

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


53
54
55
# File 'lib/recurrence/namespace.rb', line 53

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


63
64
65
# File 'lib/recurrence/namespace.rb', line 63

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


115
116
117
118
# File 'lib/recurrence/namespace.rb', line 115

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)


89
90
91
92
# File 'lib/recurrence/namespace.rb', line 89

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)


128
129
130
131
# File 'lib/recurrence/namespace.rb', line 128

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>


270
271
272
# File 'lib/recurrence/namespace.rb', line 270

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

#each!(&block) ⇒ Object

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



275
276
277
278
# File 'lib/recurrence/namespace.rb', line 275

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

]



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# File 'lib/recurrence/namespace.rb', line 217

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

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

  @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]
      valid_except = options[:except].nil? || !options[:except].include?(date)
      list << date if valid_start && valid_until && valid_except

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

      break if stop_until || stop_repeat || stop_through
    end
  end
end

#events!(options = {}) ⇒ Object

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



247
248
249
250
# File 'lib/recurrence/namespace.rb', line 247

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)


167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/recurrence/namespace.rb', line 167

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


187
188
189
# File 'lib/recurrence/namespace.rb', line 187

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


197
198
199
# File 'lib/recurrence/namespace.rb', line 197

def next!
  @event.next!
end

#reset!Object

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



156
157
158
159
# File 'lib/recurrence/namespace.rb', line 156

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