fnando-recurrence 0.0.3 → 0.0.6
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/History.txt +21 -0
- data/README.markdown +19 -15
- data/Rakefile +6 -6
- data/lib/recurrence/base.rb +61 -23
- data/lib/recurrence/event.rb +89 -55
- data/recurrence.gemspec +6 -8
- metadata +3 -4
- data/TODO.txt +0 -0
data/History.txt
CHANGED
@@ -13,3 +13,24 @@
|
|
13
13
|
* 1 major enhancement:
|
14
14
|
* The recurrence now considers the starting date and its configurations
|
15
15
|
* Added lots of specs
|
16
|
+
|
17
|
+
== 0.0.4 2008-09-30
|
18
|
+
|
19
|
+
* 1 major enhancement:
|
20
|
+
* Renamed items method to events
|
21
|
+
* Added each! method
|
22
|
+
* Added lots of specs
|
23
|
+
|
24
|
+
== 0.0.5 2008-09-30
|
25
|
+
|
26
|
+
* 1 major enhancement:
|
27
|
+
* Monthly interval now accepts symbols: monthly, bimonthly, quarterly,
|
28
|
+
semesterly
|
29
|
+
|
30
|
+
== 0.0.6 2009-01-06
|
31
|
+
|
32
|
+
* 1 major enhancement:
|
33
|
+
* Code refactoring
|
34
|
+
* Added next and next! methods
|
35
|
+
* Added more specs
|
36
|
+
* Yearly interval now accepts symbols: jan-dec and january-december
|
data/README.markdown
CHANGED
@@ -40,35 +40,39 @@ USAGE:
|
|
40
40
|
r = Recurrence.new(:every => :month, :on => 15)
|
41
41
|
r = Recurrence.new(:every => :month, :on => 31)
|
42
42
|
r = Recurrence.new(:every => :month, :on => 7, :interval => 2)
|
43
|
+
r = Recurrence.new(:every => :month, :on => 7, :interval => :monthly)
|
44
|
+
r = Recurrence.new(:every => :month, :on => 7, :interval => :bimonthly)
|
45
|
+
r = Recurrence.new(:every => :month, :on => 7, :interval => :quarterly)
|
46
|
+
r = Recurrence.new(:every => :month, :on => 7, :interval => :semesterly)
|
43
47
|
|
44
48
|
# Yearly
|
45
49
|
r = Recurrence.new(:every => :year, :on => [7, 4]) # => [month, day]
|
46
50
|
r = Recurrence.new(:every => :year, :on => [10, 31], :interval => 3)
|
51
|
+
r = Recurrence.new(:every => :year, :on => [:jan, 31])
|
52
|
+
r = Recurrence.new(:every => :year, :on => [:january, 31])
|
47
53
|
|
48
54
|
# Limit recurrence
|
49
55
|
# :starts defaults to Date.today
|
50
56
|
# :until defaults to 2037-12-31
|
51
|
-
r = Recurrence.new(:day, :starts => Date.today)
|
52
|
-
r = Recurrence.new(:day, :until => '2010-01-31')
|
53
|
-
r = Recurrence.new(:day, :starts => Date.today, :until => '2010-01-31')
|
54
|
-
|
55
|
-
# Iterating events
|
56
|
-
r.each do |date|
|
57
|
-
puts date.to_s
|
58
|
-
end
|
57
|
+
r = Recurrence.new(:every => :day, :starts => Date.today)
|
58
|
+
r = Recurrence.new(:every => :day, :until => '2010-01-31')
|
59
|
+
r = Recurrence.new(:every => :day, :starts => Date.today, :until => '2010-01-31')
|
59
60
|
|
60
61
|
# Getting an array with all events
|
61
|
-
r.
|
62
|
-
r.
|
62
|
+
r.events.each {|date| puts date.to_s } # => Memoized array
|
63
|
+
r.events!.each {|date| puts date.to_s } # => reset items cache and re-execute it
|
64
|
+
|
65
|
+
# Iterating events
|
66
|
+
r.each { |date| puts date.to_s } # => Use items method
|
67
|
+
r.each! { |date| puts date.to_s } # => Use items! method
|
63
68
|
|
64
69
|
# Check if a date is included
|
65
70
|
r.include?(Date.today) # => true or false
|
66
71
|
r.include?('2008-09-21')
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
* Write the specs
|
72
|
+
|
73
|
+
# Get next available date
|
74
|
+
r.next # => Keep the original date object
|
75
|
+
r.next! # => Change the internal date object to the next available date
|
72
76
|
|
73
77
|
MAINTAINER
|
74
78
|
----------
|
data/Rakefile
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'rake'
|
2
2
|
|
3
|
-
PKG_FILES = %w(init.rb Rakefile recurrence.gemspec History.txt License.txt README.markdown
|
3
|
+
PKG_FILES = %w(init.rb Rakefile recurrence.gemspec History.txt License.txt README.markdown) +
|
4
4
|
Dir["lib/**/*"]
|
5
5
|
|
6
6
|
spec = Gem::Specification.new do |s|
|
7
7
|
s.name = "recurrence"
|
8
|
-
s.version = "0.0.
|
8
|
+
s.version = "0.0.6"
|
9
9
|
s.summary = "A simples library that handles recurring events"
|
10
10
|
s.authors = ["Nando Vieira"]
|
11
11
|
s.email = ["fnando.vieira@gmail.com"]
|
@@ -15,7 +15,7 @@ spec = Gem::Specification.new do |s|
|
|
15
15
|
s.files = PKG_FILES
|
16
16
|
|
17
17
|
s.add_dependency "rubigen"
|
18
|
-
s.add_dependency "activesupport"
|
18
|
+
s.add_dependency "activesupport", ">=2.1.1"
|
19
19
|
end
|
20
20
|
|
21
21
|
namespace :gem do
|
@@ -31,7 +31,7 @@ namespace :gem do
|
|
31
31
|
spec.instance_variables.each do |ivar|
|
32
32
|
value = spec.instance_variable_get(ivar)
|
33
33
|
name = ivar.split("@").last
|
34
|
-
|
34
|
+
next if name == "date"
|
35
35
|
|
36
36
|
next if skip_fields.include?(name) || value.nil? || value == "" || (value.respond_to?(:empty?) && value.empty?)
|
37
37
|
if name == "dependencies"
|
@@ -71,6 +71,6 @@ namespace :gem do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
desc "Execute specs"
|
74
|
-
task :
|
75
|
-
system "spec
|
74
|
+
task :spec do
|
75
|
+
system "spec spec/recurrence_spec.rb -c -f s"
|
76
76
|
end
|
data/lib/recurrence/base.rb
CHANGED
@@ -1,17 +1,41 @@
|
|
1
1
|
class Recurrence
|
2
2
|
FREQUENCY = %w(day week month year)
|
3
3
|
DAYS = %w(sunday monday tuesday wednesday thursday friday saturday)
|
4
|
+
MONTHS = {
|
5
|
+
"jan" => 1, "january" => 1,
|
6
|
+
"feb" => 2, "february" => 2,
|
7
|
+
"mar" => 3, "march" => 3,
|
8
|
+
"apr" => 4, "april" => 4,
|
9
|
+
"may" => 5,
|
10
|
+
"jun" => 6, "june" => 6,
|
11
|
+
"jul" => 7, "july" => 7,
|
12
|
+
"aug" => 8, "august" => 8,
|
13
|
+
"sep" => 9, "september" => 9,
|
14
|
+
"oct" => 10, "october" => 10,
|
15
|
+
"nov" => 11, "november" => 11,
|
16
|
+
"dec" => 12, "december" => 12
|
17
|
+
}
|
18
|
+
|
4
19
|
INTERVALS = {
|
5
20
|
:monthly => 1,
|
6
21
|
:bimonthly => 2,
|
7
22
|
:quarterly => 3,
|
8
|
-
:
|
23
|
+
:semesterly => 6
|
9
24
|
}
|
10
25
|
|
26
|
+
attr_reader :event
|
27
|
+
|
11
28
|
def initialize(options)
|
12
|
-
raise ArgumentError, ':every
|
29
|
+
raise ArgumentError, ':every option is required' unless options.key?(:every)
|
13
30
|
raise ArgumentError, 'invalid :every option' unless FREQUENCY.include?(options[:every].to_s)
|
14
|
-
|
31
|
+
|
32
|
+
if options.key?(:interval)
|
33
|
+
if options[:every].to_sym == :month && options[:interval].is_a?(Symbol) && !INTERVALS.key?(options[:interval])
|
34
|
+
raise ArgumentError, 'interval symbol is not valid'
|
35
|
+
elsif options[:interval].to_i == 0
|
36
|
+
raise ArgumentError, 'interval should be greater than zero'
|
37
|
+
end
|
38
|
+
end
|
15
39
|
|
16
40
|
@options = initialize_dates(options)
|
17
41
|
@options[:interval] ||= 1
|
@@ -25,16 +49,19 @@ class Recurrence
|
|
25
49
|
@event = Recurrence::Event.new(:week, @options)
|
26
50
|
when :month then
|
27
51
|
raise ArgumentError, 'invalid day' unless (1..31).include?(@options[:on])
|
52
|
+
options.merge!(:interval => INTERVALS[options[:interval]]) if options[:interval].is_a?(Symbol)
|
28
53
|
@event = Recurrence::Event.new(:month, @options)
|
29
54
|
when :year then
|
30
|
-
raise ArgumentError, 'invalid month'
|
55
|
+
raise ArgumentError, 'invalid month' if !(1..12).include?(@options[:on].first) && !MONTHS.keys.include?(@options[:on].first)
|
31
56
|
raise ArgumentError, 'invalid day' unless (1..31).include?(@options[:on].last)
|
57
|
+
@options.merge!(:on => [MONTHS[@options[:on].first.to_s], @options.last]) unless @options[:on].first.kind_of?(Numeric)
|
32
58
|
@event = Recurrence::Event.new(:year, @options)
|
33
59
|
end
|
34
60
|
end
|
35
61
|
|
36
62
|
def reset!
|
37
63
|
@event.reset!
|
64
|
+
@events = nil
|
38
65
|
end
|
39
66
|
|
40
67
|
def include?(required_date)
|
@@ -51,31 +78,42 @@ class Recurrence
|
|
51
78
|
return false
|
52
79
|
end
|
53
80
|
|
54
|
-
def
|
55
|
-
@
|
56
|
-
reset!
|
57
|
-
_items = []
|
58
|
-
each { |date| _items << date }
|
59
|
-
_items
|
60
|
-
end
|
81
|
+
def next
|
82
|
+
@event.next
|
61
83
|
end
|
62
84
|
|
63
|
-
def
|
64
|
-
@
|
65
|
-
items
|
85
|
+
def next!
|
86
|
+
@event.next!
|
66
87
|
end
|
67
88
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
loop do
|
72
|
-
date = @event.find_next!
|
89
|
+
def events
|
90
|
+
@events ||= begin
|
91
|
+
_events = []
|
73
92
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
93
|
+
loop do
|
94
|
+
date = @event.next!
|
95
|
+
|
96
|
+
break if date.nil?
|
97
|
+
_events << date
|
78
98
|
end
|
99
|
+
|
100
|
+
_events
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def events!
|
105
|
+
reset!
|
106
|
+
events
|
107
|
+
end
|
108
|
+
|
109
|
+
def each!(&block)
|
110
|
+
reset!
|
111
|
+
each(&block)
|
112
|
+
end
|
113
|
+
|
114
|
+
def each(&block)
|
115
|
+
events.each do |item|
|
116
|
+
yield item
|
79
117
|
end
|
80
118
|
end
|
81
119
|
|
data/lib/recurrence/event.rb
CHANGED
@@ -1,96 +1,130 @@
|
|
1
1
|
class Recurrence::Event
|
2
|
+
attr_accessor :date, :start_date, :options, :every
|
3
|
+
|
2
4
|
def initialize(every, options={})
|
3
|
-
@every
|
5
|
+
@every = every
|
4
6
|
@options = options
|
5
|
-
@
|
6
|
-
|
7
|
+
@current = nil
|
8
|
+
@date = options[:starts]
|
9
|
+
prepare!
|
10
|
+
end
|
11
|
+
|
12
|
+
def prepare!
|
13
|
+
self.next!
|
14
|
+
@start_date = @date
|
15
|
+
end
|
16
|
+
|
17
|
+
def next?
|
18
|
+
!!@next
|
7
19
|
end
|
8
20
|
|
9
|
-
def
|
21
|
+
def next!
|
22
|
+
# just continue if date object is null or
|
23
|
+
# hasn't been initialized yet
|
24
|
+
return nil unless @date || !inited?
|
25
|
+
|
26
|
+
# return the date if is the first interaction after
|
27
|
+
# initializing object
|
28
|
+
if inited? && !next?
|
29
|
+
@next = true
|
30
|
+
return @date
|
31
|
+
end
|
32
|
+
|
10
33
|
case @every
|
11
34
|
when :day
|
12
|
-
date =
|
35
|
+
@date = next_day
|
13
36
|
when :week
|
14
|
-
date =
|
37
|
+
@date = next_week
|
15
38
|
when :month
|
16
|
-
date =
|
39
|
+
@date = next_month
|
17
40
|
when :year
|
18
|
-
date =
|
41
|
+
@date = next_year
|
19
42
|
end
|
20
43
|
|
21
|
-
date
|
22
|
-
|
44
|
+
# if limit date has been reached just set the date
|
45
|
+
# object to nil
|
46
|
+
@date = nil unless @date.to_date <= @options[:until].to_date
|
47
|
+
|
48
|
+
@date
|
23
49
|
end
|
24
50
|
|
25
|
-
def
|
26
|
-
@date
|
51
|
+
def next
|
52
|
+
@date
|
27
53
|
end
|
28
54
|
|
29
|
-
def
|
30
|
-
@date =
|
55
|
+
def reset!
|
56
|
+
@date = @start_date
|
31
57
|
end
|
32
58
|
|
33
59
|
private
|
34
|
-
def
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
def started?
|
39
|
-
@started == true
|
60
|
+
def inited?
|
61
|
+
!!@start_date
|
40
62
|
end
|
41
63
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
date = @date
|
46
|
-
else
|
47
|
-
date = @date + @options[:interval].days
|
48
|
-
end
|
64
|
+
def next_day
|
65
|
+
date = @date
|
66
|
+
date = date + @options[:interval].days if inited? || @options[:interval] > 1
|
49
67
|
|
50
68
|
date.to_date
|
51
69
|
end
|
52
70
|
|
53
|
-
def
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
else @options[:interval]
|
62
|
-
date = @date + @options[:interval].weeks
|
71
|
+
def next_week
|
72
|
+
date = @date
|
73
|
+
|
74
|
+
if inited?
|
75
|
+
date = date + @options[:interval].weeks
|
76
|
+
elsif date.wday != @options[:on]
|
77
|
+
date = date.next until @options[:on] == date.wday && date > @options[:starts]
|
78
|
+
date = date + (@options[:interval] - 1).weeks
|
63
79
|
end
|
64
80
|
|
65
81
|
date.to_date
|
66
82
|
end
|
67
83
|
|
68
|
-
def
|
69
|
-
|
70
|
-
|
71
|
-
|
84
|
+
def next_month
|
85
|
+
date = @date
|
86
|
+
|
87
|
+
if inited?
|
88
|
+
date = advance_to_month(date)
|
72
89
|
else
|
73
|
-
|
90
|
+
day = [options[:on], Time.days_in_month(date.month, date.year)].min
|
91
|
+
date = Date.new(date.year, date.month, day)
|
92
|
+
date = advance_to_month(date) if @date.day > day
|
74
93
|
end
|
75
|
-
|
76
|
-
day = [@options[:on], Time.days_in_month(date.month, date.year)].min
|
77
|
-
date = Date.new(date.year, date.month, day)
|
94
|
+
|
78
95
|
date.to_date
|
79
96
|
end
|
80
97
|
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
98
|
+
def advance_to_month(date)
|
99
|
+
date = date.beginning_of_month + @options[:interval].months
|
100
|
+
day = [options[:on], Time.days_in_month(date.month, date.year)].min
|
101
|
+
|
102
|
+
if date.day != day && date.day < day
|
103
|
+
date = date.to_date.next until date.day == day
|
104
|
+
end
|
105
|
+
|
106
|
+
date
|
107
|
+
end
|
108
|
+
|
109
|
+
def next_year
|
110
|
+
date = @date
|
111
|
+
|
112
|
+
if inited?
|
113
|
+
date = advance_to_year(date)
|
85
114
|
else
|
86
|
-
|
115
|
+
day = [options[:on].last, Time.days_in_month(options[:on].first, date.year)].min
|
116
|
+
date = Date.new(date.year, options[:on].first, day)
|
117
|
+
date = advance_to_year(date) if @date.month > date.month || @options[:on].last < @date.day
|
87
118
|
end
|
88
119
|
|
120
|
+
date.to_date
|
121
|
+
end
|
122
|
+
|
123
|
+
def advance_to_year(date)
|
124
|
+
date = date.beginning_of_month + @options[:interval].years
|
89
125
|
day = [Time.days_in_month(@options[:on].first, date.year), @options[:on].last].min
|
90
126
|
year = date.year
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
Date.new(year, @options[:on].first, day)
|
127
|
+
|
128
|
+
date = Date.new(year, @options[:on].first, day)
|
95
129
|
end
|
96
|
-
end
|
130
|
+
end
|
data/recurrence.gemspec
CHANGED
@@ -2,28 +2,26 @@
|
|
2
2
|
# RUN : 'rake gem:update_gemspec'
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
|
-
s.date = "Mon Sep 22 21:17:41 -0300 2008"
|
6
5
|
s.authors = ["Nando Vieira"]
|
6
|
+
s.require_paths = ["lib"]
|
7
7
|
s.required_rubygems_version = ">= 0"
|
8
|
-
s.
|
8
|
+
s.has_rdoc = false
|
9
9
|
s.files = ["init.rb",
|
10
10
|
"Rakefile",
|
11
11
|
"recurrence.gemspec",
|
12
12
|
"History.txt",
|
13
13
|
"License.txt",
|
14
14
|
"README.markdown",
|
15
|
-
"TODO.txt",
|
16
15
|
"lib/recurrence",
|
17
16
|
"lib/recurrence/base.rb",
|
18
17
|
"lib/recurrence/event.rb",
|
19
18
|
"lib/recurrence.rb"]
|
20
|
-
s.has_rdoc = false
|
21
19
|
s.email = ["fnando.vieira@gmail.com"]
|
22
|
-
s.
|
23
|
-
s.bindir = "bin"
|
20
|
+
s.version = "0.0.6"
|
24
21
|
s.homepage = "http://github.com/fnando/recurrence"
|
22
|
+
s.name = "recurrence"
|
25
23
|
s.summary = "A simples library that handles recurring events"
|
26
24
|
s.add_dependency "rubigen", ">= 0"
|
27
|
-
s.add_dependency "activesupport", ">=
|
28
|
-
s.
|
25
|
+
s.add_dependency "activesupport", ">= 2.1.1"
|
26
|
+
s.bindir = "bin"
|
29
27
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fnando-recurrence
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nando Vieira
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-22 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
requirements:
|
29
29
|
- - ">="
|
30
30
|
- !ruby/object:Gem::Version
|
31
|
-
version:
|
31
|
+
version: 2.1.1
|
32
32
|
version:
|
33
33
|
description:
|
34
34
|
email:
|
@@ -46,7 +46,6 @@ files:
|
|
46
46
|
- History.txt
|
47
47
|
- License.txt
|
48
48
|
- README.markdown
|
49
|
-
- TODO.txt
|
50
49
|
- lib/recurrence
|
51
50
|
- lib/recurrence/base.rb
|
52
51
|
- lib/recurrence/event.rb
|
data/TODO.txt
DELETED
File without changes
|