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,55 @@
1
+ module IceCube
2
+
3
+ module Validations::HourOfDay
4
+
5
+ # Add hour of day validations
6
+ def hour_of_day(*hours)
7
+ hours.flatten.each do |hour|
8
+ unless hour.is_a?(Fixnum)
9
+ raise ArgumentError, "expecting Fixnum value for hour, got #{hour.inspect}"
10
+ end
11
+ validations_for(:hour_of_day) << Validation.new(hour)
12
+ end
13
+ clobber_base_validations(:hour)
14
+ self
15
+ end
16
+
17
+ class Validation < Validations::FixedValue
18
+
19
+ attr_reader :hour
20
+ alias :value :hour
21
+
22
+ def initialize(hour)
23
+ @hour = hour
24
+ end
25
+
26
+ def type
27
+ :hour
28
+ end
29
+
30
+ def dst_adjust?
31
+ true
32
+ end
33
+
34
+ def build_s(builder)
35
+ builder.piece(:hour_of_day) << StringBuilder.nice_number(hour)
36
+ end
37
+
38
+ def build_hash(builder)
39
+ builder.validations_array(:hour_of_day) << hour
40
+ end
41
+
42
+ def build_ical(builder)
43
+ builder['BYHOUR'] << hour
44
+ end
45
+
46
+ StringBuilder.register_formatter(:hour_of_day) do |segments|
47
+ str = StringBuilder.sentence(segments)
48
+ IceCube::I18n.t('ice_cube.at_hours_of_the_day', count: segments.size, segments: str)
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end
@@ -0,0 +1,54 @@
1
+ module IceCube
2
+
3
+ module Validations::HourlyInterval
4
+
5
+ def interval(interval)
6
+ @interval = normalized_interval(interval)
7
+ replace_validations_for(:interval, [Validation.new(@interval)])
8
+ clobber_base_validations(:hour)
9
+ self
10
+ end
11
+
12
+ class Validation
13
+
14
+ attr_reader :interval
15
+
16
+ def initialize(interval)
17
+ @interval = interval
18
+ end
19
+
20
+ def type
21
+ :hour
22
+ end
23
+
24
+ def dst_adjust?
25
+ false
26
+ end
27
+
28
+ def validate(step_time, schedule)
29
+ t0, t1 = schedule.start_time.to_i, step_time.to_i
30
+ sec = (t1 - t1 % ONE_HOUR) -
31
+ (t0 - t0 % ONE_HOUR)
32
+ hours = sec / ONE_HOUR
33
+ offset = (hours % interval).nonzero?
34
+ interval - offset if offset
35
+ end
36
+
37
+ def build_s(builder)
38
+ builder.base = IceCube::I18n.t("ice_cube.each_hour", count: interval)
39
+ end
40
+
41
+ def build_hash(builder)
42
+ builder[:interval] = interval
43
+ end
44
+
45
+ def build_ical(builder)
46
+ builder['FREQ'] << 'HOURLY'
47
+ builder['INTERVAL'] << interval unless interval == 1
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,95 @@
1
+ module IceCube
2
+
3
+ # This validation mixin is used by the various "fixed-time" (e.g. day,
4
+ # day_of_month, hour_of_day) Validation and ScheduleLock::Validation modules.
5
+ # It is not a standalone rule validation like the others.
6
+ #
7
+ # Given the including Validation's defined +type+ field, it will lock
8
+ # to the specified +value+ or else the corresponding time unit from the
9
+ # schedule's start_time
10
+ #
11
+ module Validations::Lock
12
+
13
+ INTERVALS = {:min => 60, :sec => 60, :hour => 24, :month => 12, :wday => 7}
14
+
15
+ def validate(time, schedule)
16
+ case type
17
+ when :day then validate_day_lock(time, schedule)
18
+ when :hour then validate_hour_lock(time, schedule)
19
+ else validate_interval_lock(time, schedule)
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ # Validate if the current time unit matches the same unit from the schedule
26
+ # start time, returning the difference to the interval
27
+ #
28
+ def validate_interval_lock(time, schedule)
29
+ t0 = starting_unit(schedule.start_time)
30
+ t1 = time.send(type)
31
+ t0 >= t1 ? t0 - t1 : INTERVALS[type] - t1 + t0
32
+ end
33
+
34
+ # Lock the hour if explicitly set by hour_of_day, but allow for the nearest
35
+ # hour during DST start to keep the correct interval.
36
+ #
37
+ def validate_hour_lock(time, schedule)
38
+ h0 = starting_unit(schedule.start_time)
39
+ h1 = time.hour
40
+ if h0 >= h1
41
+ h0 - h1
42
+ else
43
+ if dst_offset = TimeUtil.dst_change(time)
44
+ h0 - h1 + dst_offset
45
+ else
46
+ 24 - h1 + h0
47
+ end
48
+ end
49
+ end
50
+
51
+ # For monthly rules that have no specified day value, the validation relies
52
+ # on the schedule start time and jumps to include every month even if it
53
+ # has fewer days than the schedule's start day.
54
+ #
55
+ # Negative day values (from month end) also include all months.
56
+ #
57
+ # Positive day values are taken literally so months with fewer days will
58
+ # be skipped.
59
+ #
60
+ def validate_day_lock(time, schedule)
61
+ days_in_month = TimeUtil.days_in_month(time)
62
+ date = Date.new(time.year, time.month, time.day)
63
+
64
+ if value && value < 0
65
+ start = TimeUtil.day_of_month(value, date)
66
+ month_overflow = days_in_month - TimeUtil.days_in_next_month(time)
67
+ elsif value && value > 0
68
+ start = value
69
+ month_overflow = 0
70
+ else
71
+ start = TimeUtil.day_of_month(schedule.start_time.day, date)
72
+ month_overflow = 0
73
+ end
74
+
75
+ sleeps = start - date.day
76
+
77
+ if value && value > 0
78
+ until_next_month = days_in_month + sleeps
79
+ else
80
+ until_next_month = start < 28 ? days_in_month : TimeUtil.days_to_next_month(date)
81
+ until_next_month += sleeps - month_overflow
82
+ end
83
+
84
+ sleeps >= 0 ? sleeps : until_next_month
85
+ end
86
+
87
+ def starting_unit(start_time)
88
+ start = value || start_time.send(type)
89
+ start += INTERVALS[type] while start < 0
90
+ start
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,54 @@
1
+ module IceCube
2
+
3
+ module Validations::MinuteOfHour
4
+
5
+ def minute_of_hour(*minutes)
6
+ minutes.flatten.each do |minute|
7
+ unless minute.is_a?(Fixnum)
8
+ raise ArgumentError, "expecting Fixnum value for minute, got #{minute.inspect}"
9
+ end
10
+ validations_for(:minute_of_hour) << Validation.new(minute)
11
+ end
12
+ clobber_base_validations(:min)
13
+ self
14
+ end
15
+
16
+ class Validation < Validations::FixedValue
17
+
18
+ attr_reader :minute
19
+ alias :value :minute
20
+
21
+ def initialize(minute)
22
+ @minute = minute
23
+ end
24
+
25
+ def type
26
+ :min
27
+ end
28
+
29
+ def dst_adjust?
30
+ false
31
+ end
32
+
33
+ def build_s(builder)
34
+ builder.piece(:minute_of_hour) << StringBuilder.nice_number(minute)
35
+ end
36
+
37
+ def build_hash(builder)
38
+ builder.validations_array(:minute_of_hour) << minute
39
+ end
40
+
41
+ def build_ical(builder)
42
+ builder['BYMINUTE'] << minute
43
+ end
44
+
45
+ StringBuilder.register_formatter(:minute_of_hour) do |segments|
46
+ str = StringBuilder.sentence(segments)
47
+ IceCube::I18n.t('ice_cube.on_minutes_of_hour', count: segments.size, segments: str)
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,54 @@
1
+ module IceCube
2
+
3
+ module Validations::MinutelyInterval
4
+
5
+ def interval(interval)
6
+ @interval = normalized_interval(interval)
7
+ replace_validations_for(:interval, [Validation.new(@interval)])
8
+ clobber_base_validations(:min)
9
+ self
10
+ end
11
+
12
+ class Validation
13
+
14
+ attr_reader :interval
15
+
16
+ def initialize(interval)
17
+ @interval = interval
18
+ end
19
+
20
+ def type
21
+ :min
22
+ end
23
+
24
+ def dst_adjust?
25
+ false
26
+ end
27
+
28
+ def validate(step_time, schedule)
29
+ t0, t1 = schedule.start_time.to_i, step_time.to_i
30
+ sec = (t1 - t1 % ONE_MINUTE) -
31
+ (t0 - t0 % ONE_MINUTE)
32
+ minutes = sec / ONE_MINUTE
33
+ offset = (minutes % interval).nonzero?
34
+ interval - offset if offset
35
+ end
36
+
37
+ def build_s(builder)
38
+ builder.base = IceCube::I18n.t('ice_cube.each_minute', count: interval)
39
+ end
40
+
41
+ def build_hash(builder)
42
+ builder[:interval] = interval
43
+ end
44
+
45
+ def build_ical(builder)
46
+ builder['FREQ'] << 'MINUTELY'
47
+ builder['INTERVAL'] << interval unless interval == 1
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,54 @@
1
+ module IceCube
2
+
3
+ module Validations::MonthOfYear
4
+
5
+ def month_of_year(*months)
6
+ months.flatten.each do |month|
7
+ unless month.is_a?(Fixnum) || month.is_a?(Symbol)
8
+ raise ArgumentError, "expecting Fixnum or Symbol value for month, got #{month.inspect}"
9
+ end
10
+ month = TimeUtil.sym_to_month(month)
11
+ validations_for(:month_of_year) << Validation.new(month)
12
+ end
13
+ clobber_base_validations :month
14
+ self
15
+ end
16
+
17
+ class Validation < Validations::FixedValue
18
+
19
+ attr_reader :month
20
+ alias :value :month
21
+
22
+ def initialize(month)
23
+ @month = month
24
+ end
25
+
26
+ def type
27
+ :month
28
+ end
29
+
30
+ def dst_adjust?
31
+ true
32
+ end
33
+
34
+ def build_s(builder)
35
+ builder.piece(:month_of_year) << IceCube::I18n.t("ice_cube.date.month_names")[month]
36
+ end
37
+
38
+ def build_hash(builder)
39
+ builder.validations_array(:month_of_year) << month
40
+ end
41
+
42
+ def build_ical(builder)
43
+ builder['BYMONTH'] << month
44
+ end
45
+
46
+ StringBuilder.register_formatter(:month_of_year) do |segments|
47
+ IceCube::I18n.t("ice_cube.in", target: StringBuilder.sentence(segments))
48
+ end
49
+
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,53 @@
1
+ module IceCube
2
+
3
+ module Validations::MonthlyInterval
4
+
5
+ def interval(interval)
6
+ @interval = normalized_interval(interval)
7
+ replace_validations_for(:interval, [Validation.new(@interval)])
8
+ clobber_base_validations(:month)
9
+ self
10
+ end
11
+
12
+ class Validation
13
+
14
+ attr_reader :interval
15
+
16
+ def initialize(interval)
17
+ @interval = interval
18
+ end
19
+
20
+ def type
21
+ :month
22
+ end
23
+
24
+ def dst_adjust?
25
+ true
26
+ end
27
+
28
+ def validate(step_time, schedule)
29
+ t0, t1 = schedule.start_time, step_time
30
+ months = (t1.month - t0.month) +
31
+ (t1.year - t0.year) * 12
32
+ offset = (months % interval).nonzero?
33
+ interval - offset if offset
34
+ end
35
+
36
+ def build_s(builder)
37
+ builder.base = IceCube::I18n.t('ice_cube.each_month', count: interval)
38
+ end
39
+
40
+ def build_hash(builder)
41
+ builder[:interval] = interval
42
+ end
43
+
44
+ def build_ical(builder)
45
+ builder['FREQ'] << 'MONTHLY'
46
+ builder['INTERVAL'] << interval unless interval == 1
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ end
@@ -0,0 +1,46 @@
1
+ module IceCube
2
+
3
+ module Validations::ScheduleLock
4
+
5
+ # Lock the given time units to the units from schedule's +start_time+
6
+ # These locks are all clobberable by other rules of the same #type
7
+ # using +clobber_base_validation+
8
+ #
9
+ def schedule_lock(*types)
10
+ types.each do |type|
11
+ validations_for(:"base_#{type}") << Validation.new(type)
12
+ end
13
+ end
14
+
15
+ class Validation < Validations::FixedValue
16
+
17
+ attr_reader :type, :value
18
+
19
+ def initialize(type)
20
+ @type = type
21
+ end
22
+
23
+ def dst_adjust?
24
+ case @type
25
+ when :sec, :min then false
26
+ else true
27
+ end
28
+ end
29
+
30
+ # no -op
31
+ def build_s(builder)
32
+ end
33
+
34
+ # no -op
35
+ def build_hash(builder)
36
+ end
37
+
38
+ # no -op
39
+ def build_ical(builder)
40
+ end
41
+
42
+ end
43
+
44
+ end
45
+
46
+ end