recurrence 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,78 +1,9 @@
1
- class Recurrence::Event
2
- CARDINALS = %w(first second third fourth fifth)
3
- DAYS = %w(sunday monday tuesday wednesday thursday friday saturday)
4
-
5
- attr_accessor :start_date
6
-
7
- def initialize(options={})
8
- every, options = nil, every if every.is_a?(Hash)
9
-
10
- @options = options
11
- @date = options[:starts]
12
- @finished = false
13
-
14
- validate
15
- raise ArgumentError, 'interval should be greater than zero' if @options[:interval] <= 0
16
-
17
- prepare!
1
+ class Recurrence
2
+ module Event
3
+ autoload :Base, "recurrence/event/base"
4
+ autoload :Daily, "recurrence/event/daily"
5
+ autoload :Monthly, "recurrence/event/monthly"
6
+ autoload :Weekly, "recurrence/event/weekly"
7
+ autoload :Yearly, "recurrence/event/yearly"
18
8
  end
19
-
20
- def next!
21
- return nil if finished?
22
- return @date = @start_date if @start_date && @date.nil?
23
-
24
- @date = next_in_recurrence
25
-
26
- @finished, @date = true, nil if @date > @options[:until]
27
- @date
28
- end
29
-
30
- def next
31
- return nil if finished?
32
- @date || @start_date
33
- end
34
-
35
- def reset!
36
- @date = nil
37
- end
38
-
39
- def finished?
40
- @finished
41
- end
42
-
43
- private
44
-
45
- def initialized?
46
- !!@start_date
47
- end
48
-
49
- def prepare!
50
- @start_date = next!
51
- @date = nil
52
- end
53
-
54
- def validate
55
- # Inject custom validations
56
- end
57
-
58
- # Common validation for inherited classes.
59
- #
60
- def valid_month_day?(day) #:nodoc:
61
- raise ArgumentError, "invalid day #{day}" unless (1..31).include?(day)
62
- end
63
-
64
- # Check if the given key has a valid weekday (0 upto 6) or a valid weekday
65
- # name (defined in the DAYS constant). If a weekday name (String) is given,
66
- # convert it to a weekday (Integer).
67
- #
68
- def valid_weekday_or_weekday_name?(value)
69
- if value.kind_of?(Numeric)
70
- raise ArgumentError, "invalid day #{value}" unless (0..6).include?(value)
71
- value
72
- else
73
- raise ArgumentError, "invalid weekday #{value}" unless DAYS.include?(value.to_s)
74
- DAYS.index(value.to_s)
75
- end
76
- end
77
-
78
9
  end
@@ -0,0 +1,80 @@
1
+ class Recurrence
2
+ module Event
3
+ class Base
4
+ CARDINALS = %w(first second third fourth fifth)
5
+ DAYS = %w(sunday monday tuesday wednesday thursday friday saturday)
6
+
7
+ attr_accessor :start_date
8
+
9
+ def initialize(options={})
10
+ every, options = nil, every if every.is_a?(Hash)
11
+
12
+ @options = options
13
+ @date = options[:starts]
14
+ @finished = false
15
+
16
+ validate
17
+ raise ArgumentError, "interval should be greater than zero" if @options[:interval] <= 0
18
+
19
+ prepare!
20
+ end
21
+
22
+ def next!
23
+ return nil if finished?
24
+ return @date = @start_date if @start_date && @date.nil?
25
+
26
+ @date = next_in_recurrence
27
+
28
+ @finished, @date = true, nil if @date > @options[:until]
29
+ @date
30
+ end
31
+
32
+ def next
33
+ return nil if finished?
34
+ @date || @start_date
35
+ end
36
+
37
+ def reset!
38
+ @date = nil
39
+ end
40
+
41
+ def finished?
42
+ @finished
43
+ end
44
+
45
+ private
46
+ def initialized?
47
+ !!@start_date
48
+ end
49
+
50
+ def prepare!
51
+ @start_date = next!
52
+ @date = nil
53
+ end
54
+
55
+ def validate
56
+ # Inject custom validations
57
+ end
58
+
59
+ # Common validation for inherited classes.
60
+ #
61
+ def valid_month_day?(day) #:nodoc:
62
+ raise ArgumentError, "invalid day #{day}" unless (1..31).include?(day)
63
+ end
64
+
65
+ # Check if the given key has a valid weekday (0 upto 6) or a valid weekday
66
+ # name (defined in the DAYS constant). If a weekday name (String) is given,
67
+ # convert it to a weekday (Integer).
68
+ #
69
+ def valid_weekday_or_weekday_name?(value)
70
+ if value.kind_of?(Numeric)
71
+ raise ArgumentError, "invalid day #{value}" unless (0..6).include?(value)
72
+ value
73
+ else
74
+ raise ArgumentError, "invalid weekday #{value}" unless DAYS.include?(value.to_s)
75
+ DAYS.index(value.to_s)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -1,10 +1,12 @@
1
- class Recurrence::Event::Daily < Recurrence::Event
2
-
3
- protected
4
- def next_in_recurrence
5
- date = @date.to_date
6
- date += @options[:interval] if initialized?
7
- date
1
+ class Recurrence
2
+ module Event
3
+ class Daily < Base
4
+ protected
5
+ def next_in_recurrence
6
+ date = @date.to_date
7
+ date += @options[:interval] if initialized?
8
+ date
9
+ end
8
10
  end
9
-
11
+ end
10
12
  end
@@ -1,102 +1,103 @@
1
- class Recurrence::Event::Monthly < Recurrence::Event
2
- INTERVALS = {
3
- :monthly => 1,
4
- :bimonthly => 2,
5
- :quarterly => 3,
6
- :semesterly => 6
7
- }
8
-
9
- protected
10
-
11
- def validate
12
- if @options.key?(:weekday)
13
-
14
- # Allow :on => :last, :weekday => :thursday contruction.
15
- if @options[:on].to_s == 'last'
16
- @options[:on] = 5
17
- elsif @options[:on].kind_of?(Numeric)
18
- valid_week?(@options[:on])
1
+ class Recurrence
2
+ module Event
3
+ class Monthly < Base
4
+ INTERVALS = {
5
+ :monthly => 1,
6
+ :bimonthly => 2,
7
+ :quarterly => 3,
8
+ :semesterly => 6
9
+ }
10
+
11
+ protected
12
+ def validate
13
+ if @options.key?(:weekday)
14
+
15
+ # Allow :on => :last, :weekday => :thursday contruction.
16
+ if @options[:on].to_s == "last"
17
+ @options[:on] = 5
18
+ elsif @options[:on].kind_of?(Numeric)
19
+ valid_week?(@options[:on])
20
+ else
21
+ valid_cardinal?(@options[:on])
22
+ @options[:on] = CARDINALS.index(@options[:on].to_s) + 1
23
+ end
24
+
25
+ @options[:weekday] = valid_weekday_or_weekday_name?(@options[:weekday])
19
26
  else
20
- valid_cardinal?(@options[:on])
21
- @options[:on] = CARDINALS.index(@options[:on].to_s) + 1
27
+ valid_month_day?(@options[:on])
22
28
  end
23
29
 
24
- @options[:weekday] = valid_weekday_or_weekday_name?(@options[:weekday])
25
- else
26
- valid_month_day?(@options[:on])
27
- end
28
-
29
- if @options[:interval].is_a?(Symbol)
30
- valid_interval?(@options[:interval])
31
- @options[:interval] = INTERVALS[@options[:interval]]
30
+ if @options[:interval].is_a?(Symbol)
31
+ valid_interval?(@options[:interval])
32
+ @options[:interval] = INTERVALS[@options[:interval]]
33
+ end
32
34
  end
33
- end
34
35
 
35
- def next_in_recurrence
36
- return next_month if self.respond_to?(:next_month)
37
- type = @options.key?(:weekday) ? :weekday : :monthday
38
-
39
- class_eval <<-METHOD
40
- def next_month
41
- if initialized?
42
- advance_to_month_by_#{type}(@date)
43
- else
44
- new_date = advance_to_month_by_#{type}(@date, 0)
45
- new_date = advance_to_month_by_#{type}(new_date) if @date > new_date
46
- new_date
36
+ def next_in_recurrence
37
+ return next_month if self.respond_to?(:next_month)
38
+ type = @options.key?(:weekday) ? :weekday : :monthday
39
+
40
+ class_eval <<-METHOD
41
+ def next_month
42
+ if initialized?
43
+ advance_to_month_by_#{type}(@date)
44
+ else
45
+ new_date = advance_to_month_by_#{type}(@date, 0)
46
+ new_date = advance_to_month_by_#{type}(new_date) if @date > new_date
47
+ new_date
48
+ end
47
49
  end
48
- end
49
- METHOD
50
+ METHOD
50
51
 
51
- next_month
52
- end
52
+ next_month
53
+ end
53
54
 
54
- def advance_to_month_by_monthday(date, interval=@options[:interval])
55
- # Have a raw month from 0 to 11 interval
56
- raw_month = date.month + interval - 1
55
+ def advance_to_month_by_monthday(date, interval=@options[:interval])
56
+ # Have a raw month from 0 to 11 interval
57
+ raw_month = date.month + interval - 1
57
58
 
58
- next_year = date.year + raw_month / 12
59
- next_month = (raw_month % 12) + 1 # change back to ruby interval
60
- next_day = [ @options[:on], Time.days_in_month(next_month, next_year) ].min
59
+ next_year = date.year + raw_month / 12
60
+ next_month = (raw_month % 12) + 1 # change back to ruby interval
61
+ next_day = [ @options[:on], Time.days_in_month(next_month, next_year) ].min
61
62
 
62
- Date.new(next_year, next_month, next_day)
63
- end
64
-
65
- def advance_to_month_by_weekday(date, interval=@options[:interval])
66
- raw_month = date.month + interval - 1
67
- next_year = date.year + raw_month / 12
68
- next_month = (raw_month % 12) + 1 # change back to ruby interval
69
- date = Date.new(next_year, next_month, 1)
63
+ Date.new(next_year, next_month, next_day)
64
+ end
70
65
 
71
- weekday, month = @options[:weekday], date.month
66
+ def advance_to_month_by_weekday(date, interval=@options[:interval])
67
+ raw_month = date.month + interval - 1
68
+ next_year = date.year + raw_month / 12
69
+ next_month = (raw_month % 12) + 1 # change back to ruby interval
70
+ date = Date.new(next_year, next_month, 1)
72
71
 
73
- # Adjust week day
74
- to_add = weekday - date.wday
75
- to_add += 7 if to_add < 0
76
- to_add += (@options[:on] - 1) * 7
77
- date += to_add
72
+ weekday, month = @options[:weekday], date.month
78
73
 
79
- # Go to the previous month if we lost it
80
- if date.month != month
81
- weeks = (date.day - 1) / 7 + 1
82
- date -= weeks * 7
83
- end
74
+ # Adjust week day
75
+ to_add = weekday - date.wday
76
+ to_add += 7 if to_add < 0
77
+ to_add += (@options[:on] - 1) * 7
78
+ date += to_add
84
79
 
85
- date
86
- end
80
+ # Go to the previous month if we lost it
81
+ if date.month != month
82
+ weeks = (date.day - 1) / 7 + 1
83
+ date -= weeks * 7
84
+ end
87
85
 
88
- private
86
+ date
87
+ end
89
88
 
90
- def valid_cardinal?(cardinal) #:nodoc:
91
- raise ArgumentError, "invalid cardinal #{cardinal}" unless CARDINALS.include?(cardinal.to_s)
92
- end
89
+ private
90
+ def valid_cardinal?(cardinal) #:nodoc:
91
+ raise ArgumentError, "invalid cardinal #{cardinal}" unless CARDINALS.include?(cardinal.to_s)
92
+ end
93
93
 
94
- def valid_interval?(interval) #:nodoc:
95
- raise ArgumentError, "invalid cardinal #{interval}" unless INTERVALS.key?(interval)
96
- end
94
+ def valid_interval?(interval) #:nodoc:
95
+ raise ArgumentError, "invalid cardinal #{interval}" unless INTERVALS.key?(interval)
96
+ end
97
97
 
98
- def valid_week?(week) #:nodoc:
99
- raise ArgumentError, "invalid week #{week}" unless (1..5).include?(week)
98
+ def valid_week?(week) #:nodoc:
99
+ raise ArgumentError, "invalid week #{week}" unless (1..5).include?(week)
100
+ end
100
101
  end
101
-
102
+ end
102
103
  end
@@ -1,27 +1,28 @@
1
- class Recurrence::Event::Weekly < Recurrence::Event
1
+ class Recurrence
2
+ module Event
3
+ class Weekly < Base
4
+ protected
5
+ def validate
6
+ @options[:on] = Array.wrap(@options[:on]).inject([]) do |days, value|
7
+ days << valid_weekday_or_weekday_name?(value)
8
+ end
2
9
 
3
- protected
4
-
5
- def validate
6
- @options[:on] = Array.wrap(@options[:on]).inject([]) do |days, value|
7
- days << valid_weekday_or_weekday_name?(value)
10
+ @options[:on].sort!
8
11
  end
9
12
 
10
- @options[:on].sort!
11
- end
13
+ def next_in_recurrence
14
+ return @date if !initialized? && @options[:on].include?(@date.wday)
12
15
 
13
- def next_in_recurrence
14
- return @date if !initialized? && @options[:on].include?(@date.wday)
16
+ if next_day = @options[:on].find { |day| day > @date.wday }
17
+ to_add = next_day - @date.wday
18
+ else
19
+ to_add = (7 - @date.wday) # Move to next week
20
+ to_add += (@options[:interval] - 1) * 7 # Add extra intervals
21
+ to_add += @options[:on].first # Go to first required day
22
+ end
15
23
 
16
- if next_day = @options[:on].find { |day| day > @date.wday }
17
- to_add = next_day - @date.wday
18
- else
19
- to_add = (7 - @date.wday) # Move to next week
20
- to_add += (@options[:interval] - 1) * 7 # Add extra intervals
21
- to_add += @options[:on].first # Go to first required day
24
+ @date.to_date + to_add
22
25
  end
23
-
24
- @date.to_date + to_add
25
26
  end
26
-
27
+ end
27
28
  end
@@ -1,58 +1,59 @@
1
- class Recurrence::Event::Yearly < Recurrence::Event
2
- MONTHS = {
3
- "jan" => 1, "january" => 1,
4
- "feb" => 2, "february" => 2,
5
- "mar" => 3, "march" => 3,
6
- "apr" => 4, "april" => 4,
7
- "may" => 5,
8
- "jun" => 6, "june" => 6,
9
- "jul" => 7, "july" => 7,
10
- "aug" => 8, "august" => 8,
11
- "sep" => 9, "september" => 9,
12
- "oct" => 10, "october" => 10,
13
- "nov" => 11, "november" => 11,
14
- "dec" => 12, "december" => 12
15
- }
16
-
17
- protected
18
-
19
- def validate
20
- valid_month_day?(@options[:on].last)
21
-
22
- if @options[:on].first.kind_of?(Numeric)
23
- valid_month?(@options[:on].first)
24
- else
25
- valid_month_name?(@options[:on].first)
26
- @options[:on] = [ MONTHS[@options[:on].first.to_s], @options.last ]
1
+ class Recurrence
2
+ module Event
3
+ class Yearly < Base
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
+
19
+ protected
20
+ def validate
21
+ valid_month_day?(@options[:on].last)
22
+
23
+ if @options[:on].first.kind_of?(Numeric)
24
+ valid_month?(@options[:on].first)
25
+ else
26
+ valid_month_name?(@options[:on].first)
27
+ @options[:on] = [ MONTHS[@options[:on].first.to_s], @options.last ]
28
+ end
27
29
  end
28
- end
29
30
 
30
- def next_in_recurrence
31
- if initialized?
32
- advance_to_year(@date)
33
- else
34
- new_date = advance_to_year(@date, 0)
35
- new_date = advance_to_year(new_date) if @date > new_date
36
- new_date
31
+ def next_in_recurrence
32
+ if initialized?
33
+ advance_to_year(@date)
34
+ else
35
+ new_date = advance_to_year(@date, 0)
36
+ new_date = advance_to_year(new_date) if @date > new_date
37
+ new_date
38
+ end
37
39
  end
38
- end
39
-
40
- def advance_to_year(date, interval=@options[:interval])
41
- next_year = date.year + interval
42
- next_month = @options[:on].first
43
- next_day = [ @options[:on].last, Time.days_in_month(next_month, next_year) ].min
44
40
 
45
- Date.new(next_year, next_month, next_day)
46
- end
41
+ def advance_to_year(date, interval=@options[:interval])
42
+ next_year = date.year + interval
43
+ next_month = @options[:on].first
44
+ next_day = [ @options[:on].last, Time.days_in_month(next_month, next_year) ].min
47
45
 
48
- private
46
+ Date.new(next_year, next_month, next_day)
47
+ end
49
48
 
50
- def valid_month?(month) #:nodoc:
51
- raise ArgumentError, "invalid month #{month}" unless (1..12).include?(month)
52
- end
49
+ private
50
+ def valid_month?(month) #:nodoc:
51
+ raise ArgumentError, "invalid month #{month}" unless (1..12).include?(month)
52
+ end
53
53
 
54
- def valid_month_name?(month) #:nodoc:
55
- raise ArgumentError, "invalid month #{month}" unless MONTHS.keys.include?(month.to_s)
54
+ def valid_month_name?(month) #:nodoc:
55
+ raise ArgumentError, "invalid month #{month}" unless MONTHS.keys.include?(month.to_s)
56
+ end
56
57
  end
57
-
58
+ end
58
59
  end