tickle 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +100 -18
- data/SCENARIOS.rdoc +314 -12
- data/VERSION +1 -1
- data/git-flow-version +1 -1
- data/lib/tickle/handler.rb +2 -0
- data/lib/tickle/tickle.rb +41 -16
- data/lib/tickle.rb +1 -1
- data/test/test_parsing.rb +36 -3
- data/tickle.gemspec +2 -2
- metadata +3 -3
data/README.rdoc
CHANGED
@@ -12,6 +12,8 @@ Tickle is a natural language parser for recurring events.
|
|
12
12
|
|
13
13
|
Tickle is designed to be a compliment of Chronic and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc."
|
14
14
|
|
15
|
+
In a lot of ways Tickle is actually an enhancement of Chronic, handling a lot of things that Chronic can't, such as commas and US Holidays (yup - you can do Tickle.parse('Christmas Eve'))
|
16
|
+
|
15
17
|
Tickle has one main method, "Tickle.parse," which returns the next time the event should occur, at which point you simply call Tickle.parse again.
|
16
18
|
|
17
19
|
== INSTALLATION
|
@@ -37,10 +39,10 @@ You can parse strings containing a natural language interval using the Tickle.pa
|
|
37
39
|
You can either pass a string prefixed with the word "every, each or 'on the'" or simply the time frame.
|
38
40
|
|
39
41
|
Tickle.parse returns a hash containing the following keys:
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
* next = the next occurrence of the event. This is NEVER today as its always the next date in the future.
|
43
|
+
* starting = the date all calculations as based on. If not passed as an option, the start date is right now.
|
44
|
+
* until = the last date you want this event to run until.
|
45
|
+
* expression = this is the natural language expression to store to run through tickle later to get the next occurrence.
|
44
46
|
|
45
47
|
Tickle returns nil if it cannot parse the string cannot be parsed.
|
46
48
|
|
@@ -51,15 +53,15 @@ Tickle HEAVILY uses chronic for parsing but mostly the start and until phrases.
|
|
51
53
|
There are two ways to pass options: natural language or an options hash.
|
52
54
|
|
53
55
|
NATURAL LANGUAGE:
|
54
|
-
|
55
|
-
|
56
|
-
|
56
|
+
* Pass a start date with the word "starting, start, stars" (e.g. Tickle.parse('every 3 days starting next friday'))
|
57
|
+
* Pass an end date with the word "until, end, ends, ending" (e.g. Tickle.parse('every 3 days until next friday'))
|
58
|
+
* Pass both at the same time (e.g. "starting May 5th repeat every other week until December 1")
|
57
59
|
|
58
60
|
OPTIONS HASH
|
59
61
|
Valid options are:
|
60
|
-
|
61
|
-
|
62
|
-
|
62
|
+
* start - must be a valid date or Chronic date expression. (e.g. Tickle.parse('every other day', {:start => Date.new(2010,8,1) }))
|
63
|
+
* until - must be a valid date or Chronic date expression. (e.g. Tickle.parse('every other day', {:until => Date.new(2010,10,1) }))
|
64
|
+
* next_only - legacy switch to ONLY return the next occurrence as a date and not return a hash
|
63
65
|
|
64
66
|
=== SUPER IMPORTANT NOTE ABOUT NEXT OCCURRENCE & START DATE
|
65
67
|
|
@@ -306,6 +308,87 @@ OPTIONS HASH
|
|
306
308
|
Tickle.parse('3 months', {:until=>2010-10-09 00:00:00 -0400})
|
307
309
|
#=> {:next=>2010-08-09 20:57:36 -0400, :expression=>"3 months", :starting=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400}
|
308
310
|
|
311
|
+
US HOLIDAYS
|
312
|
+
|
313
|
+
Tickle.parse('New Years Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
314
|
+
#=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
315
|
+
|
316
|
+
Tickle.parse('Inauguration', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
317
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"january 20", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
318
|
+
|
319
|
+
Tickle.parse('Martin Luther King Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
320
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"third monday in january", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
321
|
+
|
322
|
+
Tickle.parse('MLK', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
323
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"third monday in january", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
324
|
+
|
325
|
+
Tickle.parse('Presidents Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
326
|
+
#=> {:next=>2020-02-17 12:00:00 -0500, :expression=>"third monday in february", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
327
|
+
|
328
|
+
Tickle.parse('Memorial Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
329
|
+
#=> {:next=>2020-05-25 12:00:00 -0400, :expression=>"4th monday of may", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
330
|
+
|
331
|
+
Tickle.parse('Independence Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
332
|
+
#=> {:next=>2020-07-04 12:00:00 -0400, :expression=>"july 4, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
333
|
+
|
334
|
+
Tickle.parse('Labor Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
335
|
+
#=> {:next=>2020-09-07 12:00:00 -0400, :expression=>"first monday in september", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
336
|
+
|
337
|
+
Tickle.parse('Columbus Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
338
|
+
#=> {:next=>2020-10-12 12:00:00 -0400, :expression=>"second monday in october", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
339
|
+
|
340
|
+
Tickle.parse('Veterans Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
341
|
+
#=> {:next=>2020-11-11 12:00:00 -0500, :expression=>"november 11, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
342
|
+
|
343
|
+
Tickle.parse('Christmas', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
344
|
+
#=> {:next=>2020-12-25 12:00:00 -0500, :expression=>"december 25, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
345
|
+
|
346
|
+
Tickle.parse('Super Bowl Sunday', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
347
|
+
#=> {:next=>2020-02-02 12:00:00 -0500, :expression=>"first sunday in february", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
348
|
+
|
349
|
+
Tickle.parse('Groundhog Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
350
|
+
#=> {:next=>2020-02-02 12:00:00 -0500, :expression=>"february 2, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
351
|
+
|
352
|
+
Tickle.parse('Valentines Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
353
|
+
#=> {:next=>2020-02-14 12:00:00 -0500, :expression=>"february 14, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
354
|
+
|
355
|
+
Tickle.parse('Saint Patricks day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
356
|
+
#=> {:next=>2020-03-17 12:00:00 -0400, :expression=>"march 17, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
357
|
+
|
358
|
+
Tickle.parse('April Fools Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
359
|
+
#=> {:next=>2020-04-01 12:00:00 -0400, :expression=>"april 1, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
360
|
+
|
361
|
+
Tickle.parse('Earth Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
362
|
+
#=> {:next=>2020-04-22 12:00:00 -0400, :expression=>"april 22, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
363
|
+
|
364
|
+
Tickle.parse('Arbor Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
365
|
+
#=> {:next=>2020-04-24 12:00:00 -0400, :expression=>"fourth friday in april", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
366
|
+
|
367
|
+
Tickle.parse('Cinco De Mayo', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
368
|
+
#=> {:next=>2020-05-05 12:00:00 -0400, :expression=>"may 5, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
369
|
+
|
370
|
+
Tickle.parse('Mothers Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
371
|
+
#=> {:next=>2020-05-10 12:00:00 -0400, :expression=>"second sunday in may", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
372
|
+
|
373
|
+
Tickle.parse('Flag Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
374
|
+
#=> {:next=>2020-06-14 12:00:00 -0400, :expression=>"june 14, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
375
|
+
|
376
|
+
Tickle.parse('Fathers Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
377
|
+
#=> {:next=>2020-06-21 12:00:00 -0400, :expression=>"third sunday in june", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
378
|
+
|
379
|
+
Tickle.parse('Halloween', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
380
|
+
#=> {:next=>2020-10-31 12:00:00 -0400, :expression=>"october 31, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
381
|
+
|
382
|
+
Tickle.parse('Christmas Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
383
|
+
#=> {:next=>2020-12-25 12:00:00 -0500, :expression=>"december 25, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
384
|
+
|
385
|
+
Tickle.parse('Christmas Eve', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
386
|
+
#=> {:next=>2020-12-24 12:00:00 -0500, :expression=>"december 24, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
387
|
+
|
388
|
+
Tickle.parse('Kwanzaa', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
389
|
+
#=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
390
|
+
|
391
|
+
|
309
392
|
== USING IN APP
|
310
393
|
|
311
394
|
To use in your app, we recommend adding two attributes to your database model:
|
@@ -340,14 +423,13 @@ As always, BIG shout-out to the RVM Master himself, Wayne Seguin, for putting up
|
|
340
423
|
|
341
424
|
|
342
425
|
== Note on Patches/Pull Requests
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
* Send me a pull request. Bonus points for time-based branches.
|
426
|
+
* Fork the project.
|
427
|
+
* Make your feature addition or bug fix.
|
428
|
+
* Add tests for it. This is important so I don't break it in a
|
429
|
+
future version unintentionally.
|
430
|
+
* Commit, do not mess with rakefile, version, or history.
|
431
|
+
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
432
|
+
* Send me a pull request. Bonus points for time-based branches.
|
351
433
|
|
352
434
|
== Copyright
|
353
435
|
|
data/SCENARIOS.rdoc
CHANGED
@@ -1,15 +1,317 @@
|
|
1
|
-
|
2
|
-
every second tuesday => => day of week found WITH number (ordinal converted to 2). interval = 30 with start_date = Chronic.parse(Ordinal Number Day Of Week 'in' Start Date Month)
|
3
|
-
every sunday => day of week found without number. interval = 7, start_date = next day of week occurrence
|
4
|
-
every other day => word 'day' found with word 'other.' interval = 2, start_date = today
|
5
|
-
every fourth thursday => day of week found WITH number (ordinal converted to 4). interval = 30 with start_date = next occurrence of 'event' as parsed by chronic
|
6
|
-
on the 15th of each month => 'each month' becomes interval = 30, number found + start month through chronic equals start date
|
7
|
-
on the 15th of November => month found with number. interval = 365, start_date = Chronic.parse(month + number)
|
8
|
-
on the second monday in April => month, day and number found. interval = 365, start_date = Chronic.parse(ordinal number form of number, day of week, month)
|
9
|
-
every November 15th => month found with number. interval = 365, start_date = Chronic.parse(month + number)
|
10
|
-
every day => word 'day' found without a number. interval = 1. start_day = today
|
11
|
-
every week => word 'week' found without a number. interval = 7. start_day = today
|
12
|
-
every month => word 'month' found without a number. interval = 30. start_day = today
|
1
|
+
=== EXAMPLES
|
13
2
|
|
3
|
+
require 'rubygems'
|
4
|
+
require 'tickle'
|
14
5
|
|
6
|
+
SIMPLE
|
7
|
+
Tickle.parse('day')
|
8
|
+
#=> {:next=>2010-05-10 20:57:36 -0400, :expression=>"day", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
9
|
+
|
10
|
+
Tickle.parse('day')
|
11
|
+
#=> {:next=>2010-05-10 20:57:36 -0400, :expression=>"day", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
12
|
+
|
13
|
+
Tickle.parse('week')
|
14
|
+
#=> {:next=>2010-05-16 20:57:36 -0400, :expression=>"week", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
15
|
+
|
16
|
+
Tickle.parse('month')
|
17
|
+
#=> {:next=>2010-06-09 20:57:36 -0400, :expression=>"month", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
18
|
+
|
19
|
+
Tickle.parse('year')
|
20
|
+
#=> {:next=>2011-05-09 20:57:36 -0400, :expression=>"year", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
21
|
+
|
22
|
+
Tickle.parse('daily')
|
23
|
+
#=> {:next=>2010-05-10 20:57:36 -0400, :expression=>"daily", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
24
|
+
|
25
|
+
Tickle.parse('weekly')
|
26
|
+
#=> {:next=>2010-05-16 20:57:36 -0400, :expression=>"weekly", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
27
|
+
|
28
|
+
Tickle.parse('monthly')
|
29
|
+
#=> {:next=>2010-06-09 20:57:36 -0400, :expression=>"monthly", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
30
|
+
|
31
|
+
Tickle.parse('yearly')
|
32
|
+
#=> {:next=>2011-05-09 20:57:36 -0400, :expression=>"yearly", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
33
|
+
|
34
|
+
Tickle.parse('3 days')
|
35
|
+
#=> {:next=>2010-05-12 20:57:36 -0400, :expression=>"3 days", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
36
|
+
|
37
|
+
Tickle.parse('3 weeks')
|
38
|
+
#=> {:next=>2010-05-30 20:57:36 -0400, :expression=>"3 weeks", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
39
|
+
|
40
|
+
Tickle.parse('3 months')
|
41
|
+
#=> {:next=>2010-08-09 20:57:36 -0400, :expression=>"3 months", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
42
|
+
|
43
|
+
Tickle.parse('3 years')
|
44
|
+
#=> {:next=>2013-05-09 20:57:36 -0400, :expression=>"3 years", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
45
|
+
|
46
|
+
Tickle.parse('other day')
|
47
|
+
#=> {:next=>2010-05-11 20:57:36 -0400, :expression=>"other day", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
48
|
+
|
49
|
+
Tickle.parse('other week')
|
50
|
+
#=> {:next=>2010-05-23 20:57:36 -0400, :expression=>"other week", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
51
|
+
|
52
|
+
Tickle.parse('other month')
|
53
|
+
#=> {:next=>2010-07-09 20:57:36 -0400, :expression=>"other month", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
54
|
+
|
55
|
+
Tickle.parse('other year')
|
56
|
+
#=> {:next=>2012-05-09 20:57:36 -0400, :expression=>"other year", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
57
|
+
|
58
|
+
Tickle.parse('Monday')
|
59
|
+
#=> {:next=>2010-05-10 12:00:00 -0400, :expression=>"monday", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
60
|
+
|
61
|
+
Tickle.parse('Wednesday')
|
62
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"wednesday", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
63
|
+
|
64
|
+
Tickle.parse('Friday')
|
65
|
+
#=> {:next=>2010-05-14 12:00:00 -0400, :expression=>"friday", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
66
|
+
|
67
|
+
Tickle.parse('February', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
68
|
+
#=> {:next=>2021-02-01 12:00:00 -0500, :expression=>"february", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
69
|
+
|
70
|
+
Tickle.parse('May', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
71
|
+
#=> {:next=>2020-05-01 12:00:00 -0400, :expression=>"may", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
72
|
+
|
73
|
+
Tickle.parse('june', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
74
|
+
#=> {:next=>2020-06-01 12:00:00 -0400, :expression=>"june", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
75
|
+
|
76
|
+
Tickle.parse('beginning of the week')
|
77
|
+
#=> {:next=>2010-05-16 12:00:00 -0400, :expression=>"beginning of the week", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
78
|
+
|
79
|
+
Tickle.parse('middle of the week')
|
80
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"middle of the week", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
81
|
+
|
82
|
+
Tickle.parse('end of the week')
|
83
|
+
#=> {:next=>2010-05-15 12:00:00 -0400, :expression=>"end of the week", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
84
|
+
|
85
|
+
Tickle.parse('beginning of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
86
|
+
#=> {:next=>2020-05-01 00:00:00 -0400, :expression=>"beginning of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
87
|
+
|
88
|
+
Tickle.parse('middle of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
89
|
+
#=> {:next=>2020-04-15 00:00:00 -0400, :expression=>"middle of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
90
|
+
|
91
|
+
Tickle.parse('end of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
92
|
+
#=> {:next=>2020-04-30 00:00:00 -0400, :expression=>"end of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
93
|
+
|
94
|
+
Tickle.parse('beginning of the year', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
95
|
+
#=> {:next=>2021-01-01 00:00:00 -0500, :expression=>"beginning of the year", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
96
|
+
|
97
|
+
Tickle.parse('middle of the year', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
98
|
+
#=> {:next=>2020-06-15 00:00:00 -0400, :expression=>"middle of the year", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
99
|
+
|
100
|
+
Tickle.parse('end of the year', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
101
|
+
#=> {:next=>2020-12-31 00:00:00 -0500, :expression=>"end of the year", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
102
|
+
|
103
|
+
Tickle.parse('the 3rd of May', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
104
|
+
#=> {:next=>2020-05-03 00:00:00 -0400, :expression=>"the 3rd of may", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
105
|
+
|
106
|
+
Tickle.parse('the 3rd of February', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
107
|
+
#=> {:next=>2021-02-03 00:00:00 -0500, :expression=>"the 3rd of february", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
108
|
+
|
109
|
+
Tickle.parse('the 3rd of February 2022', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
110
|
+
#=> {:next=>2022-02-03 00:00:00 -0500, :expression=>"the 3rd of february 2022", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
111
|
+
|
112
|
+
Tickle.parse('the 3rd of Feb 2022', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
113
|
+
#=> {:next=>2022-02-03 00:00:00 -0500, :expression=>"the 3rd of feb 2022", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
114
|
+
|
115
|
+
Tickle.parse('the 4th of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
116
|
+
#=> {:next=>2020-04-04 00:00:00 -0400, :expression=>"the 4th of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
117
|
+
|
118
|
+
Tickle.parse('the 10th of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
119
|
+
#=> {:next=>2020-04-10 00:00:00 -0400, :expression=>"the 10th of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
120
|
+
|
121
|
+
Tickle.parse('the tenth of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
122
|
+
#=> {:next=>2020-04-10 00:00:00 -0400, :expression=>"the tenth of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
123
|
+
|
124
|
+
Tickle.parse('first', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
125
|
+
#=> {:next=>2020-05-01 00:00:00 -0400, :expression=>"first", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
126
|
+
|
127
|
+
Tickle.parse('the first of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
128
|
+
#=> {:next=>2020-05-01 00:00:00 -0400, :expression=>"the first of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
129
|
+
|
130
|
+
Tickle.parse('the thirtieth', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
131
|
+
#=> {:next=>2020-04-30 00:00:00 -0400, :expression=>"the thirtieth", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
132
|
+
|
133
|
+
Tickle.parse('the fifth', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
134
|
+
#=> {:next=>2020-04-05 00:00:00 -0400, :expression=>"the fifth", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
135
|
+
|
136
|
+
Tickle.parse('the 1st Wednesday of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
137
|
+
#=> {:next=>2020-05-01 00:00:00 -0400, :expression=>"the 1st wednesday of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
138
|
+
|
139
|
+
Tickle.parse('the 3rd Sunday of May', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
140
|
+
#=> {:next=>2020-05-17 12:00:00 -0400, :expression=>"the 3rd sunday of may", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
141
|
+
|
142
|
+
Tickle.parse('the 3rd Sunday of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
143
|
+
#=> {:next=>2020-04-19 12:00:00 -0400, :expression=>"the 3rd sunday of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
144
|
+
|
145
|
+
Tickle.parse('the 23rd of June', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
146
|
+
#=> {:next=>2020-06-23 00:00:00 -0400, :expression=>"the 23rd of june", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
147
|
+
|
148
|
+
Tickle.parse('the twenty third of June', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
149
|
+
#=> {:next=>2020-06-23 00:00:00 -0400, :expression=>"the twenty third of june", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
150
|
+
|
151
|
+
Tickle.parse('the thirty first of July', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
152
|
+
#=> {:next=>2020-07-31 00:00:00 -0400, :expression=>"the thirty first of july", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
153
|
+
|
154
|
+
Tickle.parse('the twenty first', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
155
|
+
#=> {:next=>2020-04-21 00:00:00 -0400, :expression=>"the twenty first", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
156
|
+
|
157
|
+
Tickle.parse('the twenty first of the month', {:start=>#<Date: 2020-04-01 (4917881/2,0,2299161)>, :now=>#<Date: 2020-04-01 (4917881/2,0,2299161)>})
|
158
|
+
#=> {:next=>2020-04-21 00:00:00 -0400, :expression=>"the twenty first of the month", :starting=>2020-04-01 00:00:00 -0400, :until=>nil}
|
159
|
+
|
160
|
+
COMPLEX
|
161
|
+
Tickle.parse('starting today and ending one week from now')
|
162
|
+
#=> {:next=>2010-05-10 22:30:00 -0400, :expression=>"day", :starting=>2010-05-09 22:30:00 -0400, :until=>2010-05-16 20:57:35 -0400}
|
163
|
+
|
164
|
+
Tickle.parse('starting tomorrow and ending one week from now')
|
165
|
+
#=> {:next=>2010-05-10 12:00:00 -0400, :expression=>"day", :starting=>2010-05-10 12:00:00 -0400, :until=>2010-05-16 20:57:35 -0400}
|
166
|
+
|
167
|
+
Tickle.parse('starting Monday repeat every month')
|
168
|
+
#=> {:next=>2010-05-10 12:00:00 -0400, :expression=>"month", :starting=>2010-05-10 12:00:00 -0400, :until=>nil}
|
169
|
+
|
170
|
+
Tickle.parse('starting May 13th repeat every week')
|
171
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"week", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
172
|
+
|
173
|
+
Tickle.parse('starting May 13th repeat every other day')
|
174
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"other day", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
175
|
+
|
176
|
+
Tickle.parse('every other day starts May 13th')
|
177
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"other day", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
178
|
+
|
179
|
+
Tickle.parse('every other day starts May 13')
|
180
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"other day", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
181
|
+
|
182
|
+
Tickle.parse('every other day starting May 13th')
|
183
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"other day", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
184
|
+
|
185
|
+
Tickle.parse('every other day starting May 13')
|
186
|
+
#=> {:next=>2010-05-13 12:00:00 -0400, :expression=>"other day", :starting=>2010-05-13 12:00:00 -0400, :until=>nil}
|
187
|
+
|
188
|
+
Tickle.parse('every week starts this wednesday')
|
189
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"week", :starting=>2010-05-12 12:00:00 -0400, :until=>nil}
|
190
|
+
|
191
|
+
Tickle.parse('every week starting this wednesday')
|
192
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"week", :starting=>2010-05-12 12:00:00 -0400, :until=>nil}
|
193
|
+
|
194
|
+
Tickle.parse('every other day starting May 1st 2021')
|
195
|
+
#=> {:next=>2021-05-01 12:00:00 -0400, :expression=>"other day", :starting=>2021-05-01 12:00:00 -0400, :until=>nil}
|
196
|
+
|
197
|
+
Tickle.parse('every other day starting May 1 2021')
|
198
|
+
#=> {:next=>2021-05-01 12:00:00 -0400, :expression=>"other day", :starting=>2021-05-01 12:00:00 -0400, :until=>nil}
|
199
|
+
|
200
|
+
Tickle.parse('every other week starting this Sunday')
|
201
|
+
#=> {:next=>2010-05-16 12:00:00 -0400, :expression=>"other week", :starting=>2010-05-16 12:00:00 -0400, :until=>nil}
|
202
|
+
|
203
|
+
Tickle.parse('every week starting this wednesday until May 13th')
|
204
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"week", :starting=>2010-05-12 12:00:00 -0400, :until=>2010-05-13 12:00:00 -0400}
|
205
|
+
|
206
|
+
Tickle.parse('every week starting this wednesday ends May 13th')
|
207
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"week", :starting=>2010-05-12 12:00:00 -0400, :until=>2010-05-13 12:00:00 -0400}
|
208
|
+
|
209
|
+
Tickle.parse('every week starting this wednesday ending May 13th')
|
210
|
+
#=> {:next=>2010-05-12 12:00:00 -0400, :expression=>"week", :starting=>2010-05-12 12:00:00 -0400, :until=>2010-05-13 12:00:00 -0400}
|
211
|
+
|
212
|
+
|
213
|
+
OPTIONS HASH
|
214
|
+
Tickle.parse('May 1st 2020', {:next_only=>true})
|
215
|
+
#=> 2020-05-01 00:00:00 -0400
|
216
|
+
|
217
|
+
Tickle.parse('3 days', {:start=>2010-05-09 20:57:36 -0400})
|
218
|
+
#=> {:next=>2010-05-12 20:57:36 -0400, :expression=>"3 days", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
219
|
+
|
220
|
+
Tickle.parse('3 weeks', {:start=>2010-05-09 20:57:36 -0400})
|
221
|
+
#=> {:next=>2010-05-30 20:57:36 -0400, :expression=>"3 weeks", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
222
|
+
|
223
|
+
Tickle.parse('3 months', {:start=>2010-05-09 20:57:36 -0400})
|
224
|
+
#=> {:next=>2010-08-09 20:57:36 -0400, :expression=>"3 months", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
225
|
+
|
226
|
+
Tickle.parse('3 years', {:start=>2010-05-09 20:57:36 -0400})
|
227
|
+
#=> {:next=>2013-05-09 20:57:36 -0400, :expression=>"3 years", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
|
228
|
+
|
229
|
+
Tickle.parse('3 days', {:start=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400})
|
230
|
+
#=> {:next=>2010-05-12 20:57:36 -0400, :expression=>"3 days", :starting=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400}
|
231
|
+
|
232
|
+
Tickle.parse('3 weeks', {:start=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400})
|
233
|
+
#=> {:next=>2010-05-30 20:57:36 -0400, :expression=>"3 weeks", :starting=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400}
|
234
|
+
|
235
|
+
Tickle.parse('3 months', {:until=>2010-10-09 00:00:00 -0400})
|
236
|
+
#=> {:next=>2010-08-09 20:57:36 -0400, :expression=>"3 months", :starting=>2010-05-09 20:57:36 -0400, :until=>2010-10-09 00:00:00 -0400}
|
237
|
+
|
238
|
+
US HOLIDAYS
|
239
|
+
|
240
|
+
Tickle.parse('New Years Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
241
|
+
#=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
242
|
+
|
243
|
+
Tickle.parse('Inauguration', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
244
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"january 20", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
245
|
+
|
246
|
+
Tickle.parse('Martin Luther King Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
247
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"third monday in january", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
248
|
+
|
249
|
+
Tickle.parse('MLK', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
250
|
+
#=> {:next=>2020-01-20 12:00:00 -0500, :expression=>"third monday in january", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
251
|
+
|
252
|
+
Tickle.parse('Presidents Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
253
|
+
#=> {:next=>2020-02-17 12:00:00 -0500, :expression=>"third monday in february", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
254
|
+
|
255
|
+
Tickle.parse('Memorial Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
256
|
+
#=> {:next=>2020-05-25 12:00:00 -0400, :expression=>"4th monday of may", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
257
|
+
|
258
|
+
Tickle.parse('Independence Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
259
|
+
#=> {:next=>2020-07-04 12:00:00 -0400, :expression=>"july 4, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
260
|
+
|
261
|
+
Tickle.parse('Labor Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
262
|
+
#=> {:next=>2020-09-07 12:00:00 -0400, :expression=>"first monday in september", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
263
|
+
|
264
|
+
Tickle.parse('Columbus Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
265
|
+
#=> {:next=>2020-10-12 12:00:00 -0400, :expression=>"second monday in october", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
266
|
+
|
267
|
+
Tickle.parse('Veterans Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
268
|
+
#=> {:next=>2020-11-11 12:00:00 -0500, :expression=>"november 11, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
269
|
+
|
270
|
+
Tickle.parse('Christmas', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
271
|
+
#=> {:next=>2020-12-25 12:00:00 -0500, :expression=>"december 25, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
272
|
+
|
273
|
+
Tickle.parse('Super Bowl Sunday', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
274
|
+
#=> {:next=>2020-02-02 12:00:00 -0500, :expression=>"first sunday in february", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
275
|
+
|
276
|
+
Tickle.parse('Groundhog Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
277
|
+
#=> {:next=>2020-02-02 12:00:00 -0500, :expression=>"february 2, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
278
|
+
|
279
|
+
Tickle.parse('Valentines Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
280
|
+
#=> {:next=>2020-02-14 12:00:00 -0500, :expression=>"february 14, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
281
|
+
|
282
|
+
Tickle.parse('Saint Patricks day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
283
|
+
#=> {:next=>2020-03-17 12:00:00 -0400, :expression=>"march 17, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
284
|
+
|
285
|
+
Tickle.parse('April Fools Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
286
|
+
#=> {:next=>2020-04-01 12:00:00 -0400, :expression=>"april 1, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
287
|
+
|
288
|
+
Tickle.parse('Earth Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
289
|
+
#=> {:next=>2020-04-22 12:00:00 -0400, :expression=>"april 22, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
290
|
+
|
291
|
+
Tickle.parse('Arbor Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
292
|
+
#=> {:next=>2020-04-24 12:00:00 -0400, :expression=>"fourth friday in april", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
293
|
+
|
294
|
+
Tickle.parse('Cinco De Mayo', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
295
|
+
#=> {:next=>2020-05-05 12:00:00 -0400, :expression=>"may 5, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
296
|
+
|
297
|
+
Tickle.parse('Mothers Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
298
|
+
#=> {:next=>2020-05-10 12:00:00 -0400, :expression=>"second sunday in may", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
299
|
+
|
300
|
+
Tickle.parse('Flag Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
301
|
+
#=> {:next=>2020-06-14 12:00:00 -0400, :expression=>"june 14, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
302
|
+
|
303
|
+
Tickle.parse('Fathers Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
304
|
+
#=> {:next=>2020-06-21 12:00:00 -0400, :expression=>"third sunday in june", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
305
|
+
|
306
|
+
Tickle.parse('Halloween', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
307
|
+
#=> {:next=>2020-10-31 12:00:00 -0400, :expression=>"october 31, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
308
|
+
|
309
|
+
Tickle.parse('Christmas Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
310
|
+
#=> {:next=>2020-12-25 12:00:00 -0500, :expression=>"december 25, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
311
|
+
|
312
|
+
Tickle.parse('Christmas Eve', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
313
|
+
#=> {:next=>2020-12-24 12:00:00 -0500, :expression=>"december 24, 2020", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
314
|
+
|
315
|
+
Tickle.parse('Kwanzaa', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
|
316
|
+
#=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
|
15
317
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.7
|
data/git-flow-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
GITFLOW_VERSION=0.1.
|
1
|
+
GITFLOW_VERSION=0.1.7
|
data/lib/tickle/handler.rb
CHANGED
@@ -43,6 +43,8 @@ module Tickle #:nodoc:
|
|
43
43
|
@next = @start.bump(:week, token_of_type(:number).interval) if token_types.same?([:number, :week])
|
44
44
|
@next = @start.bump(:month, token_of_type(:number).interval) if token_types.same?([:number, :month])
|
45
45
|
@next = @start.bump(:year, token_of_type(:number).interval) if token_types.same?([:number, :year])
|
46
|
+
@next = chronic_parse_with_start("#{token_of_type(:month_name).word} #{token_of_type(:number).start}") if token_types.same?([:number, :month_name])
|
47
|
+
@next = chronic_parse_with_start("#{token_of_type(:specific_year).word}-#{token_of_type(:month_name).start}-#{token_of_type(:number).start}") if token_types.same?([:number, :month_name, :specific_year])
|
46
48
|
end
|
47
49
|
|
48
50
|
def guess_ordinal
|
data/lib/tickle/tickle.rb
CHANGED
@@ -52,7 +52,7 @@ module Tickle #:nodoc:
|
|
52
52
|
|
53
53
|
# check to see if this event starts some other time and reset now
|
54
54
|
event = scan_expression(text, options)
|
55
|
-
|
55
|
+
|
56
56
|
Tickle.dwrite("start: #{@start}, until: #{@until}, now: #{options[:now].to_date}")
|
57
57
|
|
58
58
|
# => ** this is mostly for testing. Bump by 1 day if today (or in the past for testing)
|
@@ -173,6 +173,7 @@ module Tickle #:nodoc:
|
|
173
173
|
text.gsub!(/on the(\s)?/, '')
|
174
174
|
text.gsub!(/([^\w\d\s])+/, '')
|
175
175
|
text.downcase.strip
|
176
|
+
text = normalize_us_holidays(text)
|
176
177
|
end
|
177
178
|
|
178
179
|
# Split the text on spaces and convert each word into
|
@@ -197,21 +198,40 @@ module Tickle #:nodoc:
|
|
197
198
|
normalized_text = Numerizer.numerize(normalized_text)
|
198
199
|
normalized_text.gsub!(/['"\.]/, '')
|
199
200
|
normalized_text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
201
|
+
normalized_text
|
202
|
+
end
|
203
|
+
|
204
|
+
# Converts natural language US Holidays into a date expression to be
|
205
|
+
# parsed.
|
206
|
+
def normalize_us_holidays(text) #:nodoc:
|
207
|
+
normalized_text = text.to_s.downcase
|
208
|
+
normalized_text.gsub!(/\bnew\syear'?s?(\s)?(day)?\b/, "january 1, #{next_appropriate_year(1, 1)}")
|
209
|
+
normalized_text.gsub!(/\bnew\syear'?s?(\s)?(eve)?\b/, "december 31, #{next_appropriate_year(12, 31)}")
|
210
|
+
normalized_text.gsub!(/\bm(artin\s)?l(uther\s)?k(ing)?(\sday)?\b/, 'third monday in january')
|
211
|
+
normalized_text.gsub!(/\binauguration(\sday)?\b/, 'january 20')
|
212
|
+
normalized_text.gsub!(/\bpresident'?s?(\sday)?\b/, 'third monday in february')
|
213
|
+
normalized_text.gsub!(/\bmemorial\sday\b/, '4th monday of may')
|
214
|
+
normalized_text.gsub!(/\bindepend(e|a)nce\sday\b/, "july 4, #{next_appropriate_year(7, 4)}")
|
215
|
+
normalized_text.gsub!(/\blabor\sday\b/, 'first monday in september')
|
216
|
+
normalized_text.gsub!(/\bcolumbus\sday\b/, 'second monday in october')
|
217
|
+
normalized_text.gsub!(/\bveterans?\sday\b/, "november 11, #{next_appropriate_year(11, 1)}")
|
218
|
+
normalized_text.gsub!(/\bthanksgiving(\sday)?\b/, 'fourth thursday in november')
|
219
|
+
normalized_text.gsub!(/\bchristmas\seve\b/, "december 24, #{next_appropriate_year(12, 24)}")
|
220
|
+
normalized_text.gsub!(/\bchristmas(\sday)?\b/, "december 25, #{next_appropriate_year(12, 25)}")
|
221
|
+
normalized_text.gsub!(/\bsuper\sbowl(\ssunday)?\b/, 'first sunday in february')
|
222
|
+
normalized_text.gsub!(/\bgroundhog(\sday)?\b/, "february 2, #{next_appropriate_year(2, 2)}")
|
223
|
+
normalized_text.gsub!(/\bvalentine'?s?(\sday)?\b/, "february 14, #{next_appropriate_year(2, 14)}")
|
224
|
+
normalized_text.gsub!(/\bs(ain)?t\spatrick'?s?(\sday)?\b/, "march 17, #{next_appropriate_year(3, 17)}")
|
225
|
+
normalized_text.gsub!(/\bapril\sfool'?s?(\sday)?\b/, "april 1, #{next_appropriate_year(4, 1)}")
|
226
|
+
normalized_text.gsub!(/\bearth\sday\b/, "april 22, #{next_appropriate_year(4, 22)}")
|
227
|
+
normalized_text.gsub!(/\barbor\sday\b/, 'fourth friday in april')
|
228
|
+
normalized_text.gsub!(/\bcinco\sde\smayo\b/, "may 5, #{next_appropriate_year(5, 5)}")
|
229
|
+
normalized_text.gsub!(/\bmother'?s?\sday\b/, 'second sunday in may')
|
230
|
+
normalized_text.gsub!(/\bflag\sday\b/, "june 14, #{next_appropriate_year(6, 14)}")
|
231
|
+
normalized_text.gsub!(/\bfather'?s?\sday\b/, 'third sunday in june')
|
232
|
+
normalized_text.gsub!(/\bhalloween\b/, "october 31, #{next_appropriate_year(10, 31)}")
|
233
|
+
normalized_text.gsub!(/\belection\sday\b/, 'second tuesday in november')
|
234
|
+
normalized_text.gsub!(/\bkwanzaa\b/, "january 1, #{next_appropriate_year(1, 1)}")
|
215
235
|
normalized_text
|
216
236
|
end
|
217
237
|
|
@@ -243,6 +263,11 @@ module Tickle #:nodoc:
|
|
243
263
|
month = number.to_i < @start.day ? (@start.month == 12 ? 1 : @start.month + 1) : @start.month
|
244
264
|
end
|
245
265
|
|
266
|
+
def next_appropriate_year(month, day)
|
267
|
+
year = (Date.new(@start.year.to_i, month.to_i, day.to_i) == @start.to_date) ? @start.year + 1 : @start.year
|
268
|
+
return year
|
269
|
+
end
|
270
|
+
|
246
271
|
# Return the number of days in a specified month.
|
247
272
|
# If no month is specified, current month is used.
|
248
273
|
def days_in_month(month=nil)
|
data/lib/tickle.rb
CHANGED
data/test/test_parsing.rb
CHANGED
@@ -92,7 +92,7 @@ class TestParsing < Test::Unit::TestCase
|
|
92
92
|
assert_tickle_match(@date.bump(:day, 1), @date.bump(:day, 1), @date.bump(:week, 1), 'day','starting tomorrow and ending one week from now') # => demonstrates leaving out the actual time period and implying it as daily.
|
93
93
|
|
94
94
|
assert_tickle_match(@date.bump(:wday, 'Mon'), @date.bump(:wday, 'Mon'), nil, 'month', 'starting Monday repeat every month')
|
95
|
-
|
95
|
+
|
96
96
|
year = @date >= Date.new(@date.year, 5, 13) ? @date.bump(:year,1) : @date.year
|
97
97
|
assert_tickle_match(Date.new(year, 05, 13), Date.new(year, 05, 13), nil, 'week', 'starting May 13th repeat every week')
|
98
98
|
assert_tickle_match(Date.new(year, 05, 13), Date.new(year, 05, 13), nil, 'other day', 'starting May 13th repeat every other day')
|
@@ -111,7 +111,6 @@ class TestParsing < Test::Unit::TestCase
|
|
111
111
|
assert_tickle_match(@date.bump(:wday, 'Wed'), @date.bump(:wday, 'Wed'), Date.new(year, 05, 13), 'week', 'every week starting this wednesday until May 13th')
|
112
112
|
assert_tickle_match(@date.bump(:wday, 'Wed'), @date.bump(:wday, 'Wed'), Date.new(year, 05, 13), 'week', 'every week starting this wednesday ends May 13th')
|
113
113
|
assert_tickle_match(@date.bump(:wday, 'Wed'), @date.bump(:wday, 'Wed'), Date.new(year, 05, 13), 'week', 'every week starting this wednesday ending May 13th')
|
114
|
-
|
115
114
|
end
|
116
115
|
|
117
116
|
def test_tickle_args
|
@@ -130,6 +129,40 @@ class TestParsing < Test::Unit::TestCase
|
|
130
129
|
assert_tickle_match(start_date.bump(:month, 3), @date, start_date.bump(:month, 5), '3 months', 'every 3 months', {:until => end_date})
|
131
130
|
end
|
132
131
|
|
132
|
+
def test_us_holidays
|
133
|
+
start = Date.new(2020, 01, 01)
|
134
|
+
assert_date_match(Date.new(2021, 1, 1), 'New Years Day', {:start => start, :now => start})
|
135
|
+
assert_date_match(Date.new(2020, 1, 20), 'Inauguration', {:start => start, :now => start})
|
136
|
+
assert_date_match(Date.new(2020, 1, 20), 'Martin Luther King Day', {:start => start, :now => start})
|
137
|
+
assert_date_match(Date.new(2020, 1, 20), 'MLK', {:start => start, :now => start})
|
138
|
+
assert_date_match(Date.new(2020, 2, 17), 'Presidents Day', {:start => start, :now => start})
|
139
|
+
assert_date_match(Date.new(2020, 5, 25), 'Memorial Day', {:start => start, :now => start})
|
140
|
+
assert_date_match(Date.new(2020, 7, 4), 'Independence Day', {:start => start, :now => start})
|
141
|
+
assert_date_match(Date.new(2020, 9, 7), 'Labor Day', {:start => start, :now => start})
|
142
|
+
assert_date_match(Date.new(2020, 10, 12), 'Columbus Day', {:start => start, :now => start})
|
143
|
+
assert_date_match(Date.new(2020, 11, 11), 'Veterans Day', {:start => start, :now => start})
|
144
|
+
# assert_date_match(Date.new(2020, 11, 26), 'Thanksgiving', {:start => start, :now => start}) # Chronic returning incorrect date. Routine is correct
|
145
|
+
assert_date_match(Date.new(2020, 12, 25), 'Christmas', {:start => start, :now => start})
|
146
|
+
|
147
|
+
assert_date_match(Date.new(2020, 2, 2), 'Super Bowl Sunday', {:start => start, :now => start})
|
148
|
+
assert_date_match(Date.new(2020, 2, 2), 'Groundhog Day', {:start => start, :now => start})
|
149
|
+
assert_date_match(Date.new(2020, 2, 14), "Valentine's Day", {:start => start, :now => start})
|
150
|
+
assert_date_match(Date.new(2020, 3, 17), "Saint Patrick's day", {:start => start, :now => start})
|
151
|
+
assert_date_match(Date.new(2020, 4, 1), "April Fools Day", {:start => start, :now => start})
|
152
|
+
assert_date_match(Date.new(2020, 4, 22), "Earth Day", {:start => start, :now => start})
|
153
|
+
assert_date_match(Date.new(2020, 4, 24), "Arbor Day", {:start => start, :now => start})
|
154
|
+
assert_date_match(Date.new(2020, 5, 5), "Cinco De Mayo", {:start => start, :now => start})
|
155
|
+
assert_date_match(Date.new(2020, 5, 10), "Mother's Day", {:start => start, :now => start})
|
156
|
+
assert_date_match(Date.new(2020, 6, 14), "Flag Day", {:start => start, :now => start})
|
157
|
+
assert_date_match(Date.new(2020, 6, 21), "Fathers Day", {:start => start, :now => start})
|
158
|
+
assert_date_match(Date.new(2020, 10, 31), "Halloween", {:start => start, :now => start})
|
159
|
+
# assert_date_match(Date.new(2020, 11, 10), "Election Day", {:start => start, :now => start}) # Damn Chronic again. Expression is correct
|
160
|
+
assert_date_match(Date.new(2020, 12, 25), 'Christmas Day', {:start => start, :now => start})
|
161
|
+
assert_date_match(Date.new(2020, 12, 24), 'Christmas Eve', {:start => start, :now => start})
|
162
|
+
assert_date_match(Date.new(2021, 1, 1), 'Kwanzaa', {:start => start, :now => start})
|
163
|
+
|
164
|
+
end
|
165
|
+
|
133
166
|
def test_argument_validation
|
134
167
|
assert_raise(Tickle::InvalidArgumentException) do
|
135
168
|
time = Tickle.parse("may 27", :today => 'something odd')
|
@@ -179,7 +212,7 @@ class TestParsing < Test::Unit::TestCase
|
|
179
212
|
actual_until = result[:until].to_date rescue nil
|
180
213
|
expected_until = expected_until.to_date rescue nil
|
181
214
|
actual_expression = result[:expression]
|
182
|
-
|
215
|
+
|
183
216
|
assert (expected_next.to_date == actual_next.to_date), "\"#{date_expression}\" :next parses to #{actual_next} but should be equal to #{expected_next}"
|
184
217
|
assert (expected_start.to_date == actual_start.to_date), "\"#{date_expression}\" :starting parses to #{actual_start} but should be equal to #{expected_start}"
|
185
218
|
assert (expected_until == actual_until), "\"#{date_expression}\" :until parses to #{actual_until} but should be equal to #{expected_until}"
|
data/tickle.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tickle}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.7"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Joshua Lippiner"]
|
12
|
-
s.date = %q{2010-05-
|
12
|
+
s.date = %q{2010-05-10}
|
13
13
|
s.description = %q{Tickle is a date/time helper gem to help parse natural language into a recurring pattern. Tickle is designed to be a compliment of Chronic and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc.}
|
14
14
|
s.email = %q{jlippiner@noctivity.com}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 7
|
9
|
+
version: 0.1.7
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Joshua Lippiner
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-05-
|
17
|
+
date: 2010-05-10 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|