nickel 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,1145 @@
1
+ # Ruby Nickel Library
2
+ # Copyright (c) 2008-2011 Lou Zell, lzell11@gmail.com, http://hazelmade.com
3
+ # MIT License [http://www.opensource.org/licenses/mit-license.php]
4
+
5
+ module Nickel
6
+
7
+ class ConstructFinder
8
+ attr_reader :constructs, :components
9
+
10
+ def initialize(query, curdate, curtime)
11
+ # If query is a string (for debug), use it to initialize NLPQuery.
12
+ query.class == String && query = NLPQuery.new(query)
13
+ @curdate = curdate
14
+ @curtime = curtime
15
+ @components = query.split
16
+ @pos = 0 # iterator
17
+ @constructs = []
18
+ end
19
+
20
+ def run
21
+ while @pos < @components.size
22
+ big_if_on_current_word
23
+ @pos += 1
24
+ end
25
+ end
26
+
27
+ def reset_instance_vars
28
+ @day_index = nil
29
+ @month_index = nil
30
+ @week_num = nil
31
+ @date_array = nil
32
+ @length = nil
33
+ @time1 = nil
34
+ @time2 = nil
35
+ @date1 = nil
36
+ @date2 = nil
37
+ end
38
+
39
+ def big_if_on_current_word
40
+ reset_instance_vars
41
+
42
+ if match_every
43
+ if match_every_dayname then found_every_dayname # every tue
44
+ elsif match_every_day then found_every_day # every day
45
+ elsif match_every_other
46
+ if match_every_other_dayname then found_every_other_dayname # every other fri
47
+ elsif match_every_other_day then found_every_other_day # every other day
48
+ end
49
+ elsif match_every_3rd
50
+ if match_every_3rd_dayname then found_every_3rd_dayname # every third fri
51
+ elsif match_every_3rd_day then found_every_3rd_day # every third day
52
+ end
53
+ end
54
+
55
+ elsif match_repeats
56
+ if match_repeats_daily then found_repeats_daily # repeats daily
57
+ elsif match_repeats_altdaily then found_repeats_altdaily # repeats altdaily
58
+ elsif match_repeats_weekly_vague then found_repeats_weekly_vague # repeats weekly
59
+ elsif match_repeats_altweekly_vague then found_repeats_altweekly_vague # repeats altweekly
60
+ elsif match_repeats_monthly
61
+ if match_repeats_daymonthly then found_repeats_daymonthly # repeats monthly 1st fri
62
+ elsif match_repeats_datemonthly then found_repeats_datemonthly # repeats monthly 22nd
63
+ end
64
+ elsif match_repeats_altmonthly
65
+ if match_repeats_altmonthly_daymonthly then found_repeats_altmonthly_daymonthly # repeats altmonthly 1st fri
66
+ elsif match_repeats_altmonthly_datemonthly then found_repeats_altmonthly_datemonthly # repeats altmonthly 22nd
67
+ end
68
+ elsif match_repeats_threemonthly
69
+ if match_repeats_threemonthly_daymonthly then found_repeats_threemonthly_daymonthly # repeats threemonthly 1st fri
70
+ elsif match_repeats_threemonthly_datemonthly then found_repeats_threemonthly_datemonthly # repeats threemonthly 22nd
71
+ end
72
+ end
73
+
74
+ elsif match_for_x
75
+ if match_for_x_days then found_for_x_days # for 10 days
76
+ elsif match_for_x_weeks then found_for_x_weeks # for 10 weeks
77
+ elsif match_for_x_months then found_for_x_months # for 10 months
78
+ end
79
+
80
+ elsif match_this
81
+ if match_this_dayname then found_this_dayname # this fri
82
+ elsif match_this_week then found_this_week # this week
83
+ elsif match_this_month then found_this_month # this month (implies 9/1 to 9/30)
84
+ end # SHOULDN'T "this" HAVE "this weekend" ???
85
+
86
+ elsif match_next
87
+ if match_next_weekend then found_next_weekend # next weekend --- never hit?
88
+ elsif match_next_dayname then found_next_dayname # next tuesday
89
+ elsif match_next_x
90
+ if match_next_x_days then found_next_x_days # next 5 days --- shouldn't this be a wrapper?
91
+ elsif match_next_x_weeks then found_next_x_weeks # next 5 weeks --- shouldn't this be a wrapper?
92
+ elsif match_next_x_months then found_next_x_months # next 5 months --- shouldn't this be a wrapper?
93
+ elsif match_next_x_years then found_next_x_years # next 5 years --- shouldn't this be a wrapper?
94
+ end
95
+ elsif match_next_week then found_next_week
96
+ elsif match_next_month then found_next_month # next month (implies 10/1 to 10/31)
97
+ end
98
+
99
+ elsif match_week
100
+ if match_week_of_date then found_week_of_date # week of 1/2
101
+ elsif match_week_through_date then found_week_through_date # week through 1/2 (as in, week ending 1/2)
102
+ end
103
+
104
+ elsif match_x_weeks_from
105
+ if match_x_weeks_from_dayname then found_x_weeks_from_dayname # 5 weeks from tuesday
106
+ elsif match_x_weeks_from_this_dayname then found_x_weeks_from_this_dayname # 5 weeks from this tuesday
107
+ elsif match_x_weeks_from_next_dayname then found_x_weeks_from_next_dayname # 5 weeks from next tuesday
108
+ elsif match_x_weeks_from_tomorrow then found_x_weeks_from_tomorrow # 5 weeks from tomorrow
109
+ elsif match_x_weeks_from_now then found_x_weeks_from_now # 5 weeks from now
110
+ elsif match_x_weeks_from_yesterday then found_x_weeks_from_yesterday # 5 weeks from yesterday
111
+ end
112
+
113
+ elsif match_x_months_from
114
+ if match_x_months_from_dayname then found_x_months_from_dayname # 2 months from wed
115
+ elsif match_x_months_from_this_dayname then found_x_months_from_this_dayname # 2 months from this wed
116
+ elsif match_x_months_from_next_dayname then found_x_months_from_next_dayname # 2 months from next wed
117
+ elsif match_x_months_from_tomorrow then found_x_months_from_tomorrow # 2 months from tomorrow
118
+ elsif match_x_months_from_now then found_x_months_from_now # 2 months from now
119
+ elsif match_x_months_from_yesterday then found_x_months_from_yesterday # 2 months from yesterday
120
+ end
121
+
122
+ elsif match_x_days_from
123
+ if match_x_days_from_now then found_x_days_from_now # 5 days from now
124
+ elsif match_x_days_from_dayname then found_x_days_from_dayname # 5 days from monday
125
+ end
126
+
127
+ elsif match_x_dayname_from
128
+ if match_x_dayname_from_now then found_x_dayname_from_now # 2 fridays from now
129
+ elsif match_x_dayname_from_tomorrow then found_x_dayname_from_tomorrow # 2 fridays from tomorrow
130
+ elsif match_x_dayname_from_yesterday then found_x_dayname_from_yesterday # 2 fridays from yesterday
131
+ elsif match_x_dayname_from_this then found_x_dayname_from_this # 2 fridays from this one
132
+ elsif match_x_dayname_from_next then found_x_dayname_from_next # 2 fridays from next friday
133
+ end
134
+
135
+ elsif match_x_minutes_from_now then found_x_minutes_from_now # 5 minutes from now
136
+ elsif match_x_hours_from_now then found_x_hours_from_now # 5 hours from now
137
+
138
+ elsif match_ordinal_dayname
139
+ if match_ordinal_dayname_this_month then found_ordinal_dayname_this_month # 2nd friday this month
140
+ elsif match_ordinal_dayname_next_month then found_ordinal_dayname_next_month # 2nd friday next month
141
+ elsif match_ordinal_dayname_monthname then found_ordinal_dayname_monthname # 2nd friday december
142
+ end
143
+
144
+ elsif match_ordinal_this_month then found_ordinal_this_month # 28th this month
145
+ elsif match_ordinal_next_month then found_ordinal_next_month # 28th next month
146
+
147
+ elsif match_first_day
148
+ if match_first_day_this_month then found_first_day_this_month # first day this month
149
+ elsif match_first_day_next_month then found_first_day_next_month # first day next month
150
+ elsif match_first_day_monthname then found_first_day_monthname # first day january (well this is stupid, "first day of january" gets preprocessed into "1/1", so what is the point of this?)
151
+ end
152
+
153
+ elsif match_last_day
154
+ if match_last_day_this_month then found_last_day_this_month # last day this month
155
+ elsif match_last_day_next_month then found_last_day_next_month # last day next month
156
+ elsif match_last_day_monthname then found_last_day_monthname # last day november
157
+ end
158
+
159
+ elsif match_at
160
+ if match_at_time
161
+ if match_at_time_through_time then found_at_time_through_time # at 2 through 5pm
162
+ else found_at_time # at 2
163
+ end
164
+ end
165
+
166
+ elsif match_all_day then found_all_day # all day
167
+
168
+ elsif match_tomorrow
169
+ if match_tomorrow_through
170
+ if match_tomorrow_through_dayname then found_tomorrow_through_dayname # tomorrow through friday
171
+ elsif match_tomorrow_through_date then found_tomorrow_through_date # tomorrow through august 20th
172
+ end
173
+ else found_tomorrow # tomorrow
174
+ end
175
+
176
+ elsif match_now
177
+ if match_now_through
178
+ if match_now_through_dayname then found_now_through_dayname # today through friday
179
+ elsif match_now_through_following_dayname then found_now_through_following_dayname # REDUNDANT, PREPROCESS THIS OUT
180
+ elsif match_now_through_date then found_now_through_date # today through 10/1
181
+ elsif match_now_through_tomorrow then found_now_through_tomorrow # today through tomorrow
182
+ elsif match_now_through_next_dayname then found_now_through_next_dayname # today through next friday
183
+ end
184
+ else found_now # today
185
+ end
186
+
187
+ elsif match_dayname
188
+ if match_dayname_the_ordinal then found_dayname_the_ordinal # monday the 21st
189
+ elsif match_dayname_x_weeks_from_next then found_dayname_x_weeks_from_next # monday 2 weeks from next
190
+ elsif match_dayname_x_weeks_from_this then found_dayname_x_weeks_from_this # monday 2 weeks from this
191
+ else found_dayname # monday (also monday tuesday wed...)
192
+ end
193
+
194
+ elsif match_through_monthname then found_through_monthname # through december (implies through 11/30)
195
+ elsif match_monthname then found_monthname # december (implies 12/1 to 12/31)
196
+
197
+ # 5th constructor
198
+ elsif match_start then found_start
199
+ elsif match_through then found_through
200
+
201
+ elsif match_time # match time second to last
202
+ if match_time_through_time then found_time_through_time # 10 to 4
203
+ else found_time # 10
204
+ end
205
+
206
+ elsif match_date # match date last
207
+ if match_date_through_date then found_date_through_date # 5th through the 16th
208
+ else found_date # 5th
209
+ end
210
+ end
211
+ end # end def big_if_on_current_word
212
+
213
+ def match_every
214
+ @components[@pos]=="every"
215
+ end
216
+
217
+ def match_every_dayname
218
+ @day_index = ZDate.days_of_week.index(@components[@pos+1]) # if "every [day]"
219
+ end
220
+
221
+ def found_every_dayname
222
+ day_array=[@day_index]
223
+ j = 2
224
+ while @components[@pos+j] && ZDate.days_of_week.index(@components[@pos+j]) # if "every mon tue wed"
225
+ day_array << ZDate.days_of_week.index(@components[@pos+j])
226
+ j += 1
227
+ end
228
+ @constructs << RecurrenceConstruct.new(:repeats => :weekly, :repeats_on => day_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
229
+ end
230
+
231
+ def match_every_day
232
+ @components[@pos+1] == "day"
233
+ end
234
+
235
+ def found_every_day
236
+ @constructs << RecurrenceConstruct.new(:repeats => :daily, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
237
+ end
238
+
239
+ def match_every_other
240
+ @components[@pos+1] =~ /other|2nd/
241
+ end
242
+
243
+ def match_every_other_dayname
244
+ @day_index = ZDate.days_of_week.index(@components[@pos+2]) # if "every other mon"
245
+ end
246
+
247
+ def found_every_other_dayname
248
+ day_array = [@day_index]
249
+ j = 3
250
+ while @components[@pos+j] && ZDate.days_of_week.index(@components[@pos+j]) #if "every other mon tue wed
251
+ day_array << ZDate.days_of_week.index(@components[@pos+j])
252
+ j += 1
253
+ end
254
+ @constructs << RecurrenceConstruct.new(:repeats => :altweekly, :repeats_on => day_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
255
+ end
256
+
257
+ def match_every_other_day
258
+ @components[@pos+2] == "day" ## if "every other day"
259
+ end
260
+
261
+ def found_every_other_day
262
+ @constructs << RecurrenceConstruct.new(:repeats => :altdaily, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
263
+ end
264
+
265
+ def match_every_3rd
266
+ @components[@pos+1] == "3rd"
267
+ end
268
+
269
+ def match_every_3rd_dayname
270
+ @day_index = ZDate.days_of_week.index(@components[@pos+2]) # if "every 3rd tue"
271
+ end
272
+
273
+ def found_every_3rd_dayname
274
+ day_array = [@day_index]
275
+ j = 3
276
+ while @components[@pos+j] && ZDate.days_of_week.index(@components[@pos+j]) #if "every 3rd tue wed thu
277
+ day_array << ZDate.days_of_week.index(@components[@pos+j])
278
+ j += 1
279
+ end
280
+ @constructs << RecurrenceConstruct.new(:repeats => :threeweekly, :repeats_on => day_array, :comp_start => @pos, :comp_end => @pos += (j - i), :found_in => method_name)
281
+ end
282
+
283
+ def match_every_3rd_day
284
+ @components[@pos+2] == "day" ## if "every 3rd day"
285
+ end
286
+
287
+ def found_every_3rd_day
288
+ @constructs << RecurrenceConstruct.new(:repeats => :threedaily, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
289
+ end
290
+
291
+ def match_repeats
292
+ @components[@pos] == "repeats"
293
+ end
294
+
295
+ def match_repeats_daily
296
+ @components[@pos+1] == "daily"
297
+ end
298
+
299
+ def found_repeats_daily
300
+ @constructs << RecurrenceConstruct.new(:repeats => :daily, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
301
+ end
302
+
303
+ def match_repeats_altdaily
304
+ @components[@pos+1] == "altdaily"
305
+ end
306
+
307
+ def found_repeats_altdaily
308
+ @constructs << RecurrenceConstruct.new(:repeats => :altdaily, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
309
+ end
310
+
311
+ def match_repeats_weekly_vague
312
+ @components[@pos+1] == "weekly"
313
+ end
314
+
315
+ def found_repeats_weekly_vague
316
+ @constructs << RecurrenceConstruct.new(:repeats => :weekly, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
317
+ end
318
+
319
+ def match_repeats_altweekly_vague
320
+ @components[@pos+1] == "altweekly"
321
+ end
322
+
323
+ def found_repeats_altweekly_vague
324
+ @constructs << RecurrenceConstruct.new(:repeats => :altweekly, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
325
+ end
326
+
327
+ def match_repeats_monthly
328
+ @components[@pos+1] == "monthly"
329
+ end
330
+
331
+ def match_repeats_daymonthly
332
+ @components[@pos+2] && @components[@pos+3] && (@week_num = @components[@pos+2].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+3])) # "repeats monthly 2nd wed"
333
+ end
334
+
335
+ def found_repeats_daymonthly
336
+ rep_array = [[@week_num, @day_index]] # That is NOT a typo, not sure what I meant by that! maybe the nested array
337
+ j = 4
338
+ while @components[@pos+j] && @components[@pos+j+1] && (@week_num = @components[@pos+j].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+j+1]))
339
+ rep_array << [@week_num, @day_index]
340
+ j += 2
341
+ end
342
+ @constructs << RecurrenceConstruct.new(:repeats => :daymonthly, :repeats_on => rep_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
343
+ end
344
+
345
+ def match_repeats_datemonthly
346
+ @components[@pos+2] && @components[@pos+2].valid_dd? && @date_array = [@components[@pos+2].to_i] # repeats monthly 22nd
347
+ end
348
+
349
+ def found_repeats_datemonthly
350
+ j = 3
351
+ while @components[@pos+j] && @components[@pos+j].valid_dd?
352
+ @date_array << @components[@pos+j].to_i
353
+ j += 1
354
+ end
355
+ @constructs << RecurrenceConstruct.new(:repeats => :datemonthly, :repeats_on => @date_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
356
+ end
357
+
358
+ def match_repeats_altmonthly
359
+ @components[@pos+1] == "altmonthly"
360
+ end
361
+
362
+ def match_repeats_altmonthly_daymonthly
363
+ @components[@pos+2] && @components[@pos+3] && (@week_num = @components[@pos+2].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+3])) # "repeats altmonthly 2nd wed"
364
+ end
365
+
366
+ def found_repeats_altmonthly_daymonthly
367
+ rep_array = [[@week_num, @day_index]]
368
+ j = 4
369
+ while @components[@pos+j] && @components[@pos+j+1] && (@week_num = @components[@pos+j].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+j+1]))
370
+ rep_array << [@week_num, @day_index]
371
+ j += 2
372
+ end
373
+ @constructs << RecurrenceConstruct.new(:repeats => :altdaymonthly, :repeats_on => rep_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
374
+ end
375
+
376
+ def match_repeats_altmonthly_datemonthly
377
+ @components[@pos+2] && @components[@pos+2].valid_dd? && @date_array = [@components[@pos+2].to_i] # repeats altmonthly 22nd
378
+ end
379
+
380
+ def found_repeats_altmonthly_datemonthly
381
+ j = 3
382
+ while @components[@pos+j] && @components[@pos+j].valid_dd?
383
+ @date_array << @components[@pos+j].to_i
384
+ j += 1
385
+ end
386
+ @constructs << RecurrenceConstruct.new(:repeats => :altdatemonthly, :repeats_on => @date_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
387
+ end
388
+
389
+ def match_repeats_threemonthly
390
+ @components[@pos+1] == "threemonthly"
391
+ end
392
+
393
+ def match_repeats_threemonthly_daymonthly
394
+ @components[@pos+2] && @components[@pos+3] && (@week_num = @components[@pos+2].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+3])) # "repeats threemonthly 2nd wed"
395
+ end
396
+
397
+ def found_repeats_threemonthly_daymonthly
398
+ rep_array = [[@week_num, @day_index]] # That is NOT a typo
399
+ j = 4
400
+ while @components[@pos+j] && @components[@pos+j+1] && (@week_num = @components[@pos+j].to_i) && @week_num > 0 && @week_num <= 5 && (@day_index = ZDate.days_of_week.index(@components[@pos+j+1]))
401
+ rep_array << [@week_num, @day_index]
402
+ j += 2
403
+ end
404
+ @constructs << RecurrenceConstruct.new(:repeats => :threedaymonthly, :repeats_on => rep_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
405
+ end
406
+
407
+ def match_repeats_threemonthly_datemonthly
408
+ @components[@pos+2] && @components[@pos+2].valid_dd? && @date_array = [@components[@pos+2].to_i] # repeats threemonthly 22nd
409
+ end
410
+
411
+ def found_repeats_threemonthly_datemonthly
412
+ j = 3
413
+ while @components[@pos+j] && @components[@pos+j].valid_dd?
414
+ @date_array << @components[@pos+j].to_i
415
+ j += 1
416
+ end
417
+ @constructs << RecurrenceConstruct.new(:repeats => :threedatemonthly, :repeats_on => @date_array, :comp_start => @pos, :comp_end => @pos += (j - 1), :found_in => method_name)
418
+ end
419
+
420
+ def match_for_x
421
+ @components[@pos]=="for" && @components[@pos+1].digits_only? && @length = @components[@pos+1].to_i
422
+ end
423
+
424
+ def match_for_x_days
425
+ @components[@pos+2] =~ /days?/
426
+ end
427
+
428
+ def found_for_x_days
429
+ @constructs << WrapperConstruct.new(:wrapper_type => 2, :wrapper_length => @length, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
430
+ end
431
+
432
+ def match_for_x_weeks
433
+ @components[@pos+2] =~ /weeks?/
434
+ end
435
+
436
+ def found_for_x_weeks
437
+ @constructs << WrapperConstruct.new(:wrapper_type => 3, :wrapper_length => @length, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
438
+ end
439
+
440
+ def match_for_x_months
441
+ @components[@pos+2] =~ /months?/
442
+ end
443
+
444
+ def found_for_x_months
445
+ @constructs << WrapperConstruct.new(:wrapper_type => 4, :wrapper_length => @length, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
446
+ end
447
+
448
+ def match_this
449
+ @components[@pos]=="this"
450
+ end
451
+
452
+ def match_this_dayname
453
+ @day_index = ZDate.days_of_week.index(@components[@pos+1])
454
+ end
455
+
456
+ def found_this_dayname
457
+ day_to_add = @curdate.this(@day_index)
458
+ @constructs << DateConstruct.new(:date => day_to_add, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
459
+ while @components[@pos+1] && @day_index = ZDate.days_of_week.index(@components[@pos+1])
460
+ # note @pos gets incremented on each pass
461
+ @constructs << DateConstruct.new(:date => day_to_add = day_to_add.this(@day_index), :comp_start => @pos + 1, :comp_end => @pos += 1, :found_in => method_name)
462
+ end
463
+ end
464
+
465
+ def match_this_week
466
+ @components[@pos+1] =~ /weeks?/
467
+ end
468
+
469
+ def found_this_week
470
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_days(7), :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
471
+ end
472
+
473
+ def match_this_month
474
+ @components[@pos+1] =~ /months?/
475
+ end
476
+
477
+ def found_this_month
478
+ date = NLP::use_date_correction ? @curdate : @curdate.beginning_of_month
479
+ @constructs << DateSpanConstruct.new(:start_date => date, :end_date => @curdate.end_of_month, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
480
+ end
481
+
482
+
483
+ def match_next
484
+ @components[@pos]=="next"
485
+ end
486
+
487
+ def match_next_weekend
488
+ @components[@pos+1]=="weekend" ## "next weekend"
489
+ end
490
+
491
+ def found_next_weekend
492
+ dsc = DateSpanConstruct.new(:start_date => @curdate.next(5), :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
493
+ dsc.end_date = dsc.start_date.add_days(1)
494
+ @constructs << dsc
495
+ end
496
+
497
+ def match_next_dayname
498
+ @day_index = ZDate.days_of_week.index(@components[@pos+1]) ## if "next [day]"
499
+ end
500
+
501
+ def found_next_dayname
502
+ day_to_add = @curdate.next(@day_index)
503
+ @constructs << DateConstruct.new(:date => day_to_add, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
504
+ while @components[@pos+1] && @day_index = ZDate.days_of_week.index(@components[@pos+1])
505
+ # note @pos gets incremented on each pass
506
+ @constructs << DateConstruct.new(:date => day_to_add = day_to_add.this(@day_index), :comp_start => @pos + 1, :comp_end => @pos += 1, :found_in => method_name)
507
+ end
508
+ end
509
+
510
+ def match_next_x
511
+ @components[@pos+1] && @components[@pos+1].digits_only? && @length = @components[@pos+1].to_i
512
+ end
513
+
514
+ def match_next_x_days
515
+ @components[@pos+2] =~ /days?/ ## "next x days"
516
+ end
517
+
518
+ def found_next_x_days
519
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_days(@length), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
520
+ end
521
+
522
+ def match_next_x_weeks
523
+ @components[@pos+2] =~ /weeks?/ ## "next x weeks"
524
+ end
525
+
526
+ def found_next_x_weeks
527
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_weeks(@length), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
528
+ end
529
+
530
+ def match_next_x_months
531
+ @components[@pos+2] =~ /months?/ ## "next x months"
532
+ end
533
+
534
+ def found_next_x_months
535
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_months(@length), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
536
+ end
537
+
538
+ def match_next_x_years
539
+ @components[@pos+2] =~ /years?/ ## "next x years"
540
+ end
541
+
542
+ def found_next_x_years
543
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_years(@length), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
544
+ end
545
+
546
+ def match_next_week
547
+ @components[@pos+1] =~ /weeks?/
548
+ end
549
+
550
+ def found_next_week
551
+ sd = @curdate.add_days(7)
552
+ ed = sd.add_days(7)
553
+ @constructs << DateSpanConstruct.new(:start_date => sd, :end_date => ed, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
554
+ end
555
+
556
+ def match_next_month
557
+ # note it is important that all other uses of "next month" come after indicating words such as "every day next month"; otherwise they will be converted here
558
+ @components[@pos+1] =~ /months?/
559
+ end
560
+
561
+ def found_next_month
562
+ sd = @curdate.add_months(1).beginning_of_month
563
+ ed = sd.end_of_month
564
+ @constructs << DateSpanConstruct.new(:start_date => sd, :end_date => ed, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
565
+ end
566
+
567
+ def match_week
568
+ @components[@pos] == "week"
569
+ end
570
+
571
+ def match_week_of_date
572
+ @components[@pos+1] == "of" && @date1 = @components[@pos+2].interpret_date(@curdate)
573
+ end
574
+
575
+ def found_week_of_date
576
+ @constructs << DateSpanConstruct.new(:start_date => @date1, :end_date => @date1.add_days(7), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
577
+ end
578
+
579
+ def match_week_through_date
580
+ @components[@pos+1] == "through" && @date1 = @components[@pos+2].interpret_date(@curdate)
581
+ end
582
+
583
+ def found_week_through_date
584
+ @constructs << DateSpanConstruct.new(:start_date => @date1.sub_days(7), :end_date => @date1, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
585
+ end
586
+
587
+ def match_x_weeks_from
588
+ @components[@pos].digits_only? && @components[@pos+1] =~ /^weeks?$/ && @components[@pos+2] == "from" && @length = @components[@pos].to_i # if "x weeks from"
589
+ end
590
+
591
+ def match_x_weeks_from_dayname
592
+ @day_index = ZDate.days_of_week.index(@components[@pos+3]) # if "x weeks from monday"
593
+ end
594
+
595
+ def found_x_weeks_from_dayname
596
+ @constructs << DateConstruct.new(:date => @curdate.x_weeks_from_day(@length, @day_index), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
597
+ end
598
+
599
+ # Reduntant, preprocess out!
600
+ def match_x_weeks_from_this_dayname
601
+ @components[@pos+3] == "this" && @day_index = ZDate.days_of_week.index(@components[@pos+4]) # if "x weeks from this monday"
602
+ end
603
+
604
+ # Reduntant, preprocess out!
605
+ def found_x_weeks_from_this_dayname
606
+ # this is the exact some construct as found_x_weeks_from_dayname, just position and comp_end has to increment by 1 more; pretty stupid, this should be caught in preprocessing
607
+ @constructs << DateConstruct.new(:date => @curdate.x_weeks_from_day(@length, @day_index), :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
608
+ end
609
+
610
+ def match_x_weeks_from_next_dayname
611
+ @components[@pos+3] == "next" && @day_index = ZDate.days_of_week.index(@components[@pos+4]) # if "x weeks from next monday"
612
+ end
613
+
614
+ def found_x_weeks_from_next_dayname
615
+ @constructs << DateConstruct.new(:date => @curdate.x_weeks_from_day(@length + 1, @day_index), :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
616
+ end
617
+
618
+ def match_x_weeks_from_tomorrow
619
+ @components[@pos+3] == "tomorrow" # if "x weeks from tomorrow"
620
+ end
621
+
622
+ def found_x_weeks_from_tomorrow
623
+ @constructs << DateConstruct.new(:date => @curdate.add_days(1).add_weeks(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
624
+ end
625
+
626
+ def match_x_weeks_from_now
627
+ @components[@pos+3] =~ /\b(today)|(now)\b/ # if "x weeks from today"
628
+ end
629
+
630
+ def found_x_weeks_from_now
631
+ @constructs << DateConstruct.new(:date => @curdate.x_weeks_from_day(@length, @curdate.dayindex), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
632
+ end
633
+
634
+ def match_x_weeks_from_yesterday
635
+ @components[@pos+3] == "yesterday" # "x weeks from yesterday"
636
+ end
637
+
638
+ def found_x_weeks_from_yesterday
639
+ @constructs << DateConstruct.new(:date => @curdate.sub_days(1).add_weeks(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
640
+ end
641
+
642
+ def match_x_months_from
643
+ @components[@pos].digits_only? && @components[@pos+1] =~ /^months?$/ && @components[@pos+2] == "from" && @length = @components[@pos].to_i # if "x months from"
644
+ end
645
+
646
+ def match_x_months_from_dayname
647
+ @day_index = ZDate.days_of_week.index(@components[@pos+3]) # if "x months from monday"
648
+ end
649
+
650
+ def found_x_months_from_dayname
651
+ @constructs << DateConstruct.new(:date => @curdate.this(@day_index).add_months(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
652
+ end
653
+
654
+ def match_x_months_from_this_dayname
655
+ @components[@pos+3] == "this" && @day_index = ZDate.days_of_week.index(@components[@pos+4]) # if "x months from this monday"
656
+ end
657
+
658
+ def found_x_months_from_this_dayname
659
+ @constructs << DateConstruct.new(:date => @curdate.this(@day_index).add_months(@length), :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
660
+ end
661
+
662
+ def match_x_months_from_next_dayname
663
+ @components[@pos+3] == "next" && @day_index = ZDate.days_of_week.index(@components[@pos+4]) # if "x months from next monday"
664
+ end
665
+
666
+ def found_x_months_from_next_dayname
667
+ @constructs << DateConstruct.new(:date => @curdate.next(@day_index).add_months(@length), :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
668
+ end
669
+
670
+ def match_x_months_from_tomorrow
671
+ @components[@pos+3] == "tomorrow" # if "x months from tomorrow"
672
+ end
673
+
674
+ def found_x_months_from_tomorrow
675
+ @constructs << DateConstruct.new(:date => @curdate.add_days(1).add_months(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
676
+ end
677
+
678
+ def match_x_months_from_now
679
+ @components[@pos+3] =~ /\b(today)|(now)\b/ # if "x months from today"
680
+ end
681
+
682
+ def found_x_months_from_now
683
+ @constructs << DateConstruct.new(:date => @curdate.add_months(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
684
+ end
685
+
686
+ def match_x_months_from_yesterday
687
+ @components[@pos+3] == "yesterday" # "x months from yesterday"
688
+ end
689
+
690
+ def found_x_months_from_yesterday
691
+ @constructs << DateConstruct.new(:date => @curdate.sub_days(1).add_months(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
692
+ end
693
+
694
+ def match_x_days_from
695
+ @components[@pos].digits_only? && @components[@pos+1] =~ /^days?$/ && @components[@pos+2] == "from" && @length = @components[@pos].to_i # 3 days from
696
+ end
697
+
698
+ def match_x_days_from_now
699
+ @components[@pos+3] =~ /\b(now)|(today)\b/ # 3 days from today; 3 days from now
700
+ end
701
+
702
+ def found_x_days_from_now
703
+ @constructs << DateConstruct.new(:date => @curdate.add_days(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
704
+ end
705
+
706
+ def match_x_days_from_dayname
707
+ @day_index = ZDate.days_of_week.index(@components[@pos+3]) # 3 days from monday, why would someone do this?
708
+ end
709
+
710
+ def found_x_days_from_dayname
711
+ @constructs << DateConstruct.new(:date => @curdate.this(@day_index).add_days(@length), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
712
+ end
713
+
714
+ def match_x_dayname_from
715
+ @components[@pos].digits_only? && (@day_index = ZDate.days_of_week.index(@components[@pos+1])) && @components[@pos+2] == "from" && @length = @components[@pos].to_i # "2 tuesdays from"
716
+ end
717
+
718
+ def match_x_dayname_from_now
719
+ @components[@pos+3] =~ /\b(today)|(now)\b/ # if "2 tuesdays from now"
720
+ end
721
+
722
+ def found_x_dayname_from_now
723
+ # this isn't exactly intuitive. If someone says "two tuesday from now" and it is tuesday, they mean "in two weeks." If it is not tuesday, they mean "next tuesday"
724
+ d = (@days_index == @curdate.dayindex) ? @curdate.add_weeks(@length) : @curdate.x_weeks_from_day(@length - 1, @day_index)
725
+ @constructs << DateConstruct.new(:date => d, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
726
+ end
727
+
728
+ def match_x_dayname_from_tomorrow
729
+ @components[@pos+3] == "tomorrow"
730
+ end
731
+
732
+ def found_x_dayname_from_tomorrow
733
+ # If someone says "two tuesday from tomorrow" and tomorrow is tuesday, they mean "two weeks from tomorrow." If it is not tuesday, this person does not make sense, but we can interpet it as "next tuesday"
734
+ tomorrow_index = (@curdate.dayindex + 1) % 7
735
+ d = (@days_index == tomorrow_index) ? @curdate.add_days(1).add_weeks(@length) : @curdate.x_weeks_from_day(@length - 1, @day_index)
736
+ @constructs << DateConstruct.new(:date => d, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
737
+ end
738
+
739
+ def match_x_dayname_from_yesterday
740
+ @components[@pos+3] == "yesterday"
741
+ end
742
+
743
+ def found_x_dayname_from_yesterday
744
+ # If someone says "two tuesday from yesterday" and yesterday was tuesday, they mean "two weeks from yesterday." If it is not tuesday, this person does not make sense, but we can interpet it as "next tuesday"
745
+ yesterday_index = (@curdate.dayindex == 0 ? 6 : @curdate.dayindex - 1)
746
+ d = (@days_index == yesterday_index) ? @curdate.sub_days(1).add_weeks(@length) : @curdate.x_weeks_from_day(@length - 1, @day_index)
747
+ @constructs << DateConstruct.new(:date => d, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
748
+ end
749
+
750
+ def match_x_dayname_from_this
751
+ @components[@pos+3] == "this" # "two tuesdays from this"
752
+ end
753
+
754
+ def found_x_dayname_from_this
755
+ dc = DateConstruct.new(:date => @curdate.this(@day_index).add_weeks(@length), :comp_start => @pos, :found_in => method_name)
756
+ if @components[@post+4] == "one" || ZDate.days_of_week.index(@components[@pos+4]) # talk about redundant (2 tuesdays from this one, 2 tuesdays from this tuesday)
757
+ dc.comp_end = @pos += 4
758
+ else
759
+ dc.comp_end = @pos += 3
760
+ end
761
+ @constructs << dc
762
+ end
763
+
764
+ def match_x_dayname_from_next
765
+ @components[@pos+3] == "next" # "two tuesdays from next"
766
+ end
767
+
768
+ def found_x_dayname_from_next
769
+ dc = DateConstruct.new(:date => @curdate.next(@day_index).add_weeks(@length), :comp_start => @pos, :found_in => method_name)
770
+ if @components[@post+4] == "one" || ZDate.days_of_week.index(@components[@pos+4]) # talk about redundant (2 tuesdays from next one, 2 tuesdays from next tuesday)
771
+ dc.comp_end = @pos += 4
772
+ else
773
+ dc.comp_end = @pos += 3
774
+ end
775
+ @constructs << dc
776
+ end
777
+
778
+ def match_x_minutes_from_now
779
+ @components[@pos].digits_only? && @components[@pos+1] =~ /minutes?/ && @components[@pos+2] == "from" && @components[@pos+3] =~ /^(today|now)$/ && @length = @components[@pos].to_i
780
+ end
781
+
782
+ def found_x_minutes_from_now
783
+ date = nil # define out of scope of block
784
+ time = @curtime.add_minutes(@length) {|days_to_increment| date = @curdate.add_days(days_to_increment)}
785
+ @constructs << DateConstruct.new(:date => date, :comp_start => @pos, :comp_end => @pos + 4, :found_in => method_name)
786
+ @constructs << TimeConstruct.new(:time => time, :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
787
+ end
788
+
789
+ def match_x_hours_from_now
790
+ @components[@pos].digits_only? && @components[@pos+1] =~ /hours?/ && @components[@pos+2] == "from" && @components[@pos+3] =~ /^(today|now)$/ && @length = @components[@pos].to_i
791
+ end
792
+
793
+ def found_x_hours_from_now
794
+ date = nil
795
+ time = @curtime.add_hours(@length) {|days_to_increment| date = @curdate.add_days(days_to_increment)}
796
+ @constructs << DateConstruct.new(:date => date, :comp_start => @pos, :comp_end => @pos + 4, :found_in => method_name)
797
+ @constructs << TimeConstruct.new(:time => time, :comp_start => @pos, :comp_end => @pos += 4, :found_in => method_name)
798
+ end
799
+
800
+ def match_ordinal_dayname
801
+ @components[@pos]=~/(1st|2nd|3rd|4th|5th)/ && (@day_index = ZDate.days_of_week.index(@components[@pos+1])) && @week_num = @components[@pos].to_i # last saturday
802
+ end
803
+
804
+ def match_ordinal_dayname_this_month
805
+ @components[@pos+2] == "this" && @components[@pos+3] == "month" # last saturday this month
806
+ end
807
+
808
+ def found_ordinal_dayname_this_month
809
+ @constructs << DateConstruct.new(:date => @curdate.ordinal_dayindex(@week_num, @day_index), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
810
+ end
811
+
812
+ def match_ordinal_dayname_next_month
813
+ @components[@pos+2] == "next" && @components[@pos+3] == "month" # 1st monday next month
814
+ end
815
+
816
+ def found_ordinal_dayname_next_month
817
+ @constructs << DateConstruct.new(:date => @curdate.add_months(1).ordinal_dayindex(@week_num, @day_index), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
818
+ end
819
+
820
+ def match_ordinal_dayname_monthname
821
+ @month_index = ZDate.months_of_year.index(@components[@pos+2]) # second friday december
822
+ end
823
+
824
+ def found_ordinal_dayname_monthname
825
+ @constructs << DateConstruct.new(:date => @curdate.jump_to_month(@month_index + 1).ordinal_dayindex(@week_num, @day_index), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
826
+ end
827
+
828
+
829
+ def match_ordinal_this_month
830
+ @components[@pos]=~/(0?[1-9]|[12][0-9]|3[01])(st|nd|rd|th)/ && @components[@pos+1] == 'this' && @components[@pos+2] = 'month' && @length = @components[@pos].to_i # 28th this month
831
+ end
832
+
833
+ def match_ordinal_next_month
834
+ @components[@pos]=~/(0?[1-9]|[12][0-9]|3[01])(st|nd|rd|th)/ && @components[@pos+1] == 'next' && @components[@pos+2] = 'month' && @length = @components[@pos].to_i # 28th next month
835
+ end
836
+
837
+ def found_ordinal_this_month
838
+ if NLP::use_date_correction && @curdate.day > @length
839
+ # e.g. it is the 30th of the month and a user types "1st of the month", they mean "first of next month"
840
+ date = @curdate.add_months(1).beginning_of_month.add_days(@length - 1)
841
+ else
842
+ date = @curdate.beginning_of_month.add_days(@length - 1)
843
+ end
844
+ @constructs << DateConstruct.new(:date => date, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
845
+ end
846
+
847
+ def found_ordinal_next_month
848
+ @constructs << DateConstruct.new(:date => @curdate.add_months(1).beginning_of_month.add_days(@length - 1), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
849
+ end
850
+
851
+
852
+ def match_first_day
853
+ @components[@pos] == "1st" && @components[@pos+1] == "day" # 1st day
854
+ end
855
+
856
+ def match_first_day_this_month
857
+ @components[@pos+2] == "this" && @components[@pos+3] == "month" # 1st day this month
858
+ end
859
+
860
+ def found_first_day_this_month
861
+ @constructs << DateConstruct.new(:date => @curdate.beginning_of_month, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
862
+ end
863
+
864
+ def match_first_day_next_month
865
+ @components[@pos+2] == "next" && @components[@pos+3] == "month" # 1st day next month
866
+ end
867
+
868
+ def found_first_day_next_month
869
+ @constructs << DateConstruct.new(:date => @curdate.add_months(1).beginning_of_month, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
870
+ end
871
+
872
+ def match_first_day_monthname
873
+ @month_index = ZDate.months_of_year.index(@components[@pos+2]) # 1st day december
874
+ end
875
+
876
+ def found_first_day_monthname
877
+ @constructs << DateConstruct.new(:date => @curdate.jump_to_month(@month_index + 1), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
878
+ end
879
+
880
+ def match_last_day
881
+ @components[@pos] == "last" && @components[@pos+1] == "day" # last day
882
+ end
883
+
884
+ def match_last_day_this_month
885
+ @components[@pos+2] == "this" && @components[@pos+3] == "month" # 1st day this month
886
+ end
887
+
888
+ def found_last_day_this_month
889
+ @constructs << DateConstruct.new(:date => @curdate.end_of_month, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
890
+ end
891
+
892
+ def match_last_day_next_month
893
+ @components[@pos+2] == "next" && @components[@pos+3] == "month" # 1st day next month
894
+ end
895
+
896
+ def found_last_day_next_month
897
+ @constructs << DateConstruct.new(:date => @curdate.add_months(1).end_of_month, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
898
+ end
899
+
900
+ def match_last_day_monthname
901
+ @month_index = ZDate.months_of_year.index(@components[@pos+2]) # 1st day december
902
+ end
903
+
904
+ def found_last_day_monthname
905
+ @constructs << DateConstruct.new(:date => @curdate.jump_to_month(@month_index + 1).end_of_month, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
906
+ end
907
+
908
+ def match_at
909
+ @components[@pos]=="at"
910
+ end
911
+
912
+ def match_at_time
913
+ @components[@pos+1] && @time1 = @components[@pos+1].interpret_time
914
+ end
915
+
916
+ def match_at_time_through_time
917
+ @components[@pos+2] =~ /^(to|until|through)$/ && @components[@pos+3] && @time2 = @components[@pos+3].interpret_time
918
+ end
919
+
920
+ def found_at_time_through_time
921
+ @constructs << TimeSpanConstruct.new(:start_time => @time1, :end_time => @time2, :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
922
+ end
923
+
924
+ def found_at_time
925
+ @constructs << TimeConstruct.new(:time => @time1, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
926
+ end
927
+
928
+ def match_all_day
929
+ @components[@pos]=="all" && @components[@pos+1]=="day" # all day
930
+ end
931
+
932
+ def found_all_day
933
+ @constructs << TimeConstruct.new(:time => nil, :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
934
+ end
935
+
936
+ def match_tomorrow
937
+ @components[@pos]=="tomorrow"
938
+ end
939
+
940
+ def match_tomorrow_through
941
+ @components[@pos+1]=="until" || @components[@pos+1] == "to" || @components[@pos+1] == "through" # "tomorrow through"
942
+ end
943
+
944
+ def match_tomorrow_through_dayname
945
+ @day_index = ZDate.days_of_week.index(@components[@pos+2]) # tomorrow through thursday
946
+ end
947
+
948
+ def found_tomorrow_through_dayname
949
+ @constructs << DateSpanConstruct.new(:start_date => @curdate.add_days(1), :end_date => @curdate.add_days(1).this(@day_index), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
950
+ end
951
+
952
+ def match_tomorrow_through_date
953
+ @date1 = @components[@pos+2].interpret_date(@curdate) # tomorrow until 9/21
954
+ end
955
+
956
+ def found_tomorrow_through_date
957
+ @constructs << DateSpanConstruct.new(:start_date => @curdate.add_days(1), :end_date => @date1, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
958
+ end
959
+
960
+ def found_tomorrow
961
+ @constructs << DateConstruct.new(:date => @curdate.add_days(1), :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
962
+ end
963
+
964
+ def match_now
965
+ @components[@pos]=="today" || @components[@pos]=="now"
966
+ end
967
+
968
+ def match_now_through
969
+ @components[@pos+1]=="until" || @components[@pos+1] == "to" || @components[@pos+1] == "through" # "today through"
970
+ end
971
+
972
+ def match_now_through_dayname
973
+ @day_index = ZDate.days_of_week.index(@components[@pos+2]) # today through thursday
974
+ end
975
+
976
+ def found_now_through_dayname
977
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.this(@day_index), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
978
+ end
979
+
980
+ # redundant!! preprocess this out of here!
981
+ def match_now_through_following_dayname
982
+ @components[@pos+2] =~ /following|this/ && @day_index = ZDate.days_of_week.index(@components[@pos+3]) # today through following friday
983
+ end
984
+
985
+ # redundant!! preprocess this out of here!
986
+ def found_now_through_following_dayname
987
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.this(@day_index), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
988
+ end
989
+
990
+ def match_now_through_date
991
+ @date1 = @components[@pos+2].interpret_date(@curdate) # now until 9/21
992
+ end
993
+
994
+ def found_now_through_date
995
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @date1, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
996
+ end
997
+
998
+ def match_now_through_tomorrow
999
+ @components[@pos+2]=="tomorrow"
1000
+ end
1001
+
1002
+ def found_now_through_tomorrow
1003
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.add_days(1), :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
1004
+ end
1005
+
1006
+ def match_now_through_next_dayname
1007
+ @components[@pos+2] == "next" && @day_index = ZDate.days_of_week.index(@components[@pos+3]) # Today through next friday
1008
+ end
1009
+
1010
+ def found_now_through_next_dayname
1011
+ @constructs << DateSpanConstruct.new(:start_date => @curdate, :end_date => @curdate.next(@day_index), :comp_start => @pos, :comp_end => @pos += 3, :found_in => method_name)
1012
+ end
1013
+
1014
+ def found_now
1015
+ @constructs << DateConstruct.new(:date => @curdate, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1016
+ end
1017
+
1018
+ def match_dayname
1019
+ @day_index = ZDate.days_of_week.index(@components[@pos])
1020
+ end
1021
+
1022
+ def match_dayname_the_ordinal
1023
+ @components[@pos+1] == "the" && @date1 = @components[@pos+2].interpret_date(@curdate) # if "tue the 23rd"
1024
+ end
1025
+
1026
+ def found_dayname_the_ordinal
1027
+ # user may have specified "monday the 2nd" while in the previous month, so first check if dayname matches date.dayname, if it doesn't increment by a month and check again
1028
+ if @date1.dayname == @components[@pos] || ((tmp = @date1.add_months(1)) && tmp.dayname == @components[@pos] && @date1 = tmp)
1029
+ @constructs << DateConstruct.new(:date => @date1, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
1030
+ end
1031
+ end
1032
+
1033
+ def match_dayname_x_weeks_from_this
1034
+ @components[@pos+1] && @components[@pos+1].digits_only? && @components[@pos+2] =~ /\bweeks?\b/ && @components[@pos+3] =~ /\b(from)|(after)/ && @components[@pos+4] == "this" && @length = @components[@pos+1] # "monday two weeks from this
1035
+ end
1036
+
1037
+ def found_dayname_x_weeks_from_this
1038
+ dc = DateConstruct.new(:date => @curdate.this(@dayindex).add_weeks(@length), :comp_start => @pos, :found_in => method_name)
1039
+ if ZDate.days_of_week.include?(@components[@pos+5]) #redundant
1040
+ dc.comp_end = @pos += 5
1041
+ else
1042
+ dc.comp_end = @pos += 4
1043
+ end
1044
+ @constructs << dc
1045
+ end
1046
+
1047
+ def match_dayname_x_weeks_from_next
1048
+ @components[@pos+1] && @components[@pos+1].digits_only? && @components[@pos+2] =~ /\bweeks?\b/ && @components[@pos+3] =~ /\b(from)|(after)/ && @components[@pos+4] == "next" && @length = @components[@pos+1] # "monday two weeks from this
1049
+ end
1050
+
1051
+ def found_dayname_x_weeks_from_next
1052
+ dc = DateConstruct.new(:date => @curdate.next(@dayindex).add_weeks(@length), :comp_start => @pos, :found_in => method_name)
1053
+ if ZDate.days_of_week.include?(@components[@pos+5]) #redundant
1054
+ dc.comp_end = @pos += 5
1055
+ else
1056
+ dc.comp_end = @pos += 4
1057
+ end
1058
+ @constructs << h
1059
+ end
1060
+
1061
+ # redundant, same as found_this_dayname
1062
+ def found_dayname
1063
+ day_to_add = @curdate.this(@day_index)
1064
+ @constructs << DateConstruct.new(:date => day_to_add, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1065
+ while @components[@pos+1] && @day_index = ZDate.days_of_week.index(@components[@pos+1])
1066
+ # note @pos gets incremented here:
1067
+ @constructs << DateConstruct.new(:date => day_to_add = day_to_add.this(@day_index), :comp_start => @pos + 1, :comp_end => @pos += 1, :found_in => method_name)
1068
+ end
1069
+ end
1070
+
1071
+ def match_through_monthname
1072
+ @components[@pos] == "through" && @month_index = ZDate.months_of_year.index(@components[@pos+1])
1073
+ end
1074
+
1075
+ def found_through_monthname
1076
+ # this is really a wrapper, we don't know when the start date is, so make sure @constructs gets wrapper first, as date constructs always have to appear after wrapper
1077
+ @constructs << WrapperConstruct.new(:wrapper_type => 1, :comp_start => @pos, :comp_end => @pos + 1, :found_in => method_name)
1078
+ @constructs << DateConstruct.new(:date => @curdate.jump_to_month(@month_index + 1).sub_days(1), :comp_start => @pos, :comp_end => @pos += 1, :found_in => method_name)
1079
+ end
1080
+
1081
+ def match_monthname
1082
+ # note it is important that all other uses of monthname come after indicating words such as "the third day of december"; otherwise they will be converted here
1083
+ @month_index = ZDate.months_of_year.index(@components[@pos])
1084
+ end
1085
+
1086
+ def found_monthname
1087
+ sd = @curdate.jump_to_month(@month_index + 1)
1088
+ ed = sd.end_of_month
1089
+ @constructs << DateSpanConstruct.new(:start_date => sd, :end_date => ed, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1090
+ end
1091
+
1092
+
1093
+ def match_start
1094
+ @components[@pos] == "start"
1095
+ end
1096
+
1097
+ def found_start
1098
+ #wrapper_type 0 is a start wrapper
1099
+ @constructs << WrapperConstruct.new(:wrapper_type => 0, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1100
+ end
1101
+
1102
+ def match_through
1103
+ @components[@pos] == "through"
1104
+ end
1105
+
1106
+ def found_through
1107
+ #wrapper_type 1 is an end wrapper
1108
+ @constructs << WrapperConstruct.new(:wrapper_type => 1, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1109
+ end
1110
+
1111
+ def match_time
1112
+ @time1 = @components[@pos].interpret_time
1113
+ end
1114
+
1115
+ def match_time_through_time
1116
+ @components[@pos+1] =~ /^(to|through)$/ && @time2 = @components[@pos+2].interpret_time
1117
+ end
1118
+
1119
+ def found_time_through_time
1120
+ @constructs << TimeSpanConstruct.new(:start_time => @time1, :end_time => @time2, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
1121
+ end
1122
+
1123
+ def found_time
1124
+ @constructs << TimeConstruct.new(:time => @time1, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1125
+ match = true
1126
+ end
1127
+
1128
+ def match_date
1129
+ @date1 = @components[@pos].interpret_date(@curdate)
1130
+ end
1131
+
1132
+ def match_date_through_date
1133
+ @components[@pos+1] =~ /^(through|to|until)$/ && @date2 = @components[@pos+2].interpret_date(@curdate)
1134
+ end
1135
+
1136
+ def found_date_through_date
1137
+ @constructs << DateSpanConstruct.new(:start_date => @date1, :end_date => @date2, :comp_start => @pos, :comp_end => @pos += 2, :found_in => method_name)
1138
+ end
1139
+
1140
+ def found_date
1141
+ @constructs << DateConstruct.new(:date => @date1, :comp_start => @pos, :comp_end => @pos, :found_in => method_name)
1142
+ end
1143
+ end # END class ConstructFinder
1144
+ end
1145
+