chronic 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.md +9 -2
- data/Rakefile +0 -8
- data/chronic.gemspec +1 -1
- data/lib/chronic.rb +60 -47
- data/lib/chronic/chronic.rb +221 -90
- data/lib/chronic/grabber.rb +10 -1
- data/lib/chronic/handlers.rb +44 -186
- data/lib/chronic/mini_date.rb +6 -2
- data/lib/chronic/ordinal.rb +12 -1
- data/lib/chronic/pointer.rb +10 -1
- data/lib/chronic/repeater.rb +20 -1
- data/lib/chronic/repeaters/repeater_month.rb +13 -1
- data/lib/chronic/scalar.rb +29 -1
- data/lib/chronic/separator.rb +18 -1
- data/lib/chronic/time_zone.rb +10 -1
- data/lib/chronic/token.rb +14 -4
- data/test/test_Chronic.rb +52 -2
- data/test/test_RepeaterMonth.rb +4 -0
- metadata +2 -2
data/lib/chronic/grabber.rb
CHANGED
@@ -1,11 +1,20 @@
|
|
1
1
|
module Chronic
|
2
|
-
class Grabber < Tag
|
2
|
+
class Grabber < Tag
|
3
|
+
|
4
|
+
# Scan an Array of {Token}s and apply any necessary Grabber tags to
|
5
|
+
# each token
|
6
|
+
#
|
7
|
+
# @param [Array<Token>] tokens Array of tokens to scan
|
8
|
+
# @param [Hash] options Options specified in {Chronic.parse}
|
9
|
+
# @return [Array] list of tokens
|
3
10
|
def self.scan(tokens, options)
|
4
11
|
tokens.each_index do |i|
|
5
12
|
if t = scan_for_all(tokens[i]) then tokens[i].tag(t); next end
|
6
13
|
end
|
7
14
|
end
|
8
15
|
|
16
|
+
# @param [Token] token
|
17
|
+
# @return [Grabber, nil]
|
9
18
|
def self.scan_for_all(token)
|
10
19
|
scan_for token, self,
|
11
20
|
{
|
data/lib/chronic/handlers.rb
CHANGED
@@ -1,156 +1,10 @@
|
|
1
1
|
module Chronic
|
2
|
+
module Handlers
|
3
|
+
module_function
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
def definitions(options={}) #:nodoc:
|
6
|
-
options[:endian_precedence] ||= [:middle, :little]
|
7
|
-
# ensure the endian precedence is exactly two elements long
|
8
|
-
raise ChronicPain, "More than two elements specified for endian precedence array" unless options[:endian_precedence].length == 2
|
9
|
-
|
10
|
-
# handler for dd/mm/yyyy
|
11
|
-
@little_endian_handler ||= Handler.new([:scalar_day, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sd_sm_sy)
|
12
|
-
|
13
|
-
# handler for mm/dd/yyyy
|
14
|
-
@middle_endian_handler ||= Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_day, :separator_slash_or_dash, :scalar_year, :separator_at?, 'time?'], :handle_sm_sd_sy)
|
15
|
-
|
16
|
-
# ensure we have valid endian values
|
17
|
-
options[:endian_precedence].each do |e|
|
18
|
-
raise ChronicPain, "Unknown endian type: #{e.to_s}" unless instance_variable_defined?(endian_variable_name_for(e))
|
19
|
-
end
|
20
|
-
|
21
|
-
@definitions ||= {
|
22
|
-
:time => [
|
23
|
-
Handler.new([:repeater_time, :repeater_day_portion?], nil)
|
24
|
-
],
|
25
|
-
|
26
|
-
:date => [
|
27
|
-
Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :separator_slash_or_dash?, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
|
28
|
-
Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
|
29
|
-
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
|
30
|
-
Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
|
31
|
-
Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
|
32
|
-
Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
|
33
|
-
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
|
34
|
-
Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
|
35
|
-
Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
|
36
|
-
Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
|
37
|
-
Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
|
38
|
-
@middle_endian_handler,
|
39
|
-
@little_endian_handler,
|
40
|
-
Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
|
41
|
-
Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)
|
42
|
-
],
|
43
|
-
|
44
|
-
# tonight at 7pm
|
45
|
-
:anchor => [
|
46
|
-
Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
47
|
-
Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
|
48
|
-
Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
|
49
|
-
],
|
50
|
-
|
51
|
-
# 3 weeks from now, in 2 months
|
52
|
-
:arrow => [
|
53
|
-
Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
|
54
|
-
Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
|
55
|
-
Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)
|
56
|
-
],
|
57
|
-
|
58
|
-
# 3rd week in march
|
59
|
-
:narrow => [
|
60
|
-
Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
|
61
|
-
Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
|
62
|
-
]
|
63
|
-
}
|
64
|
-
|
65
|
-
apply_endian_precedences(options[:endian_precedence])
|
66
|
-
|
67
|
-
@definitions
|
68
|
-
end
|
69
|
-
|
70
|
-
def tokens_to_span(tokens, options) #:nodoc:
|
71
|
-
# maybe it's a specific date
|
72
|
-
|
73
|
-
definitions = self.definitions(options)
|
74
|
-
definitions[:date].each do |handler|
|
75
|
-
if handler.match(tokens, definitions)
|
76
|
-
puts "-date" if Chronic.debug
|
77
|
-
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
78
|
-
return self.send(handler.handler_method, good_tokens, options)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# I guess it's not a specific date, maybe it's just an anchor
|
83
|
-
|
84
|
-
definitions[:anchor].each do |handler|
|
85
|
-
if handler.match(tokens, definitions)
|
86
|
-
puts "-anchor" if Chronic.debug
|
87
|
-
good_tokens = tokens.select { |o| !o.get_tag Separator }
|
88
|
-
return self.send(handler.handler_method, good_tokens, options)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# not an anchor, perhaps it's an arrow
|
93
|
-
|
94
|
-
definitions[:arrow].each do |handler|
|
95
|
-
if handler.match(tokens, definitions)
|
96
|
-
puts "-arrow" if Chronic.debug
|
97
|
-
good_tokens = tokens.reject { |o| o.get_tag(SeparatorAt) || o.get_tag(SeparatorSlashOrDash) || o.get_tag(SeparatorComma) }
|
98
|
-
return self.send(handler.handler_method, good_tokens, options)
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# not an arrow, let's hope it's a narrow
|
103
|
-
|
104
|
-
definitions[:narrow].each do |handler|
|
105
|
-
if handler.match(tokens, definitions)
|
106
|
-
puts "-narrow" if Chronic.debug
|
107
|
-
#good_tokens = tokens.select { |o| !o.get_tag Separator }
|
108
|
-
return self.send(handler.handler_method, tokens, options)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
# I guess you're out of luck!
|
113
|
-
puts "-none" if Chronic.debug
|
114
|
-
return nil
|
115
|
-
end
|
116
|
-
|
117
|
-
#--------------
|
118
|
-
|
119
|
-
def apply_endian_precedences(precedences)
|
120
|
-
date_defs = @definitions[:date]
|
121
|
-
|
122
|
-
# map the precedence array to indices on @definitions[:date]
|
123
|
-
indices = precedences.map { |e|
|
124
|
-
handler = instance_variable_get(endian_variable_name_for(e))
|
125
|
-
date_defs.index(handler)
|
126
|
-
}
|
127
|
-
|
128
|
-
# swap the handlers if we discover they are at odds with the desired preferences
|
129
|
-
swap(date_defs, indices.first, indices.last) if indices.first > indices.last
|
130
|
-
end
|
131
|
-
|
132
|
-
def endian_variable_name_for(e)
|
133
|
-
"@#{e.to_s}_endian_handler".to_sym
|
134
|
-
end
|
135
|
-
|
136
|
-
# exchange two elements in an array
|
137
|
-
def swap(arr, a, b); arr[a], arr[b] = arr[b], arr[a]; end
|
138
|
-
|
139
|
-
def day_or_time(day_start, time_tokens, options)
|
140
|
-
outer_span = Span.new(day_start, day_start + (24 * 60 * 60))
|
141
|
-
|
142
|
-
if !time_tokens.empty?
|
143
|
-
@now = outer_span.begin
|
144
|
-
get_anchor(dealias_and_disambiguate_times(time_tokens, options), options)
|
145
|
-
else
|
146
|
-
outer_span
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
#--------------
|
151
|
-
|
5
|
+
# Handle month/day
|
152
6
|
def handle_m_d(month, day, time_tokens, options) #:nodoc:
|
153
|
-
month.start =
|
7
|
+
month.start = Chronic.now
|
154
8
|
span = month.this(options[:context])
|
155
9
|
|
156
10
|
day_start = Chronic.time_class.local(span.begin.year, span.begin.month, day)
|
@@ -158,10 +12,12 @@ module Chronic
|
|
158
12
|
day_or_time(day_start, time_tokens, options)
|
159
13
|
end
|
160
14
|
|
15
|
+
# Handle repeater-month-name/scalar-day
|
161
16
|
def handle_rmn_sd(tokens, options) #:nodoc:
|
162
17
|
handle_m_d(tokens[0].get_tag(RepeaterMonthName), tokens[1].get_tag(ScalarDay).type, tokens[2..tokens.size], options)
|
163
18
|
end
|
164
19
|
|
20
|
+
# Handle repeater-month-name/scalar-day with separator-on
|
165
21
|
def handle_rmn_sd_on(tokens, options) #:nodoc:
|
166
22
|
if tokens.size > 3
|
167
23
|
handle_m_d(tokens[2].get_tag(RepeaterMonthName), tokens[3].get_tag(ScalarDay).type, tokens[0..1], options)
|
@@ -170,10 +26,12 @@ module Chronic
|
|
170
26
|
end
|
171
27
|
end
|
172
28
|
|
29
|
+
# Handle repeater-month-name/ordinal-day
|
173
30
|
def handle_rmn_od(tokens, options) #:nodoc:
|
174
31
|
handle_m_d(tokens[0].get_tag(RepeaterMonthName), tokens[1].get_tag(OrdinalDay).type, tokens[2..tokens.size], options)
|
175
32
|
end
|
176
33
|
|
34
|
+
# Handle repeater-month-name/ordinal-day with separator-on
|
177
35
|
def handle_rmn_od_on(tokens, options) #:nodoc:
|
178
36
|
if tokens.size > 3
|
179
37
|
handle_m_d(tokens[2].get_tag(RepeaterMonthName), tokens[3].get_tag(OrdinalDay).type, tokens[0..1], options)
|
@@ -182,6 +40,7 @@ module Chronic
|
|
182
40
|
end
|
183
41
|
end
|
184
42
|
|
43
|
+
# Handle repeater-month-name/scalar-year
|
185
44
|
def handle_rmn_sy(tokens, options) #:nodoc:
|
186
45
|
month = tokens[0].get_tag(RepeaterMonthName).index
|
187
46
|
year = tokens[1].get_tag(ScalarYear).type
|
@@ -201,11 +60,13 @@ module Chronic
|
|
201
60
|
end
|
202
61
|
end
|
203
62
|
|
63
|
+
# Handle generic timestamp
|
204
64
|
def handle_rdn_rmn_sd_t_tz_sy(tokens, options) #:nodoc:
|
205
|
-
t = Chronic.time_class.parse(
|
65
|
+
t = Chronic.time_class.parse(options[:text])
|
206
66
|
Span.new(t, t + 1)
|
207
67
|
end
|
208
68
|
|
69
|
+
# Handle repeater-month-name/scalar-day/scalar-year
|
209
70
|
def handle_rmn_sd_sy(tokens, options) #:nodoc:
|
210
71
|
month = tokens[0].get_tag(RepeaterMonthName).index
|
211
72
|
day = tokens[1].get_tag(ScalarDay).type
|
@@ -221,6 +82,7 @@ module Chronic
|
|
221
82
|
end
|
222
83
|
end
|
223
84
|
|
85
|
+
# Handle repeater-month-name/ordinal-day/scalar-year
|
224
86
|
def handle_rmn_od_sy(tokens, options) #:nodoc:
|
225
87
|
month = tokens[0].get_tag(RepeaterMonthName).index
|
226
88
|
day = tokens[1].get_tag(OrdinalDay).type
|
@@ -236,12 +98,14 @@ module Chronic
|
|
236
98
|
end
|
237
99
|
end
|
238
100
|
|
101
|
+
# Handle scalar-day/repeater-month-name/scalar-year
|
239
102
|
def handle_sd_rmn_sy(tokens, options) #:nodoc:
|
240
103
|
new_tokens = [tokens[1], tokens[0], tokens[2]]
|
241
104
|
time_tokens = tokens.last(tokens.size - 3)
|
242
105
|
self.handle_rmn_sd_sy(new_tokens + time_tokens, options)
|
243
106
|
end
|
244
107
|
|
108
|
+
# Handle scalar-month/scalar-day/scalar-year (endian middle)
|
245
109
|
def handle_sm_sd_sy(tokens, options) #:nodoc:
|
246
110
|
month = tokens[0].get_tag(ScalarMonth).type
|
247
111
|
day = tokens[1].get_tag(ScalarDay).type
|
@@ -257,18 +121,21 @@ module Chronic
|
|
257
121
|
end
|
258
122
|
end
|
259
123
|
|
124
|
+
# Handle scalar-day/scalar-month/scalar-year (endian little)
|
260
125
|
def handle_sd_sm_sy(tokens, options) #:nodoc:
|
261
126
|
new_tokens = [tokens[1], tokens[0], tokens[2]]
|
262
127
|
time_tokens = tokens.last(tokens.size - 3)
|
263
128
|
self.handle_sm_sd_sy(new_tokens + time_tokens, options)
|
264
129
|
end
|
265
130
|
|
131
|
+
# Handle scalar-year/scalar-month/scalar-day
|
266
132
|
def handle_sy_sm_sd(tokens, options) #:nodoc:
|
267
133
|
new_tokens = [tokens[1], tokens[2], tokens[0]]
|
268
134
|
time_tokens = tokens.last(tokens.size - 3)
|
269
135
|
self.handle_sm_sd_sy(new_tokens + time_tokens, options)
|
270
136
|
end
|
271
137
|
|
138
|
+
# Handle scalar-month/scalar-year
|
272
139
|
def handle_sm_sy(tokens, options) #:nodoc:
|
273
140
|
month = tokens[0].get_tag(ScalarMonth).type
|
274
141
|
year = tokens[1].get_tag(ScalarYear).type
|
@@ -290,11 +157,13 @@ module Chronic
|
|
290
157
|
|
291
158
|
# anchors
|
292
159
|
|
160
|
+
# Handle repeaters
|
293
161
|
def handle_r(tokens, options) #:nodoc:
|
294
162
|
dd_tokens = dealias_and_disambiguate_times(tokens, options)
|
295
163
|
self.get_anchor(dd_tokens, options)
|
296
164
|
end
|
297
165
|
|
166
|
+
# Handle repeater/grabber/repeater
|
298
167
|
def handle_r_g_r(tokens, options) #:nodoc:
|
299
168
|
new_tokens = [tokens[1], tokens[0], tokens[2]]
|
300
169
|
self.handle_r(new_tokens, options)
|
@@ -302,6 +171,7 @@ module Chronic
|
|
302
171
|
|
303
172
|
# arrows
|
304
173
|
|
174
|
+
# Handle scalar/repeater/pointer helper
|
305
175
|
def handle_srp(tokens, span, options) #:nodoc:
|
306
176
|
distance = tokens[0].get_tag(Scalar).type
|
307
177
|
repeater = tokens[1].get_tag(Repeater)
|
@@ -310,31 +180,21 @@ module Chronic
|
|
310
180
|
repeater.offset(span, distance, pointer)
|
311
181
|
end
|
312
182
|
|
183
|
+
# Handle scalar/repeater/pointer
|
313
184
|
def handle_s_r_p(tokens, options) #:nodoc:
|
314
185
|
repeater = tokens[1].get_tag(Repeater)
|
315
|
-
|
316
|
-
# span =
|
317
|
-
# case true
|
318
|
-
# when [RepeaterYear, RepeaterSeason, RepeaterSeasonName, RepeaterMonth, RepeaterMonthName, RepeaterFortnight, RepeaterWeek].include?(repeater.class)
|
319
|
-
# self.parse("this hour", :guess => false, :now => @now)
|
320
|
-
# when [RepeaterWeekend, RepeaterDay, RepeaterDayName, RepeaterDayPortion, RepeaterHour].include?(repeater.class)
|
321
|
-
# self.parse("this minute", :guess => false, :now => @now)
|
322
|
-
# when [RepeaterMinute, RepeaterSecond].include?(repeater.class)
|
323
|
-
# self.parse("this second", :guess => false, :now => @now)
|
324
|
-
# else
|
325
|
-
# raise(ChronicPain, "Invalid repeater: #{repeater.class}")
|
326
|
-
# end
|
327
|
-
|
328
|
-
span = Span.new(@now, @now + 1)
|
186
|
+
span = Span.new(Chronic.now, Chronic.now + 1)
|
329
187
|
|
330
188
|
self.handle_srp(tokens, span, options)
|
331
189
|
end
|
332
190
|
|
191
|
+
# Handle pointer/scalar/repeater
|
333
192
|
def handle_p_s_r(tokens, options) #:nodoc:
|
334
193
|
new_tokens = [tokens[1], tokens[2], tokens[0]]
|
335
194
|
self.handle_s_r_p(new_tokens, options)
|
336
195
|
end
|
337
196
|
|
197
|
+
# Handle scalar/repeater/pointer/anchor
|
338
198
|
def handle_s_r_p_a(tokens, options) #:nodoc:
|
339
199
|
anchor_span = get_anchor(tokens[3..tokens.size - 1], options)
|
340
200
|
self.handle_srp(tokens, anchor_span, options)
|
@@ -342,6 +202,7 @@ module Chronic
|
|
342
202
|
|
343
203
|
# narrows
|
344
204
|
|
205
|
+
# Handle oridinal repeaters
|
345
206
|
def handle_orr(tokens, outer_span, options) #:nodoc:
|
346
207
|
repeater = tokens[1].get_tag(Repeater)
|
347
208
|
repeater.start = outer_span.begin - 1
|
@@ -357,11 +218,13 @@ module Chronic
|
|
357
218
|
span
|
358
219
|
end
|
359
220
|
|
221
|
+
# Handle ordinal/repeater/separator/repeater
|
360
222
|
def handle_o_r_s_r(tokens, options) #:nodoc:
|
361
223
|
outer_span = get_anchor([tokens[3]], options)
|
362
224
|
handle_orr(tokens[0..1], outer_span, options)
|
363
225
|
end
|
364
226
|
|
227
|
+
# Handle ordinal/repeater/grabber/repeater
|
365
228
|
def handle_o_r_g_r(tokens, options) #:nodoc:
|
366
229
|
outer_span = get_anchor(tokens[2..3], options)
|
367
230
|
handle_orr(tokens[0..1], outer_span, options)
|
@@ -369,6 +232,17 @@ module Chronic
|
|
369
232
|
|
370
233
|
# support methods
|
371
234
|
|
235
|
+
def day_or_time(day_start, time_tokens, options)
|
236
|
+
outer_span = Span.new(day_start, day_start + (24 * 60 * 60))
|
237
|
+
|
238
|
+
if !time_tokens.empty?
|
239
|
+
Chronic.now = outer_span.begin
|
240
|
+
get_anchor(dealias_and_disambiguate_times(time_tokens, options), options)
|
241
|
+
else
|
242
|
+
outer_span
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
372
246
|
def get_anchor(tokens, options) #:nodoc:
|
373
247
|
grabber = Grabber.new(:this)
|
374
248
|
pointer = :future
|
@@ -382,7 +256,7 @@ module Chronic
|
|
382
256
|
end
|
383
257
|
|
384
258
|
head = repeaters.shift
|
385
|
-
head.start =
|
259
|
+
head.start = Chronic.now
|
386
260
|
|
387
261
|
case grabber.type
|
388
262
|
when :last
|
@@ -404,8 +278,8 @@ module Chronic
|
|
404
278
|
|
405
279
|
def get_repeaters(tokens) #:nodoc:
|
406
280
|
repeaters = []
|
407
|
-
|
408
|
-
|
281
|
+
tokens.each do |token|
|
282
|
+
if t = token.get_tag(Repeater)
|
409
283
|
repeaters << t
|
410
284
|
end
|
411
285
|
end
|
@@ -464,21 +338,6 @@ module Chronic
|
|
464
338
|
end
|
465
339
|
end
|
466
340
|
|
467
|
-
# tokens.each_with_index do |t0, i|
|
468
|
-
# t1 = tokens[i + 1]
|
469
|
-
# if t1 && (t1tag = t1.get_tag(RepeaterDayPortion)) && t0.get_tag(RepeaterTime)
|
470
|
-
# if [:morning].include?(t1tag.type)
|
471
|
-
# puts '--morning->am' if Chronic.debug
|
472
|
-
# t1.untag(RepeaterDayPortion)
|
473
|
-
# t1.tag(RepeaterDayPortion.new(:am))
|
474
|
-
# elsif [:afternoon, :evening, :night].include?(t1tag.type)
|
475
|
-
# puts "--#{t1tag.type}->pm" if Chronic.debug
|
476
|
-
# t1.untag(RepeaterDayPortion)
|
477
|
-
# t1.tag(RepeaterDayPortion.new(:pm))
|
478
|
-
# end
|
479
|
-
# end
|
480
|
-
# end
|
481
|
-
|
482
341
|
# handle ambiguous times if :ambiguous_time_range is specified
|
483
342
|
if options[:ambiguous_time_range] != :none
|
484
343
|
ttokens = []
|
@@ -508,15 +367,14 @@ module Chronic
|
|
508
367
|
end
|
509
368
|
|
510
369
|
def constantize(name)
|
511
|
-
|
512
|
-
::Chronic.module_eval(camel, __FILE__, __LINE__)
|
370
|
+
Chronic.const_get name.to_s.gsub(/(^|_)(.)/) { $2.upcase }
|
513
371
|
end
|
514
372
|
|
515
373
|
def match(tokens, definitions)
|
516
374
|
token_index = 0
|
517
375
|
@pattern.each do |element|
|
518
376
|
name = element.to_s
|
519
|
-
optional = name
|
377
|
+
optional = name[-1, 1] == '?'
|
520
378
|
name = name.chop if optional
|
521
379
|
if element.instance_of? Symbol
|
522
380
|
klass = constantize(name)
|
data/lib/chronic/mini_date.rb
CHANGED
@@ -3,13 +3,17 @@ module Chronic
|
|
3
3
|
attr_accessor :month, :day
|
4
4
|
|
5
5
|
def initialize(month, day)
|
6
|
-
|
6
|
+
unless (1..12).include?(month)
|
7
|
+
raise(InvalidArgumentException, "1..12 are valid months")
|
8
|
+
end
|
9
|
+
|
7
10
|
@month = month
|
8
11
|
@day = day
|
9
12
|
end
|
10
13
|
|
11
14
|
def is_between?(md_start, md_end)
|
12
|
-
return false if (@month==md_start.month && @month==md_end.month &&
|
15
|
+
return false if (@month == md_start.month && @month == md_end.month &&
|
16
|
+
(@day < md_start.day || @day > md_end.day))
|
13
17
|
return true if (@month == md_start.month and @day >= md_start.day) ||
|
14
18
|
(@month == md_end.month and @day <= md_end.day)
|
15
19
|
i = (md_start.month % 12) + 1
|
data/lib/chronic/ordinal.rb
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
module Chronic
|
2
|
-
class Ordinal < Tag
|
2
|
+
class Ordinal < Tag
|
3
|
+
|
4
|
+
# Scan an Array of {Token}s and apply any necessary Ordinal tags to
|
5
|
+
# each token
|
6
|
+
#
|
7
|
+
# @param [Array<Token>] tokens Array of tokens to scan
|
8
|
+
# @param [Hash] options Options specified in {Chronic.parse}
|
9
|
+
# @return [Array] list of tokens
|
3
10
|
def self.scan(tokens, options)
|
4
11
|
tokens.each_index do |i|
|
5
12
|
if t = scan_for_ordinals(tokens[i]) then tokens[i].tag(t) end
|
@@ -7,10 +14,14 @@ module Chronic
|
|
7
14
|
end
|
8
15
|
end
|
9
16
|
|
17
|
+
# @param [Token] token
|
18
|
+
# @return [Ordinal, nil]
|
10
19
|
def self.scan_for_ordinals(token)
|
11
20
|
Ordinal.new($1.to_i) if token.word =~ /^(\d*)(st|nd|rd|th)$/
|
12
21
|
end
|
13
22
|
|
23
|
+
# @param [Token] token
|
24
|
+
# @return [OrdinalDay, nil]
|
14
25
|
def self.scan_for_days(token)
|
15
26
|
if token.word =~ /^(\d*)(st|nd|rd|th)$/
|
16
27
|
unless $1.to_i > 31 || $1.to_i < 1
|