ice_cube 0.6.14 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ice_cube.rb +63 -37
- data/lib/ice_cube/builders/hash_builder.rb +27 -0
- data/lib/ice_cube/builders/ical_builder.rb +59 -0
- data/lib/ice_cube/builders/string_builder.rb +74 -0
- data/lib/ice_cube/errors/count_exceeded.rb +7 -0
- data/lib/ice_cube/errors/until_exceeded.rb +7 -0
- data/lib/ice_cube/rule.rb +85 -147
- data/lib/ice_cube/rules/daily_rule.rb +5 -27
- data/lib/ice_cube/rules/hourly_rule.rb +6 -26
- data/lib/ice_cube/rules/minutely_rule.rb +5 -25
- data/lib/ice_cube/rules/monthly_rule.rb +6 -30
- data/lib/ice_cube/rules/secondly_rule.rb +5 -26
- data/lib/ice_cube/rules/weekly_rule.rb +5 -36
- data/lib/ice_cube/rules/yearly_rule.rb +8 -34
- data/lib/ice_cube/schedule.rb +257 -229
- data/lib/ice_cube/single_occurrence_rule.rb +28 -0
- data/lib/ice_cube/time_util.rb +202 -76
- data/lib/ice_cube/validated_rule.rb +107 -0
- data/lib/ice_cube/validations/count.rb +56 -0
- data/lib/ice_cube/validations/daily_interval.rb +51 -0
- data/lib/ice_cube/validations/day.rb +45 -31
- data/lib/ice_cube/validations/day_of_month.rb +44 -44
- data/lib/ice_cube/validations/day_of_week.rb +60 -47
- data/lib/ice_cube/validations/day_of_year.rb +48 -44
- data/lib/ice_cube/validations/hour_of_day.rb +42 -30
- data/lib/ice_cube/validations/hourly_interval.rb +50 -0
- data/lib/ice_cube/validations/lock.rb +47 -0
- data/lib/ice_cube/validations/minute_of_hour.rb +42 -31
- data/lib/ice_cube/validations/minutely_interval.rb +50 -0
- data/lib/ice_cube/validations/month_of_year.rb +39 -30
- data/lib/ice_cube/validations/monthly_interval.rb +47 -0
- data/lib/ice_cube/validations/schedule_lock.rb +41 -0
- data/lib/ice_cube/validations/second_of_minute.rb +39 -30
- data/lib/ice_cube/validations/secondly_interval.rb +50 -0
- data/lib/ice_cube/validations/until.rb +49 -0
- data/lib/ice_cube/validations/weekly_interval.rb +50 -0
- data/lib/ice_cube/validations/yearly_interval.rb +45 -0
- data/lib/ice_cube/version.rb +2 -2
- data/spec/spec_helper.rb +13 -0
- metadata +50 -9
- data/lib/ice_cube/rule_occurrence.rb +0 -94
- data/lib/ice_cube/validation.rb +0 -44
- data/lib/ice_cube/validation_types.rb +0 -137
data/lib/ice_cube.rb
CHANGED
@@ -1,48 +1,74 @@
|
|
1
|
-
require 'yaml.rb'
|
2
|
-
require 'set.rb'
|
3
1
|
require 'date'
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
require '
|
8
|
-
|
9
|
-
require '
|
10
|
-
|
11
|
-
require 'ice_cube/rule_occurrence'
|
3
|
+
# Use psych if we can
|
4
|
+
begin
|
5
|
+
require 'psych'
|
6
|
+
rescue LoadError
|
7
|
+
require 'yaml'
|
8
|
+
end
|
12
9
|
|
13
10
|
module IceCube
|
14
|
-
|
11
|
+
|
12
|
+
autoload :VERSION, 'ice_cube/version'
|
13
|
+
|
14
|
+
autoload :TimeUtil, 'ice_cube/time_util'
|
15
|
+
|
16
|
+
autoload :Rule, 'ice_cube/rule'
|
17
|
+
autoload :Schedule, 'ice_cube/schedule'
|
18
|
+
|
19
|
+
autoload :IcalBuilder, 'ice_cube/builders/ical_builder'
|
20
|
+
autoload :HashBuilder, 'ice_cube/builders/hash_builder'
|
21
|
+
autoload :StringBuilder, 'ice_cube/builders/string_builder'
|
22
|
+
|
23
|
+
autoload :CountExceeded, 'ice_cube/errors/count_exceeded'
|
24
|
+
autoload :UntilExceeded, 'ice_cube/errors/until_exceeded'
|
25
|
+
|
26
|
+
autoload :ValidatedRule, 'ice_cube/validated_rule'
|
27
|
+
autoload :SingleOccurrenceRule, 'ice_cube/single_occurrence_rule'
|
28
|
+
|
29
|
+
autoload :SecondlyRule, 'ice_cube/rules/secondly_rule'
|
30
|
+
autoload :MinutelyRule, 'ice_cube/rules/minutely_rule'
|
31
|
+
autoload :HourlyRule, 'ice_cube/rules/hourly_rule'
|
15
32
|
autoload :DailyRule, 'ice_cube/rules/daily_rule'
|
16
33
|
autoload :WeeklyRule, 'ice_cube/rules/weekly_rule'
|
17
34
|
autoload :MonthlyRule, 'ice_cube/rules/monthly_rule'
|
18
35
|
autoload :YearlyRule, 'ice_cube/rules/yearly_rule'
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
36
|
+
|
37
|
+
module Validations
|
38
|
+
|
39
|
+
autoload :Lock, 'ice_cube/validations/lock'
|
40
|
+
autoload :ScheduleLock, 'ice_cube/validations/schedule_lock'
|
41
|
+
|
42
|
+
autoload :Count, 'ice_cube/validations/count'
|
43
|
+
autoload :Until, 'ice_cube/validations/until'
|
44
|
+
|
45
|
+
autoload :SecondlyInterval, 'ice_cube/validations/secondly_interval'
|
46
|
+
autoload :MinutelyInterval, 'ice_cube/validations/minutely_interval'
|
47
|
+
autoload :DailyInterval, 'ice_cube/validations/daily_interval'
|
48
|
+
autoload :WeeklyInterval, 'ice_cube/validations/weekly_interval'
|
49
|
+
autoload :MonthlyInterval, 'ice_cube/validations/monthly_interval'
|
50
|
+
autoload :YearlyInterval, 'ice_cube/validations/yearly_interval'
|
51
|
+
autoload :HourlyInterval, 'ice_cube/validations/hourly_interval'
|
52
|
+
|
53
|
+
autoload :HourOfDay, 'ice_cube/validations/hour_of_day'
|
54
|
+
autoload :MonthOfYear, 'ice_cube/validations/month_of_year'
|
55
|
+
autoload :MinuteOfHour, 'ice_cube/validations/minute_of_hour'
|
56
|
+
autoload :SecondOfMinute, 'ice_cube/validations/second_of_minute'
|
57
|
+
autoload :DayOfMonth, 'ice_cube/validations/day_of_month'
|
58
|
+
autoload :DayOfWeek, 'ice_cube/validations/day_of_week'
|
59
|
+
autoload :Day, 'ice_cube/validations/day'
|
60
|
+
autoload :DayOfYear, 'ice_cube/validations/day_of_year'
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
# Define some useful constants
|
65
|
+
ONE_SECOND = 1
|
66
|
+
ONE_MINUTE = ONE_SECOND * 60
|
67
|
+
ONE_HOUR = ONE_MINUTE * 60
|
68
|
+
ONE_DAY = ONE_HOUR * 24
|
69
|
+
ONE_WEEK = ONE_DAY * 7
|
23
70
|
|
24
|
-
|
25
|
-
|
26
|
-
autoload :DayOfWeekValidation, 'ice_cube/validations/day_of_week'
|
27
|
-
autoload :DayOfYearValidation, 'ice_cube/validations/day_of_year'
|
28
|
-
autoload :HourOfDayValidation, 'ice_cube/validations/hour_of_day'
|
29
|
-
autoload :MinuteOfHourValidation, 'ice_cube/validations/minute_of_hour'
|
30
|
-
autoload :MonthOfYearValidation, 'ice_cube/validations/month_of_year'
|
31
|
-
autoload :SecondOfMinuteValidation, 'ice_cube/validations/second_of_minute'
|
32
|
-
|
33
|
-
# if you're reading this code, you've just been iced
|
34
|
-
# http://brosicingbros.com/
|
35
|
-
|
36
|
-
IceCube::ONE_DAY = 24 * 60 * 60
|
37
|
-
IceCube::ONE_HOUR = 60 * 60
|
38
|
-
IceCube::ONE_MINUTE = 60
|
39
|
-
IceCube::ONE_SECOND = 1
|
40
|
-
|
41
|
-
ICAL_DAYS = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']
|
42
|
-
DAYS = { :sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3, :thursday => 4, :friday => 5, :saturday => 6 }
|
43
|
-
MONTHS = { :january => 1, :february => 2, :march => 3, :april => 4, :may => 5, :june => 6, :july => 7, :august => 8,
|
44
|
-
:september => 9, :october => 10, :november => 11, :december => 12 }
|
45
|
-
|
46
|
-
include TimeUtil
|
71
|
+
# Formatting
|
72
|
+
TO_S_TIME_FORMAT = '%B %e, %Y'
|
47
73
|
|
48
74
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
class HashBuilder
|
4
|
+
|
5
|
+
def initialize(rule = nil)
|
6
|
+
@hash = { :validations => {}, :rule_type => rule.class.name }
|
7
|
+
end
|
8
|
+
|
9
|
+
def validations
|
10
|
+
@hash[:validations]
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(key, value)
|
14
|
+
@hash[key] = value
|
15
|
+
end
|
16
|
+
|
17
|
+
def validations_array(type)
|
18
|
+
validations[type] ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_hash
|
22
|
+
@hash
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
class IcalBuilder
|
4
|
+
|
5
|
+
ICAL_DAYS = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@hash = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.fixnum_to_ical_day(num)
|
12
|
+
ICAL_DAYS[num]
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](key)
|
16
|
+
@hash[key] ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Build for a single rule entry
|
20
|
+
def to_s
|
21
|
+
arr = []
|
22
|
+
if freq = @hash.delete('FREQ')
|
23
|
+
arr << "FREQ=#{freq.join(',')}"
|
24
|
+
end
|
25
|
+
arr.concat(@hash.map do |key, value|
|
26
|
+
if value.is_a?(Array)
|
27
|
+
"#{key}=#{value.join(',')}"
|
28
|
+
end
|
29
|
+
end.compact)
|
30
|
+
arr.join(';')
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.ical_utc_format(time)
|
34
|
+
time = time.dup.utc
|
35
|
+
"#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.ical_format(time, force_utc)
|
39
|
+
time = time.dup.utc if force_utc
|
40
|
+
if time.utc?
|
41
|
+
":#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time
|
42
|
+
else
|
43
|
+
";TZID=#{time.strftime('%Z:%Y%m%dT%H%M%S')}" # local time specified
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.ical_duration(duration)
|
48
|
+
hours = duration / 3600; duration %= 3600
|
49
|
+
minutes = duration / 60; duration %= 60
|
50
|
+
repr = ''
|
51
|
+
repr << "#{hours}H" if hours > 0
|
52
|
+
repr << "#{minutes}M" if minutes > 0
|
53
|
+
repr << "#{duration}S" if duration > 0
|
54
|
+
"PT#{repr}"
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module IceCube
|
2
|
+
|
3
|
+
class StringBuilder
|
4
|
+
|
5
|
+
attr_writer :base
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@types = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def piece(type, prefix = nil, suffix = nil)
|
12
|
+
@types[type] ||= []
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
str = @base || ''
|
17
|
+
res = @types.map do |type, segments|
|
18
|
+
if f = self.class.formatter(type)
|
19
|
+
str << ' ' + f.call(segments)
|
20
|
+
else
|
21
|
+
next if segments.empty?
|
22
|
+
str << ' ' + self.class.sentence(segments)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
str
|
26
|
+
end
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
def formatter(type)
|
31
|
+
@formatters[type]
|
32
|
+
end
|
33
|
+
|
34
|
+
def register_formatter(type, &formatter)
|
35
|
+
@formatters ||= {}
|
36
|
+
@formatters[type] = formatter
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
class << self
|
42
|
+
|
43
|
+
NUMBER_SUFFIX = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th']
|
44
|
+
SPECIAL_SUFFIX = { 11 => 'th', 12 => 'th', 13 => 'th', 14 => 'th' }
|
45
|
+
|
46
|
+
# influenced by ActiveSupport's to_sentence
|
47
|
+
def sentence(array)
|
48
|
+
case array.length
|
49
|
+
when 0 ; ''
|
50
|
+
when 1 ; array[0].to_s
|
51
|
+
when 2 ; "#{array[0]} and #{array[1]}"
|
52
|
+
else ; "#{array[0...-1].join(', ')}, and #{array[-1]}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def nice_number(number)
|
57
|
+
if number == -1
|
58
|
+
'last'
|
59
|
+
elsif number < -1
|
60
|
+
suffix = SPECIAL_SUFFIX.include?(number) ?
|
61
|
+
SPECIAL_SUFFIX[number] : NUMBER_SUFFIX[number.abs % 10]
|
62
|
+
number.abs.to_s << suffix << ' to last'
|
63
|
+
else
|
64
|
+
suffix = SPECIAL_SUFFIX.include?(number) ?
|
65
|
+
SPECIAL_SUFFIX[number] : NUMBER_SUFFIX[number.abs % 10]
|
66
|
+
number.to_s << suffix
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/lib/ice_cube/rule.rb
CHANGED
@@ -1,171 +1,109 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module IceCube
|
2
|
-
|
4
|
+
|
3
5
|
class Rule
|
4
|
-
|
5
|
-
attr_reader :occurrence_count, :until_date
|
6
|
-
attr_reader :interval
|
7
|
-
attr_reader :validations
|
8
|
-
|
9
|
-
include ValidationTypes
|
10
|
-
include Comparable
|
11
6
|
|
12
|
-
|
13
|
-
def <=>(other)
|
14
|
-
to_hash <=> other.to_hash
|
15
|
-
end
|
7
|
+
attr_reader :uses
|
16
8
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
hash[:interval] = @interval
|
21
|
-
hash[:until] = @until_date ? TimeUtil.serialize_time(@until_date) : @until_date
|
22
|
-
hash[:count] = @occurrence_count
|
23
|
-
hash[:validations] = @validations
|
24
|
-
hash
|
25
|
-
end
|
26
|
-
|
27
|
-
def self.from_hash(hash)
|
28
|
-
rule = hash[:rule_type].split('::').inject(Object) { |namespace, const_name| namespace.const_get(const_name) }.new(hash[:interval])
|
29
|
-
rule.count(hash[:count]) if hash[:count]
|
30
|
-
rule.until(hash[:until]) if hash[:until]
|
31
|
-
hash[:validations].each do |validation, data|
|
32
|
-
data.is_a?(Array) ? rule.send(validation, *data) : rule.send(validation, data)
|
33
|
-
end
|
34
|
-
rule
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_yaml(options = {})
|
38
|
-
to_hash.to_yaml(options)
|
9
|
+
# Is this a terminating schedule?
|
10
|
+
def terminating?
|
11
|
+
until_time || occurrence_count
|
39
12
|
end
|
40
13
|
|
41
|
-
def
|
42
|
-
|
14
|
+
def ==(rule)
|
15
|
+
hash = to_hash
|
16
|
+
hash && hash == rule.to_hash
|
43
17
|
end
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
18
|
+
|
19
|
+
def hash
|
20
|
+
h = to_hash
|
21
|
+
h.nil? ? super : h.hash
|
48
22
|
end
|
49
23
|
|
50
|
-
#
|
51
|
-
def
|
52
|
-
|
24
|
+
# Expected to be overridden by subclasses
|
25
|
+
def to_ical
|
26
|
+
nil
|
53
27
|
end
|
54
28
|
|
55
|
-
#
|
56
|
-
def
|
57
|
-
|
29
|
+
# Yaml implementation
|
30
|
+
def to_yaml(*args)
|
31
|
+
defined?(Psych) ? Psych::dump(to_hash) : YAML::dump(to_hash, *args)
|
58
32
|
end
|
59
33
|
|
60
|
-
#
|
61
|
-
def self.
|
62
|
-
|
34
|
+
# From yaml
|
35
|
+
def self.from_yaml(yaml)
|
36
|
+
from_hash defined?(Psych) ? Psych::load(yaml) : YAML::load(yaml)
|
63
37
|
end
|
64
|
-
|
65
|
-
#
|
66
|
-
def
|
67
|
-
|
38
|
+
|
39
|
+
# Expected to be overridden by subclasses
|
40
|
+
def to_hash
|
41
|
+
nil
|
68
42
|
end
|
69
|
-
|
70
|
-
#
|
71
|
-
def self.
|
72
|
-
|
43
|
+
|
44
|
+
# Convert from a hash and create a rule
|
45
|
+
def self.from_hash(hash)
|
46
|
+
return nil unless match = hash[:rule_type].match(/\:\:(.+?)Rule/)
|
47
|
+
rule = IceCube::Rule.send(match[1].downcase.to_sym, hash[:interval] || 1)
|
48
|
+
rule.until(TimeUtil.deserialize_time(hash[:until])) if hash[:until]
|
49
|
+
rule.count(hash[:count]) if hash[:count]
|
50
|
+
hash[:validations] && hash[:validations].each do |key, value|
|
51
|
+
key = key.to_sym unless key.is_a?(Symbol)
|
52
|
+
value.is_a?(Array) ? rule.send(key, *value) : rule.send(key, value)
|
53
|
+
end
|
54
|
+
rule
|
73
55
|
end
|
74
|
-
|
75
|
-
#
|
76
|
-
def
|
77
|
-
|
56
|
+
|
57
|
+
# Reset the uses on the rule to 0
|
58
|
+
def reset
|
59
|
+
@uses = 0
|
78
60
|
end
|
79
|
-
|
80
|
-
|
81
|
-
def until(until_date)
|
82
|
-
raise ArgumentError.new('Cannot specify until and count on the same rule') if @count #as per rfc
|
83
|
-
@until_date = until_date
|
84
|
-
self
|
61
|
+
|
62
|
+
def next_time(time, schedule, closing_time)
|
85
63
|
end
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
raise ArgumentError.new('Argument must be a positive integer') unless Integer(count) && count >= 0
|
90
|
-
@occurrence_count = count
|
91
|
-
self
|
64
|
+
|
65
|
+
def on?(time, schedule)
|
66
|
+
next_time(time, schedule, time) == time
|
92
67
|
end
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
68
|
+
|
69
|
+
# Convenience methods for creating Rules
|
70
|
+
class << self
|
71
|
+
|
72
|
+
# Secondly Rule
|
73
|
+
def secondly(interval = 1)
|
74
|
+
SecondlyRule.new(interval)
|
98
75
|
end
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
# by constantly moving the farthest back value forward
|
104
|
-
def next_suggestion(date)
|
105
|
-
# get the next date recommendation set
|
106
|
-
suggestions = {};
|
107
|
-
@validation_types.each { |k, validation| suggestions[k] = validation.send(:closest, date) }
|
108
|
-
compact_suggestions = suggestions.values.compact
|
109
|
-
# find the next date to go to
|
110
|
-
if compact_suggestions.empty?
|
111
|
-
attempt_count = 0
|
112
|
-
loop do
|
113
|
-
# keep going through rule suggestions
|
114
|
-
next_date = self.default_jump(date, attempt_count += 1)
|
115
|
-
return next_date if !next_date.nil? && validate_single_date(next_date)
|
116
|
-
end
|
117
|
-
else
|
118
|
-
loop do
|
119
|
-
compact_suggestions = suggestions.values.compact
|
120
|
-
min_suggestion = compact_suggestions.min
|
121
|
-
# validate all against the minimum
|
122
|
-
return min_suggestion if validate_single_date(min_suggestion)
|
123
|
-
# move anything that is the minimum to its next closest
|
124
|
-
@validation_types.each do |k, validation|
|
125
|
-
suggestions[k] = validation.send(:closest, min_suggestion) if min_suggestion == suggestions[k]
|
126
|
-
end
|
127
|
-
end
|
76
|
+
|
77
|
+
# Minutely Rule
|
78
|
+
def minutely(interval = 1)
|
79
|
+
MinutelyRule.new(interval)
|
128
80
|
end
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
representation << ';' << v.send(:to_ical)
|
156
|
-
end
|
157
|
-
representation << ";COUNT=#{@occurrence_count}" if @occurrence_count
|
158
|
-
representation << ";UNTIL=#{TimeUtil.ical_utc_format(@until_date)}" if @until_date
|
159
|
-
representation
|
160
|
-
end
|
161
|
-
|
162
|
-
# Set the interval for the rule. Depending on the type of rule,
|
163
|
-
# interval means every (n) weeks, months, etc. starting on the start_date's
|
164
|
-
def initialize(interval = 1)
|
165
|
-
throw ArgumentError.new('Interval must be > 0') unless interval > 0
|
166
|
-
@validations = {}
|
167
|
-
@validation_types = {}
|
168
|
-
@interval = interval
|
81
|
+
|
82
|
+
# Hourly Rule
|
83
|
+
def hourly(interval = 1)
|
84
|
+
HourlyRule.new(interval)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Daily Rule
|
88
|
+
def daily(interval = 1)
|
89
|
+
DailyRule.new(interval)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Weekly Rule
|
93
|
+
def weekly(interval = 1)
|
94
|
+
WeeklyRule.new(interval)
|
95
|
+
end
|
96
|
+
|
97
|
+
# Monthly Rule
|
98
|
+
def monthly(interval = 1)
|
99
|
+
MonthlyRule.new(interval)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Yearly Rule
|
103
|
+
def yearly(interval = 1)
|
104
|
+
YearlyRule.new(interval)
|
105
|
+
end
|
106
|
+
|
169
107
|
end
|
170
108
|
|
171
109
|
end
|