montrose 0.1.1 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 98eedcb18d91e3390bc4bf1e9962e2ddd4a596a3
4
- data.tar.gz: 3a43325e390bd795c81a5ee6246a413542a59509
3
+ metadata.gz: 72c7f27af8ab0e30ced7801cad42cf1243f9f79f
4
+ data.tar.gz: 228ad308e574dabefc4f5635e76dd878c8d105c9
5
5
  SHA512:
6
- metadata.gz: 6983022b0d6ba0aebc265c311362a5e24f6dba4a19d7334d198b0eb49b91161ddfc92276c1edb636d7d6e03bfb0039d41a8a72805932fa22e37917ac5a57676d
7
- data.tar.gz: 1264cd660fc3e6fff55485a7a273961147188935a0b22b162090ca63a9293f7a82d54459b04f7a69009aa797c9c73090ac44e7c4779c00207b3473415d52219f
6
+ metadata.gz: 94736a08ae987f52cd24adace44ce7414604d375a0d5281c823426cbc7f9d205fd25dccdbbacd46533cca4dc9bd424395374191ce26b75e4e8897e2ddc35ff25
7
+ data.tar.gz: ae7a298bc0ed9830656c85ef8cbb74faaf8eb7d22f1ecd854dde5e7ce8d1eefc5a223e27b3d2ecbe683a1113c807a29df205cfeb3ddc324832af0b251a6470b4
data/CHANGELOG.md ADDED
@@ -0,0 +1,19 @@
1
+ ### 0.2.0 - 2016-02-03
2
+
3
+ * enhancements
4
+ * extend `Montrose::Schedule` api for building and adding recurrences
5
+ * add more details to chainable docs
6
+ * merge default options at enumeration time for more consistent serialization
7
+
8
+ ### 0.1.1 - 2016-25-01
9
+
10
+ * bug fixes
11
+ * add missing `require "forwardable"`
12
+ * enhancements
13
+ * add better `#inspect` methods in `Recurrence` and `Options`
14
+ * use refinement to refactor Options internal arg merging
15
+ * support ruby 2.3.0 in travis builds
16
+
17
+ ### 0.1.0 - 2016-18-01
18
+
19
+ * initial release
data/README.md CHANGED
@@ -155,6 +155,7 @@ Montrose::Recurrence.new(every: :minute, until: "9:00 PM")
155
155
 
156
156
  # Daily
157
157
  Montrose.daily
158
+ Montrose.every(:day)
158
159
  Montrose::Recurrence.new(every: :day)
159
160
 
160
161
  Montrose.every(9.days)
@@ -218,18 +219,15 @@ Montrose.daily(except: [Date.today, "2017-01-31"])
218
219
  # Chaining
219
220
  Montrose.weekly.starting(3.weeks.from_now).on(:friday)
220
221
  Montrose.every(:day).at("4:05pm")
222
+ Montrose.yearly.between(Time.now..10.years.from_now)
221
223
 
222
224
  # Enumerating events
223
225
  r = Montrose.every(:month, mday: 31, until: "January 1, 2017")
224
226
  r.each { |time| puts time.to_s }
225
227
  r.take(10).to_a
226
228
 
227
- # Merging rules and enumerating
229
+ # Merging rules
228
230
  r.merge(starts: "2017-01-01").each { |time| puts time.to_s }
229
- r.merge(starts: "2017-01-01").each { |date| puts date.to_s }
230
- r.merge(until: "2017-01-10").each { |date| puts date.to_s }
231
- r.merge(through: "2017-01-10").each { |date| puts date.to_s }
232
- r.merge(starts: "2017-01-05", until: "2017-01-10").each {|date| puts date.to_s }
233
231
 
234
232
  # Using #events Enumerator
235
233
  r.events # => #<Enumerator: ...>
data/Rakefile CHANGED
@@ -4,10 +4,6 @@ require "rake/testtask"
4
4
  require "rubocop/rake_task"
5
5
  require "yard"
6
6
 
7
- YARD::Rake::YardocTask.new do |t|
8
- t.files = ["README.md", "lib/**/*.rb"]
9
- end
10
-
11
7
  Rake::TestTask.new(:spec) do |t|
12
8
  t.libs << "spec"
13
9
  t.libs << "lib"
@@ -19,3 +15,16 @@ task test: :spec
19
15
  RuboCop::RakeTask.new
20
16
 
21
17
  task default: [:spec, :rubocop]
18
+
19
+ namespace :doc do
20
+ desc "Generate docs and publish to gh-pages"
21
+ task :publish do
22
+ require "fileutils"
23
+ sh "yard doc"
24
+ sh "git checkout gh-pages"
25
+ sh "cp -R doc/* ."
26
+ sh "git commit -vam 'Update documentation'"
27
+ sh "git push origin gh-pages"
28
+ sh "git checkout -"
29
+ end
30
+ end
@@ -1,13 +1,19 @@
1
1
  require "montrose/options"
2
+ require "montrose/refinements/array_concat"
2
3
 
3
4
  module Montrose
4
5
  module Chainable
6
+ using Montrose::Refinements::ArrayConcat
7
+
5
8
  # Create a recurrence from the given frequency
6
- # @example
7
9
  #
10
+ # @param frequency [Symbol,String,Numeric] the recurrence frequency
11
+ # @param options [Hash] additional recurrence options
12
+ #
13
+ # @example
8
14
  # Montrose.every(:hour)
9
- # Montrose.every(:hour, interval: 2) #=> every 2 hours
10
- # Montrose.every(3.days, starts: 2.days.from_now) #=> every 3 days
15
+ # Montrose.every(:hour, interval: 2)
16
+ # Montrose.every(3.days, starts: 2.days.from_now)
11
17
  # Montrose.every(1.year, until: 10.days.from_now)
12
18
  #
13
19
  def every(frequency, options = {})
@@ -16,8 +22,9 @@ module Montrose
16
22
 
17
23
  # Create a minutely recurrence.
18
24
  #
19
- # @example
25
+ # @param options [Hash] additional recurrence options
20
26
  #
27
+ # @example
21
28
  # Montrose.minutely
22
29
  # Montrose.minutely(interval: 2) #=> every 2 minutes
23
30
  # Montrose.minutely(starts: 3.days.from_now)
@@ -31,8 +38,9 @@ module Montrose
31
38
 
32
39
  # Create a hourly recurrence.
33
40
  #
34
- # @example
41
+ # @param options [Hash] additional recurrence options
35
42
  #
43
+ # @example
36
44
  # Montrose.hourly
37
45
  # Montrose.hourly(interval: 2) #=> every 2 hours
38
46
  # Montrose.hourly(starts: 3.days.from_now)
@@ -46,8 +54,9 @@ module Montrose
46
54
 
47
55
  # Create a daily recurrence.
48
56
  #
49
- # @example
57
+ # @param options [Hash] additional recurrence options
50
58
  #
59
+ # @example
51
60
  # Montrose.daily
52
61
  # Montrose.daily(interval: 2) #=> every 2 days
53
62
  # Montrose.daily(starts: 3.days.from_now)
@@ -61,6 +70,8 @@ module Montrose
61
70
 
62
71
  # Create a weekly recurrence.
63
72
  #
73
+ # @param options [Hash] additional recurrence options
74
+ #
64
75
  # @example
65
76
  # Montrose.weekly(on: 5) #=> 0 = sunday, 1 = monday, ...
66
77
  # Montrose.weekly(on: :saturday)
@@ -74,14 +85,12 @@ module Montrose
74
85
 
75
86
  # Create a monthly recurrence.
76
87
  #
77
- # @example
78
- # Montrose.monthly(mday: [2, 15]) # 2nd and 15th of the month
79
- # Montrose.monthly(mday: -3) # third-to-last day of the month
80
- # Montrose.monthly(mday: 10..15) # 10th through the 15th day of the month
81
- #
82
- # The <tt>:on</tt> option can be one of the following:
88
+ # @param options [Hash] additional recurrence options
83
89
  #
84
- # * :sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday
90
+ # @example
91
+ # Montrose.monthly(mday: [2, 15]) # 2nd and 15th of the month
92
+ # Montrose.monthly(mday: -3) # third-to-last day of the month
93
+ # Montrose.monthly(mday: 10..15) # 10th through the 15th day of the month
85
94
  #
86
95
  def monthly(options = {})
87
96
  branch options.merge(every: :month)
@@ -89,8 +98,9 @@ module Montrose
89
98
 
90
99
  # Create a yearly recurrence.
91
100
  #
92
- # @example
101
+ # @param options [Hash] additional recurrence options
93
102
  #
103
+ # @example
94
104
  # Montrose.yearly(on: [7, 14]) #=> every Jul 14
95
105
  # Montrose.yearly(on: [7, 14], interval: 2) #=> every 2 years on Jul 14
96
106
  # Montrose.yearly(on: [:jan, 14], interval: 2)
@@ -103,7 +113,10 @@ module Montrose
103
113
 
104
114
  # Create a recurrence starting at given timestamp.
105
115
  #
106
- # @param [Time, Date] starts_at
116
+ # @param starts_at [Time, Date] start time of recurrence
117
+ #
118
+ # @example
119
+ # Montrose.daily.starting(Date.tomorrow)
107
120
  #
108
121
  def starting(starts_at)
109
122
  merge(starts: starts_at)
@@ -111,7 +124,10 @@ module Montrose
111
124
 
112
125
  # Create a recurrence ending at given timestamp.
113
126
  #
114
- # @param [Time, Date] ends_at
127
+ # @param ends_at [Time, Date] end time of recurrence
128
+ #
129
+ # @example
130
+ # Montrose.daily.ending(1.year.from_now)
115
131
  #
116
132
  def ending(ends_at)
117
133
  merge(until: ends_at)
@@ -121,13 +137,20 @@ module Montrose
121
137
  #
122
138
  # @param [Range<Date>] date_range
123
139
  #
140
+ # @example
141
+ # Montrose.weekly.between(Date.today..Date.new(2016, 3, 15))
142
+ #
124
143
  def between(date_range)
125
144
  merge(between: date_range)
126
145
  end
127
146
 
128
147
  # Create a recurrence through :on option
129
148
  #
130
- # @param [Hash,Symbol] on { friday: 13 }
149
+ # @param day [Hash,Symbol] weekday or day of month as hash, e.g. { friday: 13 }
150
+ #
151
+ # @example
152
+ # Montrose.weekly.on(:friday)
153
+ # Montrose.monthly.on(friday: 13)
131
154
  #
132
155
  def on(day)
133
156
  merge(on: day)
@@ -135,7 +158,11 @@ module Montrose
135
158
 
136
159
  # Create a recurrence at given time
137
160
  #
138
- # @param [String,Time] at
161
+ # @param time [String,Time] represents time of day
162
+ #
163
+ # @example
164
+ # Montrose.daily.at("12pm")
165
+ # Montrose.daily.at("9:37am")
139
166
  #
140
167
  def at(time)
141
168
  merge(at: time)
@@ -143,69 +170,110 @@ module Montrose
143
170
 
144
171
  # Create a recurrence for given days of month
145
172
  #
146
- # @param [Fixnum] days (1, 2, -1, ...)
173
+ # @param days [Fixnum] days of month, e.g. 1, 2, -1, ...
147
174
  #
148
- def day_of_month(*days)
149
- merge(mday: days)
175
+ # @example
176
+ # Montrose.daily.day_of_month(1, -1)
177
+ # Montrose.daily.day_of_month([1, -1])
178
+ # Montrose.daily.day_of_month(2..8)
179
+ #
180
+ def day_of_month(days, *extras)
181
+ merge(mday: days.array_concat(extras))
150
182
  end
151
183
  alias mday day_of_month
152
184
 
153
185
  # Create a recurrence for given days of week
154
186
  #
155
- # @param [Symbol] weekdays (:sunday, :monday, ...)
187
+ # @param weekdays [Symbol] days of week, e.g. :sunday, :monday, ...
188
+ #
189
+ # @example
190
+ # Montrose.daily.day_of_week(:saturday)
191
+ # Montrose.daily.day_of_week(:monday, :tuesday)
192
+ # Montrose.daily.day_of_week(2..5)
156
193
  #
157
- def day_of_week(*weekdays)
158
- merge(day: weekdays)
194
+ def day_of_week(weekdays, *extras)
195
+ merge(day: weekdays.array_concat(extras))
159
196
  end
160
197
  alias day day_of_week
161
198
 
162
199
  # Create a recurrence for given days of year
163
200
  #
164
- # @param [Fixnum] days (1, 10, 100, ...)
201
+ # @param days [Fixnum, Range, Array<Integer>] days of year, e.g., 1, 10, 100, ...
165
202
  #
166
- def day_of_year(*days)
167
- merge(yday: days)
203
+ # @example
204
+ # Montrose.daily.day_of_year(1, 10, 100)
205
+ # Montrose.daily.day_of_year([1, 10, 100])
206
+ # Montrose.daily.day_of_year(20..50)
207
+ #
208
+ def day_of_year(days, *extras)
209
+ merge(yday: days.array_concat(extras))
168
210
  end
169
211
  alias yday day_of_year
170
212
 
171
213
  # Create a recurrence for given hours of day
172
214
  #
173
- # @param [Fixnum, Range] days (1, 10, 100, ...)
215
+ # @param hours [Fixnum, Range, Array<Integer>] hours of day, e.g. 1, 10, 100, ...
174
216
  #
175
- def hour_of_day(*hours)
176
- merge(hour: hours)
217
+ # @example
218
+ # Montrose.hourly.hour_of_day(9)
219
+ # Montrose.hourly.hour_of_day(15)
220
+ # Montrose.hourly.hour_of_day(6..10)
221
+ #
222
+ def hour_of_day(hours, *extras)
223
+ merge(hour: hours.array_concat(extras))
177
224
  end
178
225
  alias hour hour_of_day
179
226
 
180
227
  # Create a recurrence for given months of year
181
228
  #
182
- # @param [Fixnum, Symbol] months (:january, :april, ...)
229
+ # @param months [Fixnum, Symbol] months of year, e.g., :january, :april, ...
230
+ #
231
+ # @example
232
+ # Montrose.monthly.month_of_year(9)
233
+ # Montrose.monthly.month_of_year([2, 5])
234
+ # Montrose.monthly.month_of_year(2..5)
183
235
  #
184
- def month_of_year(*months)
185
- merge(month: months)
236
+ def month_of_year(months, *extras)
237
+ merge(month: months.array_concat(extras))
186
238
  end
187
239
  alias month month_of_year
188
240
 
241
+ # Create a recurrence for given weeks of year
242
+ #
243
+ # @param weeks [Fixnum] weeks of year, e.g., 1, 20, 50
244
+ #
245
+ # @example
246
+ # Montrose.weekly.week_of_year(9)
247
+ # Montrose.weekly.week_of_year([2, 5])
248
+ # Montrose.weekly.week_of_year(2..5)
249
+ #
250
+ def week_of_year(weeks, *extras)
251
+ merge(week: weeks.array_concat(extras))
252
+ end
253
+
189
254
  # Create a recurrence that ends after given number
190
255
  # of occurrences
191
256
  #
192
- # @param [Fixnum] total
257
+ # @param total [Fixnum] repeat count
258
+ #
259
+ # @example
260
+ # Montrose.daily.total(10)
193
261
  #
194
262
  def total(total)
195
263
  merge(total: total)
196
264
  end
197
265
 
198
- # Create a recurrence for given weeks of year
266
+ # Create a new recurrence combining options of self
267
+ # and other. The value of entries with duplicate
268
+ # keys will be those of other
199
269
  #
200
- # @param [Fixnum] weeks (1, 20, 50)
270
+ # @param opts [Hash,Montrose::Recurrence] other options or recurrence
201
271
  #
202
- def week_of_year(*weeks)
203
- merge(week: weeks)
204
- end
205
-
206
- # @private
207
- def merge(opts = {})
208
- branch default_options.merge(opts)
272
+ # @example
273
+ # Montrose.daily.total(10)
274
+ #
275
+ def merge(other = {})
276
+ branch default_options.merge(other)
209
277
  end
210
278
 
211
279
  # @private
@@ -3,7 +3,7 @@ require "montrose/errors"
3
3
  module Montrose
4
4
  class Clock
5
5
  def initialize(opts = {})
6
- @options = Montrose::Options.new(opts)
6
+ @options = Montrose::Options.merge(opts)
7
7
  @time = nil
8
8
  @every = @options.fetch(:every) { fail ConfigurationError, "Required option :every not provided" }
9
9
  @starts = @options.fetch(:starts)
@@ -44,13 +44,13 @@ module Montrose
44
44
  # when options contain given unit as a key or as a value of
45
45
  # the key :every in options
46
46
  #
47
- # @options = { every: :day, hour: 8.12 }
47
+ # options = { every: :day, hour: 8.12 }
48
48
  # unit_step(:minute)
49
49
  # => nil
50
50
  # unit_step(:hour)
51
51
  # => { hour: 1 }
52
52
  #
53
- # @options = { every: :hour, interval: 6 }
53
+ # options = { every: :hour, interval: 6 }
54
54
  # unit_step(:minute)
55
55
  # => nil
56
56
  # unit_step(:hour)
@@ -43,7 +43,7 @@ module Montrose
43
43
  end
44
44
 
45
45
  def initialize(opts = {})
46
- opts = Montrose::Options.new(opts)
46
+ opts = Montrose::Options.merge(opts)
47
47
  @time = nil
48
48
  @starts = opts.fetch(:starts)
49
49
  @interval = opts.fetch(:interval)
@@ -58,6 +58,18 @@ module Montrose
58
58
  @default_starts
59
59
  end
60
60
  end
61
+
62
+ def merge(opts = {})
63
+ new(default_options).merge(opts)
64
+ end
65
+
66
+ def default_options
67
+ {
68
+ starts: default_starts,
69
+ until: default_until,
70
+ interval: 1
71
+ }
72
+ end
61
73
  end
62
74
 
63
75
  def_option :every
@@ -78,9 +90,9 @@ module Montrose
78
90
  def initialize(opts = {})
79
91
  defaults = {
80
92
  every: self.class.default_every,
81
- starts: self.class.default_starts,
82
- until: self.class.default_until,
83
- interval: 1,
93
+ interval: nil,
94
+ starts: nil,
95
+ until: nil,
84
96
  day: nil,
85
97
  mday: nil,
86
98
  yday: nil,
@@ -272,7 +284,7 @@ module Montrose
272
284
 
273
285
  def assert_range_includes(range, item, absolute = false)
274
286
  test = absolute ? item.abs : item
275
- fail ConfigurationError, "Out of range" unless range.include?(test)
287
+ fail ConfigurationError, "Out of range: #{range.inspect} does not include #{test}" unless range.include?(test)
276
288
 
277
289
  item
278
290
  end
@@ -56,7 +56,7 @@ module Montrose
56
56
  private
57
57
 
58
58
  def event_enum
59
- opts = @default_options
59
+ opts = Options.merge(@default_options)
60
60
  stack = Stack.new(opts)
61
61
  clock = Clock.new(opts)
62
62
 
@@ -0,0 +1,11 @@
1
+ module Montrose
2
+ module Refinements
3
+ module ArrayConcat
4
+ refine Object do
5
+ def array_concat(other)
6
+ Array(self) + other
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -9,7 +9,7 @@ module Montrose
9
9
 
10
10
  # Initializes rule
11
11
  #
12
- # @param [Array<Fixnum>] hour - valid hours of days, e.g. [1, 2, 24]
12
+ # @param hours [Array<Fixnum>] valid hours of days, e.g. [1, 2, 24]
13
13
  #
14
14
  def initialize(hours)
15
15
  @hours = hours
@@ -2,6 +2,12 @@ module Montrose
2
2
  class Schedule
3
3
  attr_accessor :rules
4
4
 
5
+ def self.build
6
+ schedule = new
7
+ yield schedule if block_given?
8
+ schedule
9
+ end
10
+
5
11
  def initialize
6
12
  @rules = []
7
13
  end
@@ -21,8 +27,7 @@ module Montrose
21
27
  enums = @rules.map { |r| r.merge(opts).events }
22
28
  Enumerator.new do |y|
23
29
  loop do
24
- enums = active_enums(enums)
25
- enum = enums.min_by(&:peek) or break
30
+ enum = active_enums(enums).min_by(&:peek) or break
26
31
  y << enum.next
27
32
  end
28
33
  end
@@ -31,10 +36,11 @@ module Montrose
31
36
  private
32
37
 
33
38
  def active_enums(enums)
34
- enums.each_with_object([]) do |enum, actives|
39
+ enums.select do |e|
35
40
  begin
36
- actives << enum if enum.peek
41
+ e.peek
37
42
  rescue StopIteration
43
+ false
38
44
  end
39
45
  end
40
46
  end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Montrose
3
- VERSION = "0.1.1".freeze
3
+ VERSION = "0.2.0".freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: montrose
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ross Kaffenberger
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-01-25 00:00:00.000000000 Z
11
+ date: 2016-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -119,6 +119,7 @@ files:
119
119
  - ".gitignore"
120
120
  - ".rubocop.yml"
121
121
  - ".travis.yml"
122
+ - CHANGELOG.md
122
123
  - CODE_OF_CONDUCT.md
123
124
  - Gemfile
124
125
  - Guardfile
@@ -145,6 +146,7 @@ files:
145
146
  - lib/montrose/frequency/yearly.rb
146
147
  - lib/montrose/options.rb
147
148
  - lib/montrose/recurrence.rb
149
+ - lib/montrose/refinements/array_concat.rb
148
150
  - lib/montrose/rule.rb
149
151
  - lib/montrose/rule/after.rb
150
152
  - lib/montrose/rule/before.rb
@@ -184,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
186
  version: '0'
185
187
  requirements: []
186
188
  rubyforge_project:
187
- rubygems_version: 2.5.1
189
+ rubygems_version: 2.4.5.1
188
190
  signing_key:
189
191
  specification_version: 4
190
192
  summary: Recurring events in Ruby