ice_cube_chosko 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +7 -0
  2. data/config/locales/en.yml +178 -0
  3. data/config/locales/es.yml +176 -0
  4. data/config/locales/ja.yml +107 -0
  5. data/lib/ice_cube.rb +92 -0
  6. data/lib/ice_cube/builders/hash_builder.rb +27 -0
  7. data/lib/ice_cube/builders/ical_builder.rb +59 -0
  8. data/lib/ice_cube/builders/string_builder.rb +76 -0
  9. data/lib/ice_cube/deprecated.rb +36 -0
  10. data/lib/ice_cube/errors/count_exceeded.rb +7 -0
  11. data/lib/ice_cube/errors/until_exceeded.rb +7 -0
  12. data/lib/ice_cube/flexible_hash.rb +40 -0
  13. data/lib/ice_cube/i18n.rb +24 -0
  14. data/lib/ice_cube/null_i18n.rb +28 -0
  15. data/lib/ice_cube/occurrence.rb +101 -0
  16. data/lib/ice_cube/parsers/hash_parser.rb +91 -0
  17. data/lib/ice_cube/parsers/ical_parser.rb +91 -0
  18. data/lib/ice_cube/parsers/yaml_parser.rb +19 -0
  19. data/lib/ice_cube/rule.rb +123 -0
  20. data/lib/ice_cube/rules/daily_rule.rb +16 -0
  21. data/lib/ice_cube/rules/hourly_rule.rb +16 -0
  22. data/lib/ice_cube/rules/minutely_rule.rb +16 -0
  23. data/lib/ice_cube/rules/monthly_rule.rb +16 -0
  24. data/lib/ice_cube/rules/secondly_rule.rb +15 -0
  25. data/lib/ice_cube/rules/weekly_rule.rb +16 -0
  26. data/lib/ice_cube/rules/yearly_rule.rb +16 -0
  27. data/lib/ice_cube/schedule.rb +529 -0
  28. data/lib/ice_cube/single_occurrence_rule.rb +28 -0
  29. data/lib/ice_cube/time_util.rb +328 -0
  30. data/lib/ice_cube/validated_rule.rb +184 -0
  31. data/lib/ice_cube/validations/count.rb +61 -0
  32. data/lib/ice_cube/validations/daily_interval.rb +54 -0
  33. data/lib/ice_cube/validations/day.rb +71 -0
  34. data/lib/ice_cube/validations/day_of_month.rb +55 -0
  35. data/lib/ice_cube/validations/day_of_week.rb +77 -0
  36. data/lib/ice_cube/validations/day_of_year.rb +61 -0
  37. data/lib/ice_cube/validations/fixed_value.rb +95 -0
  38. data/lib/ice_cube/validations/hour_of_day.rb +55 -0
  39. data/lib/ice_cube/validations/hourly_interval.rb +54 -0
  40. data/lib/ice_cube/validations/lock.rb +95 -0
  41. data/lib/ice_cube/validations/minute_of_hour.rb +54 -0
  42. data/lib/ice_cube/validations/minutely_interval.rb +54 -0
  43. data/lib/ice_cube/validations/month_of_year.rb +54 -0
  44. data/lib/ice_cube/validations/monthly_interval.rb +53 -0
  45. data/lib/ice_cube/validations/schedule_lock.rb +46 -0
  46. data/lib/ice_cube/validations/second_of_minute.rb +54 -0
  47. data/lib/ice_cube/validations/secondly_interval.rb +51 -0
  48. data/lib/ice_cube/validations/until.rb +57 -0
  49. data/lib/ice_cube/validations/weekly_interval.rb +67 -0
  50. data/lib/ice_cube/validations/yearly_interval.rb +53 -0
  51. data/lib/ice_cube/version.rb +5 -0
  52. data/spec/spec_helper.rb +64 -0
  53. metadata +166 -0
@@ -0,0 +1,91 @@
1
+ module IceCube
2
+ class HashParser
3
+
4
+ attr_reader :hash
5
+
6
+ def initialize(original_hash)
7
+ @hash = original_hash
8
+ end
9
+
10
+ def to_schedule
11
+ data = normalize_keys(hash)
12
+ schedule = IceCube::Schedule.new parse_time(data[:start_time])
13
+ apply_duration schedule, data
14
+ apply_end_time schedule, data
15
+ apply_rrules schedule, data
16
+ apply_exrules schedule, data
17
+ apply_rtimes schedule, data
18
+ apply_extimes schedule, data
19
+ yield schedule if block_given?
20
+ schedule
21
+ end
22
+
23
+ private
24
+
25
+ def normalize_keys(hash)
26
+ data = IceCube::FlexibleHash.new(hash.dup)
27
+
28
+ if (start_date = data.delete(:start_date))
29
+ warn "IceCube: :start_date is deprecated, please use :start_time at: #{ caller[0] }"
30
+ data[:start_time] = start_date
31
+ end
32
+
33
+ {:rdates => :rtimes, :exdates => :extimes}.each do |old_key, new_key|
34
+ if (times = data.delete(old_key))
35
+ warn "IceCube: :#{old_key} is deprecated, please use :#{new_key} at: #{ caller[0] }"
36
+ (data[new_key] ||= []).concat times
37
+ end
38
+ end
39
+
40
+ data
41
+ end
42
+
43
+ def apply_duration(schedule, data)
44
+ return unless data[:duration]
45
+ schedule.duration = data[:duration].to_i
46
+ end
47
+
48
+ def apply_end_time(schedule, data)
49
+ return unless data[:end_time]
50
+ schedule.end_time = parse_time(data[:end_time])
51
+ end
52
+
53
+ def apply_rrules(schedule, data)
54
+ return unless data[:rrules]
55
+ data[:rrules].each do |h|
56
+ rrule = h.is_a?(IceCube::Rule) ? h : IceCube::Rule.from_hash(h)
57
+
58
+ schedule.rrule(rrule)
59
+ end
60
+ end
61
+
62
+ def apply_exrules(schedule, data)
63
+ return unless data[:exrules]
64
+ warn "IceCube: :exrules is deprecated, and will be removed in a future release. at: #{ caller[0] }"
65
+ data[:exrules].each do |h|
66
+ rrule = h.is_a?(IceCube::Rule) ? h : IceCube::Rule.from_hash(h)
67
+
68
+ schedule.exrule(rrule)
69
+ end
70
+ end
71
+
72
+ def apply_rtimes(schedule, data)
73
+ return unless data[:rtimes]
74
+ data[:rtimes].each do |t|
75
+ schedule.add_recurrence_time TimeUtil.deserialize_time(t)
76
+ end
77
+ end
78
+
79
+ def apply_extimes(schedule, data)
80
+ return unless data[:extimes]
81
+ data[:extimes].each do |t|
82
+ schedule.add_exception_time TimeUtil.deserialize_time(t)
83
+ end
84
+ end
85
+
86
+ def parse_time(time)
87
+ TimeUtil.deserialize_time(time)
88
+ end
89
+
90
+ end
91
+ end
@@ -0,0 +1,91 @@
1
+ module IceCube
2
+ class IcalParser
3
+ def self.schedule_from_ical(ical_string, options = {})
4
+ data = {}
5
+ ical_string.each_line do |line|
6
+ (property, value) = line.split(':')
7
+ (property, tzid) = property.split(';')
8
+ case property
9
+ when 'DTSTART'
10
+ data[:start_time] = Time.parse(value)
11
+ when 'DTEND'
12
+ data[:end_time] = Time.parse(value)
13
+ when 'EXDATE'
14
+ data[:extimes] ||= []
15
+ data[:extimes] += value.split(',').map{|v| Time.parse(v)}
16
+ when 'DURATION'
17
+ data[:duration] # FIXME
18
+ when 'RRULE'
19
+ data[:rrules] ||= []
20
+ data[:rrules] += [rule_from_ical(value)]
21
+ end
22
+ end
23
+ Schedule.from_hash data
24
+ end
25
+
26
+ def self.rule_from_ical(ical)
27
+ params = { validations: { } }
28
+
29
+ ical.split(';').each do |rule|
30
+ (name, value) = rule.split('=')
31
+ value.strip!
32
+ case name
33
+ when 'FREQ'
34
+ params[:freq] = value.downcase
35
+ when 'INTERVAL'
36
+ params[:interval] = value.to_i
37
+ when 'COUNT'
38
+ params[:count] = value.to_i
39
+ when 'UNTIL'
40
+ params[:until] = Time.parse(value).utc
41
+ when 'WKST'
42
+ params[:wkst] = TimeUtil.ical_day_to_symbol(value)
43
+ when 'BYSECOND'
44
+ params[:validations][:second_of_minute] = value.split(',').collect(&:to_i)
45
+ when 'BYMINUTE'
46
+ params[:validations][:minute_of_hour] = value.split(',').collect(&:to_i)
47
+ when 'BYHOUR'
48
+ params[:validations][:hour_of_day] = value.split(',').collect(&:to_i)
49
+ when 'BYDAY'
50
+ dows = {}
51
+ days = []
52
+ value.split(',').each do |expr|
53
+ day = TimeUtil.ical_day_to_symbol(expr.strip[-2..-1])
54
+ if expr.strip.length > 2 # day with occurence
55
+ occ = expr[0..-3].to_i
56
+ dows[day].nil? ? dows[day] = [occ] : dows[day].push(occ)
57
+ days.delete(TimeUtil.sym_to_wday(day))
58
+ else
59
+ days.push TimeUtil.sym_to_wday(day) if dows[day].nil?
60
+ end
61
+ end
62
+ params[:validations][:day_of_week] = dows unless dows.empty?
63
+ params[:validations][:day] = days unless days.empty?
64
+ when 'BYMONTHDAY'
65
+ params[:validations][:day_of_month] = value.split(',').collect(&:to_i)
66
+ when 'BYMONTH'
67
+ params[:validations][:month_of_year] = value.split(',').collect(&:to_i)
68
+ when 'BYYEARDAY'
69
+ params[:validations][:day_of_year] = value.split(',').collect(&:to_i)
70
+ when 'BYSETPOS'
71
+ else
72
+ raise "Invalid or unsupported rrule command: #{name}"
73
+ end
74
+ end
75
+
76
+ params[:interval] ||= 1
77
+
78
+ # WKST only valid for weekly rules
79
+ params.delete(:wkst) unless params[:freq] == 'weekly'
80
+
81
+ rule = Rule.send(*params.values_at(:freq, :interval, :wkst).compact)
82
+ rule.count(params[:count]) if params[:count]
83
+ rule.until(params[:until]) if params[:until]
84
+ params[:validations].each do |key, value|
85
+ value.is_a?(Array) ? rule.send(key, *value) : rule.send(key, value)
86
+ end
87
+
88
+ rule
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,19 @@
1
+ require 'yaml'
2
+
3
+ module IceCube
4
+ class YamlParser < HashParser
5
+
6
+ SERIALIZED_START = /start_(?:time|date): .+(?<tz>(?:-|\+)\d{2}:\d{2})$/
7
+
8
+ attr_reader :hash
9
+
10
+ def initialize(yaml)
11
+ @hash = YAML::load(yaml)
12
+ yaml.match SERIALIZED_START do |match|
13
+ start_time = hash[:start_time] || hash[:start_date]
14
+ TimeUtil.restore_deserialized_offset start_time, match[:tz]
15
+ end
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,123 @@
1
+ require 'yaml'
2
+
3
+ module IceCube
4
+
5
+ class Rule
6
+
7
+ attr_reader :uses
8
+
9
+ # Is this a terminating schedule?
10
+ def terminating?
11
+ until_time || occurrence_count
12
+ end
13
+
14
+ def ==(rule)
15
+ if rule.is_a? Rule
16
+ hash = to_hash
17
+ hash && hash == rule.to_hash
18
+ end
19
+ end
20
+
21
+ def hash
22
+ h = to_hash
23
+ h.nil? ? super : h.hash
24
+ end
25
+
26
+ def to_ical
27
+ raise MethodNotImplemented, "Expected to be overrridden by subclasses"
28
+ end
29
+
30
+ # Convert from ical string and create a rule
31
+ def self.from_ical(ical)
32
+ IceCube::IcalParser.rule_from_ical(ical)
33
+ end
34
+
35
+ # Yaml implementation
36
+ def to_yaml(*args)
37
+ YAML::dump(to_hash, *args)
38
+ end
39
+
40
+ # From yaml
41
+ def self.from_yaml(yaml)
42
+ from_hash YAML::load(yaml)
43
+ end
44
+
45
+ def to_hash
46
+ raise MethodNotImplemented, "Expected to be overridden by subclasses"
47
+ end
48
+
49
+ # Convert from a hash and create a rule
50
+ def self.from_hash(original_hash)
51
+ hash = IceCube::FlexibleHash.new original_hash
52
+ return nil unless match = hash[:rule_type].match(/\:\:(.+?)Rule/)
53
+ rule = IceCube::Rule.send(match[1].downcase.to_sym, hash[:interval] || 1)
54
+ rule.interval(hash[:interval] || 1, TimeUtil.wday_to_sym(hash[:week_start] || 0)) if match[1] == "Weekly"
55
+ rule.until(TimeUtil.deserialize_time(hash[:until])) if hash[:until]
56
+ rule.count(hash[:count]) if hash[:count]
57
+ hash[:validations] && hash[:validations].each do |key, value|
58
+ key = key.to_sym unless key.is_a?(Symbol)
59
+ value.is_a?(Array) ? rule.send(key, *value) : rule.send(key, value)
60
+ end
61
+ rule
62
+ end
63
+
64
+ # Reset the uses on the rule to 0
65
+ def reset
66
+ @uses = 0
67
+ end
68
+
69
+ def next_time(time, schedule, closing_time)
70
+ end
71
+
72
+ def on?(time, schedule)
73
+ next_time(time, schedule, time).to_i == time.to_i
74
+ end
75
+
76
+ # Whether this rule requires a full run
77
+ def full_required?
78
+ !@count.nil?
79
+ end
80
+
81
+ # Convenience methods for creating Rules
82
+ class << self
83
+
84
+ # Secondly Rule
85
+ def secondly(interval = 1)
86
+ SecondlyRule.new(interval)
87
+ end
88
+
89
+ # Minutely Rule
90
+ def minutely(interval = 1)
91
+ MinutelyRule.new(interval)
92
+ end
93
+
94
+ # Hourly Rule
95
+ def hourly(interval = 1)
96
+ HourlyRule.new(interval)
97
+ end
98
+
99
+ # Daily Rule
100
+ def daily(interval = 1)
101
+ DailyRule.new(interval)
102
+ end
103
+
104
+ # Weekly Rule
105
+ def weekly(interval = 1, week_start = :sunday)
106
+ WeeklyRule.new(interval, week_start)
107
+ end
108
+
109
+ # Monthly Rule
110
+ def monthly(interval = 1)
111
+ MonthlyRule.new(interval)
112
+ end
113
+
114
+ # Yearly Rule
115
+ def yearly(interval = 1)
116
+ YearlyRule.new(interval)
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class DailyRule < ValidatedRule
4
+
5
+ include Validations::DailyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ schedule_lock(:hour, :min, :sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class HourlyRule < ValidatedRule
4
+
5
+ include Validations::HourlyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ schedule_lock(:min, :sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class MinutelyRule < ValidatedRule
4
+
5
+ include Validations::MinutelyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ schedule_lock(:sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class MonthlyRule < ValidatedRule
4
+
5
+ include Validations::MonthlyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ schedule_lock(:day, :hour, :min, :sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,15 @@
1
+ module IceCube
2
+
3
+ class SecondlyRule < ValidatedRule
4
+
5
+ include Validations::SecondlyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ reset
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class WeeklyRule < ValidatedRule
4
+
5
+ include Validations::WeeklyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval, week_start)
10
+ schedule_lock(:wday, :hour, :min, :sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,16 @@
1
+ module IceCube
2
+
3
+ class YearlyRule < ValidatedRule
4
+
5
+ include Validations::YearlyInterval
6
+
7
+ def initialize(interval = 1, week_start = :sunday)
8
+ super
9
+ interval(interval)
10
+ schedule_lock(:month, :day, :hour, :min, :sec)
11
+ reset
12
+ end
13
+
14
+ end
15
+
16
+ end