montrose 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rubocop.yml +113 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +13 -0
  6. data/Gemfile +13 -0
  7. data/Guardfile +34 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +191 -0
  10. data/Rakefile +21 -0
  11. data/bin/_guard-core +16 -0
  12. data/bin/console +7 -0
  13. data/bin/guard +16 -0
  14. data/bin/m +16 -0
  15. data/bin/rake +16 -0
  16. data/bin/rubocop +16 -0
  17. data/bin/setup +7 -0
  18. data/lib/montrose.rb +20 -0
  19. data/lib/montrose/chainable.rb +210 -0
  20. data/lib/montrose/clock.rb +77 -0
  21. data/lib/montrose/errors.rb +5 -0
  22. data/lib/montrose/frequency.rb +63 -0
  23. data/lib/montrose/frequency/daily.rb +9 -0
  24. data/lib/montrose/frequency/hourly.rb +9 -0
  25. data/lib/montrose/frequency/minutely.rb +9 -0
  26. data/lib/montrose/frequency/monthly.rb +9 -0
  27. data/lib/montrose/frequency/weekly.rb +19 -0
  28. data/lib/montrose/frequency/yearly.rb +9 -0
  29. data/lib/montrose/options.rb +293 -0
  30. data/lib/montrose/recurrence.rb +67 -0
  31. data/lib/montrose/rule.rb +47 -0
  32. data/lib/montrose/rule/after.rb +27 -0
  33. data/lib/montrose/rule/before.rb +23 -0
  34. data/lib/montrose/rule/day_of_month.rb +31 -0
  35. data/lib/montrose/rule/day_of_week.rb +23 -0
  36. data/lib/montrose/rule/day_of_year.rb +37 -0
  37. data/lib/montrose/rule/hour_of_day.rb +23 -0
  38. data/lib/montrose/rule/month_of_year.rb +23 -0
  39. data/lib/montrose/rule/nth_day_matcher.rb +32 -0
  40. data/lib/montrose/rule/nth_day_of_month.rb +63 -0
  41. data/lib/montrose/rule/nth_day_of_year.rb +63 -0
  42. data/lib/montrose/rule/time_of_day.rb +33 -0
  43. data/lib/montrose/rule/total.rb +29 -0
  44. data/lib/montrose/rule/week_of_year.rb +23 -0
  45. data/lib/montrose/schedule.rb +42 -0
  46. data/lib/montrose/stack.rb +51 -0
  47. data/lib/montrose/utils.rb +32 -0
  48. data/lib/montrose/version.rb +3 -0
  49. data/montrose.gemspec +32 -0
  50. metadata +192 -0
@@ -0,0 +1,27 @@
1
+ module Montrose
2
+ module Rule
3
+ class After
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:starts]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Time] start_time - lower bound timestamp
13
+ #
14
+ def initialize(start_time)
15
+ @start_time = start_time
16
+ end
17
+
18
+ def include?(time)
19
+ time >= @start_time
20
+ end
21
+
22
+ def continue?
23
+ false
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class Before
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:until]
8
+ end
9
+
10
+ def initialize(end_time)
11
+ @end_time = end_time
12
+ end
13
+
14
+ def include?(time)
15
+ time < @end_time
16
+ end
17
+
18
+ def continue?
19
+ false
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,31 @@
1
+ module Montrose
2
+ module Rule
3
+ class DayOfMonth
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:mday]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array<Fixnum>] days - valid days of month, i.e. [1, 2, -1]
13
+ #
14
+ def initialize(days)
15
+ @days = days
16
+ end
17
+
18
+ def include?(time)
19
+ @days.include?(time.mday) || included_from_end_of_month?(time)
20
+ end
21
+
22
+ private
23
+
24
+ # matches days specified at negative numbers
25
+ def included_from_end_of_month?(time)
26
+ month_days = Time.days_in_month(time.month, time.year) # given by activesupport
27
+ @days.any? { |d| month_days + d + 1 == time.mday }
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class DayOfWeek
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:day]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array<Fixnum>] days - valid days of week, e.g. [1, 2, 7]
13
+ #
14
+ def initialize(days)
15
+ @days = days
16
+ end
17
+
18
+ def include?(time)
19
+ @days.include?(time.wday)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ module Montrose
2
+ module Rule
3
+ class DayOfYear
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:yday]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array<Fixnum>] days - valid days of year, e.g. [1, 2, -1]
13
+ #
14
+ def initialize(days)
15
+ @days = days
16
+ end
17
+
18
+ def include?(time)
19
+ @days.include?(time.yday) || included_from_end_of_month?(time)
20
+ end
21
+
22
+ private
23
+
24
+ def included_from_end_of_month?(time)
25
+ year_days = days_in_year(time.year) # given by activesupport
26
+ @days.any? { |d| year_days + d + 1 == time.yday }
27
+ end
28
+
29
+ # Returns the number of days in the given year.
30
+ # If no year is specified, it will use the current year.
31
+ # https://github.com/rails/rails/pull/22244
32
+ def days_in_year(year)
33
+ Time.days_in_month(2, year) + 337
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class HourOfDay
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:hour]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array<Fixnum>] hour - valid hours of days, e.g. [1, 2, 24]
13
+ #
14
+ def initialize(hours)
15
+ @hours = hours
16
+ end
17
+
18
+ def include?(time)
19
+ @hours.include?(time.hour)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class MonthOfYear
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:month]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array] months - valid month numbers
13
+ #
14
+ def initialize(months)
15
+ @months = months
16
+ end
17
+
18
+ def include?(time)
19
+ @months.include?(time.month)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,32 @@
1
+ module Montrose
2
+ module Rule
3
+ class NthDayMatcher
4
+ extend Forwardable
5
+
6
+ def_delegators :@period_day, :nth_day, :first_wday, :total_days
7
+
8
+ def initialize(wday, period_day)
9
+ @wday = wday
10
+ @period_day = period_day
11
+ end
12
+
13
+ def matches?(nth_occ)
14
+ nth_occ == current_occ || (nth_occ < 0 && (total_occ + nth_occ + 1) == current_occ)
15
+ end
16
+
17
+ private
18
+
19
+ def current_occ
20
+ @current_occ ||= (nth_day - first_occ) / 7 + 1
21
+ end
22
+
23
+ def total_occ
24
+ @total_occ ||= ((total_days - first_occ + 1) / 7.0).ceil
25
+ end
26
+
27
+ def first_occ
28
+ @first_occ ||= ((7 - first_wday) + @wday) % 7 + 1
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,63 @@
1
+ require "montrose/rule/nth_day_matcher"
2
+
3
+ module Montrose
4
+ module Rule
5
+ class NthDayOfMonth
6
+ include Montrose::Rule
7
+
8
+ def self.apply_options?(opts)
9
+ opts[:every] == :month && opts[:day].is_a?(Hash)
10
+ end
11
+
12
+ def self.apply_options(opts)
13
+ opts[:day]
14
+ end
15
+
16
+ # Initializes rule
17
+ #
18
+ # @param [Hash] days - valid days of week to month occurrence pairs
19
+ #
20
+ def initialize(days)
21
+ @days = days
22
+ end
23
+
24
+ def include?(time)
25
+ @days.key?(time.wday) && nth_day?(time)
26
+ end
27
+
28
+ private
29
+
30
+ def nth_day?(time)
31
+ expected_occurrences = @days[time.wday]
32
+ nth_day = NthDayMatcher.new(time.wday, MonthDay.new(time))
33
+ expected_occurrences.any? { |n| nth_day.matches?(n) }
34
+ end
35
+
36
+ class MonthDay
37
+ def initialize(time)
38
+ @time = time
39
+ end
40
+
41
+ def nth_day
42
+ @time.mday
43
+ end
44
+
45
+ def first_wday
46
+ @time.beginning_of_month.wday
47
+ end
48
+
49
+ def total_days
50
+ days_in_month(@time)
51
+ end
52
+
53
+ private
54
+
55
+ # Get the days in the month for +time
56
+ def days_in_month(time)
57
+ date = Date.new(time.year, time.month, 1)
58
+ ((date >> 1) - date).to_i
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,63 @@
1
+ require "montrose/rule/nth_day_matcher"
2
+
3
+ module Montrose
4
+ module Rule
5
+ class NthDayOfYear
6
+ include Montrose::Rule
7
+
8
+ def self.apply_options?(opts)
9
+ opts[:every] == :year && opts[:day].is_a?(Hash)
10
+ end
11
+
12
+ def self.apply_options(opts)
13
+ opts[:day]
14
+ end
15
+
16
+ # Initializes rule
17
+ #
18
+ # @param [Hash] days - valid days of week to year occurrence pairs
19
+ #
20
+ def initialize(days)
21
+ @days = days
22
+ end
23
+
24
+ def include?(time)
25
+ @days.key?(time.wday) && nth_day?(time)
26
+ end
27
+
28
+ private
29
+
30
+ def nth_day?(time)
31
+ expected_occurrences = @days[time.wday]
32
+ nth_day = NthDayMatcher.new(time.wday, YearDay.new(time))
33
+ expected_occurrences.any? { |n| nth_day.matches?(n) }
34
+ end
35
+
36
+ class YearDay
37
+ def initialize(time)
38
+ @time = time
39
+ end
40
+
41
+ def nth_day
42
+ @time.yday
43
+ end
44
+
45
+ def first_wday
46
+ @time.beginning_of_year.wday
47
+ end
48
+
49
+ def total_days
50
+ days_in_year(@time)
51
+ end
52
+
53
+ private
54
+
55
+ # Get the days in the month for +time
56
+ def days_in_year(time)
57
+ date = time.to_date
58
+ ((date + 1.year) - date).to_i
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,33 @@
1
+ module Montrose
2
+ module Rule
3
+ class TimeOfDay
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:at]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array<Time>] times - valid hours of days
13
+ #
14
+ def initialize(times)
15
+ @times = times
16
+ end
17
+
18
+ def include?(time)
19
+ times_of_day.include?(parts(time))
20
+ end
21
+
22
+ private
23
+
24
+ def parts(time)
25
+ [time.hour, time.min]
26
+ end
27
+
28
+ def times_of_day
29
+ @times_of_day ||= @times.map { |t| parts(t) }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Montrose
2
+ module Rule
3
+ class Total
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:total]
8
+ end
9
+
10
+ def initialize(max)
11
+ @max = max
12
+ @count = 0
13
+ end
14
+
15
+ def include?(_time)
16
+ continue?
17
+ end
18
+
19
+ def advance!(_time)
20
+ @count += 1
21
+ continue?
22
+ end
23
+
24
+ def continue?
25
+ @count <= @max
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class WeekOfYear
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:week]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Array[Fixnum]] weeks - valid weeks of year
13
+ #
14
+ def initialize(weeks)
15
+ @weeks = weeks
16
+ end
17
+
18
+ def include?(time)
19
+ @weeks.include?(time.to_date.cweek)
20
+ end
21
+ end
22
+ end
23
+ end