montrose 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: edcfdb878952330a2fcc9a78db4f4e7780e643e3
4
- data.tar.gz: 619002eee045e0d960de83d2bdf78078d7d74883
3
+ metadata.gz: a88cd103fc68290cf832c8e41ec2e8a1ca4d4a87
4
+ data.tar.gz: c74c51dad1844316155c1b138b0b34f548d27dfd
5
5
  SHA512:
6
- metadata.gz: 7be4df5c22b3677978134b446d30c7e3bac3e33309d35f66253aea93ed62d5e60a17bf9b1a8eb8a3745260ef38dee9f74d7f057a0b2fa181f752e7a3183336b1
7
- data.tar.gz: 5a1c3a19e2e5fc6a7b64c620be48926d9d257e33b3b2fde91b0588b3d1355052b0b016e011ec7cf396f2046a2e3005b10fab43de0cd648224b55b7b90383f1c4
6
+ metadata.gz: 3d186764038aaeb902fb809225a5e26779831e55a3ed0cc11998a6395821c9ab4e34af9d0152f43558f660c39d02ad9e2eff82630e24d56986e1958d0ff51de6
7
+ data.tar.gz: 4c939c9c4e6a416f20fb24b718d6fab5026b17650f72e5769b03abaa40ecc10d002a6a8210cd0ec6ae44c832d41020a222cf5e248597ede1754d830e8587d92b
@@ -1,3 +1,14 @@
1
+ ### 0.3.0 - (2016-02-19)
2
+
3
+ * enhancements
4
+ * Adds `:except` option and chainable method to filter timestamps by date (by
5
+ @thewatts)
6
+ * bug fixes
7
+ * Fix recurrences when specifying both `:starts` and `:at` by treating
8
+ `:starts` value like a date
9
+ * Respect recurrence rules using multiple `:at` values
10
+ * Using `Montrose.r` without any arguments no longer throws `ArgumentError`
11
+
1
12
  ### 0.2.2 - 2016-02-08
2
13
 
3
14
  * bug fixes
@@ -5,6 +16,7 @@
5
16
  * enhancements
6
17
  * Adds `Montrose.r` method for starting a new recurrence
7
18
  * Adds `Chainable` alias methods including `#starts`, `#until`, `#repeat`
19
+ * README updates (by @thegcat)
8
20
 
9
21
  ### 0.2.1 - 2016-02-03
10
22
 
data/Gemfile CHANGED
@@ -1,6 +1,5 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in cure.gemspec
4
3
  gemspec
5
4
 
6
5
  group :development do
data/README.md CHANGED
@@ -7,7 +7,9 @@
7
7
 
8
8
  Montrose is an easy-to-use library for defining recurring events in Ruby. It uses a simple chaining system for building recurrences, inspired heavily by the design principles of [HTTP.rb](https://github.com/httprb/http) and rule definitions available in [Recurrence](https://github.com/fnando/recurrence).
9
9
 
10
- [Introduction](https://rossta.net/blog/recurring-events-in-ruby.html)
10
+ * [Introductory blog post](http://bit.ly/1PA68Zb)
11
+ * [NYC.rb
12
+ presentation](https://speaderdeck.com/rossta/recurring-events-with-montrose)
11
13
 
12
14
  ## Installation
13
15
 
@@ -25,6 +27,135 @@ Or install it yourself as:
25
27
 
26
28
  $ gem install montrose
27
29
 
30
+ ## Why
31
+
32
+ Dealing with recurring events is hard. `Montrose` provides a simple interface for specifying and enumerating recurring events as `Time` objects.
33
+
34
+ More specifically, this project intends to:
35
+
36
+ * embrace Ruby idioms
37
+ * support Ruby 2.1+
38
+ * be reasonably performant
39
+ * serialize to yaml, hash, and [ical](http://www.kanzaki.com/docs/ical/rrule.html#basic) formats
40
+ * be suitable for integration with persistence libraries
41
+
42
+ What `Montrose` doesn't do:
43
+
44
+ * support all calendaring use cases under the sun
45
+ * schedule recurring jobs for you. See instead [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler), [sidekiq-cron](https://github.com/ondrejbartas/sidekiq-cron), [sidetiq](https://github.com/tobiassvn/sidetiq), [whenever](https://github.com/javan/whenever)
46
+
47
+ ## Concepts
48
+
49
+ Montrose allows you to easily create "recurrence" objects through chaining:
50
+
51
+ ```ruby
52
+ # Every Monday at 10:30am
53
+ Montrose.weekly.on(:monday).at("10:30 am")
54
+ => #<Montrose::Recurrence...>
55
+ ```
56
+
57
+ Each chained recurrence returns a **new object** so they can be composed and merged. In both examples below, recurrence `r4` represents 'every week on Tuesday and Thursday at noon for four occurrences'.
58
+
59
+ ```ruby
60
+ # Example 1 - building recurrence in succession
61
+ r1 = Montrose.every(:week)
62
+ r2 = r1.on([:tuesday, :thursday])
63
+ r3 = r2.at("12 pm")
64
+ r4 = r3.total(4)
65
+
66
+ # Example 2 - merging distinct recurrences
67
+ r1 = Montrose.every(:week)
68
+ r2 = Montrose.on([:tuesday, :thursday])
69
+ r3 = Montrose.at("12 pm")
70
+ r4 = r1.merge(r2).merge(r3).total(4)
71
+ ```
72
+
73
+ Most recurrence methods accept additional options if you favor the hash-syntax:
74
+
75
+ ```ruby
76
+ Montrose.r(every: :week, on: :monday, at: "10:30 am")
77
+ => #<Montrose::Recurrence...>
78
+ ```
79
+
80
+ See [the docs for `Montrose::Chainable`](https://rossta.net/montrose/Montrose/Chainable.html) for more info on recurrence creation methods.
81
+
82
+ A Montrose recurrence responds to `#events`, which returns an [`Enumerator`](/blog/what-is-enumerator.html) that can generate timestamps:
83
+
84
+ ```ruby
85
+ r = Montrose.hourly
86
+ => #<Montrose::Recurrence...>
87
+
88
+ r.events
89
+ => #<Enumerator:...>
90
+
91
+ r.events.take(10)
92
+ => [2016-02-03 18:26:08 -0500,
93
+ 2016-02-03 19:26:08 -0500,
94
+ 2016-02-03 20:26:08 -0500,
95
+ 2016-02-03 21:26:08 -0500,
96
+ 2016-02-03 22:26:08 -0500,
97
+ 2016-02-03 23:26:08 -0500,
98
+ 2016-02-04 00:26:08 -0500,
99
+ 2016-02-04 01:26:08 -0500,
100
+ 2016-02-04 02:26:08 -0500,
101
+ 2016-02-04 03:26:08 -0500]
102
+ ```
103
+
104
+ Montrose recurrences are themselves enumerable:
105
+
106
+ ```ruby
107
+ # Every month starting a year from now on Friday the 13th for 5 occurrences
108
+ r = Montrose.monthly.starting(1.year.from_now).on(friday: 13).repeat(5)
109
+
110
+ r.map(&:to_date)
111
+ => [Fri, 13 Oct 2017,
112
+ Fri, 13 Apr 2018,
113
+ Fri, 13 Jul 2018,
114
+ Fri, 13 Sep 2019,
115
+ Fri, 13 Dec 2019]
116
+ ```
117
+
118
+ Conceptually, recurrences can represent an infinite sequence. When we say
119
+ simply "every day", there is no implied ending. It's therefore possible to
120
+ create a recurrence that can enumerate forever, so use your `Enumerable` methods wisely.
121
+
122
+ ```ruby
123
+ # Every day starting now
124
+ r = Montrose.daily
125
+
126
+ # this expression will never complete, Ctrl-c!
127
+ r.map(&:to_date)
128
+
129
+ # use `lazy` enumerator to avoid eager enumeration
130
+ r.lazy.map(&:to_date).select { |d| d.mday > 25 }.take(5).to_a
131
+ => [Fri, 26 Feb 2016,
132
+ Sat, 27 Feb 2016,
133
+ Sun, 28 Feb 2016,
134
+ Mon, 29 Feb 2016,
135
+ Sat, 26 Mar 2016]
136
+ ```
137
+
138
+ It's straightforward to convert a recurrence to a hash and back.
139
+
140
+ ```ruby
141
+ opts = Montrose::Recurrence.new(every: 10.minutes).to_h
142
+ => {:every=>:minute, :interval=>10}
143
+
144
+ Montrose::Recurrence.new(opts).take(3)
145
+ => [2016-02-03 19:06:07 -0500,
146
+ 2016-02-03 19:16:07 -0500,
147
+ 2016-02-03 19:26:07 -0500]
148
+ ```
149
+
150
+ A recurrence object must minimally specify a frequency, e.g. `:minute`, `:hour`, `:day`, `:week`, `:month`, or, `:year`, to be viable. Otherwise, you'll see an informative error message when attempting to enumerate the recurrence.
151
+
152
+ ```ruby
153
+ r = Montrose.at("12pm")
154
+ => #<Montrose::Recurrence...>
155
+ r.each
156
+ Montrose::ConfigurationError: Please specify the :every option
157
+ ```
158
+
28
159
  ## Usage
29
160
 
30
161
  ```ruby
@@ -60,7 +191,7 @@ Montrose.weekly(total: 10)
60
191
  # weekly until December 23, 2015
61
192
  ends_on = Date.new(2015, 12, 23)
62
193
  starts_on = ends_on - 15.weeks
63
- Montrose.every(:week, until: ends_on, starts: starts_on
194
+ Montrose.every(:week, until: ends_on, starts: starts_on)
64
195
 
65
196
  # every other week forever
66
197
  Montrose.every(2.weeks)
@@ -219,7 +350,6 @@ Montrose.yearly(yday: [1, 100]) # yearly on the 1st and 100th day of year
219
350
  Montrose.yearly(on: { january: 31 })
220
351
  Montrose.r(every: :year, on: { 10 => 31 }, interval: 3)
221
352
 
222
- # TODO: Remove a date in the series with :except date(s)
223
353
  Montrose.daily(:day, except: "2017-01-31")
224
354
  Montrose.daily(except: [Date.today, "2017-01-31"])
225
355
 
@@ -242,125 +372,6 @@ r.events.take(10).each { |date| puts date.to_s }
242
372
  r.events.lazy.select { |time| time > 1.month.from_now }.take(3).each { |date| puts date.to_s }
243
373
  ```
244
374
 
245
- ## Why?
246
-
247
- `Montrose` aims to provide a simple interface for specifying and enumerating recurring events as `Time` objects.
248
-
249
- More specifically, this project intends to:
250
-
251
- * embrace Ruby idioms
252
- * support Ruby 2.1+
253
- * be reasonably performant
254
- * serialize to yaml, hash, and [ical](http://www.kanzaki.com/docs/ical/rrule.html#basic) formats
255
- * be suitable for integration with persistence libraries
256
-
257
- What `Montrose` doesn't do:
258
-
259
- * support all calendaring use cases under the sun
260
- * schedule recurring jobs for you. See instead [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler), [sidetiq](https://github.com/tobiassvn/sidetiq), [whenever](https://github.com/javan/whenever)
261
-
262
- ## Concepts
263
-
264
- Montrose allows you to easily create "recurrence" objects through chaining:
265
-
266
- ```ruby
267
- # Every Monday at 10:30am
268
- Montrose.weekly.on(:monday).at("10:30 am")
269
- => #<Montrose::Recurrence...>
270
- ```
271
-
272
- Or the constructor hash-syntax:
273
-
274
- ```ruby
275
- Montrose.r(every: :week, on: :monday, at: "10:30 am")
276
- => #<Montrose::Recurrence...>
277
- ```
278
-
279
- A Montrose recurrence responds to `#events`, which returns an [`Enumerator`](/blog/what-is-enumerator.html) that can generate timestamps:
280
-
281
- ```ruby
282
- r = Montrose.hourly
283
- => #<Montrose::Recurrence...>
284
-
285
- r.events
286
- => #<Enumerator:...>
287
-
288
- r.events.take(10)
289
- => [2016-02-03 18:26:08 -0500,
290
- 2016-02-03 19:26:08 -0500,
291
- 2016-02-03 20:26:08 -0500,
292
- 2016-02-03 21:26:08 -0500,
293
- 2016-02-03 22:26:08 -0500,
294
- 2016-02-03 23:26:08 -0500,
295
- 2016-02-04 00:26:08 -0500,
296
- 2016-02-04 01:26:08 -0500,
297
- 2016-02-04 02:26:08 -0500,
298
- 2016-02-04 03:26:08 -0500]
299
- ```
300
-
301
- Montrose recurrences are themselves enumerable:
302
-
303
- ```ruby
304
- # Every month starting a year from now on Friday the 13th for 5 occurrences
305
- r = Montrose.monthly.starting(1.year.from_now).on(friday: 13).repeat(5)
306
-
307
- r.map(&:to_date)
308
- => [Fri, 13 Oct 2017,
309
- Fri, 13 Apr 2018,
310
- Fri, 13 Jul 2018,
311
- Fri, 13 Sep 2019,
312
- Fri, 13 Dec 2019]
313
- ```
314
-
315
- Each chained recurrence returns a new object so they can be composed and
316
- merged:
317
-
318
- ```ruby
319
- # Every week
320
- r1 = Montrose.every(:week)
321
- r2 = Montrose.on([:tuesday, :thursday])
322
- r3 = Montrose.at("12 pm")
323
- r4 = Montrose.total(4)
324
-
325
- r1.merge(r2).merge(r3).merge(r4).to_a
326
- => [2016-02-04 12:00:00 -0500,
327
- 2016-02-09 12:00:00 -0500,
328
- 2016-02-11 12:00:00 -0500,
329
- 2016-02-16 12:00:00 -0500]
330
- ```
331
-
332
- Conceptually, recurrences can represent an infinite sequence. When we say
333
- simply "every day", there is no implied ending. It's therefore possible to
334
- create a recurrence that can enumerate forever.
335
-
336
- ```ruby
337
- # Every day starting now
338
- r = Montrose.daily
339
-
340
- # this expression will never complete, Ctrl-c!
341
- r.map(&:to_date)
342
-
343
- # so use your `Enumerable` methods wisely
344
- r.lazy.map(&:to_date).select { |d| d.mday > 25 }.take(5).to_a
345
- => [Fri, 26 Feb 2016,
346
- Sat, 27 Feb 2016,
347
- Sun, 28 Feb 2016,
348
- Mon, 29 Feb 2016,
349
- Sat, 26 Mar 2016]
350
- ```
351
-
352
- It's straightforward to convert a recurrence to a hash and back.
353
-
354
- ```ruby
355
- opts = Montrose::Recurrence.new(every: 10.minutes).to_h
356
- => {:every=>:minute, :interval=>10}
357
-
358
- Montrose::Recurrence.new(opts).take(3)
359
- => [2016-02-03 19:06:07 -0500,
360
- 2016-02-03 19:16:07 -0500,
361
- 2016-02-03 19:26:07 -0500]
362
- ```
363
-
364
375
  ## Inspiration
365
376
 
366
377
  Montrose is named after the beautifully diverse and artistic [neighborhood in Houston, Texas](https://en.wikipedia.org/wiki/Montrose,_Houston).
@@ -369,9 +380,10 @@ Montrose is named after the beautifully diverse and artistic [neighborhood in Ho
369
380
 
370
381
  Check out following related projects, all of which have provided inspiration for `Montrose`.
371
382
 
372
- * [recurrence](https://github.com/fnando/recurrence)
373
383
  * [ice_cube](https://github.com/seejohnrun/ice_cube)
384
+ * [recurrence](https://github.com/fnando/recurrence)
374
385
  * [runt](https://github.com/mlipper/runt)
386
+ * [http.rb](https://github.com/httprb/http) - not a recurrence project, but inspirational to design, implementation, and interface of `Montrose`
375
387
 
376
388
  ## Development
377
389
 
@@ -30,7 +30,9 @@ module Montrose
30
30
  #
31
31
  # @return [Montrose::Recurrence]
32
32
  #
33
- alias recurrence branch
34
- alias r branch
33
+ def recurrence(options = {})
34
+ branch(options)
35
+ end
36
+ alias r recurrence
35
37
  end
36
38
  end
@@ -194,6 +194,20 @@ module Montrose
194
194
  merge(at: time)
195
195
  end
196
196
 
197
+ # Create a recurrence with dates except dates given
198
+ #
199
+ # @param date [String, Date] represents date
200
+ #
201
+ # @example
202
+ # Montrose.daily.except("2016-03-01")
203
+ # Montrose.daily.except(Date.today)
204
+ #
205
+ # @return [Montrose::Recurrence]
206
+ #
207
+ def except(date)
208
+ merge(except: date)
209
+ end
210
+
197
211
  # Create a recurrence for given days of month
198
212
  #
199
213
  # @param days [Fixnum] days of month, e.g. 1, 2, -1, ...
@@ -6,8 +6,9 @@ module Montrose
6
6
  @options = Montrose::Options.merge(opts)
7
7
  @time = nil
8
8
  @every = @options.fetch(:every) { fail ConfigurationError, "Required option :every not provided" }
9
- @starts = @options.fetch(:starts)
10
9
  @interval = @options.fetch(:interval)
10
+ @start_time = @options.fetch(:start_time)
11
+ @at = @options.fetch(:at, nil)
11
12
  end
12
13
 
13
14
  # Advances time to new unit by increment and sets
@@ -18,13 +19,25 @@ module Montrose
18
19
  end
19
20
 
20
21
  def peek
21
- return @starts if @time.nil?
22
+ return @start_time if @time.nil?
22
23
 
23
- @time.advance(step)
24
+ if @at
25
+ times = @at.map { |(hour, min)| @time.change(hour: hour, min: min) }
26
+
27
+ min_next = times.select { |t| t > @time }.min and return min_next
28
+
29
+ advance_step(times.min || @time)
30
+ else
31
+ advance_step(@time)
32
+ end
24
33
  end
25
34
 
26
35
  private
27
36
 
37
+ def advance_step(time)
38
+ time.advance(step)
39
+ end
40
+
28
41
  def step
29
42
  @step ||= smallest_step or fail ConfigurationError, "No step for #{@options.inspect}"
30
43
  end
@@ -45,7 +45,7 @@ module Montrose
45
45
  def initialize(opts = {})
46
46
  opts = Montrose::Options.merge(opts)
47
47
  @time = nil
48
- @starts = opts.fetch(:starts)
48
+ @starts = opts.fetch(:start_time)
49
49
  @interval = opts.fetch(:interval)
50
50
  end
51
51
 
@@ -1,5 +1,7 @@
1
1
  module Montrose
2
2
  class Options
3
+ include Montrose::Utils
4
+
3
5
  @default_starts = nil
4
6
  @default_until = nil
5
7
  @default_every = nil
@@ -65,7 +67,6 @@ module Montrose
65
67
 
66
68
  def default_options
67
69
  {
68
- starts: default_starts,
69
70
  until: default_until,
70
71
  interval: 1
71
72
  }
@@ -86,6 +87,7 @@ module Montrose
86
87
  def_option :between
87
88
  def_option :at
88
89
  def_option :on
90
+ def_option :except
89
91
 
90
92
  def initialize(opts = {})
91
93
  defaults = {
@@ -163,7 +165,7 @@ module Montrose
163
165
  end
164
166
 
165
167
  def day=(days)
166
- @day = nested_map_arg(days) { |d| Montrose::Utils.day_number!(d) }
168
+ @day = nested_map_arg(days) { |d| day_number!(d) }
167
169
  end
168
170
 
169
171
  def mday=(mdays)
@@ -179,7 +181,7 @@ module Montrose
179
181
  end
180
182
 
181
183
  def month=(months)
182
- @month = map_arg(months) { |d| Montrose::Utils.month_number!(d) }
184
+ @month = map_arg(months) { |d| month_number!(d) }
183
185
  end
184
186
 
185
187
  def between=(range)
@@ -194,11 +196,7 @@ module Montrose
194
196
  end
195
197
 
196
198
  def at=(time)
197
- times = map_arg(time) { |t| as_time(t) }
198
- now = Time.now
199
- first = times.map { |t| t < now ? t + 24.hours : t }.min
200
- self[:starts] = first if first
201
- @at = times
199
+ @at = map_arg(time) { |t| as_time_parts(t) }
202
200
  end
203
201
 
204
202
  def on=(arg)
@@ -209,12 +207,30 @@ module Montrose
209
207
  @on = arg
210
208
  end
211
209
 
210
+ def except=(date)
211
+ @except = map_arg(date) { |d| as_date(d) }
212
+ end
213
+
212
214
  def inspect
213
215
  "#<#{self.class} #{to_h.inspect}>"
214
216
  end
215
217
 
218
+ def start_time
219
+ time = starts || default_starts
220
+
221
+ if at
222
+ at.map { |(hour, min)| time.change(hour: hour, min: min) }.min || time
223
+ else
224
+ time
225
+ end
226
+ end
227
+
216
228
  private
217
229
 
230
+ def default_starts
231
+ self.class.default_starts
232
+ end
233
+
218
234
  def nested_map_arg(arg, &block)
219
235
  case arg
220
236
  when Hash
@@ -233,7 +249,7 @@ module Montrose
233
249
  end
234
250
 
235
251
  def map_days(arg)
236
- map_arg(arg) { |d| Montrose::Utils.day_number!(d) }
252
+ map_arg(arg) { |d| day_number!(d) }
237
253
  end
238
254
 
239
255
  def map_mdays(arg)
@@ -275,9 +291,9 @@ module Montrose
275
291
  end
276
292
 
277
293
  def month_or_day(key)
278
- month = Montrose::Utils.month_number(key)
294
+ month = month_number(key)
279
295
  return [:month, month] if month
280
- day = Montrose::Utils.day_number(key)
296
+ day = day_number(key)
281
297
  return [:day, day] if day
282
298
  fail ConfigurationError, "Did not recognize #{key} as a month or day"
283
299
  end
@@ -289,17 +305,11 @@ module Montrose
289
305
  item
290
306
  end
291
307
 
292
- def as_time(time)
293
- return nil unless time
308
+ def as_time_parts(arg)
309
+ return arg if arg.is_a?(Array)
294
310
 
295
- case
296
- when time.is_a?(String)
297
- Time.parse(time)
298
- when time.respond_to?(:to_time)
299
- time.to_time
300
- else
301
- Array(time).flat_map { |d| as_time(d) }
302
- end
311
+ time = as_time(arg)
312
+ [time.hour, time.min]
303
313
  end
304
314
 
305
315
  def parse_frequency(input)
@@ -38,6 +38,7 @@ require "montrose/rule/before"
38
38
  require "montrose/rule/day_of_month"
39
39
  require "montrose/rule/day_of_week"
40
40
  require "montrose/rule/day_of_year"
41
+ require "montrose/rule/except"
41
42
  require "montrose/rule/hour_of_day"
42
43
  require "montrose/rule/month_of_year"
43
44
  require "montrose/rule/nth_day_of_month"
@@ -0,0 +1,23 @@
1
+ module Montrose
2
+ module Rule
3
+ class Except
4
+ include Montrose::Rule
5
+
6
+ def self.apply_options(opts)
7
+ opts[:except]
8
+ end
9
+
10
+ # Initializes rule
11
+ #
12
+ # @param [Date] dates - array of date objects
13
+ #
14
+ def initialize(dates)
15
+ @dates = dates
16
+ end
17
+
18
+ def include?(time)
19
+ !@dates.include?(time.to_date)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -16,7 +16,7 @@ module Montrose
16
16
  end
17
17
 
18
18
  def include?(time)
19
- times_of_day.include?(parts(time))
19
+ @times.include?(parts(time))
20
20
  end
21
21
 
22
22
  private
@@ -24,10 +24,6 @@ module Montrose
24
24
  def parts(time)
25
25
  [time.hour, time.min]
26
26
  end
27
-
28
- def times_of_day
29
- @times_of_day ||= @times.map { |t| parts(t) }
30
- end
31
27
  end
32
28
  end
33
29
  end
@@ -11,6 +11,7 @@ module Montrose
11
11
  Frequency,
12
12
  Rule::After,
13
13
  Rule::Before,
14
+ Rule::Except,
14
15
  Rule::Total,
15
16
  Rule::TimeOfDay,
16
17
  Rule::HourOfDay,
@@ -5,6 +5,23 @@ module Montrose
5
5
  MONTHS = Date::MONTHNAMES
6
6
  DAYS = Date::DAYNAMES
7
7
 
8
+ def as_time(time)
9
+ return nil unless time
10
+
11
+ case
12
+ when time.is_a?(String)
13
+ Time.parse(time)
14
+ when time.respond_to?(:to_time)
15
+ time.to_time
16
+ else
17
+ Array(time).flat_map { |d| as_time(d) }
18
+ end
19
+ end
20
+
21
+ def as_date(time)
22
+ as_time(time).to_date
23
+ end
24
+
8
25
  def month_number(name)
9
26
  case name
10
27
  when Symbol, String
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Montrose
3
- VERSION = "0.2.2".freeze
3
+ VERSION = "0.3.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.2.2
4
+ version: 0.3.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-02-09 00:00:00.000000000 Z
11
+ date: 2016-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -153,6 +153,7 @@ files:
153
153
  - lib/montrose/rule/day_of_month.rb
154
154
  - lib/montrose/rule/day_of_week.rb
155
155
  - lib/montrose/rule/day_of_year.rb
156
+ - lib/montrose/rule/except.rb
156
157
  - lib/montrose/rule/hour_of_day.rb
157
158
  - lib/montrose/rule/month_of_year.rb
158
159
  - lib/montrose/rule/nth_day_matcher.rb
@@ -186,7 +187,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
187
  version: '0'
187
188
  requirements: []
188
189
  rubyforge_project:
189
- rubygems_version: 2.5.1
190
+ rubygems_version: 2.4.5.1
190
191
  signing_key:
191
192
  specification_version: 4
192
193
  summary: Recurring events in Ruby