texp 0.0.7 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ChangeLog +4 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +12 -0
- data/{README → README.rdoc} +7 -2
- data/Rakefile +9 -25
- data/TAGS +400 -323
- data/lib/texp.rb +5 -2
- data/lib/texp/base.rb +10 -0
- data/lib/texp/day_interval.rb +19 -5
- data/lib/texp/day_of_week.rb +4 -2
- data/lib/texp/day_of_week_interval.rb +38 -0
- data/lib/texp/dsl.rb +1 -1
- data/lib/texp/month_interval.rb +29 -0
- data/lib/texp/parse.rb +10 -6
- data/lib/texp/version.rb +1 -1
- data/lib/texp/week_interval.rb +13 -0
- data/test/test_helper.rb +4 -0
- data/test/texp/base_test.rb +9 -4
- data/test/texp/day_interval_test.rb +2 -5
- data/test/texp/day_of_month_test.rb +2 -7
- data/test/texp/day_of_week_test.rb +2 -7
- data/test/texp/dsl_test.rb +16 -17
- data/test/texp/every_day_test.rb +2 -9
- data/test/texp/ext_test.rb +2 -7
- data/test/texp/inspect_test.rb +8 -13
- data/test/texp/logic_test.rb +2 -7
- data/test/texp/month_test.rb +2 -7
- data/test/texp/operators_test.rb +2 -5
- data/test/texp/parse_test.rb +19 -16
- data/test/texp/time_ext_test.rb +2 -3
- data/test/texp/week_interval_test.rb +32 -0
- data/test/texp/week_test.rb +2 -7
- data/test/texp/window_test.rb +2 -7
- data/test/texp/year_test.rb +3 -8
- data/test/texp_tests.rb +2 -2
- metadata +37 -37
- data/lib/texp/builder.rb +0 -254
data/lib/texp.rb
CHANGED
@@ -4,15 +4,18 @@ require 'texp/version'
|
|
4
4
|
require 'texp/errors'
|
5
5
|
require 'texp/base'
|
6
6
|
require 'texp/parse'
|
7
|
+
require 'texp/logic'
|
8
|
+
require 'texp/operators'
|
7
9
|
require 'texp/day_of_week'
|
8
10
|
require 'texp/day_of_month'
|
9
11
|
require 'texp/week'
|
10
12
|
require 'texp/month'
|
11
13
|
require 'texp/year'
|
12
14
|
require 'texp/day_interval'
|
15
|
+
require 'texp/week_interval'
|
16
|
+
require 'texp/day_of_week_interval'
|
17
|
+
require 'texp/month_interval'
|
13
18
|
require 'texp/every_day'
|
14
19
|
require 'texp/window'
|
15
|
-
require 'texp/logic'
|
16
20
|
require 'texp/dsl'
|
17
|
-
require 'texp/operators'
|
18
21
|
require 'texp/ext'
|
data/lib/texp/base.rb
CHANGED
@@ -1,4 +1,10 @@
|
|
1
1
|
module TExp
|
2
|
+
|
3
|
+
class TExpError < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
class TExpIncludeError < TExpError
|
7
|
+
end
|
2
8
|
|
3
9
|
####################################################################
|
4
10
|
# Abstract Base class for all Texp Temporal Expressions.
|
@@ -13,6 +19,10 @@ module TExp
|
|
13
19
|
codes.join("")
|
14
20
|
end
|
15
21
|
|
22
|
+
def include?(*args)
|
23
|
+
raise TExpIncludeError, "Use includes? rather than include?"
|
24
|
+
end
|
25
|
+
|
16
26
|
# Create a new temporal expression with a new anchor date.
|
17
27
|
def reanchor(date)
|
18
28
|
self
|
data/lib/texp/day_interval.rb
CHANGED
@@ -2,8 +2,16 @@ module TExp
|
|
2
2
|
class DayInterval < Base
|
3
3
|
register_parse_callback('i')
|
4
4
|
|
5
|
-
attr_reader :base_date
|
5
|
+
attr_reader :base_date, :interval
|
6
6
|
|
7
|
+
def day_multiplier
|
8
|
+
1
|
9
|
+
end
|
10
|
+
|
11
|
+
def interval_unit
|
12
|
+
"day"
|
13
|
+
end
|
14
|
+
|
7
15
|
def initialize(base_date, interval)
|
8
16
|
@base_date = base_date.kind_of?(Date) ? base_date : nil
|
9
17
|
@interval = interval
|
@@ -14,7 +22,7 @@ module TExp
|
|
14
22
|
if @base_date.nil? || date < @base_date
|
15
23
|
false
|
16
24
|
else
|
17
|
-
((date.mjd - base_mjd) % @interval) == 0
|
25
|
+
((date.mjd - base_mjd) % (@interval * day_multiplier)) == 0
|
18
26
|
end
|
19
27
|
end
|
20
28
|
|
@@ -26,9 +34,11 @@ module TExp
|
|
26
34
|
# Human readable version of the temporal expression.
|
27
35
|
def inspect
|
28
36
|
if @interval == 1
|
29
|
-
"every
|
37
|
+
"every #{interval_unit}"
|
38
|
+
elsif @interval == 2
|
39
|
+
"every other #{interval_unit}"
|
30
40
|
else
|
31
|
-
"every #{
|
41
|
+
"every #{@interval} #{pluralize(interval_unit)}"
|
32
42
|
end
|
33
43
|
end
|
34
44
|
|
@@ -44,6 +54,10 @@ module TExp
|
|
44
54
|
|
45
55
|
private
|
46
56
|
|
57
|
+
def pluralize(word)
|
58
|
+
"#{word}s"
|
59
|
+
end
|
60
|
+
|
47
61
|
def base_mjd
|
48
62
|
@base_date.mjd
|
49
63
|
end
|
@@ -52,7 +66,7 @@ module TExp
|
|
52
66
|
def parse_callback(stack)
|
53
67
|
interval = stack.pop
|
54
68
|
date = stack.pop
|
55
|
-
stack.push
|
69
|
+
stack.push self.new(date, interval)
|
56
70
|
end
|
57
71
|
end
|
58
72
|
end
|
data/lib/texp/day_of_week.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
module TExp
|
2
2
|
class DayOfWeek < Base
|
3
|
+
attr_reader :days
|
4
|
+
|
3
5
|
register_parse_callback('w')
|
4
6
|
|
5
7
|
def initialize(days)
|
@@ -13,8 +15,8 @@ module TExp
|
|
13
15
|
|
14
16
|
# Human readable version of the temporal expression.
|
15
17
|
def inspect
|
16
|
-
"
|
17
|
-
humanize_list(@days) { |d| Date::DAYNAMES[d] }
|
18
|
+
"on " +
|
19
|
+
humanize_list(@days, "and") { |d| Date::DAYNAMES[d] }
|
18
20
|
end
|
19
21
|
|
20
22
|
# Encode the temporal expression into +codes+.
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# To change this template, choose Tools | Templates
|
2
|
+
# and open the template in the editor.
|
3
|
+
module TExp
|
4
|
+
class DayOfWeekInterval < And
|
5
|
+
register_parse_callback('q')
|
6
|
+
def initialize(*args)
|
7
|
+
if args.size == 3
|
8
|
+
day, week_interval, start_date = args[0..2]
|
9
|
+
@day_texp = DayOfWeek.new(day)
|
10
|
+
@week_interval_texp = WeekInterval.new(
|
11
|
+
find_day_of_week_on_or_after(start_date, day),
|
12
|
+
week_interval
|
13
|
+
)
|
14
|
+
super(@day_texp, @week_interval_texp)
|
15
|
+
else
|
16
|
+
@day_texp, @week_interval_texp = args[0], args[1]
|
17
|
+
super(@day_texp, @week_interval_texp)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_day_of_week_on_or_after(date, day_of_week)
|
22
|
+
raise ArgumentError, "#{day_of_week} is not a valid day of week" unless
|
23
|
+
(0..6).to_a.include? day_of_week
|
24
|
+
while date.wday != day_of_week
|
25
|
+
date = date + 1
|
26
|
+
end
|
27
|
+
date
|
28
|
+
end
|
29
|
+
|
30
|
+
def reanchor(date)
|
31
|
+
super(find_day_of_week_on_or_after(date, @day_texp.days[0]))
|
32
|
+
end
|
33
|
+
|
34
|
+
def inspect
|
35
|
+
"#{@week_interval_texp.inspect} #{@day_texp.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/texp/dsl.rb
CHANGED
@@ -164,7 +164,7 @@ module TExp
|
|
164
164
|
# Evaluate a temporal expression in the TExp environment.
|
165
165
|
# Redirect missing method calls to the containing environment.
|
166
166
|
def evaluate_expression_in_environment(&block) # :nodoc:
|
167
|
-
env = EvalEnvironment.new(block)
|
167
|
+
env = EvalEnvironment.new(block.binding)
|
168
168
|
env.instance_eval(&block)
|
169
169
|
end
|
170
170
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module TExp
|
2
|
+
class MonthInterval < DayInterval
|
3
|
+
register_parse_callback('c')
|
4
|
+
|
5
|
+
def day_multiplier
|
6
|
+
28
|
7
|
+
end
|
8
|
+
|
9
|
+
def interval_unit
|
10
|
+
"month"
|
11
|
+
end
|
12
|
+
|
13
|
+
def inspect
|
14
|
+
case interval
|
15
|
+
when 1
|
16
|
+
"once per month"
|
17
|
+
when 0.5
|
18
|
+
base = "twice per month"
|
19
|
+
when 0.25
|
20
|
+
base = "4 times per month"
|
21
|
+
else
|
22
|
+
base = super
|
23
|
+
end
|
24
|
+
base + " (#{interval * day_multiplier} days)"
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/texp/parse.rb
CHANGED
@@ -26,7 +26,7 @@ module TExp
|
|
26
26
|
def register_parse_callback(token, callback)
|
27
27
|
PARSE_CALLBACKS[token] = callback
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
# Return the temporal expression encoded by string.
|
31
31
|
def parse(string)
|
32
32
|
@stack = []
|
@@ -37,6 +37,10 @@ module TExp
|
|
37
37
|
@stack.pop
|
38
38
|
end
|
39
39
|
|
40
|
+
def parse_callbacks
|
41
|
+
PARSE_CALLBACKS
|
42
|
+
end
|
43
|
+
|
40
44
|
private
|
41
45
|
|
42
46
|
# Compile the token into the current definition.
|
@@ -51,7 +55,7 @@ module TExp
|
|
51
55
|
when /^[-+]?\d+$/
|
52
56
|
@stack.push tok.to_i
|
53
57
|
else
|
54
|
-
fail ParseError, "
|
58
|
+
fail ParseError, "Unrecognized TExp Token '#{tok}'"
|
55
59
|
end
|
56
60
|
end
|
57
61
|
end
|
@@ -67,18 +71,18 @@ module TExp
|
|
67
71
|
@callback.call(stack)
|
68
72
|
end
|
69
73
|
end
|
70
|
-
|
74
|
+
|
71
75
|
# List parsing handlers
|
72
|
-
|
76
|
+
|
73
77
|
# Mark the end of the list.
|
74
78
|
MARK = :mark # :nodoc:
|
75
|
-
|
79
|
+
|
76
80
|
# Push a mark on the stack to start a list.
|
77
81
|
register_parse_callback('[',
|
78
82
|
ParseCallback.new do |stack|
|
79
83
|
stack.push MARK
|
80
84
|
end)
|
81
|
-
|
85
|
+
|
82
86
|
# Pop the stack and build a list until you find a mark.
|
83
87
|
register_parse_callback(']',
|
84
88
|
ParseCallback.new do |stack|
|
data/lib/texp/version.rb
CHANGED
data/test/test_helper.rb
ADDED
data/test/texp/base_test.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'texp'
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
|
-
class BaseEachTest < Test
|
3
|
+
class BaseEachTest < Minitest::Test
|
5
4
|
def test_each_on_base
|
6
5
|
te = basic_texp
|
7
6
|
assert_equal [te], te.collect { |t| t }
|
@@ -17,6 +16,12 @@ class BaseEachTest < Test::Unit::TestCase
|
|
17
16
|
assert_equal [@basic, @multi], te.collect { |t| t }
|
18
17
|
end
|
19
18
|
|
19
|
+
def test_complains_about_include
|
20
|
+
assert_raises TExp::TExpIncludeError do
|
21
|
+
basic_texp.include? Date.parse("Feb 1, 2009")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
20
25
|
private
|
21
26
|
|
22
27
|
def basic_texp
|
@@ -33,7 +38,7 @@ class BaseEachTest < Test::Unit::TestCase
|
|
33
38
|
|
34
39
|
end
|
35
40
|
|
36
|
-
class BaseAnchorTest < Test
|
41
|
+
class BaseAnchorTest < Minitest::Test
|
37
42
|
def test_setting_anchor_date
|
38
43
|
start_date = Date.parse("Feb 10, 2008")
|
39
44
|
te = TExp::DayInterval.new(start_date, 3)
|
@@ -1,8 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
class DayIntervalTest < Test::Unit::TestCase
|
3
|
+
class DayIntervalTest < Minitest::Test
|
6
4
|
|
7
5
|
def test_day_interval
|
8
6
|
te = TExp::DayInterval.new(Date.parse("Feb 10, 2008"), 3)
|
@@ -31,4 +29,3 @@ class DayIntervalTest < Test::Unit::TestCase
|
|
31
29
|
assert_not_includes te, date-3, date-2, date-1
|
32
30
|
end
|
33
31
|
end
|
34
|
-
|
@@ -1,10 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
require 'test/unit'
|
5
|
-
require 'texp'
|
6
|
-
|
7
|
-
class DayOfMonthTest < Test::Unit::TestCase
|
3
|
+
class DayOfMonthTest < Minitest::Test
|
8
4
|
|
9
5
|
def test_day_of_month_with_single_arg
|
10
6
|
te = TExp::DayOfMonth.new(14)
|
@@ -24,4 +20,3 @@ class DayOfMonthTest < Test::Unit::TestCase
|
|
24
20
|
assert te.includes?(Date.parse("Feb 16, 2008"))
|
25
21
|
end
|
26
22
|
end
|
27
|
-
|
@@ -1,10 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'test_helper'
|
2
2
|
|
3
|
-
|
4
|
-
require 'test/unit'
|
5
|
-
require 'texp'
|
6
|
-
|
7
|
-
class DayOfWeekTest < Test::Unit::TestCase
|
3
|
+
class DayOfWeekTest < Minitest::Test
|
8
4
|
|
9
5
|
def test_day_of_week_include_with_one_day
|
10
6
|
te = TExp::DayOfWeek.new([1])
|
@@ -28,4 +24,3 @@ class DayOfWeekTest < Test::Unit::TestCase
|
|
28
24
|
assert ! te.includes?(Date.parse("Feb 16, 2008"))
|
29
25
|
end
|
30
26
|
end
|
31
|
-
|
data/test/texp/dsl_test.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require 'texp'
|
1
|
+
require 'test_helper'
|
3
2
|
|
4
|
-
class BuilderTest < Test
|
3
|
+
class BuilderTest < Minitest::Test
|
5
4
|
def test_day_builder
|
6
5
|
date = d("Mar 12, 2008")
|
7
6
|
te = TExp.day(12)
|
@@ -152,19 +151,19 @@ class BuilderTest < Test::Unit::TestCase
|
|
152
151
|
end
|
153
152
|
|
154
153
|
def test_on_builder_with_invalid_arguments
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
154
|
+
assert_raises(ArgumentError) do TExp.on(1) end
|
155
|
+
assert_raises(ArgumentError) do TExp.on(1,2,3,4) end
|
156
|
+
assert_raises(ArgumentError) do TExp.on(nil, nil) end
|
157
|
+
assert_raises(ArgumentError) do TExp.on(0, 1) end
|
158
|
+
assert_raises(ArgumentError) do TExp.on(1, 0) end
|
159
|
+
assert_raises(ArgumentError) do TExp.on(32, 1) end
|
160
|
+
assert_raises(ArgumentError) do TExp.on(1, 13) end
|
161
|
+
assert_raises(ArgumentError) do TExp.on(0, 1, 2008) end
|
162
|
+
assert_raises(ArgumentError) do TExp.on(1, 0, 2008) end
|
163
|
+
assert_raises(ArgumentError) do TExp.on(32, 1, 2008) end
|
164
|
+
assert_raises(ArgumentError) do TExp.on(1, 13, 2008) end
|
165
|
+
assert_raises(ArgumentError) do TExp.on(1, 'nox') end
|
166
|
+
assert_raises(ArgumentError) do TExp.on(1, 'nox', 2008) end
|
168
167
|
end
|
169
168
|
|
170
169
|
def test_dow_builder
|
@@ -259,7 +258,7 @@ class BuilderTest < Test::Unit::TestCase
|
|
259
258
|
end
|
260
259
|
|
261
260
|
def test_window_builder_with_bad_units
|
262
|
-
|
261
|
+
assert_raises ArgumentError do
|
263
262
|
te = TExp.on(Date.today).window(1, nil)
|
264
263
|
end
|
265
264
|
end
|
data/test/texp/every_day_test.rb
CHANGED
@@ -1,15 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'date'
|
5
|
-
|
6
|
-
require 'texp'
|
7
|
-
|
8
|
-
class EveryDayTest < Test::Unit::TestCase
|
1
|
+
require 'test_helper'
|
9
2
|
|
3
|
+
class EveryDayTest < Minitest::Test
|
10
4
|
def test_every_day
|
11
5
|
te = TExp::EveryDay.new
|
12
6
|
assert te.includes?(Date.parse("Feb 15, 2008"))
|
13
7
|
end
|
14
8
|
end
|
15
|
-
|
data/test/texp/ext_test.rb
CHANGED
@@ -1,8 +1,4 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
require 'test/unit'
|
4
|
-
require 'date'
|
5
|
-
require 'texp'
|
1
|
+
require 'test_helper'
|
6
2
|
|
7
3
|
module TExp
|
8
4
|
|
@@ -64,7 +60,7 @@ module TExp
|
|
64
60
|
end # module Extensions
|
65
61
|
end # module TExp
|
66
62
|
|
67
|
-
class ExtensionsTest < Test
|
63
|
+
class ExtensionsTest < Minitest::Test
|
68
64
|
def test_never
|
69
65
|
te = TExp::Extensions::MyExt::Never.new
|
70
66
|
assert ! te.includes?(Date.today)
|
@@ -79,4 +75,3 @@ class ExtensionsTest < Test::Unit::TestCase
|
|
79
75
|
assert_equal "<MyExt::never>", TExp.parse("<MyExt::never>").to_s
|
80
76
|
end
|
81
77
|
end
|
82
|
-
|