schedulability 0.1.0 → 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: 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