schedulability 0.1.0 → 0.2.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: 50fb75892fe34a90d09b2b053f07d7e60209aee6
4
- data.tar.gz: fc229096b9d9395dbc2717194a4b6391440f6266
3
+ metadata.gz: 8eded0bd62f85e98614fb6f8c2f57300036be176
4
+ data.tar.gz: b7fc81a9f3bae2ed902bc6f123ed6d9537012675
5
5
  SHA512:
6
- metadata.gz: 774433974b322f79241580ff4378173f009526cfad3b93a49bea994719fa8df0dbb15d0393bd9fe046c9a3a4ed6be9a842c1bc7abdd110449c763bb77276d2a5
7
- data.tar.gz: 2cc54b3bfc288409a73eeea2c68881354766c7fde08c47aa77cfc41392fc104c402f131ea4efe3f3e2f4a706fecbecac652fdda05be4d17c6ca62400c57755c2
6
+ metadata.gz: 9e8d048d6cd378fc9b0b5532d1c7acc2ed667ea885eaec6cd1cdf6b0e8e59e7cc3a4e8f5e6d016d231b251b6d0b50c0659b921f0eff1a518128aa5ec408cc622
7
+ data.tar.gz: ca2bbea2c50b9fce77c3ff4b3d5ab2a2c0bf037ce278bde3fc6e5bf1dce60eed84f2f11c1789af515947e528116048c510de9bb1c293571352af1bafd173f704
Binary file
data.tar.gz.sig CHANGED
Binary file
data/ChangeLog CHANGED
@@ -1,8 +1,47 @@
1
+ 2016-07-14 Jason Rogers <jacaetevha@gmail.com>
2
+
3
+ * lib/schedulability/parser.rb, spec/schedulability/schedule_spec.rb:
4
+ [PATCH] bug fixes for the 0th second or minute, and the 59th second
5
+ From bc2864a832fa60bc39958b9aaa26e6f546936539 Mon Sep 17 00:00:00
6
+ 2001 or minute
7
+ --- lib/schedulability/parser.rb | 8 +++---
8
+ spec/schedulability/schedule_spec.rb | 52
9
+ ++++++++++++++++++++++++++++++++++++ 2 files changed, 57
10
+ insertions(+), 3 deletions(-)
11
+ [0f59486cf040] [github/master, tip]
12
+
13
+ 2016-07-15 Michael Granger <ged@FaerieMUD.org>
14
+
15
+ * README.md, Rakefile, lib/schedulability/schedule.rb,
16
+ schedulability.gemspec, spec/schedulability/schedule_spec.rb:
17
+ Fix some README discrepancies and implement some missing stuff
18
+ [b99801aa4e3f]
19
+
20
+ * lib/schedulability.rb, lib/schedulability/mixins.rb,
21
+ lib/schedulability/parser.rb, lib/schedulability/schedule.rb,
22
+ spec/schedulability/mixins_spec.rb,
23
+ spec/schedulability/parser_spec.rb,
24
+ spec/schedulability/schedule_spec.rb:
25
+ Implement a simplistic Schedule#to_s, add some missing specs.
26
+ [eda686d951b7]
27
+
1
28
  2015-12-30 Michael Granger <ged@FaerieMUD.org>
2
29
 
30
+ * .hgtags:
31
+ Added tag v0.1.0 for changeset 45f35fbd585b
32
+ [3e26b7e59243]
33
+
34
+ * .hgsigs:
35
+ Added signature for changeset 0f46dc0d8056
36
+ [45f35fbd585b] [v0.1.0]
37
+
38
+ * cert/ged.pem, cert/mahlon.pem:
39
+ Add gem certs.
40
+ [0f46dc0d8056]
41
+
3
42
  * .hgtags:
4
43
  Backed out tag for v0.1.0; trying again
5
- [342ac3d0b6db] [tip]
44
+ [342ac3d0b6db]
6
45
 
7
46
  * Rakefile, schedulability.gemspec:
8
47
  Explicitly set urls in the Hoespec, since Hoe can't read Markdown.
@@ -38,7 +77,7 @@
38
77
  lib/schedulability/schedule.rb,
39
78
  spec/schedulability/schedule_spec.rb:
40
79
  Implement negated periods; invert the meaning of empty schedule.
41
- [9a401a820265] [github/master]
80
+ [9a401a820265]
42
81
 
43
82
  * lib/schedulability/parser.rb, lib/schedulability/schedule.rb,
44
83
  spec/schedulability/schedule_spec.rb:
data/History.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## v0.2.0 [2016-07-20] Michael Granger <ged@FaerieMUD.org>
2
+
3
+ Bugfixes:
4
+ - fixes for the 0th second or minute, and the 59th second
5
+ (thanks to Jason Rogers <jacaetevha@gmail.com> for the patch)
6
+ - Make Schedule#empty? take negative periods into account
7
+
8
+ Enhancements
9
+ - Add missing Schedule#overlaps? and #exclusive predicate methods.
10
+ - Add a Schedule#to_s that stringifies them back into schedule descriptions
11
+
12
+
13
+
1
14
  ## v0.1.0 [2015-12-30] Michael Granger <ged@FaerieMUD.org>
2
15
 
3
16
  First release. Happy New Year!
@@ -11,5 +11,7 @@ lib/schedulability/mixins.rb
11
11
  lib/schedulability/parser.rb
12
12
  lib/schedulability/schedule.rb
13
13
  spec/helpers.rb
14
+ spec/schedulability/mixins_spec.rb
15
+ spec/schedulability/parser_spec.rb
14
16
  spec/schedulability/schedule_spec.rb
15
17
  spec/schedulability_spec.rb
data/README.md CHANGED
@@ -15,28 +15,41 @@ github
15
15
 
16
16
  ## Description
17
17
 
18
- Schedulability is a library for describing scheduled time. You can specify one or more periods of time using a simple syntax, then combine them to describe more-complex schedules.
18
+ Schedulability is a library for describing scheduled time. You can specify one
19
+ or more periods of time using a simple syntax, then combine them to describe
20
+ more-complex schedules.
19
21
 
20
22
 
21
23
  ## Usage
22
24
 
23
- Schedules are represented with Schedulability::Schedule objects, which are empty by default:
25
+ Schedules are represented with Schedulability::Schedule objects, which are
26
+ empty by default:
24
27
 
25
28
  schedule = Schedulability::Schedule.new
26
29
  # => #<Schedulability::Schedule:0x007ffcf2b982b8 (empty)>
27
30
 
28
31
  An empty Schedule has no time restrictions, and will match any time.
29
32
 
30
- To specify matching times, you'll need to construct a Schedule with one or more periods.
33
+ To specify matching times, you'll need to construct a Schedule with one or more
34
+ periods.
31
35
 
32
36
 
33
37
  ### Periods
34
38
 
35
- A schedule is specified as a String that contains a comma-separated list of period descriptions. The string `"never"` can be specified to explicitly create a schedule which will not match any time.
39
+ A schedule is made up of zero or more positive periods, and zero or more
40
+ negative periods. A time is within the schedule if at least one positive period
41
+ and no negative periods match it.
42
+
43
+ Periods are specified as a String that contains a comma-separated list of
44
+ period descriptions. The string `"never"` can be specified to explicitly create
45
+ a schedule which will not match any time.
36
46
 
37
47
  A period description is of the form
38
48
 
39
- scale {range [range ...]} [scale {range [range ...]}]
49
+ [!] scale {range [range ...]} [scale {range [range ...]}]
50
+
51
+ Negative periods begin with a `!`; you may also use `not` or `except` for
52
+ readability.
40
53
 
41
54
  Scale must be one of nine different scales (or their equivalent codes):
42
55
 
@@ -54,25 +67,39 @@ Scale must be one of nine different scales (or their equivalent codes):
54
67
  minute | min | 0-59
55
68
  second | sec | 0-59
56
69
 
57
- The same scale type may be specified multiple times. Additional scales are unioned with the ranges defined by previous scales of the same type in the same sub-period.
70
+ The same scale type may be specified multiple times. Additional scales are
71
+ unioned with the ranges defined by previous scales of the same type in the same
72
+ sub-period.
58
73
 
59
- A `range` is an exclusive Time range in the form:
74
+ A `range` is specified in the form:
60
75
 
61
- t
76
+ <range value>
62
77
  or
63
78
 
64
- t1-t2
79
+ <range value>-<range value>
65
80
 
66
- For two-value ranges, the range is defined as the period between `t1` and `t2`. Scales which are in
67
- seconds granularity are exclusive of their end value, but the rest are inclusive. For example, `hr {9am-5pm}` means 9:00:00 AM until 4:59:59 PM, but `wd {Wed-Sat}` runs until one second before midnight on Saturday.
81
+ For two-value ranges, the range is defined as the period between the first and
82
+ second `range value`s. Scales which are in seconds granularity are exclusive of
83
+ their end value, but the rest are inclusive. For example, `hr {9am-5pm}` means
84
+ 9:00:00 AM until 4:59:59 PM, but `wd {Wed-Sat}` runs until one second before
85
+ midnight on Saturday.
68
86
 
69
- If the first value is larger than the second value (e.g. `min {20-10}`), the range wraps (except when the scale specification is `year`). For example, `month {9-2}` is the same as specifying `month {1-2 9-12}` or `month {1-2} month {9-12}` or even `month {Jan-Feb Sep-Dec}`.
87
+ If the first value is larger than the second value (e.g. `min {20-10}`), the
88
+ range wraps (except when the scale specification is `year`). For example,
89
+ `month {9-2}` is the same as specifying `month {1-2 9-12}` or `month {1-2}
90
+ month {9-12}` or even `month {Jan-Feb Sep-Dec}`.
70
91
 
71
- The range specified by the single-value specification is implicitly between the value of `t` and its next sequential whole value. For example, `hr {9}` is the same as specifying `hr {9-10}`, `mday {15}` is the same as `mday {15-16}`, etc.
92
+ The range specified by the single-value specification is implicitly between the
93
+ `range value` and its next sequential whole value. For example, `hr {9}` is the
94
+ same as specifying `hr {9-10}`, `mday {15}` is the same as `mday {15-16}`, etc.
72
95
 
73
- Neither extra whitespace or case are significant in a period description. Scales must be specified either in long form (`year`, `month`, `week`, etc.) or in code form (`yr`, `mo`, `wk`, etc.). Scale forms may be mixed in a period statement.
96
+ Neither extra whitespace nor case are significant in a period description.
97
+ Scales must be specified either in long form (`year`, `month`, `week`, etc.) or
98
+ in code form (`yr`, `mo`, `wk`, etc.). Scale forms may be mixed in a period
99
+ statement.
74
100
 
75
- Values for week days can be abbreviated to two characters (`Wednesday` == `Wed` == `we`), and months can be abbreviated to three (`September` == `Sep`).
101
+ Values for week days and months can be abbreviated to three characters
102
+ (`Wednesday` == `Wed`, `September` == `Sep`).
76
103
 
77
104
 
78
105
  #### Period Examples
@@ -82,8 +109,8 @@ Values for week days can be abbreviated to two characters (`Wednesday` == `Wed`
82
109
  <dd>Monday through Friday, 9am to 5pm</dd>
83
110
 
84
111
  <dt><code>wd {Mon Wed Fri} hr {9am-4pm}, wd{Tue Thu} hr {9am-2pm}</code></dt>
85
- <dd>Monday through Friday, 9:00:00am to 3:59:59pm on Monday, Wednesday, and Friday,
86
- and 9:00:00am to 1:59:59pm on Tuesday and Thursday</dd>
112
+ <dd>Monday through Friday, 9:00:00am to 3:59:59pm on Monday, Wednesday, and
113
+ Friday, and 9:00:00am to 1:59:59pm on Tuesday and Thursday</dd>
87
114
 
88
115
  <dt><code>wk {1 3 5} wd {Mon-Fri} hr {9am-5pm}</code></dt>
89
116
  <dd>Mon-Fri 9:00:00am-4:59:59pm, on odd weeks in the month</dd>
@@ -94,6 +121,9 @@ Values for week days can be abbreviated to two characters (`Wednesday` == `Wed`
94
121
  <dt><code>mo {Nov-Feb}</code></dt>
95
122
  <dd>The same thing (Winter) as a wrapped range.</dd>
96
123
 
124
+ <dt><code>not mo {Mar-Oct}</code></dt>
125
+ <dd>The same thing (Winter) as a negative range.</dd>
126
+
97
127
  <dt><code>mo {jan feb nov dec}</code></dt>
98
128
  <dd>Northern Winter as single months</dd>
99
129
 
@@ -106,12 +136,16 @@ Values for week days can be abbreviated to two characters (`Wednesday` == `Wed`
106
136
  <dt><code>minute { 0-29 }</code></dt>
107
137
  <dd>The first half of every hour.</dd>
108
138
 
109
- <dt><code>hour { 12am-12pm }</code></dt>
139
+ <dt><code>hour { 12am - 12pm }</code></dt>
110
140
  <dd>During the morning.</dd>
111
141
 
112
142
  <dt><code>sec {0-4 10-14 20-24 30-34 40-44 50-54}</code></dt>
113
143
  <dd>Alternating 5-second periods every hour.</dd>
114
144
 
145
+ <dt><code>wd {mon wed fri} hr {8am - 5pm}, except day {1}</code></dt>
146
+ <dd>Every Monday, Wednesday, and Friday from 8am until 4:59:59 PM, except on
147
+ the first of the month.</dd>
148
+
115
149
  <dt><code>wd {1 3 5 7} min {0-29}, wd {2 4 6} min {30-59}</code></dt>
116
150
  <dd>Every first half-hour on alternating week days, and the second half-hour the
117
151
  rest of the week.</dd>
@@ -121,8 +155,8 @@ Values for week days can be abbreviated to two characters (`Wednesday` == `Wed`
121
155
  ### Schedule Objects
122
156
 
123
157
  Schedules are immutable after they're created, but they have mutator methods to
124
- allow you to compose the schedule you want by combining them, or by using mutator
125
- methods that return a changed copy of the original:
158
+ allow you to compose the schedule you want by combining them, or by using
159
+ mutator methods that return a changed copy of the original:
126
160
 
127
161
  weekend = Schedulability::Schedule( "wd {Sat - Sun}" )
128
162
  weekdays = Schedulability::Schedule( "wd {Mon - Fri}" )
@@ -159,14 +193,6 @@ methods that return a changed copy of the original:
159
193
  send_email( "Stuff happened." )
160
194
  end
161
195
 
162
- ### Enumerators
163
- on_duty.each_minute
164
- # => #<Enumerator: ...>
165
- on_duty.each_hour
166
- # => #<Enumerator: ...>
167
- on_duty.each_day
168
- # => #<Enumerator: ...>
169
-
170
196
 
171
197
  ## Prerequisites
172
198
 
@@ -194,18 +220,20 @@ and generate the API documentation.
194
220
 
195
221
  ## License
196
222
 
197
- This library borrows much of its schedule description syntax and several implementation strategies from the Time::Period Perl module by Patrick Ryan, used under the terms of the Perl Artistic License.
198
-
199
- Patrick Ryan <perl@pryan.org> wrote it.
200
- Paul Boyd <pboyd@cpan.org> fixed a few bugs.
223
+ This library borrows much of its schedule description syntax and several
224
+ implementation strategies from the Time::Period Perl module by Patrick Ryan,
225
+ used under the terms of the Perl Artistic License.
201
226
 
202
- Copyright (c) 1997 Patrick Ryan. All rights reserved. This Perl
203
- module uses the conditions given by Perl. This module may only
204
- be distributed and or modified under the conditions given by Perl.
227
+ > Patrick Ryan <perl@pryan.org> wrote it.
228
+ > Paul Boyd <pboyd@cpan.org> fixed a few bugs.
229
+ >
230
+ > Copyright (c) 1997 Patrick Ryan. All rights reserved. This Perl
231
+ > module uses the conditions given by Perl. This module may only
232
+ > be distributed and or modified under the conditions given by Perl.
205
233
 
206
234
  The rest is:
207
235
 
208
- Copyright (c) 2015, Michael Granger and Mahlon E. Smith
236
+ Copyright (c) 2015-2016, Michael Granger and Mahlon E. Smith
209
237
  All rights reserved.
210
238
 
211
239
  Redistribution and use in source and binary forms, with or without
data/Rakefile CHANGED
@@ -33,9 +33,9 @@ hoespec = Hoe.spec 'schedulability' do
33
33
  self.dependency 'loggability', '~> 0.11'
34
34
 
35
35
  self.dependency 'timecop', '~> 0.8', :developer
36
- self.dependency 'hoe-deveiate', '~> 0.4', :developer
37
- self.dependency 'hoe-bundler', '~> 1.2', :developer
38
- self.dependency 'simplecov', '~> 0.7', :developer
36
+ self.dependency 'rdoc', '~> 4.2', :developer
37
+ self.dependency 'hoe-deveiate', '~> 0.8', :developer
38
+ self.dependency 'simplecov', '~> 0.12', :developer
39
39
 
40
40
  self.license "BSD-3-Clause"
41
41
  self.require_ruby_version( '>=2.2.0' )
@@ -67,7 +67,7 @@ if File.directory?( '.hg' )
67
67
  RDoc::Task.new( 'docs' ) do |rdoc|
68
68
  rdoc.main = "README.md"
69
69
  rdoc.rdoc_files.include( "*.rdoc", "*.md", "ChangeLog", "lib/**/*.rb" )
70
- rdoc.generator = :sixfish
70
+ rdoc.generator = :fivefish
71
71
  rdoc.title = 'Schedulability'
72
72
  rdoc.rdoc_dir = 'doc'
73
73
  end
@@ -10,10 +10,10 @@ module Schedulability
10
10
  extend Loggability
11
11
 
12
12
  # Package version constant
13
- VERSION = '0.1.0'
13
+ VERSION = '0.2.0'
14
14
 
15
15
  # VCS revision
16
- REVISION = %q$Revision: 39de155fb60f $
16
+ REVISION = %q$Revision: bd7566ac26d5 $
17
17
 
18
18
 
19
19
  # Loggability API -- set up a logger for Schedulability objects
@@ -24,5 +24,9 @@ module Schedulability
24
24
  autoload :Parser, 'schedulability/parser'
25
25
  autoload :TimeRefinements, 'schedulability/mixins'
26
26
 
27
+ autoload :Error, 'schedulability/exceptions'
28
+ autoload :ParseError, 'schedulability/exceptions'
29
+ autoload :RangeError, 'schedulability/exceptions'
30
+
27
31
  end # module Schedulability
28
32
 
@@ -120,6 +120,81 @@ module Schedulability
120
120
  end
121
121
 
122
122
  end # refine Numeric
123
+
124
+
125
+ refine Time do
126
+
127
+ # Approximate Time Constants (in seconds)
128
+ MINUTES = 60
129
+ HOURS = 60 * MINUTES
130
+ DAYS = 24 * HOURS
131
+ WEEKS = 7 * DAYS
132
+ MONTHS = 30 * DAYS
133
+ YEARS = 365.25 * DAYS
134
+
135
+
136
+ ### Returns +true+ if the receiver is a Time in the future.
137
+ def future?
138
+ return self > Time.now
139
+ end
140
+
141
+
142
+ ### Returns +true+ if the receiver is a Time in the past.
143
+ def past?
144
+ return self < Time.now
145
+ end
146
+
147
+
148
+ ### Return a description of the receiving Time object in relation to the current
149
+ ### time.
150
+ ###
151
+ ### Example:
152
+ ###
153
+ ### "Saved %s ago." % object.updated_at.as_delta
154
+ def as_delta
155
+ now = Time.now
156
+ if now > self
157
+ seconds = now - self
158
+ return "%s ago" % [ timeperiod(seconds) ]
159
+ else
160
+ seconds = self - now
161
+ return "%s from now" % [ timeperiod(seconds) ]
162
+ end
163
+ end
164
+
165
+
166
+ ### Return a description of +seconds+ as the nearest whole unit of time.
167
+ def timeperiod( seconds )
168
+ return case
169
+ when seconds < MINUTES - 5
170
+ 'less than a minute'
171
+ when seconds < 50 * MINUTES
172
+ if seconds <= 89
173
+ "a minute"
174
+ else
175
+ "%d minutes" % [ (seconds.to_f / MINUTES).ceil ]
176
+ end
177
+ when seconds < 90 * MINUTES
178
+ 'about an hour'
179
+ when seconds < 18 * HOURS
180
+ "%d hours" % [ (seconds.to_f / HOURS).ceil ]
181
+ when seconds < 30 * HOURS
182
+ 'about a day'
183
+ when seconds < WEEKS
184
+ "%d days" % [ (seconds.to_f / DAYS).ceil ]
185
+ when seconds < 2 * WEEKS
186
+ 'about a week'
187
+ when seconds < 3 * MONTHS
188
+ "%d weeks" % [ (seconds.to_f / WEEKS).round ]
189
+ when seconds < 18 * MONTHS
190
+ "%d months" % [ (seconds.to_f / MONTHS).ceil ]
191
+ else
192
+ "%d years" % [ (seconds.to_f / YEARS).ceil ]
193
+ end
194
+ end
195
+
196
+ end # refine Time
197
+
123
198
  end # module TimeRefinements
124
199
 
125
200
  end # module Schedulability
@@ -56,6 +56,35 @@ module Schedulability::Parser
56
56
  module_function
57
57
  ###############
58
58
 
59
+ ### Normalize an array of parsed periods into a human readable string.
60
+ def stringify( periods )
61
+ strings = []
62
+ periods.each do |period|
63
+ period_string = []
64
+ period.sort_by{|k, v| k}.each do |scale, ranges|
65
+ range_string = ""
66
+ range_string << "%s { " % [ scale.to_s ]
67
+
68
+ range_strings = ranges.each_with_object( [] ).each do |range, acc|
69
+ if range.min == range.max
70
+ acc << range.min
71
+ elsif range.exclude_end?
72
+ acc << "%d-%d" % [ range.min, range.max + 1 ]
73
+ else
74
+ acc << "%d-%d" % [ range.min, range.max ]
75
+ end
76
+ end
77
+
78
+ range_string << range_strings.join( ' ' ) << " }"
79
+ period_string << range_string
80
+ end
81
+ strings << period_string.join( ' ' )
82
+ end
83
+
84
+ return strings.join( ', ' )
85
+ end
86
+
87
+
59
88
  ### Scan +expression+ for periods and return them in an Array.
60
89
  def extract_periods( expression )
61
90
  positive_periods = []
@@ -64,7 +93,6 @@ module Schedulability::Parser
64
93
  expression.strip.downcase.split( /\s*,\s*/ ).each do |subexpr|
65
94
  hash, negative = self.extract_period( subexpr )
66
95
  if negative
67
- self.log.debug "Adding %p to the negative "
68
96
  negative_periods << hash
69
97
  else
70
98
  positive_periods << hash
@@ -81,7 +109,6 @@ module Schedulability::Parser
81
109
  scanner = StringScanner.new( expression )
82
110
 
83
111
  negative = scanner.skip( /\s*(!|not |except )\s*/ )
84
- self.log.debug "Period %p is %snegative!" % [ expression, negative ? "" : "not " ]
85
112
 
86
113
  while scanner.scan( PERIOD_PATTERN )
87
114
  ranges = scanner[:ranges].strip
@@ -187,7 +214,7 @@ module Schedulability::Parser
187
214
 
188
215
  ### Return an Array of Integer minute Ranges for the specified +ranges+ expression.
189
216
  def extract_minute_ranges( ranges )
190
- return self.extract_ranges( :minute, ranges, 0, 59 ) do |val|
217
+ return self.extract_ranges( :minute, ranges, 0, 60 ) do |val|
191
218
  Integer( strip_leading_zeros(val) )
192
219
  end
193
220
  end
@@ -195,7 +222,7 @@ module Schedulability::Parser
195
222
 
196
223
  ### Return an Array of Integer second Ranges for the specified +ranges+ expression.
197
224
  def extract_second_ranges( ranges )
198
- return self.extract_ranges( :second, ranges, 0, 59 ) do |val|
225
+ return self.extract_ranges( :second, ranges, 0, 60 ) do |val|
199
226
  Integer( strip_leading_zeros(val) )
200
227
  end
201
228
  end
@@ -233,7 +260,6 @@ module Schedulability::Parser
233
260
 
234
261
  ints = ranges.split( /(?<!-)\s+(?!-)/ ).flat_map do |range|
235
262
  min, max = range.split( /\s*-\s*/, 2 )
236
- self.log.debug "Min = %p, max = %p" % [ min, max ]
237
263
 
238
264
  min = yield( min )
239
265
  raise Schedulability::ParseError, "invalid %s value: %p" % [ scale, min ] unless
@@ -243,10 +269,8 @@ module Schedulability::Parser
243
269
  max = yield( max )
244
270
  raise Schedulability::ParseError, "invalid %s value: %p" % [ scale, max ] unless
245
271
  valid_range.cover?( max )
246
- self.log.debug "Parsed min = %p, max = %p" % [ min, max ]
247
272
 
248
273
  if min > max
249
- self.log.debug "wrapped: %d-%d and %d-%d" % [ minval, max, min, maxval ]
250
274
  Range.new( minval, max, exclude_end ).to_a +
251
275
  Range.new( min, maxval, false ).to_a
252
276
  else
@@ -261,8 +285,6 @@ module Schedulability::Parser
261
285
  ### Coalese an Array of non-contiguous Range objects from the specified +ints+ for +scale+.
262
286
  def coalesce_ranges( ints, scale )
263
287
  exclude_end = EXCLUSIVE_RANGED_SCALES.include?( scale )
264
- self.log.debug "Coalescing %d ints to Ranges (%p, %s)" %
265
- [ ints.size, ints, exclude_end ? "exclusive" : "inclusive" ]
266
288
  ints.flatten!
267
289
  return [] if ints.empty?
268
290
 
@@ -276,8 +298,6 @@ module Schedulability::Parser
276
298
  last_val = values.last
277
299
  last_val += 1 if exclude_end
278
300
  Range.new( values.first, last_val, exclude_end )
279
- end.tap do |ranges|
280
- self.log.debug "Coalesced range integers to Ranges: %p" % [ ranges ]
281
301
  end
282
302
  end
283
303
 
@@ -302,8 +322,10 @@ module Schedulability::Parser
302
322
 
303
323
 
304
324
  ### Return a copy of the specified +val+ with any leading zeros stripped.
325
+ ### If the resulting string is empty, return "0".
305
326
  def strip_leading_zeros( val )
306
- return val.sub( /\A0+/, '' )
327
+ return val.sub( /\A0+(?!$)/, '' )
307
328
  end
308
329
 
309
330
  end # module Schedulability::Parser
331
+
@@ -46,7 +46,7 @@ class Schedulability::Schedule
46
46
 
47
47
  ### Returns +true+ if the schedule doesn't have any time periods.
48
48
  def empty?
49
- return self.positive_periods.empty?
49
+ return self.positive_periods.empty? && self.negative_periods.empty?
50
50
  end
51
51
 
52
52
 
@@ -62,7 +62,6 @@ class Schedulability::Schedule
62
62
  time.to_time
63
63
  else
64
64
  time_obj = Time.parse( time.to_s )
65
- self.log.debug "Parsed %p to time %p" % [ time, time_obj ]
66
65
  time_obj
67
66
  end
68
67
 
@@ -86,6 +85,22 @@ class Schedulability::Schedule
86
85
  end
87
86
 
88
87
 
88
+ ### Returns +true+ if the schedule has any times which overlap those of +other_schedule+.
89
+ def overlaps?( other_schedule )
90
+ return ! self.exclusive?( other_schedule )
91
+ end
92
+ alias_method :overlaps_with?, :overlaps?
93
+
94
+
95
+ ### Returns +true+ if the schedule does not have any times which overlap those
96
+ ### of +other_schedule+.
97
+ def exclusive?( other_schedule )
98
+ return ( self & other_schedule ).empty?
99
+ end
100
+ alias_method :exclusive_of?, :exclusive?
101
+ alias_method :is_exclusive_of?, :exclusive?
102
+
103
+
89
104
  ### Returns +true+ if the time periods for +other_schedule+ are the same as those for the
90
105
  ### receiver.
91
106
  def ==( other_schedule )
@@ -125,6 +140,17 @@ class Schedulability::Schedule
125
140
  end
126
141
 
127
142
 
143
+ ### Return a string from previously parsed Schedule period objects.
144
+ def to_s
145
+ str = Schedulability::Parser.stringify( self.positive_periods )
146
+ unless self.negative_periods.empty?
147
+ str << ", not %s" % [ Schedulability::Parser.stringify(self.negative_periods) ]
148
+ end
149
+
150
+ return str
151
+ end
152
+
153
+
128
154
  #######
129
155
  private
130
156
  #######
@@ -161,7 +187,6 @@ class Schedulability::Schedule
161
187
  when :wk
162
188
  return ( time.day / 7.0 ).ceil
163
189
  when :yr
164
- self.log.debug "Year match: %p" % [ time.year ]
165
190
  return time.year
166
191
  else
167
192
  # If this happens, it's likely a bug in the parser.
@@ -0,0 +1,164 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../helpers'
4
+
5
+ require 'schedulability/mixins'
6
+
7
+
8
+ describe Schedulability, 'mixins' do
9
+
10
+
11
+ describe Schedulability::TimeRefinements do
12
+
13
+ using( described_class )
14
+
15
+
16
+ describe "used to extend Numeric objects" do
17
+
18
+ SECONDS_IN_A_MINUTE = 60
19
+ SECONDS_IN_AN_HOUR = SECONDS_IN_A_MINUTE * 60
20
+ SECONDS_IN_A_DAY = SECONDS_IN_AN_HOUR * 24
21
+ SECONDS_IN_A_WEEK = SECONDS_IN_A_DAY * 7
22
+ SECONDS_IN_A_FORTNIGHT = SECONDS_IN_A_WEEK * 2
23
+ SECONDS_IN_A_MONTH = SECONDS_IN_A_DAY * 30
24
+ SECONDS_IN_A_YEAR = Integer( SECONDS_IN_A_DAY * 365.25 )
25
+
26
+
27
+ it "can calculate the number of seconds for various units of time" do
28
+ expect( 1.second ).to eq( 1 )
29
+ expect( 14.seconds ).to eq( 14 )
30
+
31
+ expect( 1.minute ).to eq( SECONDS_IN_A_MINUTE )
32
+ expect( 18.minutes ).to eq( SECONDS_IN_A_MINUTE * 18 )
33
+
34
+ expect( 1.hour ).to eq( SECONDS_IN_AN_HOUR )
35
+ expect( 723.hours ).to eq( SECONDS_IN_AN_HOUR * 723 )
36
+
37
+ expect( 1.day ).to eq( SECONDS_IN_A_DAY )
38
+ expect( 3.days ).to eq( SECONDS_IN_A_DAY * 3 )
39
+
40
+ expect( 1.week ).to eq( SECONDS_IN_A_WEEK )
41
+ expect( 28.weeks ).to eq( SECONDS_IN_A_WEEK * 28 )
42
+
43
+ expect( 1.fortnight ).to eq( SECONDS_IN_A_FORTNIGHT )
44
+ expect( 31.fortnights ).to eq( SECONDS_IN_A_FORTNIGHT * 31 )
45
+
46
+ expect( 1.month ).to eq( SECONDS_IN_A_MONTH )
47
+ expect( 67.months ).to eq( SECONDS_IN_A_MONTH * 67 )
48
+
49
+ expect( 1.year ).to eq( SECONDS_IN_A_YEAR )
50
+ expect( 13.years ).to eq( SECONDS_IN_A_YEAR * 13 )
51
+ end
52
+
53
+
54
+ it "can calculate various time offsets" do
55
+ starttime = Time.now
56
+
57
+ expect( 1.second.after( starttime ) ).to eq( starttime + 1 )
58
+ expect( 18.seconds.from_now ).to be_within( 10.seconds ).of( starttime + 18 )
59
+
60
+ expect( 1.second.before( starttime ) ).to eq( starttime - 1 )
61
+ expect( 3.hours.ago ).to be_within( 10.seconds ).of( starttime - 10800 )
62
+ end
63
+
64
+ end
65
+
66
+
67
+ context "used to extend Time objects" do
68
+
69
+ it "makes them aware of whether they're in the future or not" do
70
+ Timecop.freeze do
71
+ time = Time.now
72
+ expect( time.future? ).to be_falsey
73
+
74
+ future_time = time + 1
75
+ expect( future_time.future? ).to be_truthy
76
+
77
+ past_time = time - 1
78
+ expect( past_time.future? ).to be_falsey
79
+ end
80
+ end
81
+
82
+
83
+ it "makes them aware of whether they're in the past or not" do
84
+ Timecop.freeze do
85
+ time = Time.now
86
+ expect( time.past? ).to be_falsey
87
+
88
+ future_time = time + 1
89
+ expect( future_time.past? ).to be_falsey
90
+
91
+ past_time = time - 1
92
+ expect( past_time.past? ).to be_truthy
93
+ end
94
+ end
95
+
96
+
97
+ it "adds the ability to express themselves as an offset in English" do
98
+ Timecop.freeze do
99
+ expect( 1.second.ago.as_delta ).to eq( 'less than a minute ago' )
100
+ expect( 1.second.from_now.as_delta ).to eq( 'less than a minute from now' )
101
+
102
+ expect( 1.minute.ago.as_delta ).to eq( 'a minute ago' )
103
+ expect( 1.minute.from_now.as_delta ).to eq( 'a minute from now' )
104
+ expect( 68.seconds.ago.as_delta ).to eq( 'a minute ago' )
105
+ expect( 68.seconds.from_now.as_delta ).to eq( 'a minute from now' )
106
+ expect( 2.minutes.ago.as_delta ).to eq( '2 minutes ago' )
107
+ expect( 2.minutes.from_now.as_delta ).to eq( '2 minutes from now' )
108
+ expect( 38.minutes.ago.as_delta ).to eq( '38 minutes ago' )
109
+ expect( 38.minutes.from_now.as_delta ).to eq( '38 minutes from now' )
110
+
111
+ expect( 1.hour.ago.as_delta ).to eq( 'about an hour ago' )
112
+ expect( 1.hour.from_now.as_delta ).to eq( 'about an hour from now' )
113
+ expect( 75.minutes.ago.as_delta ).to eq( 'about an hour ago' )
114
+ expect( 75.minutes.from_now.as_delta ).to eq( 'about an hour from now' )
115
+
116
+ expect( 2.hours.ago.as_delta ).to eq( '2 hours ago' )
117
+ expect( 2.hours.from_now.as_delta ).to eq( '2 hours from now' )
118
+ expect( 14.hours.ago.as_delta ).to eq( '14 hours ago' )
119
+ expect( 14.hours.from_now.as_delta ).to eq( '14 hours from now' )
120
+
121
+ expect( 22.hours.ago.as_delta ).to eq( 'about a day ago' )
122
+ expect( 22.hours.from_now.as_delta ).to eq( 'about a day from now' )
123
+ expect( 28.hours.ago.as_delta ).to eq( 'about a day ago' )
124
+ expect( 28.hours.from_now.as_delta ).to eq( 'about a day from now' )
125
+
126
+ expect( 36.hours.ago.as_delta ).to eq( '2 days ago' )
127
+ expect( 36.hours.from_now.as_delta ).to eq( '2 days from now' )
128
+ expect( 4.days.ago.as_delta ).to eq( '4 days ago' )
129
+ expect( 4.days.from_now.as_delta ).to eq( '4 days from now' )
130
+
131
+ expect( 1.week.ago.as_delta ).to eq( 'about a week ago' )
132
+ expect( 1.week.from_now.as_delta ).to eq( 'about a week from now' )
133
+ expect( 8.days.ago.as_delta ).to eq( 'about a week ago' )
134
+ expect( 8.days.from_now.as_delta ).to eq( 'about a week from now' )
135
+
136
+ expect( 15.days.ago.as_delta ).to eq( '2 weeks ago' )
137
+ expect( 15.days.from_now.as_delta ).to eq( '2 weeks from now' )
138
+ expect( 3.weeks.ago.as_delta ).to eq( '3 weeks ago' )
139
+ expect( 3.weeks.from_now.as_delta ).to eq( '3 weeks from now' )
140
+
141
+ expect( 1.month.ago.as_delta ).to eq( '4 weeks ago' )
142
+ expect( 1.month.from_now.as_delta ).to eq( '4 weeks from now' )
143
+ expect( 36.days.ago.as_delta ).to eq( '5 weeks ago' )
144
+ expect( 36.days.from_now.as_delta ).to eq( '5 weeks from now' )
145
+
146
+ expect( 6.months.ago.as_delta ).to eq( '6 months ago' )
147
+ expect( 6.months.from_now.as_delta ).to eq( '6 months from now' )
148
+ expect( 14.months.ago.as_delta ).to eq( '14 months ago' )
149
+ expect( 14.months.from_now.as_delta ).to eq( '14 months from now' )
150
+
151
+ expect( 6.year.ago.as_delta ).to eq( '6 years ago' )
152
+ expect( 6.year.from_now.as_delta ).to eq( '6 years from now' )
153
+ expect( 14.years.ago.as_delta ).to eq( '14 years ago' )
154
+ expect( 14.years.from_now.as_delta ).to eq( '14 years from now' )
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+
163
+ end
164
+
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env rspec -cfd
2
+
3
+ require_relative '../helpers'
4
+
5
+ require 'schedulability/parser'
6
+
7
+
8
+ describe Schedulability::Parser do
9
+
10
+
11
+ it "can parse a single time period structure from a string" do
12
+ range, negative = described_class.extract_period( "min {25-35}" )
13
+
14
+ expect( range ).to be_a( Hash )
15
+ expect( range ).to include( min: [25...35] )
16
+ expect( negative ).to be_falsey
17
+ end
18
+
19
+
20
+ it "parses single values as one-unit ranges" do
21
+ range, _ = described_class.extract_period( "min {0 15 30 45}" )
22
+
23
+ expect( range ).to be_a( Hash )
24
+ expect( range ).to include( min: [0...1, 15...16, 30...31, 45...46] )
25
+ end
26
+
27
+
28
+ it "can parse a single negative time period structure from a string" do
29
+ range, negative = described_class.extract_period( "except hr {6-8}" )
30
+
31
+ expect( range ).to be_a( Hash )
32
+ expect( range ).to include( hr: [6...8] )
33
+ expect( negative ).to be_truthy
34
+ end
35
+
36
+
37
+ it "can parse multiple time period structures from string descriptions joined by commas" do
38
+ positive, negative = described_class.extract_periods( "wd {Mon-Fri}, except hr {6am-8pm}" )
39
+ expect( positive ).to eq( [{wd: [1..5]}] )
40
+ expect( negative ).to eq( [{hr: [6...20]}] )
41
+ end
42
+
43
+
44
+ it "can stringify an array of parsed time period structures" do
45
+ schedule_string = "wd { 1-5 }, hr { 6-19 }, min { 0 15 30 45 }"
46
+ periods, _ = described_class.extract_periods( schedule_string )
47
+
48
+ expect( described_class.stringify(periods) ).
49
+ to eq( schedule_string )
50
+ end
51
+
52
+
53
+ describe "can extract Range objects from expressions" do
54
+
55
+ describe "for years"
56
+ describe "for months"
57
+ describe "for weeks of the month"
58
+ describe "for days of the year"
59
+ describe "for days of the month"
60
+ describe "for hours"
61
+ describe "for minutes"
62
+ describe "for seconds"
63
+
64
+ end
65
+
66
+ end
67
+
@@ -25,6 +25,13 @@ describe Schedulability::Schedule do
25
25
  let( :testing_time ) { Time.iso8601('2015-12-15T12:00:00-00:00') }
26
26
 
27
27
 
28
+ RSpec::Matchers.define( :overlap ) do |other|
29
+ match do |schedule|
30
+ schedule.overlaps?( other )
31
+ end
32
+ end
33
+
34
+
28
35
  context "with no periods" do
29
36
 
30
37
  let( :schedule ) { described_class.new }
@@ -161,6 +168,13 @@ describe Schedulability::Schedule do
161
168
  expect( schedule ).to include( 'Wed Dec 16 12:00:00 2015' )
162
169
  expect( schedule ).to_not include( 'Wed Dec 16 15:05:00 2015' )
163
170
  end
171
+
172
+
173
+ it "can be stringified" do
174
+ schedule = described_class.
175
+ parse( "wd {Mon Wed Fri} hr {8am-4pm}, wd {Tue Thu} hr {9am-5pm}, not hour { 3pm }" )
176
+ expect( schedule.to_s ).to eq( "hr { 8-16 } wd { 1 3 5 }, hr { 9-17 } wd { 2 4 }, not hr { 15 }" )
177
+ end
164
178
  end
165
179
 
166
180
 
@@ -709,6 +723,32 @@ describe Schedulability::Schedule do
709
723
  end
710
724
 
711
725
 
726
+ it "doesn't raise a parse error for second values equal to 59" do
727
+ expect {
728
+ described_class.parse( 'sec {1 5 10 59}' )
729
+ }.not_to raise_error
730
+ expect {
731
+ described_class.parse( 'sec {59}' )
732
+ }.not_to raise_error
733
+ expect {
734
+ described_class.parse( 'sec {0-59}' )
735
+ }.not_to raise_error
736
+ end
737
+
738
+
739
+ it "allows second values equal to 0" do
740
+ expect {
741
+ described_class.parse( 'sec {0 5 10 59}' )
742
+ }.not_to raise_error
743
+ expect {
744
+ described_class.parse( 'sec {0}' )
745
+ }.not_to raise_error
746
+ expect {
747
+ described_class.parse( 'sec {0-59}' )
748
+ }.not_to raise_error
749
+ end
750
+
751
+
712
752
  it "raises a parse error for minute values greater than 59" do
713
753
  expect {
714
754
  described_class.parse( 'min {09 28 68}' )
@@ -719,6 +759,32 @@ describe Schedulability::Schedule do
719
759
  end
720
760
 
721
761
 
762
+ it "doesn't raise a parse error for minute values equal to 59" do
763
+ expect {
764
+ described_class.parse( 'min {1 5 10 59}' )
765
+ }.not_to raise_error
766
+ expect {
767
+ described_class.parse( 'min {59}' )
768
+ }.not_to raise_error
769
+ expect {
770
+ described_class.parse( 'min {0-59}' )
771
+ }.not_to raise_error
772
+ end
773
+
774
+
775
+ it "allows minute values equal to 0" do
776
+ expect {
777
+ described_class.parse( 'min {0 5 10 59}' )
778
+ }.not_to raise_error
779
+ expect {
780
+ described_class.parse( 'min {0}' )
781
+ }.not_to raise_error
782
+ expect {
783
+ described_class.parse( 'min {0-59}' )
784
+ }.not_to raise_error
785
+ end
786
+
787
+
722
788
  it "raises a parse error for minute ranges with invalid values" do
723
789
  expect {
724
790
  described_class.parse( 'min {120-15}' )
@@ -784,6 +850,15 @@ describe Schedulability::Schedule do
784
850
  end
785
851
 
786
852
 
853
+ it "treats scales present in one schedule as infinite in the other when intersecting" do
854
+ schedule1 = described_class.parse( 'hr {6am-8am}' )
855
+ schedule2 = described_class.parse( 'wday {Thu Sat}' )
856
+ schedule3 = schedule1 & schedule2
857
+
858
+ expect( schedule3 ).to be == described_class.parse( 'hr {6am-8am} wday {Thu Sat}' )
859
+ end
860
+
861
+
787
862
  it "can calculate unions of schedules with negated periods" do
788
863
  schedule1 = described_class.parse( '! wday { Mon-Fri }' )
789
864
  schedule2 = described_class.parse( '! wday { Thu }' )
@@ -824,5 +899,31 @@ describe Schedulability::Schedule do
824
899
 
825
900
  end
826
901
 
902
+
903
+ describe "predicates" do
904
+
905
+ it "can test if one schedule overlaps another" do
906
+ schedule1 = described_class.parse( "hr {8am - 5pm}" )
907
+ schedule2 = described_class.parse( "hr {5pm - 8am}" )
908
+ schedule3 = described_class.parse( "wd {Mon - Fri}" )
909
+
910
+ expect( schedule1 ).to_not overlap( schedule2 )
911
+ expect( schedule1 ).to overlap( schedule3 )
912
+ expect( schedule2 ).to overlap( schedule3 )
913
+ end
914
+
915
+
916
+ it "can test if one schedule is exclusive of another" do
917
+ schedule1 = described_class.parse( "hr {8am - 5pm}" )
918
+ schedule2 = described_class.parse( "hr {5pm - 8am}" )
919
+ schedule3 = described_class.parse( "wd {Mon - Fri}" )
920
+
921
+ expect( schedule1 ).to be_exclusive_of( schedule2 )
922
+ expect( schedule1 ).to_not be_exclusive_of( schedule3 )
923
+ expect( schedule2 ).to_not be_exclusive_of( schedule3 )
924
+ end
925
+
926
+ end
927
+
827
928
  end
828
929
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schedulability
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Granger
@@ -11,9 +11,9 @@ bindir: bin
11
11
  cert_chain:
12
12
  - |
13
13
  -----BEGIN CERTIFICATE-----
14
- MIIDbDCCAlSgAwIBAgIBATANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
14
+ MIIDMDCCAhigAwIBAgIBAjANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
15
15
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
16
- HhcNMTUwNDAxMjEyNDEzWhcNMTYwMzMxMjEyNDEzWjA+MQwwCgYDVQQDDANnZWQx
16
+ HhcNMTYwNjAyMDE1NTQ2WhcNMTcwNjAyMDE1NTQ2WjA+MQwwCgYDVQQDDANnZWQx
17
17
  GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
18
18
  ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDb92mkyYwuGBg1oRxt2tkH
19
19
  +Uo3LAsaL/APBfSLzy8o3+B3AUHKCjMUaVeBoZdWtMHB75X3VQlvXfZMyBxj59Vo
@@ -21,17 +21,16 @@ cert_chain:
21
21
  OkOzAscMwkfQxBkXDzjvAWa6UF4c5c9kR/T79iA21kDx9+bUMentU59aCJtUcbxa
22
22
  7kcKJhPEYsk4OdxR9q2dphNMFDQsIdRO8rywX5FRHvcb+qnXC17RvxLHtOjysPtp
23
23
  EWsYoZMxyCDJpUqbwoeiM+tAHoz2ABMv3Ahie3Qeb6+MZNAtMmaWfBx3dg2u+/WN
24
- AgMBAAGjdTBzMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSZ0hCV
25
- qoHr122fGKelqffzEQBhszAcBgNVHREEFTATgRFnZWRARmFlcmllTVVELm9yZzAc
26
- BgNVHRIEFTATgRFnZWRARmFlcmllTVVELm9yZzANBgkqhkiG9w0BAQUFAAOCAQEA
27
- lUKo3NXePpuvN3QGsOLJ6QhNd4+Q9Rz75GipuMrCl296V8QFkd2gg9EG44Pqtk+9
28
- Zac8TkKc9bCSR0snakp+cCPplVvZF0/gMzkSTUJkDBHlNV16z73CyWpbQQa+iLJ4
29
- uisI6gF2ZXK919MYLn2bFJfb7OsCvVfyTPqq8afPY+rq9vlf9ZPwU49AlD8bPRic
30
- 0LX0gO5ykvETIOv+WgGcqp96ceNi9XVuJMh20uWuw6pmv/Ub2RqAf82jQSbpz09G
31
- G8LHR7EjtPPmqCCunfyecJ6MmCNaiJCBxq2NYzyNmluPyHT8+0fuB5kccUVZm6CD
32
- xn3DzOkDE6NYbk8gC9rTsA==
24
+ AgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBSZ0hCV
25
+ qoHr122fGKelqffzEQBhszANBgkqhkiG9w0BAQUFAAOCAQEAF2XCzjfTFxkcVvuj
26
+ hhBezFkZnMDYtWezg4QCkR0RHg4sl1LdXjpvvI59SIgD/evD1hOteGKsXqD8t0E4
27
+ OPAWWv/z+JRma72zeYsBZLSDRPIUvBoul6qCpvY0MiWTh496mFwOxT5lvSAUoh+U
28
+ pQ/MQeH/yC6hbGp7IYska6J8T4z5XkYqafYZ3eKQ8H+xPd/z+gYx+jd0PfkWf1Wk
29
+ QQdziL01SKBHf33OAH/p/puCpwS+ZDfgnNx5oMijWbc671UXkrt7zjD0kGakq+9I
30
+ hnfm736z8j1wvWddqf45++gwPpDr1E4zoAq2PgRl/WBNyR0hfoZLpi3TnHu3eC0x
31
+ uALKNA==
33
32
  -----END CERTIFICATE-----
34
- date: 2015-12-31 00:00:00.000000000 Z
33
+ date: 2016-07-20 00:00:00.000000000 Z
35
34
  dependencies:
36
35
  - !ruby/object:Gem::Dependency
37
36
  name: loggability
@@ -67,14 +66,14 @@ dependencies:
67
66
  requirements:
68
67
  - - "~>"
69
68
  - !ruby/object:Gem::Version
70
- version: '0.7'
69
+ version: '0.8'
71
70
  type: :development
72
71
  prerelease: false
73
72
  version_requirements: !ruby/object:Gem::Requirement
74
73
  requirements:
75
74
  - - "~>"
76
75
  - !ruby/object:Gem::Version
77
- version: '0.7'
76
+ version: '0.8'
78
77
  - !ruby/object:Gem::Dependency
79
78
  name: hoe-highline
80
79
  requirement: !ruby/object:Gem::Requirement
@@ -117,50 +116,37 @@ dependencies:
117
116
  - - "~>"
118
117
  - !ruby/object:Gem::Version
119
118
  version: '0.8'
120
- - !ruby/object:Gem::Dependency
121
- name: hoe-bundler
122
- requirement: !ruby/object:Gem::Requirement
123
- requirements:
124
- - - "~>"
125
- - !ruby/object:Gem::Version
126
- version: '1.2'
127
- type: :development
128
- prerelease: false
129
- version_requirements: !ruby/object:Gem::Requirement
130
- requirements:
131
- - - "~>"
132
- - !ruby/object:Gem::Version
133
- version: '1.2'
134
119
  - !ruby/object:Gem::Dependency
135
120
  name: simplecov
136
121
  requirement: !ruby/object:Gem::Requirement
137
122
  requirements:
138
123
  - - "~>"
139
124
  - !ruby/object:Gem::Version
140
- version: '0.7'
125
+ version: '0.12'
141
126
  type: :development
142
127
  prerelease: false
143
128
  version_requirements: !ruby/object:Gem::Requirement
144
129
  requirements:
145
130
  - - "~>"
146
131
  - !ruby/object:Gem::Version
147
- version: '0.7'
132
+ version: '0.12'
148
133
  - !ruby/object:Gem::Dependency
149
134
  name: hoe
150
135
  requirement: !ruby/object:Gem::Requirement
151
136
  requirements:
152
137
  - - "~>"
153
138
  - !ruby/object:Gem::Version
154
- version: '3.14'
139
+ version: '3.15'
155
140
  type: :development
156
141
  prerelease: false
157
142
  version_requirements: !ruby/object:Gem::Requirement
158
143
  requirements:
159
144
  - - "~>"
160
145
  - !ruby/object:Gem::Version
161
- version: '3.14'
162
- description: Schedulability is a library for describing scheduled time. You can specify
163
- one or more periods of time using a simple syntax, then combine them to describe
146
+ version: '3.15'
147
+ description: |-
148
+ Schedulability is a library for describing scheduled time. You can specify one
149
+ or more periods of time using a simple syntax, then combine them to describe
164
150
  more-complex schedules.
165
151
  email:
166
152
  - ged@FaerieMUD.org
@@ -185,6 +171,8 @@ files:
185
171
  - lib/schedulability/parser.rb
186
172
  - lib/schedulability/schedule.rb
187
173
  - spec/helpers.rb
174
+ - spec/schedulability/mixins_spec.rb
175
+ - spec/schedulability/parser_spec.rb
188
176
  - spec/schedulability/schedule_spec.rb
189
177
  - spec/schedulability_spec.rb
190
178
  homepage: http://deveiate.org/projects/schedulability
metadata.gz.sig CHANGED
Binary file