ice_cube_chosko 0.1.0

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.
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