mojombo-chronic 0.3.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/README +167 -0
- data/lib/chronic.rb +127 -0
- data/lib/chronic/chronic.rb +248 -0
- data/lib/chronic/grabber.rb +26 -0
- data/lib/chronic/handlers.rb +524 -0
- data/lib/chronic/ordinal.rb +40 -0
- data/lib/chronic/pointer.rb +27 -0
- data/lib/chronic/repeater.rb +129 -0
- data/lib/chronic/repeaters/repeater_day.rb +52 -0
- data/lib/chronic/repeaters/repeater_day_name.rb +51 -0
- data/lib/chronic/repeaters/repeater_day_portion.rb +94 -0
- data/lib/chronic/repeaters/repeater_fortnight.rb +70 -0
- data/lib/chronic/repeaters/repeater_hour.rb +57 -0
- data/lib/chronic/repeaters/repeater_minute.rb +57 -0
- data/lib/chronic/repeaters/repeater_month.rb +66 -0
- data/lib/chronic/repeaters/repeater_month_name.rb +98 -0
- data/lib/chronic/repeaters/repeater_season.rb +150 -0
- data/lib/chronic/repeaters/repeater_season_name.rb +45 -0
- data/lib/chronic/repeaters/repeater_second.rb +41 -0
- data/lib/chronic/repeaters/repeater_time.rb +120 -0
- data/lib/chronic/repeaters/repeater_week.rb +73 -0
- data/lib/chronic/repeaters/repeater_weekday.rb +77 -0
- data/lib/chronic/repeaters/repeater_weekend.rb +65 -0
- data/lib/chronic/repeaters/repeater_year.rb +64 -0
- data/lib/chronic/scalar.rb +76 -0
- data/lib/chronic/separator.rb +91 -0
- data/lib/chronic/time_zone.rb +23 -0
- data/lib/numerizer/numerizer.rb +97 -0
- data/test/suite.rb +9 -0
- data/test/test_Chronic.rb +50 -0
- data/test/test_Handler.rb +110 -0
- data/test/test_Numerizer.rb +52 -0
- data/test/test_RepeaterDayName.rb +52 -0
- data/test/test_RepeaterFortnight.rb +63 -0
- data/test/test_RepeaterHour.rb +65 -0
- data/test/test_RepeaterMonth.rb +47 -0
- data/test/test_RepeaterMonthName.rb +57 -0
- data/test/test_RepeaterTime.rb +72 -0
- data/test/test_RepeaterWeek.rb +63 -0
- data/test/test_RepeaterWeekday.rb +56 -0
- data/test/test_RepeaterWeekend.rb +75 -0
- data/test/test_RepeaterYear.rb +63 -0
- data/test/test_Span.rb +24 -0
- data/test/test_Time.rb +50 -0
- data/test/test_Token.rb +26 -0
- data/test/test_parsing.rb +706 -0
- metadata +102 -0
@@ -0,0 +1,41 @@
|
|
1
|
+
class Chronic::RepeaterSecond < Chronic::Repeater #:nodoc:
|
2
|
+
SECOND_SECONDS = 1 # haha, awesome
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@second_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer = :future)
|
10
|
+
super
|
11
|
+
|
12
|
+
direction = pointer == :future ? 1 : -1
|
13
|
+
|
14
|
+
if !@second_start
|
15
|
+
@second_start = @now + (direction * SECOND_SECONDS)
|
16
|
+
else
|
17
|
+
@second_start += SECOND_SECONDS * direction
|
18
|
+
end
|
19
|
+
|
20
|
+
Chronic::Span.new(@second_start, @second_start + SECOND_SECONDS)
|
21
|
+
end
|
22
|
+
|
23
|
+
def this(pointer = :future)
|
24
|
+
super
|
25
|
+
|
26
|
+
Chronic::Span.new(@now, @now + 1)
|
27
|
+
end
|
28
|
+
|
29
|
+
def offset(span, amount, pointer)
|
30
|
+
direction = pointer == :future ? 1 : -1
|
31
|
+
span + direction * amount * SECOND_SECONDS
|
32
|
+
end
|
33
|
+
|
34
|
+
def width
|
35
|
+
SECOND_SECONDS
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
super << '-second'
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
class Chronic::RepeaterTime < Chronic::Repeater #:nodoc:
|
2
|
+
class Tick #:nodoc:
|
3
|
+
attr_accessor :time
|
4
|
+
|
5
|
+
def initialize(time, ambiguous = false)
|
6
|
+
@time = time
|
7
|
+
@ambiguous = ambiguous
|
8
|
+
end
|
9
|
+
|
10
|
+
def ambiguous?
|
11
|
+
@ambiguous
|
12
|
+
end
|
13
|
+
|
14
|
+
def *(other)
|
15
|
+
Tick.new(@time * other, @ambiguous)
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_f
|
19
|
+
@time.to_f
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
@time.to_s + (@ambiguous ? '?' : '')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(time, options = {})
|
28
|
+
@current_time = nil
|
29
|
+
t = time.gsub(/\:/, '')
|
30
|
+
|
31
|
+
@type =
|
32
|
+
case t.size
|
33
|
+
when 1..2
|
34
|
+
hours = t.to_i
|
35
|
+
hours == 12 ? Tick.new(0 * 60 * 60, true) : Tick.new(hours * 60 * 60, true)
|
36
|
+
when 3
|
37
|
+
Tick.new((t[0..0].to_i * 60 * 60) + (t[1..2].to_i * 60), true)
|
38
|
+
when 4
|
39
|
+
ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
|
40
|
+
hours = t[0..1].to_i
|
41
|
+
hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60, ambiguous)
|
42
|
+
when 5
|
43
|
+
Tick.new(t[0..0].to_i * 60 * 60 + t[1..2].to_i * 60 + t[3..4].to_i, true)
|
44
|
+
when 6
|
45
|
+
ambiguous = time =~ /:/ && t[0..0].to_i != 0 && t[0..1].to_i <= 12
|
46
|
+
hours = t[0..1].to_i
|
47
|
+
hours == 12 ? Tick.new(0 * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous) : Tick.new(hours * 60 * 60 + t[2..3].to_i * 60 + t[4..5].to_i, ambiguous)
|
48
|
+
else
|
49
|
+
raise("Time cannot exceed six digits")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return the next past or future Span for the time that this Repeater represents
|
54
|
+
# pointer - Symbol representing which temporal direction to fetch the next day
|
55
|
+
# must be either :past or :future
|
56
|
+
def next(pointer)
|
57
|
+
super
|
58
|
+
|
59
|
+
half_day = 60 * 60 * 12
|
60
|
+
full_day = 60 * 60 * 24
|
61
|
+
|
62
|
+
first = false
|
63
|
+
|
64
|
+
unless @current_time
|
65
|
+
first = true
|
66
|
+
midnight = Chronic.time_class.local(@now.year, @now.month, @now.day)
|
67
|
+
yesterday_midnight = midnight - full_day
|
68
|
+
tomorrow_midnight = midnight + full_day
|
69
|
+
|
70
|
+
catch :done do
|
71
|
+
if pointer == :future
|
72
|
+
if @type.ambiguous?
|
73
|
+
[midnight + @type, midnight + half_day + @type, tomorrow_midnight + @type].each do |t|
|
74
|
+
(@current_time = t; throw :done) if t >= @now
|
75
|
+
end
|
76
|
+
else
|
77
|
+
[midnight + @type, tomorrow_midnight + @type].each do |t|
|
78
|
+
(@current_time = t; throw :done) if t >= @now
|
79
|
+
end
|
80
|
+
end
|
81
|
+
else # pointer == :past
|
82
|
+
if @type.ambiguous?
|
83
|
+
[midnight + half_day + @type, midnight + @type, yesterday_midnight + @type * 2].each do |t|
|
84
|
+
(@current_time = t; throw :done) if t <= @now
|
85
|
+
end
|
86
|
+
else
|
87
|
+
[midnight + @type, yesterday_midnight + @type].each do |t|
|
88
|
+
(@current_time = t; throw :done) if t <= @now
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
@current_time || raise("Current time cannot be nil at this point")
|
95
|
+
end
|
96
|
+
|
97
|
+
unless first
|
98
|
+
increment = @type.ambiguous? ? half_day : full_day
|
99
|
+
@current_time += pointer == :future ? increment : -increment
|
100
|
+
end
|
101
|
+
|
102
|
+
Chronic::Span.new(@current_time, @current_time + width)
|
103
|
+
end
|
104
|
+
|
105
|
+
def this(context = :future)
|
106
|
+
super
|
107
|
+
|
108
|
+
context = :future if context == :none
|
109
|
+
|
110
|
+
self.next(context)
|
111
|
+
end
|
112
|
+
|
113
|
+
def width
|
114
|
+
1
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_s
|
118
|
+
super << '-time-' << @type.to_s
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
class Chronic::RepeaterWeek < Chronic::Repeater #:nodoc:
|
2
|
+
WEEK_SECONDS = 604800 # (7 * 24 * 60 * 60)
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@current_week_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer)
|
10
|
+
super
|
11
|
+
|
12
|
+
if !@current_week_start
|
13
|
+
case pointer
|
14
|
+
when :future
|
15
|
+
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
16
|
+
sunday_repeater.start = @now
|
17
|
+
next_sunday_span = sunday_repeater.next(:future)
|
18
|
+
@current_week_start = next_sunday_span.begin
|
19
|
+
when :past
|
20
|
+
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
21
|
+
sunday_repeater.start = (@now + Chronic::RepeaterDay::DAY_SECONDS)
|
22
|
+
sunday_repeater.next(:past)
|
23
|
+
last_sunday_span = sunday_repeater.next(:past)
|
24
|
+
@current_week_start = last_sunday_span.begin
|
25
|
+
end
|
26
|
+
else
|
27
|
+
direction = pointer == :future ? 1 : -1
|
28
|
+
@current_week_start += direction * WEEK_SECONDS
|
29
|
+
end
|
30
|
+
|
31
|
+
Chronic::Span.new(@current_week_start, @current_week_start + WEEK_SECONDS)
|
32
|
+
end
|
33
|
+
|
34
|
+
def this(pointer = :future)
|
35
|
+
super
|
36
|
+
|
37
|
+
case pointer
|
38
|
+
when :future
|
39
|
+
this_week_start = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour) + Chronic::RepeaterHour::HOUR_SECONDS
|
40
|
+
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
41
|
+
sunday_repeater.start = @now
|
42
|
+
this_sunday_span = sunday_repeater.this(:future)
|
43
|
+
this_week_end = this_sunday_span.begin
|
44
|
+
Chronic::Span.new(this_week_start, this_week_end)
|
45
|
+
when :past
|
46
|
+
this_week_end = Chronic.time_class.local(@now.year, @now.month, @now.day, @now.hour)
|
47
|
+
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
48
|
+
sunday_repeater.start = @now
|
49
|
+
last_sunday_span = sunday_repeater.next(:past)
|
50
|
+
this_week_start = last_sunday_span.begin
|
51
|
+
Chronic::Span.new(this_week_start, this_week_end)
|
52
|
+
when :none
|
53
|
+
sunday_repeater = Chronic::RepeaterDayName.new(:sunday)
|
54
|
+
sunday_repeater.start = @now
|
55
|
+
last_sunday_span = sunday_repeater.next(:past)
|
56
|
+
this_week_start = last_sunday_span.begin
|
57
|
+
Chronic::Span.new(this_week_start, this_week_start + WEEK_SECONDS)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def offset(span, amount, pointer)
|
62
|
+
direction = pointer == :future ? 1 : -1
|
63
|
+
span + direction * amount * WEEK_SECONDS
|
64
|
+
end
|
65
|
+
|
66
|
+
def width
|
67
|
+
WEEK_SECONDS
|
68
|
+
end
|
69
|
+
|
70
|
+
def to_s
|
71
|
+
super << '-week'
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
class Chronic::RepeaterWeekday < Chronic::Repeater #:nodoc:
|
2
|
+
WEEK_WEEKDAYS = 5
|
3
|
+
DAY_SECONDS = 86400 # (24 * 60 * 60)
|
4
|
+
|
5
|
+
def initialize(type)
|
6
|
+
super
|
7
|
+
@current_weekday_start = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
def next(pointer)
|
11
|
+
super
|
12
|
+
|
13
|
+
direction = pointer == :future ? 1 : -1
|
14
|
+
|
15
|
+
if !@current_weekday_start
|
16
|
+
@current_weekday_start = Time.construct(@now.year, @now.month, @now.day)
|
17
|
+
@current_weekday_start += direction * DAY_SECONDS
|
18
|
+
|
19
|
+
until is_weekday?(@current_weekday_start.wday)
|
20
|
+
@current_weekday_start += direction * DAY_SECONDS
|
21
|
+
end
|
22
|
+
else
|
23
|
+
loop do
|
24
|
+
@current_weekday_start += direction * DAY_SECONDS
|
25
|
+
break if is_weekday?(@current_weekday_start.wday)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
Chronic::Span.new(@current_weekday_start, @current_weekday_start + DAY_SECONDS)
|
30
|
+
end
|
31
|
+
|
32
|
+
def this(pointer = :future)
|
33
|
+
super
|
34
|
+
|
35
|
+
case pointer
|
36
|
+
when :past
|
37
|
+
self.next(:past)
|
38
|
+
when :future, :none
|
39
|
+
self.next(:future)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def offset(span, amount, pointer)
|
44
|
+
direction = pointer == :future ? 1 : -1
|
45
|
+
|
46
|
+
num_weekdays_passed = 0; offset = 0
|
47
|
+
until num_weekdays_passed == amount
|
48
|
+
offset += direction * DAY_SECONDS
|
49
|
+
num_weekdays_passed += 1 if is_weekday?((span.begin+offset).wday)
|
50
|
+
end
|
51
|
+
|
52
|
+
span + offset
|
53
|
+
end
|
54
|
+
|
55
|
+
def width
|
56
|
+
DAY_SECONDS
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_s
|
60
|
+
super << '-weekday'
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def is_weekend?(day)
|
66
|
+
day == symbol_to_number(:saturday) || day == symbol_to_number(:sunday)
|
67
|
+
end
|
68
|
+
|
69
|
+
def is_weekday?(day)
|
70
|
+
!is_weekend?(day)
|
71
|
+
end
|
72
|
+
|
73
|
+
def symbol_to_number(sym)
|
74
|
+
lookup = {:sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3, :thursday => 4, :friday => 5, :saturday => 6}
|
75
|
+
lookup[sym] || raise("Invalid symbol specified")
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class Chronic::RepeaterWeekend < Chronic::Repeater #:nodoc:
|
2
|
+
WEEKEND_SECONDS = 172_800 # (2 * 24 * 60 * 60)
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@current_week_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer)
|
10
|
+
super
|
11
|
+
|
12
|
+
if !@current_week_start
|
13
|
+
case pointer
|
14
|
+
when :future
|
15
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
16
|
+
saturday_repeater.start = @now
|
17
|
+
next_saturday_span = saturday_repeater.next(:future)
|
18
|
+
@current_week_start = next_saturday_span.begin
|
19
|
+
when :past
|
20
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
21
|
+
saturday_repeater.start = (@now + Chronic::RepeaterDay::DAY_SECONDS)
|
22
|
+
last_saturday_span = saturday_repeater.next(:past)
|
23
|
+
@current_week_start = last_saturday_span.begin
|
24
|
+
end
|
25
|
+
else
|
26
|
+
direction = pointer == :future ? 1 : -1
|
27
|
+
@current_week_start += direction * Chronic::RepeaterWeek::WEEK_SECONDS
|
28
|
+
end
|
29
|
+
|
30
|
+
Chronic::Span.new(@current_week_start, @current_week_start + WEEKEND_SECONDS)
|
31
|
+
end
|
32
|
+
|
33
|
+
def this(pointer = :future)
|
34
|
+
super
|
35
|
+
|
36
|
+
case pointer
|
37
|
+
when :future, :none
|
38
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
39
|
+
saturday_repeater.start = @now
|
40
|
+
this_saturday_span = saturday_repeater.this(:future)
|
41
|
+
Chronic::Span.new(this_saturday_span.begin, this_saturday_span.begin + WEEKEND_SECONDS)
|
42
|
+
when :past
|
43
|
+
saturday_repeater = Chronic::RepeaterDayName.new(:saturday)
|
44
|
+
saturday_repeater.start = @now
|
45
|
+
last_saturday_span = saturday_repeater.this(:past)
|
46
|
+
Chronic::Span.new(last_saturday_span.begin, last_saturday_span.begin + WEEKEND_SECONDS)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def offset(span, amount, pointer)
|
51
|
+
direction = pointer == :future ? 1 : -1
|
52
|
+
weekend = Chronic::RepeaterWeekend.new(:weekend)
|
53
|
+
weekend.start = span.begin
|
54
|
+
start = weekend.next(pointer).begin + (amount - 1) * direction * Chronic::RepeaterWeek::WEEK_SECONDS
|
55
|
+
Chronic::Span.new(start, start + (span.end - span.begin))
|
56
|
+
end
|
57
|
+
|
58
|
+
def width
|
59
|
+
WEEKEND_SECONDS
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_s
|
63
|
+
super << '-weekend'
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
|
2
|
+
YEAR_SECONDS = 31536000 # 365 * 24 * 60 * 60
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@current_year_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer)
|
10
|
+
super
|
11
|
+
|
12
|
+
if !@current_year_start
|
13
|
+
case pointer
|
14
|
+
when :future
|
15
|
+
@current_year_start = Time.construct(@now.year + 1)
|
16
|
+
when :past
|
17
|
+
@current_year_start = Time.construct(@now.year - 1)
|
18
|
+
end
|
19
|
+
else
|
20
|
+
diff = pointer == :future ? 1 : -1
|
21
|
+
@current_year_start = Time.construct(@current_year_start.year + diff)
|
22
|
+
end
|
23
|
+
|
24
|
+
Chronic::Span.new(@current_year_start, Time.construct(@current_year_start.year + 1))
|
25
|
+
end
|
26
|
+
|
27
|
+
def this(pointer = :future)
|
28
|
+
super
|
29
|
+
|
30
|
+
case pointer
|
31
|
+
when :future
|
32
|
+
this_year_start = Time.construct(@now.year, @now.month, @now.day) + Chronic::RepeaterDay::DAY_SECONDS
|
33
|
+
this_year_end = Time.construct(@now.year + 1, 1, 1)
|
34
|
+
when :past
|
35
|
+
this_year_start = Time.construct(@now.year, 1, 1)
|
36
|
+
this_year_end = Time.construct(@now.year, @now.month, @now.day)
|
37
|
+
when :none
|
38
|
+
this_year_start = Time.construct(@now.year, 1, 1)
|
39
|
+
this_year_end = Time.construct(@now.year + 1, 1, 1)
|
40
|
+
end
|
41
|
+
|
42
|
+
Chronic::Span.new(this_year_start, this_year_end)
|
43
|
+
end
|
44
|
+
|
45
|
+
def offset(span, amount, pointer)
|
46
|
+
direction = pointer == :future ? 1 : -1
|
47
|
+
|
48
|
+
sb = span.begin
|
49
|
+
new_begin = Time.construct(sb.year + (amount * direction), sb.month, sb.day, sb.hour, sb.min, sb.sec)
|
50
|
+
|
51
|
+
se = span.end
|
52
|
+
new_end = Time.construct(se.year + (amount * direction), se.month, se.day, se.hour, se.min, se.sec)
|
53
|
+
|
54
|
+
Chronic::Span.new(new_begin, new_end)
|
55
|
+
end
|
56
|
+
|
57
|
+
def width
|
58
|
+
(365 * 24 * 60 * 60)
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
super << '-year'
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Chronic
|
2
|
+
|
3
|
+
class Scalar < Tag #:nodoc:
|
4
|
+
def self.scan(tokens)
|
5
|
+
# for each token
|
6
|
+
tokens.each_index do |i|
|
7
|
+
if t = self.scan_for_scalars(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
8
|
+
if t = self.scan_for_days(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
9
|
+
if t = self.scan_for_months(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
10
|
+
if t = self.scan_for_years(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
|
11
|
+
end
|
12
|
+
tokens
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.scan_for_scalars(token, post_token)
|
16
|
+
if token.word =~ /^\d*$/
|
17
|
+
unless post_token && %w{am pm morning afternoon evening night}.include?(post_token)
|
18
|
+
return Scalar.new(token.word.to_i)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
return nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.scan_for_days(token, post_token)
|
25
|
+
if token.word =~ /^\d\d?$/
|
26
|
+
toi = token.word.to_i
|
27
|
+
unless toi > 31 || toi < 1 || (post_token && %w{am pm morning afternoon evening night}.include?(post_token.word))
|
28
|
+
return ScalarDay.new(toi)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.scan_for_months(token, post_token)
|
35
|
+
if token.word =~ /^\d\d?$/
|
36
|
+
toi = token.word.to_i
|
37
|
+
unless toi > 12 || toi < 1 || (post_token && %w{am pm morning afternoon evening night}.include?(post_token.word))
|
38
|
+
return ScalarMonth.new(toi)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
return nil
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.scan_for_years(token, post_token)
|
45
|
+
if token.word =~ /^([1-9]\d)?\d\d?$/
|
46
|
+
unless post_token && %w{am pm morning afternoon evening night}.include?(post_token.word)
|
47
|
+
return ScalarYear.new(token.word.to_i)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
return nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
'scalar'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
class ScalarDay < Scalar #:nodoc:
|
59
|
+
def to_s
|
60
|
+
super << '-day-' << @type.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class ScalarMonth < Scalar #:nodoc:
|
65
|
+
def to_s
|
66
|
+
super << '-month-' << @type.to_s
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class ScalarYear < Scalar #:nodoc:
|
71
|
+
def to_s
|
72
|
+
super << '-year-' << @type.to_s
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|