runt 0.3.0 → 0.5.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.
- data/CHANGES +107 -71
- data/LICENSE.txt +43 -43
- data/README +100 -94
- data/Rakefile +119 -120
- data/TODO +11 -20
- data/doc/tutorial_schedule.rdoc +84 -51
- data/doc/tutorial_te.rdoc +190 -190
- data/lib/runt.rb +219 -110
- data/lib/runt/daterange.rb +74 -74
- data/lib/runt/dprecision.rb +141 -137
- data/lib/runt/pdate.rb +153 -126
- data/lib/runt/schedule.rb +88 -89
- data/lib/runt/temporalexpression.rb +695 -524
- data/setup.rb +1331 -1331
- data/site/blue-robot3.css +131 -131
- data/site/index.html +94 -93
- data/site/runt-logo.psd +0 -0
- data/test/daterangetest.rb +87 -87
- data/test/dprecisiontest.rb +55 -45
- data/test/icalendartest.rb +524 -0
- data/test/pdatetest.rb +117 -104
- data/test/runttest.rb +101 -0
- data/test/scheduletest.rb +148 -88
- data/test/temporalexpressiontest.rb +612 -402
- metadata +56 -43
- data/test/alltests.rb +0 -10
data/lib/runt.rb
CHANGED
@@ -1,110 +1,219 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
# :title:Runt -- Ruby Temporal Expressions
|
4
|
-
#
|
5
|
-
# == Runt -- Ruby Temporal Expressions
|
6
|
-
#
|
7
|
-
# The usage and design patterns expressed in this library are mostly...*uhm*..
|
8
|
-
# <em>entirely</em>..*cough*...based on a series of
|
9
|
-
# <tt>articles</tt>[http://www.martinfowler.com] by Martin Fowler.
|
10
|
-
#
|
11
|
-
# It highly recommended that anyone using Runt (or writing
|
12
|
-
# object-oriented software :) take a moment to peruse the wealth of useful info
|
13
|
-
# that Fowler has made publicly available:
|
14
|
-
#
|
15
|
-
# * An excellent introductory summation of temporal <tt>patterns</tt>[http://martinfowler.com/ap2/timeNarrative.html]
|
16
|
-
# * Recurring event <tt>pattern</tt>[http://martinfowler.com/apsupp/recurring.pdf]
|
17
|
-
#
|
18
|
-
# Also, for those of you (like me, for example) still chained in your cubicle and forced
|
19
|
-
# to write <tt>Java</tt>[http://java.sun.com] code, check out the original version of
|
20
|
-
# project called <tt>ChronicJ</tt>[http://chronicj.org].
|
21
|
-
#
|
22
|
-
# ---
|
23
|
-
# Author:: Matthew Lipper (mailto:
|
24
|
-
# Copyright:: Copyright (c) 2004 Digital Clash, LLC
|
25
|
-
# License:: See LICENSE.txt
|
26
|
-
#
|
27
|
-
# = Warranty
|
28
|
-
#
|
29
|
-
# This software is provided "as is" and without any express or
|
30
|
-
# implied warranties, including, without limitation, the implied
|
31
|
-
# warranties of merchantibility and fitness for a particular
|
32
|
-
# purpose.
|
33
|
-
|
34
|
-
require '
|
35
|
-
require 'date
|
36
|
-
require
|
37
|
-
require "runt/
|
38
|
-
require "runt/
|
39
|
-
require "runt/
|
40
|
-
require "runt/
|
41
|
-
|
42
|
-
|
43
|
-
#
|
44
|
-
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# :title:Runt -- Ruby Temporal Expressions
|
4
|
+
#
|
5
|
+
# == Runt -- Ruby Temporal Expressions
|
6
|
+
#
|
7
|
+
# The usage and design patterns expressed in this library are mostly...*uhm*..
|
8
|
+
# <em>entirely</em>..*cough*...based on a series of
|
9
|
+
# <tt>articles</tt>[http://www.martinfowler.com] by Martin Fowler.
|
10
|
+
#
|
11
|
+
# It highly recommended that anyone using Runt (or writing
|
12
|
+
# object-oriented software :) take a moment to peruse the wealth of useful info
|
13
|
+
# that Fowler has made publicly available:
|
14
|
+
#
|
15
|
+
# * An excellent introductory summation of temporal <tt>patterns</tt>[http://martinfowler.com/ap2/timeNarrative.html]
|
16
|
+
# * Recurring event <tt>pattern</tt>[http://martinfowler.com/apsupp/recurring.pdf]
|
17
|
+
#
|
18
|
+
# Also, for those of you (like me, for example) still chained in your cubicle and forced
|
19
|
+
# to write <tt>Java</tt>[http://java.sun.com] code, check out the original version of
|
20
|
+
# project called <tt>ChronicJ</tt>[http://chronicj.org].
|
21
|
+
#
|
22
|
+
# ---
|
23
|
+
# Author:: Matthew Lipper (mailto:mlipper@gmail.com)
|
24
|
+
# Copyright:: Copyright (c) 2004 Digital Clash, LLC
|
25
|
+
# License:: See LICENSE.txt
|
26
|
+
#
|
27
|
+
# = Warranty
|
28
|
+
#
|
29
|
+
# This software is provided "as is" and without any express or
|
30
|
+
# implied warranties, including, without limitation, the implied
|
31
|
+
# warranties of merchantibility and fitness for a particular
|
32
|
+
# purpose.
|
33
|
+
|
34
|
+
require 'time'
|
35
|
+
require 'date'
|
36
|
+
require 'date/format'
|
37
|
+
require "runt/dprecision"
|
38
|
+
require "runt/pdate"
|
39
|
+
require "runt/temporalexpression"
|
40
|
+
require "runt/schedule"
|
41
|
+
require "runt/daterange"
|
42
|
+
|
43
|
+
#
|
44
|
+
# The Runt module is the main namespace for all Runt modules and classes. Using
|
45
|
+
# require statements, it makes the entire Runt library available.It also
|
46
|
+
# defines some new constants and exposes some already defined in the standard
|
47
|
+
# library classes <tt>Date</tt> and <tt>DateTime</tt>.
|
48
|
+
#
|
49
|
+
# <b>See also</b> date.rb
|
50
|
+
#
|
51
|
+
module Runt
|
52
|
+
|
53
|
+
class << self
|
54
|
+
|
55
|
+
def day_name(number)
|
56
|
+
Date::DAYNAMES[number]
|
57
|
+
end
|
58
|
+
|
59
|
+
def month_name(number)
|
60
|
+
Date::MONTHNAMES[number]
|
61
|
+
end
|
62
|
+
|
63
|
+
def format_time(date)
|
64
|
+
date.strftime('%I:%M%p')
|
65
|
+
end
|
66
|
+
|
67
|
+
def format_date(date)
|
68
|
+
date.ctime
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Cut and pasted from activesupport-1.2.5/lib/inflector.rb
|
73
|
+
#
|
74
|
+
def ordinalize(number)
|
75
|
+
if (number.to_i==-1)
|
76
|
+
'last'
|
77
|
+
elsif (number.to_i==-2)
|
78
|
+
'second to last'
|
79
|
+
elsif (11..13).include?(number.to_i % 100)
|
80
|
+
"#{number}th"
|
81
|
+
else
|
82
|
+
case number.to_i % 10
|
83
|
+
when 1: "#{number}st"
|
84
|
+
when 2: "#{number}nd"
|
85
|
+
when 3: "#{number}rd"
|
86
|
+
else "#{number}th"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
#Yes it's true, I'm a big idiot!
|
94
|
+
Sunday = Date::DAYNAMES.index("Sunday")
|
95
|
+
Monday = Date::DAYNAMES.index("Monday")
|
96
|
+
Tuesday = Date::DAYNAMES.index("Tuesday")
|
97
|
+
Wednesday = Date::DAYNAMES.index("Wednesday")
|
98
|
+
Thursday = Date::DAYNAMES.index("Thursday")
|
99
|
+
Friday = Date::DAYNAMES.index("Friday")
|
100
|
+
Saturday = Date::DAYNAMES.index("Saturday")
|
101
|
+
Sun = Date::ABBR_DAYNAMES.index("Sun")
|
102
|
+
Mon = Date::ABBR_DAYNAMES.index("Mon")
|
103
|
+
Tue = Date::ABBR_DAYNAMES.index("Tue")
|
104
|
+
Wed = Date::ABBR_DAYNAMES.index("Wed")
|
105
|
+
Thu = Date::ABBR_DAYNAMES.index("Thu")
|
106
|
+
Fri = Date::ABBR_DAYNAMES.index("Fri")
|
107
|
+
Sat = Date::ABBR_DAYNAMES.index("Sat")
|
108
|
+
First = 1
|
109
|
+
Second = 2
|
110
|
+
Third = 3
|
111
|
+
Fourth = 4
|
112
|
+
Fifth = 5
|
113
|
+
Sixth = 6
|
114
|
+
Seventh = 7
|
115
|
+
Eigth = 8
|
116
|
+
Ninth = 9
|
117
|
+
Tenth = 10
|
118
|
+
|
119
|
+
private
|
120
|
+
class ApplyLast #:nodoc:
|
121
|
+
def initialize
|
122
|
+
@negate=Proc.new{|n| n*-1}
|
123
|
+
end
|
124
|
+
def [](arg)
|
125
|
+
@negate.call(arg)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
LastProc = ApplyLast.new
|
129
|
+
|
130
|
+
public
|
131
|
+
Last = LastProc[First]
|
132
|
+
Last_of = LastProc[First]
|
133
|
+
Second_to_last = LastProc[Second]
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# Add precision +Runt::DPrecision+ to standard library classes Date and DateTime
|
139
|
+
# (which is a subclass of Date). Also, add an inlcude? method for interoperability
|
140
|
+
# with +Runt::TExpr+ classes
|
141
|
+
#
|
142
|
+
class Date
|
143
|
+
|
144
|
+
include Runt
|
145
|
+
|
146
|
+
attr_accessor :date_precision
|
147
|
+
|
148
|
+
def include?(expr)
|
149
|
+
eql?(expr)
|
150
|
+
end
|
151
|
+
|
152
|
+
def date_precision
|
153
|
+
return @date_precision unless @date_precision.nil?
|
154
|
+
return Runt::DPrecision::DEFAULT
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
#
|
159
|
+
# Add the ability to use Time class
|
160
|
+
#
|
161
|
+
# Contributed by Paul Wright
|
162
|
+
#
|
163
|
+
class Time
|
164
|
+
|
165
|
+
include Runt
|
166
|
+
|
167
|
+
attr_accessor :date_precision
|
168
|
+
alias_method :old_initialize, :initialize
|
169
|
+
def initialize(*args)
|
170
|
+
if(args[0].instance_of?(Runt::DPrecision::Precision))
|
171
|
+
@precision=args.shift
|
172
|
+
else
|
173
|
+
@precision=Runt::DPrecision::DEFAULT
|
174
|
+
end
|
175
|
+
old_initialize(*args)
|
176
|
+
end
|
177
|
+
|
178
|
+
class << self
|
179
|
+
alias_method :old_parse, :parse
|
180
|
+
def parse(*args)
|
181
|
+
precision=Runt::DPrecision::DEFAULT
|
182
|
+
if(args[0].instance_of?(Runt::DPrecision::Precision))
|
183
|
+
precision=args.shift
|
184
|
+
end
|
185
|
+
_parse=old_parse(*args)
|
186
|
+
_parse.date_precision=precision
|
187
|
+
_parse
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def date_precision
|
192
|
+
return @date_precision unless @date_precision.nil?
|
193
|
+
return Runt::DPrecision::DEFAULT
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
#
|
198
|
+
# Useful shortcuts!
|
199
|
+
#
|
200
|
+
# Contributed by Ara T. Howard who is pretty sure he got the idea from
|
201
|
+
# somewhere else. :-)
|
202
|
+
#
|
203
|
+
class Numeric #:nodoc:
|
204
|
+
def microseconds() Float(self * (10 ** -6)) end
|
205
|
+
def milliseconds() Float(self * (10 ** -3)) end
|
206
|
+
def seconds() self end
|
207
|
+
def minutes() 60 * seconds end
|
208
|
+
def hours() 60 * minutes end
|
209
|
+
def days() 24 * hours end
|
210
|
+
def weeks() 7 * days end
|
211
|
+
def months() 30 * days end
|
212
|
+
def years() 365 * days end
|
213
|
+
def decades() 10 * years end
|
214
|
+
# This causes RDoc to hurl:
|
215
|
+
%w[
|
216
|
+
microseconds milliseconds seconds minutes hours days weeks months years decades
|
217
|
+
].each{|m| alias_method m.chop, m}
|
218
|
+
end
|
219
|
+
|
data/lib/runt/daterange.rb
CHANGED
@@ -1,74 +1,74 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require 'date'
|
4
|
-
require 'runt'
|
5
|
-
|
6
|
-
|
7
|
-
module Runt
|
8
|
-
# :title:DateRange
|
9
|
-
# == DateRange
|
10
|
-
#
|
11
|
-
#
|
12
|
-
# Based the <tt>range</tt>[http://martinfowler.com/ap2/range.html] pattern by Martin Fowler.
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
# Author:: Matthew Lipper
|
17
|
-
class DateRange < Range
|
18
|
-
|
19
|
-
include DPrecision
|
20
|
-
|
21
|
-
attr_reader :start_expr, :end_expr
|
22
|
-
|
23
|
-
def initialize(start_expr, end_expr,exclusive=false)
|
24
|
-
super(start_expr, end_expr,exclusive)
|
25
|
-
@start_expr, @end_expr = start_expr, end_expr
|
26
|
-
end
|
27
|
-
|
28
|
-
def include?(obj)
|
29
|
-
return super(obj.min) && super(obj.max) if obj.kind_of? Range
|
30
|
-
return super(obj)
|
31
|
-
end
|
32
|
-
|
33
|
-
def overlap?(obj)
|
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
|
-
end
|
38
|
-
|
39
|
-
def empty?
|
40
|
-
return @start_expr>@end_expr
|
41
|
-
end
|
42
|
-
|
43
|
-
def gap(obj)
|
44
|
-
|
45
|
-
return EMPTY if self.overlap? obj
|
46
|
-
|
47
|
-
lower=nil
|
48
|
-
higher=nil
|
49
|
-
|
50
|
-
if((self<=>obj)<0)
|
51
|
-
lower=self
|
52
|
-
higher=obj
|
53
|
-
else
|
54
|
-
lower=obj
|
55
|
-
higher=self
|
56
|
-
end
|
57
|
-
|
58
|
-
return DateRange.new((lower.end_expr+1),(higher.start_expr-1))
|
59
|
-
end
|
60
|
-
|
61
|
-
def <=>(other)
|
62
|
-
return @start_expr <=> other.start_expr if(@start_expr != other.start_expr)
|
63
|
-
return @end_expr <=> other.end_expr
|
64
|
-
end
|
65
|
-
|
66
|
-
def min; @start_expr end
|
67
|
-
def max; @end_expr end
|
68
|
-
def to_s; @start_expr.to_s + " " + @end_expr.to_s end
|
69
|
-
|
70
|
-
|
71
|
-
EMPTY = DateRange.new(PDate.day(2004,2,2),PDate.day(2004,2,1))
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'date'
|
4
|
+
require 'runt'
|
5
|
+
|
6
|
+
|
7
|
+
module Runt
|
8
|
+
# :title:DateRange
|
9
|
+
# == DateRange
|
10
|
+
#
|
11
|
+
#
|
12
|
+
# Based the <tt>range</tt>[http://martinfowler.com/ap2/range.html] pattern by Martin Fowler.
|
13
|
+
#
|
14
|
+
#
|
15
|
+
#
|
16
|
+
# Author:: Matthew Lipper
|
17
|
+
class DateRange < Range
|
18
|
+
|
19
|
+
include DPrecision
|
20
|
+
|
21
|
+
attr_reader :start_expr, :end_expr
|
22
|
+
|
23
|
+
def initialize(start_expr, end_expr,exclusive=false)
|
24
|
+
super(start_expr, end_expr,exclusive)
|
25
|
+
@start_expr, @end_expr = start_expr, end_expr
|
26
|
+
end
|
27
|
+
|
28
|
+
def include?(obj)
|
29
|
+
return super(obj.min) && super(obj.max) if obj.kind_of? Range
|
30
|
+
return super(obj)
|
31
|
+
end
|
32
|
+
|
33
|
+
def overlap?(obj)
|
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
|
+
end
|
38
|
+
|
39
|
+
def empty?
|
40
|
+
return @start_expr>@end_expr
|
41
|
+
end
|
42
|
+
|
43
|
+
def gap(obj)
|
44
|
+
|
45
|
+
return EMPTY if self.overlap? obj
|
46
|
+
|
47
|
+
lower=nil
|
48
|
+
higher=nil
|
49
|
+
|
50
|
+
if((self<=>obj)<0)
|
51
|
+
lower=self
|
52
|
+
higher=obj
|
53
|
+
else
|
54
|
+
lower=obj
|
55
|
+
higher=self
|
56
|
+
end
|
57
|
+
|
58
|
+
return DateRange.new((lower.end_expr+1),(higher.start_expr-1))
|
59
|
+
end
|
60
|
+
|
61
|
+
def <=>(other)
|
62
|
+
return @start_expr <=> other.start_expr if(@start_expr != other.start_expr)
|
63
|
+
return @end_expr <=> other.end_expr
|
64
|
+
end
|
65
|
+
|
66
|
+
def min; @start_expr end
|
67
|
+
def max; @end_expr end
|
68
|
+
def to_s; @start_expr.to_s + " " + @end_expr.to_s end
|
69
|
+
|
70
|
+
|
71
|
+
EMPTY = DateRange.new(PDate.day(2004,2,2),PDate.day(2004,2,1))
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|