pangel-chronic 0.3.0.3 → 0.3.10
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.rdoc → README.txt} +7 -22
- data/lib/chronic.rb +89 -12
- data/lib/chronic/chronic.rb +260 -301
- data/lib/chronic/grabber.rb +23 -23
- data/lib/chronic/handlers.rb +538 -557
- data/lib/chronic/ordinal.rb +36 -35
- data/lib/chronic/pointer.rb +24 -26
- data/lib/chronic/repeater.rb +128 -138
- data/lib/chronic/repeaters/repeater_day.rb +51 -51
- data/lib/chronic/repeaters/repeater_day_name.rb +50 -52
- data/lib/chronic/repeaters/repeater_day_portion.rb +93 -93
- data/lib/chronic/repeaters/repeater_fortnight.rb +66 -66
- data/lib/chronic/repeaters/repeater_hour.rb +56 -57
- data/lib/chronic/repeaters/repeater_minute.rb +56 -56
- data/lib/chronic/repeaters/repeater_month.rb +71 -62
- data/lib/chronic/repeaters/repeater_month_name.rb +95 -95
- data/lib/chronic/repeaters/repeater_season.rb +142 -142
- data/lib/chronic/repeaters/repeater_season_name.rb +42 -42
- data/lib/chronic/repeaters/repeater_second.rb +40 -40
- data/lib/chronic/repeaters/repeater_time.rb +124 -123
- data/lib/chronic/repeaters/repeater_week.rb +70 -70
- data/lib/chronic/repeaters/repeater_weekday.rb +76 -76
- data/lib/chronic/repeaters/repeater_weekend.rb +63 -63
- data/lib/chronic/repeaters/repeater_year.rb +63 -63
- data/lib/chronic/scalar.rb +89 -70
- data/lib/chronic/separator.rb +88 -88
- data/lib/chronic/time_zone.rb +23 -20
- data/lib/numerizer/numerizer.rb +93 -94
- data/test/suite.rb +2 -2
- data/test/test_Chronic.rb +47 -47
- data/test/test_Handler.rb +106 -106
- data/test/test_Numerizer.rb +47 -49
- data/test/test_RepeaterDayName.rb +48 -48
- data/test/test_RepeaterFortnight.rb +59 -59
- data/test/test_RepeaterHour.rb +61 -64
- data/test/test_RepeaterMonth.rb +43 -43
- data/test/test_RepeaterMonthName.rb +53 -53
- data/test/test_RepeaterTime.rb +68 -68
- data/test/test_RepeaterWeek.rb +59 -59
- data/test/test_RepeaterWeekday.rb +53 -53
- data/test/test_RepeaterWeekend.rb +71 -71
- data/test/test_RepeaterYear.rb +59 -59
- data/test/test_Span.rb +19 -28
- data/test/test_Time.rb +46 -46
- data/test/test_Token.rb +22 -22
- data/test/test_parsing.rb +726 -792
- metadata +6 -10
@@ -1,77 +1,77 @@
|
|
1
1
|
class Chronic::RepeaterWeekday < Chronic::Repeater #:nodoc:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
end
|
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
|
@@ -1,65 +1,65 @@
|
|
1
1
|
class Chronic::RepeaterWeekend < Chronic::Repeater #:nodoc:
|
2
|
-
|
2
|
+
WEEKEND_SECONDS = 172_800 # (2 * 24 * 60 * 60)
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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
|
-
end
|
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
|
@@ -1,64 +1,64 @@
|
|
1
1
|
class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
end
|
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
|
data/lib/chronic/scalar.rb
CHANGED
@@ -1,76 +1,95 @@
|
|
1
1
|
module Chronic
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
+
# Ruby 1.9.2 accepts 2 digit years so we need to guess
|
48
|
+
# Of course, this means there is no way to enter a date
|
49
|
+
# that happened before 100. Probably an OK tradeoff
|
50
|
+
# as it didn't work before, either.
|
51
|
+
year = token.word.to_i
|
52
|
+
if year < 100
|
53
|
+
this_year = Chronic.time_class.now.year
|
54
|
+
suffix = this_year.to_s.slice(-2,2).to_i
|
55
|
+
year = this_year + (year - suffix)
|
14
56
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
57
|
+
# We could just split 50/50 to decide if the user
|
58
|
+
# meant the future, however, a user is more likely
|
59
|
+
# going to use a 2 digit number while looking back
|
60
|
+
# unless in the near future. Splitting the difference
|
61
|
+
# at 80/20, however, this could probably be even
|
62
|
+
# more conservative (90/10 even)
|
63
|
+
year -= 100 if (year - this_year).to_i >= 20
|
64
|
+
end
|
23
65
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
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
|
66
|
+
return ScalarYear.new(year)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
return nil
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_s
|
73
|
+
'scalar'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
class ScalarDay < Scalar #:nodoc:
|
78
|
+
def to_s
|
79
|
+
super << '-day-' << @type.to_s
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
class ScalarMonth < Scalar #:nodoc:
|
84
|
+
def to_s
|
85
|
+
super << '-month-' << @type.to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class ScalarYear < Scalar #:nodoc:
|
90
|
+
def to_s
|
91
|
+
super << '-year-' << @type.to_s
|
92
|
+
end
|
93
|
+
end
|
75
94
|
|
76
95
|
end
|