chronic 0.8.0 → 0.9.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/HISTORY.md +11 -0
- data/README.md +38 -45
- data/lib/chronic.rb +97 -69
- data/lib/chronic/handler.rb +7 -7
- data/lib/chronic/handlers.rb +68 -21
- data/lib/chronic/{chronic.rb → parser.rb} +52 -134
- data/lib/chronic/repeater.rb +11 -11
- data/lib/chronic/separator.rb +15 -1
- data/test/test_chronic.rb +9 -27
- data/test/test_handler.rb +17 -13
- data/test/test_numerizer.rb +1 -1
- data/test/test_parsing.rb +112 -18
- metadata +4 -3
@@ -1,25 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
# Returns a Hash of default configuration options.
|
4
|
-
DEFAULT_OPTIONS = {
|
5
|
-
:context => :future,
|
6
|
-
:now => nil,
|
7
|
-
:guess => true,
|
8
|
-
:ambiguous_time_range => 6,
|
9
|
-
:endian_precedence => [:middle, :little],
|
10
|
-
:ambiguous_year_future_bias => 50
|
11
|
-
}
|
1
|
+
require 'chronic/handlers'
|
12
2
|
|
13
|
-
|
3
|
+
module Chronic
|
4
|
+
class Parser
|
5
|
+
include Handlers
|
6
|
+
|
7
|
+
# Hash of default configuration options.
|
8
|
+
DEFAULT_OPTIONS = {
|
9
|
+
:context => :future,
|
10
|
+
:now => nil,
|
11
|
+
:guess => true,
|
12
|
+
:ambiguous_time_range => 6,
|
13
|
+
:endian_precedence => [:middle, :little],
|
14
|
+
:ambiguous_year_future_bias => 50
|
15
|
+
}
|
16
|
+
|
17
|
+
attr_accessor :now
|
18
|
+
attr_reader :options
|
14
19
|
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# If the parser can find a date or time, either a Time or Chronic::Span
|
18
|
-
# will be returned (depending on the value of `:guess`). If no
|
19
|
-
# date or time can be found, `nil` will be returned.
|
20
|
-
#
|
21
|
-
# text - The String text to parse.
|
22
|
-
# opts - An optional Hash of configuration options:
|
20
|
+
# options - An optional Hash of configuration options:
|
23
21
|
# :context - If your string represents a birthday, you can set
|
24
22
|
# this value to :past and if an ambiguous string is
|
25
23
|
# given, it will assume it is in the past.
|
@@ -47,31 +45,18 @@ module Chronic
|
|
47
45
|
# look x amount of years into the future and past. If the
|
48
46
|
# two digit year is `now + x years` it's assumed to be the
|
49
47
|
# future, `now - x years` is assumed to be the past.
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
# ensure the specified options are valid
|
56
|
-
(opts.keys - DEFAULT_OPTIONS.keys).each do |key|
|
57
|
-
raise ArgumentError, "#{key} is not a valid option key."
|
58
|
-
end
|
59
|
-
|
60
|
-
unless [:past, :future, :none].include?(options[:context])
|
61
|
-
raise ArgumentError, "Invalid context, :past/:future only"
|
62
|
-
end
|
63
|
-
|
64
|
-
options[:text] = text
|
65
|
-
Chronic.now = options[:now] || Chronic.time_class.now
|
48
|
+
def initialize(options = {})
|
49
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
50
|
+
@now = options.delete(:now) || Chronic.time_class.now
|
51
|
+
end
|
66
52
|
|
67
|
-
|
53
|
+
# Parse "text" with the given options
|
54
|
+
# Returns either a Time or Chronic::Span, depending on the value of options[:guess]
|
55
|
+
def parse(text)
|
68
56
|
tokens = tokenize(text, options)
|
57
|
+
span = tokens_to_span(tokens, options.merge(:text => text))
|
69
58
|
|
70
|
-
if Chronic.debug
|
71
|
-
puts "+#{'-' * 51}\n| #{tokens}\n+#{'-' * 51}"
|
72
|
-
end
|
73
|
-
|
74
|
-
span = tokens_to_span(tokens, options)
|
59
|
+
puts "+#{'-' * 51}\n| #{tokens}\n+#{'-' * 51}" if Chronic.debug
|
75
60
|
|
76
61
|
if span
|
77
62
|
options[:guess] ? guess(span) : span
|
@@ -107,7 +92,7 @@ module Chronic
|
|
107
92
|
text.gsub!(/^second /, '2nd ')
|
108
93
|
text.gsub!(/\bsecond (of|day|month|hour|minute|second)\b/, '2nd \1')
|
109
94
|
text = Numerizer.numerize(text)
|
110
|
-
text.gsub!(
|
95
|
+
text.gsub!(/\-(\d{2}:?\d{2})\b/, 'tzminus\1')
|
111
96
|
text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
|
112
97
|
text.gsub!(/(?:^|\s)0(\d+:\d+\s*pm?\b)/, ' \1')
|
113
98
|
text.gsub!(/\btoday\b/, 'this day')
|
@@ -116,12 +101,17 @@ module Chronic
|
|
116
101
|
text.gsub!(/\bnoon\b/, '12:00pm')
|
117
102
|
text.gsub!(/\bmidnight\b/, '24:00')
|
118
103
|
text.gsub!(/\bnow\b/, 'this second')
|
104
|
+
text.gsub!('quarter', '15')
|
105
|
+
text.gsub!('half', '30')
|
106
|
+
text.gsub!(/(\d{1,2}) (to|till|prior to|before)\b/, '\1 minutes past')
|
107
|
+
text.gsub!(/(\d{1,2}) (after|past)\b/, '\1 minutes future')
|
119
108
|
text.gsub!(/\b(?:ago|before(?: now)?)\b/, 'past')
|
120
109
|
text.gsub!(/\bthis (?:last|past)\b/, 'last')
|
121
110
|
text.gsub!(/\b(?:in|during) the (morning)\b/, '\1')
|
122
111
|
text.gsub!(/\b(?:in the|during the|at) (afternoon|evening|night)\b/, '\1')
|
123
112
|
text.gsub!(/\btonight\b/, 'this night')
|
124
113
|
text.gsub!(/\b\d+:?\d*[ap]\b/,'\0m')
|
114
|
+
text.gsub!(/\b(\d{2})(\d{2})(am|pm)\b/, '\1:\2\3')
|
125
115
|
text.gsub!(/(\d)([ap]m|oclock)\b/, '\1 \2')
|
126
116
|
text.gsub!(/\b(hence|after|from)\b/, 'future')
|
127
117
|
text.gsub!(/^\s?an? /i, '1 ')
|
@@ -129,16 +119,6 @@ module Chronic
|
|
129
119
|
text
|
130
120
|
end
|
131
121
|
|
132
|
-
# Convert number words to numbers (three => 3, fourth => 4th).
|
133
|
-
#
|
134
|
-
# text - The String to convert.
|
135
|
-
#
|
136
|
-
# Returns a new String with words converted to numbers.
|
137
|
-
def numericize_numbers(text)
|
138
|
-
warn "Chronic.numericize_numbers will be deprecated in version 0.7.0. Please use Chronic::Numerizer.numerize instead"
|
139
|
-
Numerizer.numerize(text)
|
140
|
-
end
|
141
|
-
|
142
122
|
# Guess a specific time within the given span.
|
143
123
|
#
|
144
124
|
# span - The Chronic::Span object to calcuate a guess from.
|
@@ -152,17 +132,16 @@ module Chronic
|
|
152
132
|
end
|
153
133
|
end
|
154
134
|
|
155
|
-
# List of Handler definitions. See
|
135
|
+
# List of Handler definitions. See Chronic.parse for a list of options this
|
156
136
|
# method accepts.
|
157
137
|
#
|
158
|
-
# options - An optional Hash of configuration options
|
159
|
-
# :endian_precedence -
|
138
|
+
# options - An optional Hash of configuration options.
|
160
139
|
#
|
161
|
-
# Returns
|
162
|
-
def definitions(options={})
|
140
|
+
# Returns a Hash of Handler definitions.
|
141
|
+
def definitions(options = {})
|
163
142
|
options[:endian_precedence] ||= [:middle, :little]
|
164
143
|
|
165
|
-
|
144
|
+
@@definitions ||= {
|
166
145
|
:time => [
|
167
146
|
Handler.new([:repeater_time, :repeater_day_portion?], nil)
|
168
147
|
],
|
@@ -172,12 +151,15 @@ module Chronic
|
|
172
151
|
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day], :handle_rdn_rmn_sd),
|
173
152
|
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :scalar_year], :handle_rdn_rmn_sd_sy),
|
174
153
|
Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day], :handle_rdn_rmn_od),
|
154
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rdn_rmn_sd),
|
155
|
+
Handler.new([:repeater_day_name, :repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rdn_rmn_od),
|
156
|
+
Handler.new([:repeater_day_name, :ordinal_day, :separator_at?, 'time?'], :handle_rdn_od),
|
175
157
|
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :repeater_time, :time_zone], :handle_generic),
|
176
158
|
Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
|
177
159
|
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
|
178
160
|
Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
|
179
161
|
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
|
180
|
-
Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
|
162
|
+
Handler.new([:repeater_month_name, :separator_slash_or_dash?, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
|
181
163
|
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
|
182
164
|
Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
|
183
165
|
Handler.new([:ordinal_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_od_rmn_sy),
|
@@ -187,29 +169,26 @@ module Chronic
|
|
187
169
|
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
|
188
170
|
Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
|
189
171
|
Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
|
190
|
-
Handler.new([:scalar_day, :repeater_month_name, :separator_at?, 'time?'], :handle_sd_rmn),
|
172
|
+
Handler.new([:scalar_day, :separator_slash_or_dash?, :repeater_month_name, :separator_at?, 'time?'], :handle_sd_rmn),
|
191
173
|
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
|
192
174
|
Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy),
|
193
175
|
Handler.new([:scalar_day, :separator_slash_or_dash, :repeater_month_name, :separator_slash_or_dash, :scalar_year, :repeater_time?], :handle_sm_rmn_sy),
|
194
|
-
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :time_zone], :handle_generic)
|
195
|
-
|
176
|
+
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar?, :time_zone], :handle_generic),
|
196
177
|
],
|
197
178
|
|
198
|
-
# tonight at 7pm
|
199
179
|
:anchor => [
|
200
180
|
Handler.new([:separator_on?, :grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
201
181
|
Handler.new([:grabber?, :repeater, :repeater, :separator?, :repeater?, :repeater?], :handle_r),
|
202
182
|
Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
|
203
183
|
],
|
204
184
|
|
205
|
-
# 3 weeks from now, in 2 months
|
206
185
|
:arrow => [
|
207
186
|
Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
|
187
|
+
Handler.new([:scalar, :repeater, :separator_and?, :scalar, :repeater, :pointer, :separator_at?, 'anchor'], :handle_s_r_a_s_r_p_a),
|
208
188
|
Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
|
209
189
|
Handler.new([:scalar, :repeater, :pointer, :separator_at?, 'anchor'], :handle_s_r_p_a)
|
210
190
|
],
|
211
191
|
|
212
|
-
# 3rd week in march
|
213
192
|
:narrow => [
|
214
193
|
Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
|
215
194
|
Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
|
@@ -225,68 +204,12 @@ module Chronic
|
|
225
204
|
|
226
205
|
case endian = Array(options[:endian_precedence]).first
|
227
206
|
when :little
|
228
|
-
|
207
|
+
@@definitions.merge(:endian => endians.reverse)
|
229
208
|
when :middle
|
230
|
-
|
209
|
+
@@definitions.merge(:endian => endians)
|
231
210
|
else
|
232
211
|
raise ArgumentError, "Unknown endian option '#{endian}'"
|
233
212
|
end
|
234
|
-
|
235
|
-
@definitions
|
236
|
-
end
|
237
|
-
|
238
|
-
# Construct a new time object determining possible month overflows
|
239
|
-
# and leap years.
|
240
|
-
#
|
241
|
-
# year - Integer year.
|
242
|
-
# month - Integer month.
|
243
|
-
# day - Integer day.
|
244
|
-
# hour - Integer hour.
|
245
|
-
# minute - Integer minute.
|
246
|
-
# second - Integer second.
|
247
|
-
#
|
248
|
-
# Returns a new Time object constructed from these params.
|
249
|
-
def construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
|
250
|
-
if second >= 60
|
251
|
-
minute += second / 60
|
252
|
-
second = second % 60
|
253
|
-
end
|
254
|
-
|
255
|
-
if minute >= 60
|
256
|
-
hour += minute / 60
|
257
|
-
minute = minute % 60
|
258
|
-
end
|
259
|
-
|
260
|
-
if hour >= 24
|
261
|
-
day += hour / 24
|
262
|
-
hour = hour % 24
|
263
|
-
end
|
264
|
-
|
265
|
-
# determine if there is a day overflow. this is complicated by our crappy calendar
|
266
|
-
# system (non-constant number of days per month)
|
267
|
-
day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
|
268
|
-
if day > 28
|
269
|
-
# no month ever has fewer than 28 days, so only do this if necessary
|
270
|
-
leap_year_month_days = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
271
|
-
common_year_month_days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
|
272
|
-
days_this_month = Date.leap?(year) ? leap_year_month_days[month - 1] : common_year_month_days[month - 1]
|
273
|
-
if day > days_this_month
|
274
|
-
month += day / days_this_month
|
275
|
-
day = day % days_this_month
|
276
|
-
end
|
277
|
-
end
|
278
|
-
|
279
|
-
if month > 12
|
280
|
-
if month % 12 == 0
|
281
|
-
year += (month - 12) / 12
|
282
|
-
month = 12
|
283
|
-
else
|
284
|
-
year += month / 12
|
285
|
-
month = month % 12
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
Chronic.time_class.local(year, month, day, hour, minute, second)
|
290
213
|
end
|
291
214
|
|
292
215
|
private
|
@@ -306,37 +229,32 @@ module Chronic
|
|
306
229
|
(definitions[:endian] + definitions[:date]).each do |handler|
|
307
230
|
if handler.match(tokens, definitions)
|
308
231
|
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
309
|
-
return handler.invoke(:date, good_tokens, options)
|
232
|
+
return handler.invoke(:date, good_tokens, self, options)
|
310
233
|
end
|
311
234
|
end
|
312
235
|
|
313
236
|
definitions[:anchor].each do |handler|
|
314
237
|
if handler.match(tokens, definitions)
|
315
238
|
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
316
|
-
return handler.invoke(:anchor, good_tokens, options)
|
239
|
+
return handler.invoke(:anchor, good_tokens, self, options)
|
317
240
|
end
|
318
241
|
end
|
319
242
|
|
320
243
|
definitions[:arrow].each do |handler|
|
321
244
|
if handler.match(tokens, definitions)
|
322
|
-
good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
|
323
|
-
return handler.invoke(:arrow, good_tokens, options)
|
245
|
+
good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) || o.get_tag(SeparatorAnd) }
|
246
|
+
return handler.invoke(:arrow, good_tokens, self, options)
|
324
247
|
end
|
325
248
|
end
|
326
249
|
|
327
250
|
definitions[:narrow].each do |handler|
|
328
251
|
if handler.match(tokens, definitions)
|
329
|
-
return handler.invoke(:narrow, tokens, options)
|
252
|
+
return handler.invoke(:narrow, tokens, self, options)
|
330
253
|
end
|
331
254
|
end
|
332
255
|
|
333
256
|
puts "-none" if Chronic.debug
|
334
257
|
return nil
|
335
258
|
end
|
336
|
-
|
337
|
-
end
|
338
|
-
|
339
|
-
# Internal exception
|
340
|
-
class ChronicPain < Exception
|
341
259
|
end
|
342
260
|
end
|
data/lib/chronic/repeater.rb
CHANGED
@@ -38,18 +38,18 @@ module Chronic
|
|
38
38
|
def self.scan_for_month_names(token)
|
39
39
|
scan_for token, RepeaterMonthName,
|
40
40
|
{
|
41
|
-
/^jan
|
42
|
-
/^feb
|
43
|
-
/^mar
|
44
|
-
/^apr
|
41
|
+
/^jan[:\.]?(uary)?$/ => :january,
|
42
|
+
/^feb[:\.]?(ruary)?$/ => :february,
|
43
|
+
/^mar[:\.]?(ch)?$/ => :march,
|
44
|
+
/^apr[:\.]?(il)?$/ => :april,
|
45
45
|
/^may$/ => :may,
|
46
|
-
/^jun
|
47
|
-
/^jul
|
48
|
-
/^aug
|
49
|
-
/^sep
|
50
|
-
/^oct
|
51
|
-
/^nov
|
52
|
-
/^dec
|
46
|
+
/^jun[:\.]?e?$/ => :june,
|
47
|
+
/^jul[:\.]?y?$/ => :july,
|
48
|
+
/^aug[:\.]?(ust)?$/ => :august,
|
49
|
+
/^sep[:\.]?(t[:\.]?|tember)?$/ => :september,
|
50
|
+
/^oct[:\.]?(ober)?$/ => :october,
|
51
|
+
/^nov[:\.]?(ember)?$/ => :november,
|
52
|
+
/^dec[:\.]?(ember)?$/ => :december
|
53
53
|
}
|
54
54
|
end
|
55
55
|
|
data/lib/chronic/separator.rb
CHANGED
@@ -15,6 +15,7 @@ module Chronic
|
|
15
15
|
if t = scan_for_at(token) then token.tag(t); next end
|
16
16
|
if t = scan_for_in(token) then token.tag(t); next end
|
17
17
|
if t = scan_for_on(token) then token.tag(t); next end
|
18
|
+
if t = scan_for_and(token) then token.tag(t); next end
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -57,6 +58,13 @@ module Chronic
|
|
57
58
|
scan_for token, SeparatorOn, { /^on$/ => :on }
|
58
59
|
end
|
59
60
|
|
61
|
+
# token - The Token object we want to scan.
|
62
|
+
#
|
63
|
+
# Returns a new SeperatorAnd Object object.
|
64
|
+
def self.scan_for_and(token)
|
65
|
+
scan_for token, SeparatorAnd, { /^and$/ => :and }
|
66
|
+
end
|
67
|
+
|
60
68
|
def to_s
|
61
69
|
'separator'
|
62
70
|
end
|
@@ -91,4 +99,10 @@ module Chronic
|
|
91
99
|
super << '-on'
|
92
100
|
end
|
93
101
|
end
|
94
|
-
|
102
|
+
|
103
|
+
class SeparatorAnd < Separator #:nodoc:
|
104
|
+
def to_s
|
105
|
+
super << '-and'
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
data/test/test_chronic.rb
CHANGED
@@ -8,12 +8,12 @@ class TestChronic < TestCase
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def test_pre_normalize
|
11
|
-
assert_equal Chronic.pre_normalize('12:55 pm'), Chronic.pre_normalize('12.55 pm')
|
11
|
+
assert_equal Chronic::Parser.new.pre_normalize('12:55 pm'), Chronic::Parser.new.pre_normalize('12.55 pm')
|
12
12
|
end
|
13
13
|
|
14
14
|
def test_pre_normalize_numerized_string
|
15
15
|
string = 'two and a half years'
|
16
|
-
assert_equal Chronic::Numerizer.numerize(string), Chronic.pre_normalize(string)
|
16
|
+
assert_equal Chronic::Numerizer.numerize(string), Chronic::Parser.new.pre_normalize(string)
|
17
17
|
end
|
18
18
|
|
19
19
|
def test_post_normalize_am_pm_aliases
|
@@ -46,21 +46,13 @@ class TestChronic < TestCase
|
|
46
46
|
|
47
47
|
def test_guess
|
48
48
|
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0))
|
49
|
-
assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
|
49
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic::Parser.new.guess(span)
|
50
50
|
|
51
51
|
span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0, 0, 1))
|
52
|
-
assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
|
52
|
+
assert_equal Time.local(2006, 8, 16, 12), Chronic::Parser.new.guess(span)
|
53
53
|
|
54
54
|
span = Chronic::Span.new(Time.local(2006, 11), Time.local(2006, 12))
|
55
|
-
assert_equal Time.local(2006, 11, 16), Chronic.guess(span)
|
56
|
-
end
|
57
|
-
|
58
|
-
def test_now
|
59
|
-
Chronic.parse('now', :now => Time.local(2006, 01))
|
60
|
-
assert_equal Time.local(2006, 01), Chronic.now
|
61
|
-
|
62
|
-
Chronic.parse('now', :now => Time.local(2007, 01))
|
63
|
-
assert_equal Time.local(2007, 01), Chronic.now
|
55
|
+
assert_equal Time.local(2006, 11, 16), Chronic::Parser.new.guess(span)
|
64
56
|
end
|
65
57
|
|
66
58
|
def test_endian_definitions
|
@@ -72,26 +64,16 @@ class TestChronic < TestCase
|
|
72
64
|
Chronic::Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
|
73
65
|
]
|
74
66
|
|
75
|
-
assert_equal endians, Chronic.definitions[:endian]
|
67
|
+
assert_equal endians, Chronic::Parser.new.definitions[:endian]
|
76
68
|
|
77
|
-
defs = Chronic.definitions(:endian_precedence => :little)
|
69
|
+
defs = Chronic::Parser.new.definitions(:endian_precedence => :little)
|
78
70
|
assert_equal endians.reverse, defs[:endian]
|
79
71
|
|
80
|
-
defs = Chronic.definitions(:endian_precedence => [:little, :middle])
|
72
|
+
defs = Chronic::Parser.new.definitions(:endian_precedence => [:little, :middle])
|
81
73
|
assert_equal endians.reverse, defs[:endian]
|
82
74
|
|
83
75
|
assert_raises(ArgumentError) do
|
84
|
-
Chronic.definitions(:endian_precedence => :invalid)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def test_passing_options
|
89
|
-
assert_raises(ArgumentError) do
|
90
|
-
Chronic.parse('now', :invalid => :option)
|
91
|
-
end
|
92
|
-
|
93
|
-
assert_raises(ArgumentError) do
|
94
|
-
Chronic.parse('now', :context => :invalid_context)
|
76
|
+
Chronic::Parser.new.definitions(:endian_precedence => :invalid)
|
95
77
|
end
|
96
78
|
end
|
97
79
|
|
data/test/test_handler.rb
CHANGED
@@ -7,18 +7,22 @@ class TestHandler < TestCase
|
|
7
7
|
@now = Time.local(2006, 8, 16, 14, 0, 0, 0)
|
8
8
|
end
|
9
9
|
|
10
|
+
def definitions
|
11
|
+
@definitions ||= Chronic::Parser.new.definitions
|
12
|
+
end
|
13
|
+
|
10
14
|
def test_handler_class_1
|
11
15
|
handler = Chronic::Handler.new([:repeater], :handler)
|
12
16
|
|
13
17
|
tokens = [Chronic::Token.new('friday')]
|
14
18
|
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
15
19
|
|
16
|
-
assert handler.match(tokens,
|
20
|
+
assert handler.match(tokens, definitions)
|
17
21
|
|
18
22
|
tokens << Chronic::Token.new('afternoon')
|
19
23
|
tokens[1].tag(Chronic::RepeaterDayPortion.new(:afternoon))
|
20
24
|
|
21
|
-
assert !handler.match(tokens,
|
25
|
+
assert !handler.match(tokens, definitions)
|
22
26
|
end
|
23
27
|
|
24
28
|
def test_handler_class_2
|
@@ -27,17 +31,17 @@ class TestHandler < TestCase
|
|
27
31
|
tokens = [Chronic::Token.new('friday')]
|
28
32
|
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
29
33
|
|
30
|
-
assert handler.match(tokens,
|
34
|
+
assert handler.match(tokens, definitions)
|
31
35
|
|
32
36
|
tokens << Chronic::Token.new('afternoon')
|
33
37
|
tokens[1].tag(Chronic::RepeaterDayPortion.new(:afternoon))
|
34
38
|
|
35
|
-
assert handler.match(tokens,
|
39
|
+
assert handler.match(tokens, definitions)
|
36
40
|
|
37
41
|
tokens << Chronic::Token.new('afternoon')
|
38
42
|
tokens[2].tag(Chronic::RepeaterDayPortion.new(:afternoon))
|
39
43
|
|
40
|
-
assert !handler.match(tokens,
|
44
|
+
assert !handler.match(tokens, definitions)
|
41
45
|
end
|
42
46
|
|
43
47
|
def test_handler_class_3
|
@@ -46,12 +50,12 @@ class TestHandler < TestCase
|
|
46
50
|
tokens = [Chronic::Token.new('friday')]
|
47
51
|
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
48
52
|
|
49
|
-
assert handler.match(tokens,
|
53
|
+
assert handler.match(tokens, definitions)
|
50
54
|
|
51
55
|
tokens << Chronic::Token.new('afternoon')
|
52
56
|
tokens[1].tag(Chronic::RepeaterDayPortion.new(:afternoon))
|
53
57
|
|
54
|
-
assert !handler.match(tokens,
|
58
|
+
assert !handler.match(tokens, definitions)
|
55
59
|
end
|
56
60
|
|
57
61
|
def test_handler_class_4
|
@@ -60,12 +64,12 @@ class TestHandler < TestCase
|
|
60
64
|
tokens = [Chronic::Token.new('may')]
|
61
65
|
tokens[0].tag(Chronic::RepeaterMonthName.new(:may))
|
62
66
|
|
63
|
-
assert !handler.match(tokens,
|
67
|
+
assert !handler.match(tokens, definitions)
|
64
68
|
|
65
69
|
tokens << Chronic::Token.new('27')
|
66
70
|
tokens[1].tag(Chronic::ScalarDay.new(27))
|
67
71
|
|
68
|
-
assert handler.match(tokens,
|
72
|
+
assert handler.match(tokens, definitions)
|
69
73
|
end
|
70
74
|
|
71
75
|
def test_handler_class_5
|
@@ -74,17 +78,17 @@ class TestHandler < TestCase
|
|
74
78
|
tokens = [Chronic::Token.new('friday')]
|
75
79
|
tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
|
76
80
|
|
77
|
-
assert handler.match(tokens,
|
81
|
+
assert handler.match(tokens, definitions)
|
78
82
|
|
79
83
|
tokens << Chronic::Token.new('5:00')
|
80
84
|
tokens[1].tag(Chronic::RepeaterTime.new('5:00'))
|
81
85
|
|
82
|
-
assert handler.match(tokens,
|
86
|
+
assert handler.match(tokens, definitions)
|
83
87
|
|
84
88
|
tokens << Chronic::Token.new('pm')
|
85
89
|
tokens[2].tag(Chronic::RepeaterDayPortion.new(:pm))
|
86
90
|
|
87
|
-
assert handler.match(tokens,
|
91
|
+
assert handler.match(tokens, definitions)
|
88
92
|
end
|
89
93
|
|
90
94
|
def test_handler_class_6
|
@@ -98,7 +102,7 @@ class TestHandler < TestCase
|
|
98
102
|
tokens[1].tag(Chronic::RepeaterYear.new(:year))
|
99
103
|
tokens[2].tag(Chronic::Pointer.new(:past))
|
100
104
|
|
101
|
-
assert handler.match(tokens,
|
105
|
+
assert handler.match(tokens, definitions)
|
102
106
|
end
|
103
107
|
|
104
108
|
end
|