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 +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
|