rizwanreza-chronic 0.0.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.
- data/README.rdoc +188 -0
- data/lib/chronic.rb +57 -0
- data/lib/chronic/blunt.rb +234 -0
- data/lib/chronic/chronic.rb +326 -0
- data/lib/chronic/grabber.rb +26 -0
- data/lib/chronic/handlers.rb +549 -0
- data/lib/chronic/ordinal.rb +39 -0
- data/lib/chronic/pointer.rb +29 -0
- data/lib/chronic/repeater.rb +139 -0
- data/lib/chronic/repeaters/repeater_day.rb +52 -0
- data/lib/chronic/repeaters/repeater_day_name.rb +53 -0
- data/lib/chronic/repeaters/repeater_day_portion.rb +94 -0
- data/lib/chronic/repeaters/repeater_decade.rb +23 -0
- data/lib/chronic/repeaters/repeater_fortnight.rb +70 -0
- data/lib/chronic/repeaters/repeater_hour.rb +58 -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 +124 -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 +26 -0
- data/lib/core_ext/object.rb +7 -0
- data/lib/core_ext/time.rb +74 -0
- data/lib/numerizer/numerizer.rb +98 -0
- data/test/test_Chronic.rb +75 -0
- data/test/test_DaylightSavings.rb +119 -0
- data/test/test_Handler.rb +110 -0
- data/test/test_Numerizer.rb +54 -0
- data/test/test_RepeaterDayName.rb +52 -0
- data/test/test_RepeaterDecade.rb +46 -0
- data/test/test_RepeaterFortnight.rb +63 -0
- data/test/test_RepeaterHour.rb +68 -0
- data/test/test_RepeaterMinute.rb +35 -0
- data/test/test_RepeaterMonth.rb +47 -0
- data/test/test_RepeaterMonthName.rb +57 -0
- data/test/test_RepeaterSeason.rb +43 -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 +33 -0
- data/test/test_Time.rb +50 -0
- data/test/test_Token.rb +26 -0
- data/test/test_parsing.rb +809 -0
- metadata +118 -0
@@ -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*$/ || token.word =~ /^\d\.\d*$/
|
17
|
+
unless post_token && %w{am pm morning afternoon evening night}.include?(post_token)
|
18
|
+
return Scalar.new(token.word.to_f)
|
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
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module Chronic
|
2
|
+
|
3
|
+
class Separator < Tag #:nodoc:
|
4
|
+
def self.scan(tokens)
|
5
|
+
tokens.each_index do |i|
|
6
|
+
if t = self.scan_for_commas(tokens[i]) then tokens[i].tag(t); next end
|
7
|
+
if t = self.scan_for_slash_or_dash(tokens[i]) then tokens[i].tag(t); next end
|
8
|
+
if t = self.scan_for_at(tokens[i]) then tokens[i].tag(t); next end
|
9
|
+
if t = self.scan_for_in(tokens[i]) then tokens[i].tag(t); next end
|
10
|
+
if t = self.scan_for_on(tokens[i]) then tokens[i].tag(t); next end
|
11
|
+
end
|
12
|
+
tokens
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.scan_for_commas(token)
|
16
|
+
scanner = {/^,$/ => :comma}
|
17
|
+
scanner.keys.each do |scanner_item|
|
18
|
+
return SeparatorComma.new(scanner[scanner_item]) if scanner_item =~ token.word
|
19
|
+
end
|
20
|
+
return nil
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.scan_for_slash_or_dash(token)
|
24
|
+
scanner = {/^-$/ => :dash,
|
25
|
+
/^\/$/ => :slash}
|
26
|
+
scanner.keys.each do |scanner_item|
|
27
|
+
return SeparatorSlashOrDash.new(scanner[scanner_item]) if scanner_item =~ token.word
|
28
|
+
end
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.scan_for_at(token)
|
33
|
+
scanner = {/^(at|@)$/i => :at}
|
34
|
+
scanner.keys.each do |scanner_item|
|
35
|
+
return SeparatorAt.new(scanner[scanner_item]) if scanner_item =~ token.word
|
36
|
+
end
|
37
|
+
return nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.scan_for_in(token)
|
41
|
+
scanner = {/^in$/i => :in}
|
42
|
+
scanner.keys.each do |scanner_item|
|
43
|
+
return SeparatorIn.new(scanner[scanner_item]) if scanner_item =~ token.word
|
44
|
+
end
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.scan_for_on(token)
|
49
|
+
scanner = {/^on$/i => :on}
|
50
|
+
scanner.keys.each do |scanner_item|
|
51
|
+
return SeparatorOn.new(scanner[scanner_item]) if scanner_item =~ token.word
|
52
|
+
end
|
53
|
+
return nil
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
'separator'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class SeparatorComma < Separator #:nodoc:
|
62
|
+
def to_s
|
63
|
+
super << '-comma'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class SeparatorSlashOrDash < Separator #:nodoc:
|
68
|
+
def to_s
|
69
|
+
super << '-slashordash-' << @type.to_s
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class SeparatorAt < Separator #:nodoc:
|
74
|
+
def to_s
|
75
|
+
super << '-at'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class SeparatorIn < Separator #:nodoc:
|
80
|
+
def to_s
|
81
|
+
super << '-in'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class SeparatorOn < Separator #:nodoc:
|
86
|
+
def to_s
|
87
|
+
super << '-on'
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Chronic
|
2
|
+
class TimeZone < Tag #:nodoc:
|
3
|
+
def self.scan(tokens)
|
4
|
+
tokens.each_index do |i|
|
5
|
+
if t = self.scan_for_all(tokens[i]) then tokens[i].tag(t); next end
|
6
|
+
end
|
7
|
+
tokens
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.scan_for_all(token)
|
11
|
+
if RUBY_VERSION =~ /1\.9\./
|
12
|
+
scanner = {/[PMCE][DS]T/i => :tz}
|
13
|
+
else
|
14
|
+
scanner = {/[PMCE][DS]T/i => :tz, /(tzminus)?[01]\d[304][05]/ => :tz}
|
15
|
+
end
|
16
|
+
scanner.keys.each do |scanner_item|
|
17
|
+
return self.new(scanner[scanner_item]) if scanner_item =~ token.word
|
18
|
+
end
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
'timezone'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
# class Time
|
4
|
+
# def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
5
|
+
# # extra_seconds = second > 60 ? second - 60 : 0
|
6
|
+
# # extra_minutes = minute > 59 ? minute - 59 : 0
|
7
|
+
# # extra_hours = hour > 23 ? hour - 23 : 0
|
8
|
+
# # extra_days = day >
|
9
|
+
#
|
10
|
+
# if month > 12
|
11
|
+
# if month % 12 == 0
|
12
|
+
# year += (month - 12) / 12
|
13
|
+
# month = 12
|
14
|
+
# else
|
15
|
+
# year += month / 12
|
16
|
+
# month = month % 12
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# base = Time.local(year, month)
|
21
|
+
# puts base
|
22
|
+
# offset = ((day - 1) * 24 * 60 * 60) + (hour * 60 * 60) + (minute * 60) + second
|
23
|
+
# puts offset.to_s
|
24
|
+
# date = base + offset
|
25
|
+
# puts date
|
26
|
+
# date
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
|
30
|
+
class Time
|
31
|
+
def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
32
|
+
if second >= 60
|
33
|
+
minute += second / 60
|
34
|
+
second = second % 60
|
35
|
+
end
|
36
|
+
|
37
|
+
if minute >= 60
|
38
|
+
hour += minute / 60
|
39
|
+
minute = minute % 60
|
40
|
+
end
|
41
|
+
|
42
|
+
if hour >= 24
|
43
|
+
day += hour / 24
|
44
|
+
hour = hour % 24
|
45
|
+
end
|
46
|
+
|
47
|
+
# determine if there is a day overflow. this is complicated by our crappy calendar
|
48
|
+
# system (non-constant number of days per month)
|
49
|
+
day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
|
50
|
+
if day > 28
|
51
|
+
# no month ever has fewer than 28 days, so only do this if necessary
|
52
|
+
leap_year = (year % 4 == 0) && !(year % 100 == 0)
|
53
|
+
leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
54
|
+
common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
55
|
+
days_this_month = leap_year ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
|
56
|
+
if day > days_this_month
|
57
|
+
month += day / days_this_month
|
58
|
+
day = day % days_this_month
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if month > 12
|
63
|
+
if month % 12 == 0
|
64
|
+
year += (month - 12) / 12
|
65
|
+
month = 12
|
66
|
+
else
|
67
|
+
year += month / 12
|
68
|
+
month = month % 12
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Chronic.time_class.local(year, month, day, hour, minute, second)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class Numerizer
|
4
|
+
|
5
|
+
DIRECT_NUMS = [
|
6
|
+
['eleven', '11'],
|
7
|
+
['twelve', '12'],
|
8
|
+
['thirteen', '13'],
|
9
|
+
['fourteen', '14'],
|
10
|
+
['fifteen', '15'],
|
11
|
+
['sixteen', '16'],
|
12
|
+
['seventeen', '17'],
|
13
|
+
['eighteen', '18'],
|
14
|
+
['nineteen', '19'],
|
15
|
+
['ninteen', '19'], # Common mis-spelling
|
16
|
+
['zero', '0'],
|
17
|
+
['one', '1'],
|
18
|
+
['two', '2'],
|
19
|
+
['three', '3'],
|
20
|
+
['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
|
21
|
+
['five', '5'],
|
22
|
+
['six(\W|$)', '6\1'],
|
23
|
+
['seven(\W|$)', '7\1'],
|
24
|
+
['eight(\W|$)', '8\1'],
|
25
|
+
['nine(\W|$)', '9\1'],
|
26
|
+
['ten', '10'],
|
27
|
+
['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
|
28
|
+
]
|
29
|
+
|
30
|
+
TEN_PREFIXES = [ ['twenty', 20],
|
31
|
+
['thirty', 30],
|
32
|
+
['forty', 40],
|
33
|
+
['fourty', 40], # Common misspelling
|
34
|
+
['fifty', 50],
|
35
|
+
['sixty', 60],
|
36
|
+
['seventy', 70],
|
37
|
+
['eighty', 80],
|
38
|
+
['ninety', 90]
|
39
|
+
]
|
40
|
+
|
41
|
+
BIG_PREFIXES = [ ['hundred', 100],
|
42
|
+
['thousand', 1000],
|
43
|
+
['million', 1_000_000],
|
44
|
+
['billion', 1_000_000_000],
|
45
|
+
['trillion', 1_000_000_000_000],
|
46
|
+
]
|
47
|
+
|
48
|
+
def self.numerize(string)
|
49
|
+
string = string.dup
|
50
|
+
|
51
|
+
# preprocess
|
52
|
+
string.gsub!(/ +|([^\d])-([^\d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
|
53
|
+
string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
|
54
|
+
|
55
|
+
# easy/direct replacements
|
56
|
+
|
57
|
+
DIRECT_NUMS.each do |dn|
|
58
|
+
string.gsub!(/#{dn[0]}/i, '<num>' + dn[1])
|
59
|
+
end
|
60
|
+
|
61
|
+
# ten, twenty, etc.
|
62
|
+
|
63
|
+
TEN_PREFIXES.each do |tp|
|
64
|
+
string.gsub!(/(?:#{tp[0]}) *<num>(\d(?=[^\d]|$))*/i) { '<num>' + (tp[1] + $1.to_i).to_s }
|
65
|
+
end
|
66
|
+
|
67
|
+
TEN_PREFIXES.each do |tp|
|
68
|
+
string.gsub!(/#{tp[0]}/i) { '<num>' + tp[1].to_s }
|
69
|
+
end
|
70
|
+
|
71
|
+
# hundreds, thousands, millions, etc.
|
72
|
+
|
73
|
+
BIG_PREFIXES.each do |bp|
|
74
|
+
string.gsub!(/(?:<num>)?(\d*) *#{bp[0]}/i) { '<num>' + (bp[1] * $1.to_i).to_s}
|
75
|
+
andition(string)
|
76
|
+
end
|
77
|
+
|
78
|
+
# fractional addition
|
79
|
+
# I'm not combining this with the previous block as using float addition complicates the strings
|
80
|
+
# (with extraneous .0's and such )
|
81
|
+
string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
|
82
|
+
|
83
|
+
string.gsub(/<num>/, '')
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
def self.andition(string)
|
89
|
+
sc = StringScanner.new(string)
|
90
|
+
while(sc.scan_until(/<num>(\d+)( | and )<num>(\d+)(?=[^\w]|$)/i))
|
91
|
+
if sc[2] =~ /and/ || sc[1].size > sc[3].size
|
92
|
+
string[(sc.pos - sc.matched_size)..(sc.pos-1)] = '<num>' + (sc[1].to_i + sc[3].to_i).to_s
|
93
|
+
sc.reset
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path('../../lib/chronic', __FILE__)
|
2
|
+
require 'test/unit'
|
3
|
+
|
4
|
+
class TestChronic < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
# Wed Aug 16 14:00:00 UTC 2006
|
8
|
+
@now = Time.local(2006, 8, 16, 14, 0, 0, 0)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_post_normalize_am_pm_aliases
|
12
|
+
# affect wanted patterns
|
13
|
+
|
14
|
+
tokens = [Chronic::Token.new("5:00"), Chronic::Token.new("morning")]
|
15
|
+
tokens[0].tag(Chronic::RepeaterTime.new("5:00"))
|
16
|
+
tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
|
17
|
+
|
18
|
+
assert_equal :morning, tokens[1].tags[0].type
|
19
|
+
|
20
|
+
tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
|
21
|
+
|
22
|
+
assert_equal :am, tokens[1].tags[0].type
|
23
|
+
assert_equal 2, tokens.size
|
24
|
+
|
25
|
+
# don't affect unwanted patterns
|
26
|
+
|
27
|
+
tokens = [Chronic::Token.new("friday"), Chronic::Token.new("morning")]
|
28
|
+
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
29
|
+
tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
|
30
|
+
|
31
|
+
assert_equal :morning, tokens[1].tags[0].type
|
32
|
+
|
33
|
+
tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
|
34
|
+
|
35
|
+
assert_equal :morning, tokens[1].tags[0].type
|
36
|
+
assert_equal 2, tokens.size
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_guess
|
40
|
+
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0))
|
41
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
|
42
|
+
|
43
|
+
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0, 0, 1))
|
44
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
|
45
|
+
|
46
|
+
span = Chronic::Span.new(Time.local(2006, 11), Time.local(2006, 12))
|
47
|
+
assert_equal Time.local(2006, 11, 16), Chronic.guess(span)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_date_string
|
51
|
+
assert_equal(Chronic.date_string("9pm"), Chronic.date_string("9pm"))
|
52
|
+
assert_equal(Chronic.date_string("9/27/2009"), Chronic.date_string("9/27/2009"))
|
53
|
+
assert_equal(Chronic.date_string("9/27/2009"), Chronic.date_string("Meeting 9/27/2009"))
|
54
|
+
assert_equal(Chronic.date_string("this day"), Chronic.date_string("Meeting today"))
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_tokenize_ignores_trailing_tokens
|
58
|
+
# tokenize will keep tokens like "at" in the string "Meeting 9/27/2009 at the bar" even though it is
|
59
|
+
# not part of the date
|
60
|
+
tokens = Chronic.tokenize("9/27/2009 at")
|
61
|
+
assert_nil(tokens[-1].get_tag(Chronic::Separator), "The last token in this string should not be tagged")
|
62
|
+
assert_equal(Chronic.date_string("9/27/2009"), Chronic.date_string("9/27/2009 at"))
|
63
|
+
|
64
|
+
# test a string with two of the same separator -- one of which will be tagged, one will not
|
65
|
+
separator_test = "Meeting 9/27/2009 at 7pm at the bar"
|
66
|
+
tokens = Chronic.tokenize(separator_test)
|
67
|
+
assert_not_nil(tokens[6].get_tag(Chronic::Separator))
|
68
|
+
assert_nil(tokens[9].get_tag(Chronic::Separator))
|
69
|
+
assert_equal("Meeting at the bar", Chronic.strip_tokens(separator_test))
|
70
|
+
assert_equal(Chronic.date_string("9/27/2009 at 7pm"), Chronic.date_string(separator_test), "date_string does not return the correct date string for <#{separator_test}>")
|
71
|
+
|
72
|
+
# because the trailing "at" separator here is not tagged anymore, it will be part of the strip_tokens string
|
73
|
+
assert_equal("Meeting at the bar", Chronic.strip_tokens("Meeting 9/27/2009 at the bar"))
|
74
|
+
end
|
75
|
+
end
|