runt 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +23 -0
- data/README +9 -3
- data/Rakefile +19 -16
- data/TODO +7 -6
- data/doc/tutorial_schedule.rdoc +1 -1
- data/doc/tutorial_te.rdoc +2 -2
- data/lib/runt.rb +21 -4
- data/lib/runt/daterange.rb +4 -4
- data/lib/runt/pdate.rb +0 -1
- data/lib/runt/temporalexpression.rb +143 -86
- data/site/index.html +2 -1
- data/test/alltests.rb +0 -2
- data/test/daterangetest.rb +7 -2
- data/test/dprecisiontest.rb +8 -9
- data/test/pdatetest.rb +1 -3
- data/test/scheduletest.rb +34 -2
- data/test/temporalexpressiontest.rb +126 -6
- metadata +13 -5
data/CHANGES
CHANGED
@@ -1,5 +1,28 @@
|
|
1
1
|
= Runt Changelog
|
2
2
|
|
3
|
+
== Version 0.3.0
|
4
|
+
|
5
|
+
* TExpr (finally!) becomes a Module instead of a superclass
|
6
|
+
|
7
|
+
* Added overlap? method for all temporal expressions and DateRange
|
8
|
+
|
9
|
+
* Added REMonth expression which matches a range of dates each month
|
10
|
+
|
11
|
+
* Contributed by Emmett Shear: TExpr#dates method which returns an array of dates occurring within the supplied DateRange
|
12
|
+
|
13
|
+
* Rakefile fixes:
|
14
|
+
- test path allow gem to be installed with -t switch
|
15
|
+
- usage of gzip which will break on Win32
|
16
|
+
|
17
|
+
* Removed and then subsequently restored SpecTE
|
18
|
+
|
19
|
+
* General clean-up, including:
|
20
|
+
- renamed several methods on PDate
|
21
|
+
- renamed 'dateprecisiontest.rb' to 'dprecisiontest.rb'
|
22
|
+
|
23
|
+
* Fixed Object.id deprecation warning
|
24
|
+
|
25
|
+
|
3
26
|
== Version 0.2.0
|
4
27
|
|
5
28
|
* Fixed Schedule class
|
data/README
CHANGED
@@ -8,6 +8,10 @@
|
|
8
8
|
|
9
9
|
= INSTALL
|
10
10
|
|
11
|
+
* gem install runt
|
12
|
+
|
13
|
+
<b>or</b>
|
14
|
+
|
11
15
|
* Unpack the Runt distribution.
|
12
16
|
|
13
17
|
$ tar -xzvf runt-<version>.tar.gz
|
@@ -32,7 +36,7 @@
|
|
32
36
|
|
33
37
|
* require 'runt'
|
34
38
|
|
35
|
-
* See http://runt.rubyforge.org
|
39
|
+
* See Runt website[http://runt.rubyforge.org].
|
36
40
|
|
37
41
|
* See $UNPACK_DIR/runt/test/*.rb for example usage.
|
38
42
|
|
@@ -66,7 +70,9 @@ The ruby-nyc user's group for their suggestions and feedback.
|
|
66
70
|
|
67
71
|
BlueRobot[http://www.bluerobot.com/web/layouts/] for the CSS used to prettify the Runt website.
|
68
72
|
|
69
|
-
|
73
|
+
Emmett Shear for contributed TExpr#dates code and several thought-provoking feature requests.
|
74
|
+
|
75
|
+
The number 12, and the letters E, J, and B.
|
70
76
|
|
71
77
|
---
|
72
78
|
|
@@ -85,4 +91,4 @@ implied warranties, including, without limitation, the implied
|
|
85
91
|
warranties of merchantibility and fitness for a particular
|
86
92
|
purpose.
|
87
93
|
|
88
|
-
link://../dcl-small.gif
|
94
|
+
link://../dcl-small.gif
|
data/Rakefile
CHANGED
@@ -10,15 +10,17 @@ require 'rake'
|
|
10
10
|
require 'rake/clean'
|
11
11
|
require 'rake/testtask'
|
12
12
|
require 'rake/rdoctask'
|
13
|
-
#require 'rake/packagetask'
|
14
|
-
|
15
13
|
require 'rake/contrib/sshpublisher'
|
16
14
|
require 'rake/contrib/rubyforgepublisher'
|
17
15
|
require 'fileutils'
|
18
16
|
|
17
|
+
#####################################################################
|
18
|
+
# Constants
|
19
|
+
#####################################################################
|
20
|
+
|
19
21
|
# Build Settings
|
20
|
-
PKG_VERSION = "0.
|
21
|
-
|
22
|
+
PKG_VERSION = "0.3.0"
|
23
|
+
|
22
24
|
# Files to be included in Runt distribution
|
23
25
|
PKG_FILES = FileList[
|
24
26
|
'setup.rb',
|
@@ -29,10 +31,19 @@ PKG_FILES = FileList[
|
|
29
31
|
'site/**/*'
|
30
32
|
].exclude("*.ses")
|
31
33
|
|
34
|
+
if(RUBY_PLATFORM =~ /win32/i)
|
35
|
+
PKG_EXEC_TAR = false
|
36
|
+
else
|
37
|
+
PKG_EXEC_TAR = true
|
38
|
+
end
|
39
|
+
|
32
40
|
# build directory
|
33
41
|
TARGET_DIR = "target"
|
34
42
|
|
43
|
+
#####################################################################
|
35
44
|
# Targets
|
45
|
+
#####################################################################
|
46
|
+
|
36
47
|
task :default => [:test]
|
37
48
|
task :clobber => [:clobber_build_dir]
|
38
49
|
|
@@ -55,14 +66,7 @@ end
|
|
55
66
|
Rake::TestTask.new do |t|
|
56
67
|
t.libs << "test"
|
57
68
|
t.pattern = 'test/alltests.rb'
|
58
|
-
t.verbose =
|
59
|
-
end
|
60
|
-
|
61
|
-
Rake::PackageTask.new("runt", PKG_VERSION) do |p|
|
62
|
-
p.package_dir="#{TARGET_DIR}/#{p.package_dir}"
|
63
|
-
p.need_tar = true
|
64
|
-
p.need_zip = true
|
65
|
-
p.package_files.include(PKG_FILES)
|
69
|
+
t.verbose = false
|
66
70
|
end
|
67
71
|
|
68
72
|
desc "Copy html files for the Runt website to the build directory."
|
@@ -79,7 +83,7 @@ task :publish => [:rdoc,:copy_site,:clobber_package] do |t|
|
|
79
83
|
end
|
80
84
|
|
81
85
|
desc "Publish the Documentation to the build dir."
|
82
|
-
task :test_publish => [:
|
86
|
+
task :test_publish => [:rdoc,:copy_site,:clobber_package] do |t|
|
83
87
|
puts "YAY! We've tested publish! YAY!"
|
84
88
|
end
|
85
89
|
|
@@ -100,8 +104,7 @@ else
|
|
100
104
|
s.email = 'matt@digitalclash.com'
|
101
105
|
s.homepage = 'http://runt.rubyforge.org'
|
102
106
|
s.has_rdoc = true
|
103
|
-
|
104
|
-
# s.rdoc_options = rd.option_list
|
107
|
+
s.test_files = Dir['test/*test.rb']
|
105
108
|
s.rubyforge_project = 'runt'
|
106
109
|
s.description = <<EOF
|
107
110
|
Runt is a Ruby version of temporal patterns by
|
@@ -112,6 +115,6 @@ EOF
|
|
112
115
|
|
113
116
|
Rake::GemPackageTask.new(spec) do |pkg|
|
114
117
|
pkg.need_zip = true
|
115
|
-
pkg.need_tar =
|
118
|
+
pkg.need_tar = PKG_EXEC_TAR
|
116
119
|
end
|
117
120
|
end
|
data/TODO
CHANGED
@@ -4,16 +4,17 @@ Send suggestions, questions, threats, etc. for this list to Matt[mailto:matt@dig
|
|
4
4
|
|
5
5
|
=== To Do
|
6
6
|
|
7
|
-
*
|
7
|
+
* Schedule tutorial
|
8
8
|
|
9
|
-
*
|
9
|
+
* Example usage with Rails
|
10
10
|
|
11
|
-
*
|
11
|
+
* Persistence strategy:
|
12
|
+
- Marshall
|
13
|
+
- database...create storable grammar, expression stack?
|
12
14
|
|
13
|
-
*
|
15
|
+
* Fix REWeek so that ordinal day values where the end day < start day does not fail
|
14
16
|
|
15
|
-
*
|
17
|
+
* Make Schedule a Module instead of a class
|
16
18
|
|
17
19
|
* Address performance issues due to implementation (in particular, PDate#<=>)
|
18
20
|
|
19
|
-
* Use RDoc properly so Runt website and README don't cause DRY violations
|
data/doc/tutorial_schedule.rdoc
CHANGED
@@ -48,4 +48,4 @@ We created a temporal expression to match this time period, like so:
|
|
48
48
|
|
49
49
|
* Fowler's recurring event pattern[http://martinfowler.com/apsupp/recurring.pdf]
|
50
50
|
|
51
|
-
* Other temporal patterns[http://martinfowler.com/ap2/timeNarrative.html]
|
51
|
+
* Other temporal patterns[http://martinfowler.com/ap2/timeNarrative.html]
|
data/doc/tutorial_te.rdoc
CHANGED
@@ -181,10 +181,10 @@ easy to write your own.
|
|
181
181
|
|
182
182
|
Fowler's paper[http://martinfowler.com/apsupp/recurring.pdf] also goes
|
183
183
|
on to describe another element of this pattern: the <tt>Schedule</tt>.
|
184
|
-
See the schedule tutorial[http://runt.rubyforge.org/doc/files/doc/
|
184
|
+
See the schedule tutorial[http://runt.rubyforge.org/doc/files/doc/tutorial_schedule_rdoc.html] for details.
|
185
185
|
|
186
186
|
<em>See Also:</em>
|
187
187
|
|
188
188
|
* Fowler's recurring event pattern[http://martinfowler.com/apsupp/recurring.pdf]
|
189
189
|
|
190
|
-
* Other temporal patterns[http://martinfowler.com/ap2/timeNarrative.html]
|
190
|
+
* Other temporal patterns[http://martinfowler.com/ap2/timeNarrative.html]
|
data/lib/runt.rb
CHANGED
@@ -84,10 +84,27 @@ module Runt
|
|
84
84
|
@negate.call(arg)
|
85
85
|
end
|
86
86
|
end
|
87
|
+
LastProc = ApplyLast.new
|
87
88
|
|
88
89
|
public
|
89
|
-
Last =
|
90
|
-
Last_of =
|
91
|
-
Second_to_last =
|
90
|
+
Last = LastProc[First]
|
91
|
+
Last_of = LastProc[First]
|
92
|
+
Second_to_last = LastProc[Second]
|
92
93
|
|
93
|
-
end
|
94
|
+
end
|
95
|
+
|
96
|
+
#
|
97
|
+
# Add precision +Runt::DPrecision+ to standard library classes Date and DateTime
|
98
|
+
# (which is a subclass of Date).
|
99
|
+
#
|
100
|
+
class Date
|
101
|
+
|
102
|
+
include Runt::DPrecision
|
103
|
+
|
104
|
+
attr_accessor :date_precision
|
105
|
+
|
106
|
+
def date_precision
|
107
|
+
return @date_precision unless @date_precision.nil?
|
108
|
+
return Runt::DPrecision::DEFAULT
|
109
|
+
end
|
110
|
+
end
|
data/lib/runt/daterange.rb
CHANGED
@@ -31,9 +31,9 @@ module Runt
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def overlap?(obj)
|
34
|
-
return true if( include?(obj.min) || include?(obj.max) )
|
35
|
-
|
36
|
-
|
34
|
+
return true if( member?(obj) || include?(obj.min) || include?(obj.max) )
|
35
|
+
return true if( obj.kind_of?(Range) && obj.include?(self) )
|
36
|
+
false
|
37
37
|
end
|
38
38
|
|
39
39
|
def empty?
|
@@ -71,4 +71,4 @@ module Runt
|
|
71
71
|
EMPTY = DateRange.new(PDate.day(2004,2,2),PDate.day(2004,2,1))
|
72
72
|
|
73
73
|
end
|
74
|
-
end
|
74
|
+
end
|
data/lib/runt/pdate.rb
CHANGED
@@ -2,19 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'date'
|
4
4
|
require 'runt/dprecision'
|
5
|
+
require 'runt/pdate'
|
5
6
|
|
6
7
|
#
|
7
8
|
# Author:: Matthew Lipper
|
8
9
|
|
9
10
|
module Runt
|
10
11
|
|
11
|
-
# FKA = 'Formally Known As'
|
12
|
-
|
13
|
-
|
14
|
-
# FKA: TemporalExpression
|
15
|
-
#
|
16
|
-
# Base class for all TExpr classes that has proved itself usefull enough to
|
17
|
-
# avoid O's Razor, but that may wind up as a module.
|
18
12
|
#
|
19
13
|
# 'TExpr' is short for 'TemporalExpression' and are inspired by the recurring event
|
20
14
|
# <tt>pattern</tt>[http://martinfowler.com/apsupp/recurring.pdf]
|
@@ -22,11 +16,12 @@ module Runt
|
|
22
16
|
# specifying recurring events using set expressions.
|
23
17
|
#
|
24
18
|
# See also [tutorial_te.rdoc]
|
25
|
-
|
19
|
+
module TExpr
|
26
20
|
|
27
21
|
# Returns true or false depending on whether this TExpr includes the supplied
|
28
22
|
# date expression.
|
29
23
|
def include?(date_expr); false end
|
24
|
+
|
30
25
|
def to_s; "TExpr" end
|
31
26
|
|
32
27
|
def or (arg)
|
@@ -65,44 +60,25 @@ class TExpr
|
|
65
60
|
self.minus(expr){|adjusted| adjusted }
|
66
61
|
end
|
67
62
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
end
|
76
|
-
|
77
|
-
def max_day_of_month(date)
|
78
|
-
result = 1
|
79
|
-
date.step( Date.new(date.year,date.mon+1,1), 1 ){ |d| result=d.day unless d.day < result }
|
80
|
-
result
|
81
|
-
end
|
82
|
-
|
83
|
-
def week_matches?(index,date)
|
84
|
-
if(index > 0)
|
85
|
-
return week_from_start_matches?(index,date)
|
86
|
-
else
|
87
|
-
return week_from_end_matches?(index,date)
|
63
|
+
# Contributed by Emmett Shear:
|
64
|
+
# Returns an Array of Date-like objects which occur within the supplied
|
65
|
+
# DateRange.
|
66
|
+
def dates(date_range)
|
67
|
+
result = []
|
68
|
+
date_range.each do |date|
|
69
|
+
result << date if self.include? date
|
88
70
|
end
|
89
|
-
|
90
|
-
|
91
|
-
def week_from_start_matches?(index,date)
|
92
|
-
week_in_month(date.day)==index
|
93
|
-
end
|
94
|
-
|
95
|
-
def week_from_end_matches?(index,date)
|
96
|
-
n = days_left_in_month(date) + 1
|
97
|
-
week_in_month(n)==index.abs
|
71
|
+
result
|
98
72
|
end
|
99
73
|
|
100
74
|
end
|
101
75
|
|
102
76
|
# Base class for TExpr classes that can be composed of other
|
103
77
|
# TExpr objects imlpemented using the <tt>Composite(GoF)</tt> pattern.
|
104
|
-
class Collection
|
105
|
-
|
78
|
+
class Collection
|
79
|
+
|
80
|
+
include TExpr
|
81
|
+
|
106
82
|
attr_reader :expressions
|
107
83
|
protected :expressions
|
108
84
|
|
@@ -115,6 +91,16 @@ class Collection < TExpr
|
|
115
91
|
self
|
116
92
|
end
|
117
93
|
|
94
|
+
# Will return true if the supplied object overlaps with the range used to
|
95
|
+
# create this instance
|
96
|
+
def overlap?(date_expr)
|
97
|
+
@expressions.each do | interval |
|
98
|
+
return true if date_expr.overlap?(interval)
|
99
|
+
end
|
100
|
+
false
|
101
|
+
end
|
102
|
+
|
103
|
+
|
118
104
|
def to_s; "Collection:" + @expressions.to_s end
|
119
105
|
end
|
120
106
|
|
@@ -137,7 +123,6 @@ end
|
|
137
123
|
class Intersect < Collection
|
138
124
|
|
139
125
|
def include?(aDate)
|
140
|
-
#Handle @expressions.size==0
|
141
126
|
result = false
|
142
127
|
@expressions.each do |expr|
|
143
128
|
return false unless (result = expr.include?(aDate))
|
@@ -149,8 +134,10 @@ class Intersect < Collection
|
|
149
134
|
end
|
150
135
|
|
151
136
|
# TExpr that will be true only if the first of
|
152
|
-
#
|
153
|
-
class Diff
|
137
|
+
# its two contained expressions is true and the second is false.
|
138
|
+
class Diff
|
139
|
+
|
140
|
+
include TExpr
|
154
141
|
|
155
142
|
def initialize(expr1, expr2)
|
156
143
|
@expr1 = expr1
|
@@ -166,8 +153,10 @@ class Diff < TExpr
|
|
166
153
|
end
|
167
154
|
|
168
155
|
# TExpr that provides for inclusion of an arbitrary date.
|
169
|
-
class Spec
|
170
|
-
|
156
|
+
class Spec
|
157
|
+
|
158
|
+
include TExpr
|
159
|
+
|
171
160
|
def initialize(date_expr)
|
172
161
|
@date_expr = date_expr
|
173
162
|
end
|
@@ -187,10 +176,11 @@ end
|
|
187
176
|
# facilitating inclusion of an arbitrary range in a temporal expression.
|
188
177
|
#
|
189
178
|
# See also: Range
|
190
|
-
class RSpec
|
179
|
+
class RSpec
|
180
|
+
|
181
|
+
include TExpr
|
191
182
|
|
192
183
|
def initialize(date_expr)
|
193
|
-
raise TypeError, 'expected range' unless date_expr.kind_of?(Range)
|
194
184
|
@date_expr = date_expr
|
195
185
|
end
|
196
186
|
|
@@ -199,10 +189,62 @@ class RSpec < TExpr
|
|
199
189
|
def include?(date_expr)
|
200
190
|
return @date_expr.include?(date_expr)
|
201
191
|
end
|
192
|
+
|
193
|
+
# Will return true if the supplied object overlaps with the range used to
|
194
|
+
# create this instance
|
195
|
+
def overlap?(date_expr)
|
196
|
+
@date_expr.each do | interval |
|
197
|
+
return true if date_expr.include?(interval)
|
198
|
+
end
|
199
|
+
false
|
200
|
+
end
|
202
201
|
|
203
202
|
def to_s; "RSpec" end
|
204
203
|
end
|
205
204
|
|
205
|
+
#######################################################################
|
206
|
+
# Utility methods common to some expressions
|
207
|
+
|
208
|
+
module TExprUtils
|
209
|
+
def week_in_month(day_in_month)
|
210
|
+
((day_in_month - 1) / 7) + 1
|
211
|
+
end
|
212
|
+
|
213
|
+
def days_left_in_month(date)
|
214
|
+
return max_day_of_month(date) - date.day
|
215
|
+
end
|
216
|
+
|
217
|
+
def max_day_of_month(date)
|
218
|
+
result = 1
|
219
|
+
next_month = nil
|
220
|
+
if(date.mon==12)
|
221
|
+
next_month = Date.new(date.year+1,1,1)
|
222
|
+
else
|
223
|
+
next_month = Date.new(date.year,date.mon+1,1)
|
224
|
+
end
|
225
|
+
date.step(next_month,1){ |d| result=d.day unless d.day < result }
|
226
|
+
result
|
227
|
+
end
|
228
|
+
|
229
|
+
def week_matches?(index,date)
|
230
|
+
if(index > 0)
|
231
|
+
return week_from_start_matches?(index,date)
|
232
|
+
else
|
233
|
+
return week_from_end_matches?(index,date)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
def week_from_start_matches?(index,date)
|
238
|
+
week_in_month(date.day)==index
|
239
|
+
end
|
240
|
+
|
241
|
+
def week_from_end_matches?(index,date)
|
242
|
+
n = days_left_in_month(date) + 1
|
243
|
+
week_in_month(n)==index.abs
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
247
|
+
|
206
248
|
# TExpr that provides support for building a temporal
|
207
249
|
# expression using the form:
|
208
250
|
#
|
@@ -228,7 +270,10 @@ end
|
|
228
270
|
# DIMonth.new(Last,Saturday)
|
229
271
|
#
|
230
272
|
# See also: Date, Runt
|
231
|
-
class DIMonth
|
273
|
+
class DIMonth
|
274
|
+
|
275
|
+
include TExpr
|
276
|
+
include TExprUtils
|
232
277
|
|
233
278
|
def initialize(week_of_month_index,day_index)
|
234
279
|
@day_index = day_index
|
@@ -243,17 +288,6 @@ class DIMonth < TExpr
|
|
243
288
|
"DIMonth"
|
244
289
|
end
|
245
290
|
|
246
|
-
def print(date)
|
247
|
-
puts "DIMonth: #{date}"
|
248
|
-
puts "include? == #{include?(date)}"
|
249
|
-
puts "day_matches? == #{day_matches?(date)}"
|
250
|
-
puts "week_matches? == #{week_matches?(date)}"
|
251
|
-
puts "week_from_start_matches? == #{week_from_start_matches?(date)}"
|
252
|
-
puts "week_from_end_matches? == #{week_from_end_matches?(date)}"
|
253
|
-
puts "days_left_in_month == #{days_left_in_month(date)}"
|
254
|
-
puts "max_day_of_month == #{max_day_of_month(date)}"
|
255
|
-
end
|
256
|
-
|
257
291
|
private
|
258
292
|
def day_matches?(date)
|
259
293
|
@day_index == date.wday
|
@@ -275,7 +309,9 @@ end
|
|
275
309
|
# DIWeek.new(Sunday)
|
276
310
|
#
|
277
311
|
# See also: Date, Runt
|
278
|
-
class DIWeek
|
312
|
+
class DIWeek
|
313
|
+
|
314
|
+
include TExpr
|
279
315
|
|
280
316
|
VALID_RANGE = 0..6
|
281
317
|
|
@@ -298,20 +334,21 @@ end
|
|
298
334
|
# If start and end day are equal, the entire week will match true.
|
299
335
|
#
|
300
336
|
# See also: Date
|
301
|
-
class REWeek
|
337
|
+
class REWeek
|
338
|
+
|
339
|
+
include TExpr
|
302
340
|
|
303
341
|
VALID_RANGE = 0..6
|
304
342
|
|
305
|
-
|
343
|
+
# Creates a REWeek using the supplied start
|
306
344
|
# day(range = 0..6, where 0=>Sunday) and an optional end
|
307
345
|
# day. If an end day is not supplied, the maximum value
|
308
346
|
# (6 => Saturday) is assumed.
|
309
347
|
#
|
310
348
|
# If the start day is greater than the end day, an
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
validate(start_day,end_day)
|
349
|
+
# ArgumentError will be raised
|
350
|
+
def initialize(start_day,end_day=6)
|
351
|
+
validate(start_day,end_day)
|
315
352
|
@start_day = start_day
|
316
353
|
@end_day = end_day
|
317
354
|
end
|
@@ -325,7 +362,7 @@ class REWeek < TExpr
|
|
325
362
|
"REWeek"
|
326
363
|
end
|
327
364
|
|
328
|
-
|
365
|
+
private
|
329
366
|
def validate(start_day,end_day)
|
330
367
|
unless start_day<=end_day
|
331
368
|
raise ArgumentError, 'end day of week must be greater than start day'
|
@@ -336,10 +373,11 @@ class REWeek < TExpr
|
|
336
373
|
end
|
337
374
|
end
|
338
375
|
|
339
|
-
class REYear
|
376
|
+
class REYear
|
340
377
|
|
378
|
+
include TExpr
|
379
|
+
|
341
380
|
def initialize(start_month, start_day=0, end_month=start_month, end_day=0)
|
342
|
-
super()
|
343
381
|
@start_month = start_month
|
344
382
|
@start_day = start_day
|
345
383
|
@end_month = end_month
|
@@ -356,14 +394,6 @@ class REYear < TExpr
|
|
356
394
|
"REYear"
|
357
395
|
end
|
358
396
|
|
359
|
-
def print(date)
|
360
|
-
puts "DIMonth: #{date}"
|
361
|
-
puts "include? == #{include?(date)}"
|
362
|
-
puts "months_include? == #{months_include?(date)}"
|
363
|
-
puts "end_month_include? == #{end_month_include?(date)}"
|
364
|
-
puts "start_month_include? == #{start_month_include?(date)}"
|
365
|
-
end
|
366
|
-
|
367
397
|
private
|
368
398
|
def months_include?(date)
|
369
399
|
(date.mon > @start_month) && (date.mon < @end_month)
|
@@ -385,7 +415,9 @@ end
|
|
385
415
|
# is assumed to be on the following day.
|
386
416
|
#
|
387
417
|
# See also: Date
|
388
|
-
class REDay
|
418
|
+
class REDay
|
419
|
+
|
420
|
+
include TExpr
|
389
421
|
|
390
422
|
CURRENT=28
|
391
423
|
NEXT=29
|
@@ -406,8 +438,9 @@ class REDay < TExpr
|
|
406
438
|
end
|
407
439
|
|
408
440
|
def include?(date)
|
409
|
-
|
410
|
-
|
441
|
+
# If precision is day or greater, then the result is always true
|
442
|
+
return true if date.date_precision <= DPrecision::DAY
|
443
|
+
|
411
444
|
if(@spans_midnight&&date.hour<12) then
|
412
445
|
#Assume next day
|
413
446
|
return @range.include?(get_next(date.hour,date.min))
|
@@ -421,17 +454,11 @@ class REDay < TExpr
|
|
421
454
|
"REDay"
|
422
455
|
end
|
423
456
|
|
424
|
-
def print(date)
|
425
|
-
puts "DIMonth: #{date}"
|
426
|
-
puts "include? == #{include?(date)}"
|
427
|
-
end
|
428
|
-
|
429
457
|
private
|
430
458
|
def spans_midnight?(start_hour, end_hour)
|
431
459
|
return end_hour <= start_hour
|
432
460
|
end
|
433
461
|
|
434
|
-
private
|
435
462
|
def get_current(hour,minute)
|
436
463
|
PDate.min(ANY_DATE.year,ANY_DATE.month,CURRENT,hour,minute)
|
437
464
|
end
|
@@ -447,7 +474,10 @@ end
|
|
447
474
|
# WIMonth.new(1)
|
448
475
|
#
|
449
476
|
# See also: Date
|
450
|
-
class WIMonth
|
477
|
+
class WIMonth
|
478
|
+
|
479
|
+
include TExpr
|
480
|
+
include TExprUtils
|
451
481
|
|
452
482
|
VALID_RANGE = -2..5
|
453
483
|
|
@@ -464,4 +494,31 @@ class WIMonth < TExpr
|
|
464
494
|
|
465
495
|
end
|
466
496
|
|
497
|
+
# TExpr that matches a range of dates within a month. For example:
|
498
|
+
#
|
499
|
+
# REMonth.(12,28)
|
500
|
+
#
|
501
|
+
# matches from the 12th thru the 28th of any month. If end_day==0
|
502
|
+
# or is not given, start_day will define the range with that single day.
|
503
|
+
#
|
504
|
+
# See also: Date
|
505
|
+
class REMonth
|
506
|
+
|
507
|
+
include TExpr
|
508
|
+
|
509
|
+
def initialize(start_day, end_day=0)
|
510
|
+
end_day=start_day if end_day==0
|
511
|
+
@range = start_day..end_day
|
512
|
+
end
|
513
|
+
|
514
|
+
def include?(date)
|
515
|
+
@range.include? date.mday
|
516
|
+
end
|
517
|
+
|
518
|
+
def to_s
|
519
|
+
"REMonth"
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
467
524
|
end
|
data/site/index.html
CHANGED
@@ -49,6 +49,7 @@
|
|
49
49
|
ideas off-line.
|
50
50
|
</li>
|
51
51
|
<li><a href="http://www.bluerobot.com/web/layouts/">Blue Robot</a> for the CSS</li>
|
52
|
+
<li>Emmett Shear for contributed <a href="http://runt.rubyforge.org/doc/classes/Runt/TExpr.html">TExpr#dates</a> code and several thought-provoking feature requests.</li>
|
52
53
|
</ul>
|
53
54
|
</p>
|
54
55
|
</div>
|
@@ -89,4 +90,4 @@
|
|
89
90
|
<!-- BlueRobot was here. -->
|
90
91
|
|
91
92
|
</body>
|
92
|
-
</html>
|
93
|
+
</html>
|
data/test/alltests.rb
CHANGED
data/test/daterangetest.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$:<<'../lib'
|
4
|
-
|
5
3
|
require 'test/unit'
|
6
4
|
require 'runt'
|
7
5
|
require 'date'
|
@@ -57,6 +55,13 @@ class DateRangeTest < Test::Unit::TestCase
|
|
57
55
|
assert(o_range.overlap?(range))
|
58
56
|
assert(o_range.overlap?(DateRange.new(r_start,o_end)))
|
59
57
|
assert(o_range.overlap?(DateRange.new(o_start,r_end)))
|
58
|
+
|
59
|
+
# September 18th - 19th, 2005, 8am - 10am
|
60
|
+
expr1=DateRange.new(PDate.day(2005,9,18),PDate.day(2005,9,19))
|
61
|
+
# September 19th - 20th, 2005, 9am - 11am
|
62
|
+
expr2=DateRange.new(PDate.day(2005,9,19),PDate.day(2005,9,20))
|
63
|
+
|
64
|
+
assert(expr1.overlap?(expr2))
|
60
65
|
end
|
61
66
|
|
62
67
|
def test_empty
|
data/test/dprecisiontest.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$:<<'../lib'
|
4
|
-
|
5
3
|
require 'test/unit'
|
6
4
|
require 'runt'
|
7
5
|
require 'date'
|
@@ -9,6 +7,7 @@ require 'date'
|
|
9
7
|
# Unit tests for DPrecision class
|
10
8
|
#
|
11
9
|
# Author:: Matthew Lipper
|
10
|
+
|
12
11
|
class DPrecisionTest < Test::Unit::TestCase
|
13
12
|
|
14
13
|
include Runt
|
@@ -23,13 +22,13 @@ class DPrecisionTest < Test::Unit::TestCase
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def test_pseudo_singleton_instance
|
26
|
-
assert(DPrecision::YEAR.
|
27
|
-
assert(DPrecision::MONTH.
|
28
|
-
assert(DPrecision::DAY.
|
29
|
-
assert(DPrecision::HOUR.
|
30
|
-
assert(DPrecision::MIN.
|
31
|
-
assert(DPrecision::SEC.
|
32
|
-
assert(DPrecision::MILLI.
|
25
|
+
assert(DPrecision::YEAR.object_id==DPrecision::YEAR.object_id, "Object Id's not equal.")
|
26
|
+
assert(DPrecision::MONTH.object_id==DPrecision::MONTH.object_id, "Object Id's not equal.")
|
27
|
+
assert(DPrecision::DAY.object_id==DPrecision::DAY.object_id, "Object Id's not equal.")
|
28
|
+
assert(DPrecision::HOUR.object_id==DPrecision::HOUR.object_id, "Object Id's not equal.")
|
29
|
+
assert(DPrecision::MIN.object_id==DPrecision::MIN.object_id, "Object Id's not equal.")
|
30
|
+
assert(DPrecision::SEC.object_id==DPrecision::SEC.object_id, "Object Id's not equal.")
|
31
|
+
assert(DPrecision::MILLI.object_id==DPrecision::MILLI.object_id, "Object Id's not equal.")
|
33
32
|
end
|
34
33
|
|
35
34
|
def test_to_precision
|
data/test/pdatetest.rb
CHANGED
data/test/scheduletest.rb
CHANGED
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$:<<'../lib'
|
4
|
-
|
5
3
|
require 'test/unit'
|
6
4
|
require 'runt'
|
7
5
|
require 'date'
|
@@ -52,5 +50,39 @@ class ScheduleTest < Test::Unit::TestCase
|
|
52
50
|
assert_equal(expected,dates)
|
53
51
|
end
|
54
52
|
|
53
|
+
def test_using_a_schedule
|
54
|
+
|
55
|
+
# September 18th - 19th, 2005, 8am - 10am
|
56
|
+
expr1=RSpec.new(DateRange.new(PDate.day(2005,9,18),PDate.day(2005,9,19))) & REDay.new(8,0,10,0)
|
57
|
+
assert(expr1.include?(PDate.min(2005,9,18,8,15)))
|
58
|
+
# September 19th - 20th, 2005, 9am - 11am
|
59
|
+
expr2=RSpec.new(DateRange.new(PDate.day(2005,9,19),PDate.day(2005,9,20))) & REDay.new(9,0,11,0)
|
60
|
+
# Quick sanuty check
|
61
|
+
assert(expr1.overlap?(expr2))
|
62
|
+
# Setup a schedule w/first expression
|
63
|
+
sched = Schedule.new
|
64
|
+
sched.add(Event.new("Snafubar Opening"),expr1)
|
65
|
+
resource = Resource.new(sched)
|
66
|
+
# Add a another overlapping event
|
67
|
+
resource.add_event(Event.new("Yodeling Lesson"),expr2)
|
68
|
+
# Create a new resource using the same schedule
|
69
|
+
resource2 = Resource.new(sched)
|
70
|
+
# Add a another overlapping event and pass a block which should complain
|
71
|
+
#resource.add_event(Event.new("Yodeling Lesson"),expr2) \
|
72
|
+
#{|e,s| raise "Resource not available at requested time(s)." \
|
73
|
+
# if (@schedule.overlap?(s))}
|
74
|
+
end
|
55
75
|
end
|
56
76
|
|
77
|
+
class Resource
|
78
|
+
def initialize(schedule)
|
79
|
+
@schedule=schedule
|
80
|
+
end
|
81
|
+
def add_event(event,expr)
|
82
|
+
if(block_given?)
|
83
|
+
yield(event,expr)
|
84
|
+
else
|
85
|
+
@schedule.add(event,expr)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
$:<<'../lib'
|
4
|
-
|
5
3
|
require 'test/unit'
|
6
4
|
require 'runt'
|
7
5
|
require 'date'
|
@@ -10,11 +8,13 @@ $DEBUG=false
|
|
10
8
|
|
11
9
|
# Unit tests for TExpr classes
|
12
10
|
# Author:: Matthew Lipper
|
11
|
+
|
13
12
|
class TExprTest < Test::Unit::TestCase
|
14
13
|
|
15
14
|
include Runt
|
16
15
|
include DPrecision
|
17
16
|
|
17
|
+
|
18
18
|
def test_collection_te
|
19
19
|
#base class that should always return false
|
20
20
|
expr = Collection.new
|
@@ -166,19 +166,28 @@ class TExprTest < Test::Unit::TestCase
|
|
166
166
|
#12:01 am (January 28th, 2004 - ignored)
|
167
167
|
assert(!expr2.include?(PDate.min(2004,1,28,0,01)))
|
168
168
|
end
|
169
|
-
def test_range_each_week_te
|
170
169
|
|
171
|
-
|
170
|
+
def test_range_each_day_te_again
|
171
|
+
dr = DateRange.new(PDate.day(2005,9,19),PDate.day(2005,9,20))
|
172
|
+
red = REDay.new(8,0,10,0)
|
173
|
+
result = false
|
174
|
+
dr.each do |interval|
|
175
|
+
result = red.include?(interval)
|
176
|
+
break if result
|
177
|
+
end
|
178
|
+
assert(result)
|
179
|
+
end
|
172
180
|
|
181
|
+
def test_range_each_week_te
|
182
|
+
assert_raises(ArgumentError){ expr = REWeek.new(10,4) }
|
173
183
|
expr1 = REWeek.new(Mon,Fri) & REDay.new(8,00,8,30)
|
174
184
|
assert(!expr1.include?(PDate.new(2004,5,1,8,06)))
|
175
|
-
|
176
|
-
|
177
185
|
#Sunday through Thursday
|
178
186
|
expr2 = REWeek.new(0,4)
|
179
187
|
assert(expr2.include?(PDate.min(2004,2,19,23,59,59)))
|
180
188
|
assert(!expr2.include?(PDate.min(2004,2,20,0,0,0)))
|
181
189
|
end
|
190
|
+
|
182
191
|
def test_combined_te
|
183
192
|
#This is a hack.....
|
184
193
|
#In the U.S., Memorial Day begins the last Monday of May
|
@@ -279,4 +288,115 @@ class TExprTest < Test::Unit::TestCase
|
|
279
288
|
assert(!ticket.include?(DateTime.new(2004,3,11,1,15)))
|
280
289
|
end
|
281
290
|
|
291
|
+
def test_re_month_te
|
292
|
+
# October 22nd, 2005
|
293
|
+
dt1 = Date.civil(2005,10,22)
|
294
|
+
# The 20th through the 29th of any month
|
295
|
+
expr1 = REMonth.new(20,29)
|
296
|
+
assert(expr1.include?(dt1))
|
297
|
+
assert(!expr1.include?(PDate.new(2010,12,12)))
|
298
|
+
# August 17th, 1975
|
299
|
+
dt2 = Date.civil(1975,8,17)
|
300
|
+
# The 17th of any month
|
301
|
+
expr2 = REMonth.new(17)
|
302
|
+
assert(expr2.include?(dt2))
|
303
|
+
assert(!expr2.include?(dt1))
|
304
|
+
end
|
305
|
+
|
306
|
+
###
|
307
|
+
# Dates functionality & tests contributed by Emmett Shear
|
308
|
+
###
|
309
|
+
def test_day_in_month_dates
|
310
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 12, 31)
|
311
|
+
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
312
|
+
expr = DIMonth.new(First, Tuesday)
|
313
|
+
dates = expr.dates(date_range)
|
314
|
+
assert dates.size == 12
|
315
|
+
dates.each do |d|
|
316
|
+
assert d.wday == 2 # tuesday
|
317
|
+
assert d.day < 8 # in the first week
|
318
|
+
end
|
319
|
+
expr2 = DIMonth.new(Last, Friday)
|
320
|
+
dates2 = expr2.dates(date_range)
|
321
|
+
assert dates2.size == 12
|
322
|
+
dates2.each do |d|
|
323
|
+
assert d.wday == 5 # friday
|
324
|
+
assert d.day > month_days[d.month-1] - 8 # last week
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def test_day_in_week_dates
|
329
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 1, 31)
|
330
|
+
expr = DIWeek.new(Sunday)
|
331
|
+
dates = expr.dates(date_range)
|
332
|
+
assert( dates.size == 5 )
|
333
|
+
assert( dates.include?( Date.civil(2005, 1, 16) ) )
|
334
|
+
assert( dates.include?( Date.civil(2005, 1, 30) ) )
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_union_dates
|
338
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 12, 31)
|
339
|
+
month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
340
|
+
expr = DIMonth.new(Last, Friday) | DIMonth.new(1, Tuesday)
|
341
|
+
dates = expr.dates(date_range)
|
342
|
+
assert dates.size == 24
|
343
|
+
dates.each do |d|
|
344
|
+
unless (d.wday == 2 and d.day < 8) or \
|
345
|
+
(d.wday == 5 and d.day > month_days[d.month-1] - 8)
|
346
|
+
assert false, d.to_s
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def test_intersection_dates
|
352
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 12, 31)
|
353
|
+
expr = DIWeek.new(Sunday) & DIMonth.new(Second, Sunday)
|
354
|
+
dates = expr.dates(date_range)
|
355
|
+
assert( dates.size == 12 )
|
356
|
+
other_dates = DIMonth.new(Second, Sunday).dates(date_range)
|
357
|
+
dates.each { |d| assert( other_dates.include?(d) ) }
|
358
|
+
end
|
359
|
+
|
360
|
+
def test_range_each_week_dates
|
361
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 1, 31)
|
362
|
+
expr = REWeek.new(3, 5)
|
363
|
+
dates = expr.dates(date_range)
|
364
|
+
assert dates.size == 12
|
365
|
+
end
|
366
|
+
|
367
|
+
def test_range_each_year_dates
|
368
|
+
date_range = Date.civil(2004, 5, 1)..Date.civil(2006, 5, 4)
|
369
|
+
expr = REYear.new(4, 28, 5, 6)
|
370
|
+
dates = expr.dates(date_range)
|
371
|
+
assert dates.size == 22, dates.size
|
372
|
+
end
|
373
|
+
|
374
|
+
def test_week_in_month_dates
|
375
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 2, 28)
|
376
|
+
expr = WIMonth.new(2)
|
377
|
+
dates = expr.dates(date_range)
|
378
|
+
assert dates.size == 14, dates.size
|
379
|
+
assert dates.first.mday == 8
|
380
|
+
assert dates.last.mday == 14
|
381
|
+
expr_2 = WIMonth.new(Last)
|
382
|
+
dates_2 = expr_2.dates(date_range)
|
383
|
+
assert dates_2.size == 14, dates_2.size
|
384
|
+
assert dates_2.first.mday == 25
|
385
|
+
assert dates_2.last.mday == 28
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_range_each_month_dates
|
389
|
+
date_range = Date.civil(2005, 1, 7)..Date.civil(2005, 1, 15)
|
390
|
+
expr = REMonth.new(5, 9)
|
391
|
+
dates = expr.dates(date_range)
|
392
|
+
assert dates.size == 3, dates.size
|
393
|
+
assert false if dates.include? Date.civil(2005, 1, 6)
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_diff_dates
|
397
|
+
date_range = Date.civil(2005, 1, 1)..Date.civil(2005, 1, 31)
|
398
|
+
expr = REYear.new(1, 1, 1, 31) - REMonth.new(7, 15)
|
399
|
+
dates = expr.dates(date_range)
|
400
|
+
assert dates.size == 22, dates.size
|
401
|
+
end
|
282
402
|
end
|
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.8.
|
2
|
+
rubygems_version: 0.8.11
|
3
3
|
specification_version: 1
|
4
4
|
name: runt
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date:
|
6
|
+
version: 0.3.0
|
7
|
+
date: 2005-10-22 00:00:00 -04:00
|
8
8
|
summary: Ruby Temporal Expressions.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
|
-
author: Matthew Lipper
|
12
11
|
email: matt@digitalclash.com
|
13
12
|
homepage: http://runt.rubyforge.org
|
14
13
|
rubyforge_project: runt
|
@@ -25,6 +24,10 @@ required_ruby_version: !ruby/object:Gem::Version::Requirement
|
|
25
24
|
version: 0.0.0
|
26
25
|
version:
|
27
26
|
platform: ruby
|
27
|
+
signing_key:
|
28
|
+
cert_chain:
|
29
|
+
authors:
|
30
|
+
- Matthew Lipper
|
28
31
|
files:
|
29
32
|
- setup.rb
|
30
33
|
- CHANGES
|
@@ -52,7 +55,12 @@ files:
|
|
52
55
|
- site/logohover.png
|
53
56
|
- site/runt-logo.gif
|
54
57
|
- site/runt-logo.psd
|
55
|
-
test_files:
|
58
|
+
test_files:
|
59
|
+
- test/daterangetest.rb
|
60
|
+
- test/dprecisiontest.rb
|
61
|
+
- test/pdatetest.rb
|
62
|
+
- test/scheduletest.rb
|
63
|
+
- test/temporalexpressiontest.rb
|
56
64
|
rdoc_options: []
|
57
65
|
extra_rdoc_files: []
|
58
66
|
executables: []
|