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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/ChangeLog +41 -2
- data/History.md +13 -0
- data/Manifest.txt +2 -0
- data/README.md +64 -36
- data/Rakefile +4 -4
- data/lib/schedulability.rb +6 -2
- data/lib/schedulability/mixins.rb +75 -0
- data/lib/schedulability/parser.rb +34 -12
- data/lib/schedulability/schedule.rb +28 -3
- data/spec/schedulability/mixins_spec.rb +164 -0
- data/spec/schedulability/parser_spec.rb +67 -0
- data/spec/schedulability/schedule_spec.rb +101 -0
- metadata +23 -35
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8eded0bd62f85e98614fb6f8c2f57300036be176
|
4
|
+
data.tar.gz: b7fc81a9f3bae2ed902bc6f123ed6d9537012675
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e8d048d6cd378fc9b0b5532d1c7acc2ed667ea885eaec6cd1cdf6b0e8e59e7cc3a4e8f5e6d016d231b251b6d0b50c0659b921f0eff1a518128aa5ec408cc622
|
7
|
+
data.tar.gz: ca2bbea2c50b9fce77c3ff4b3d5ab2a2c0bf037ce278bde3fc6e5bf1dce60eed84f2f11c1789af515947e528116048c510de9bb1c293571352af1bafd173f704
|
checksums.yaml.gz.sig
CHANGED
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]
|
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]
|
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!
|
data/Manifest.txt
CHANGED
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
|
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
|
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
|
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
|
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
|
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
|
74
|
+
A `range` is specified in the form:
|
60
75
|
|
61
|
-
|
76
|
+
<range value>
|
62
77
|
or
|
63
78
|
|
64
|
-
|
79
|
+
<range value>-<range value>
|
65
80
|
|
66
|
-
For two-value ranges, the range is defined as the period between
|
67
|
-
|
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
|
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
|
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
|
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
|
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
|
86
|
-
|
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
|
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
|
198
|
-
|
199
|
-
|
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
|
-
|
203
|
-
|
204
|
-
|
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 '
|
37
|
-
self.dependency 'hoe-
|
38
|
-
self.dependency 'simplecov', '~> 0.
|
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 = :
|
70
|
+
rdoc.generator = :fivefish
|
71
71
|
rdoc.title = 'Schedulability'
|
72
72
|
rdoc.rdoc_dir = 'doc'
|
73
73
|
end
|
data/lib/schedulability.rb
CHANGED
@@ -10,10 +10,10 @@ module Schedulability
|
|
10
10
|
extend Loggability
|
11
11
|
|
12
12
|
# Package version constant
|
13
|
-
VERSION = '0.
|
13
|
+
VERSION = '0.2.0'
|
14
14
|
|
15
15
|
# VCS revision
|
16
|
-
REVISION = %q$Revision:
|
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,
|
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,
|
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.
|
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
|
-
|
14
|
+
MIIDMDCCAhigAwIBAgIBAjANBgkqhkiG9w0BAQUFADA+MQwwCgYDVQQDDANnZWQx
|
15
15
|
GTAXBgoJkiaJk/IsZAEZFglGYWVyaWVNVUQxEzARBgoJkiaJk/IsZAEZFgNvcmcw
|
16
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
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:
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
162
|
-
description:
|
163
|
-
|
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
|