tickle 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +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
|