texp 0.0.7 → 0.1.1
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 +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
|
-
|