tickle 0.1.7 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6c9f24bf840e38c2196e61c1428caa9d84eeb7b5
4
+ data.tar.gz: 6e8111fb7b6098f3c285d537b2adb529ede9ad36
5
+ SHA512:
6
+ metadata.gz: 84a13f5b64bd9e49327bca5456bbcb197b7d66b90b0f349ea035f842ffe8aa440a263aefc690d163c5023ac24e13b398b395da9e6d7240e9a89220c7c4ca9433
7
+ data.tar.gz: 2514f63b04e43ec3610932dc115ad127b29b9a384e9b99fe6c52606982ebb2537cb20ac06beccf2cfcc25630a5c2f7c5021870119ab39395b7fe9f4361af5a1b
data/.gitignore CHANGED
@@ -1,21 +1,21 @@
1
- ## MAC OS
2
1
  .DS_Store
3
2
 
4
- ## TEXTMATE
5
3
  *.tmproj
6
4
  tmtags
7
5
 
8
- ## EMACS
9
6
  *~
10
7
  \#*
11
8
  .\#*
12
9
 
13
- ## VIM
14
10
  *.swp
15
-
16
- ## PROJECT::GENERAL
11
+ doc/
17
12
  coverage
18
13
  rdoc
19
14
  pkg
20
-
21
- ## PROJECT::SPECIFIC
15
+ bin/
16
+ vendor/
17
+ Gemfile.lock
18
+ spec/
19
+ .yardoc/
20
+ .bundle/
21
+ .rspec
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.7
4
+ - jruby
5
+ - truffleruby
6
+
7
+ # whitelist
8
+ branches:
9
+ only:
10
+ - master
11
+ - develop
12
+ - v1-branch
@@ -0,0 +1,47 @@
1
+ # CH CH CH CH CHANGES! #
2
+
3
+ ## Friday the 18th of September 2020, v1.2.0
4
+
5
+ - Changed the dependency from chronic to gitlab-chronic
6
+ - Required numerizer explicitly to stop a bug
7
+ - Formatted the regex for legibility
8
+ - Fixed bug with "today and" in the tests
9
+ - Fixed a bug previously fixed on the v2 branch in 2f2a32ce9 with @start
10
+ - Added Timecop because we're beyond the date chosen in the tests. Tempus fugit!
11
+
12
+ ----
13
+
14
+ ## Wednesday the 15th of March 2017, v1.1.1 ##
15
+
16
+ * Bit of easier debugging added in.
17
+ * Bug fixes, thanks to https://github.com/dodomarocgenex for finding and helping with them.
18
+
19
+ ----
20
+
21
+ ## Wednesday the 22nd of February 2017, v1.1.0 ##
22
+
23
+ * Numerizer duplication removed. Thanks to https://github.com/bjonord.
24
+ * Some very minor changes to the project, no other code changes.
25
+
26
+ ----
27
+
28
+
29
+ ## Monday the 11th of November 2015, v1.0.2 ##
30
+
31
+ * Shoulda and simplecov aren't runtime dependencies, fixed that in the gemfile.
32
+ * Got the version number right this time ;-)
33
+
34
+ ----
35
+
36
+ ## Monday the 11th of November 2015, v1.0.1 ##
37
+
38
+ * Moved library to new maintainer [https://github.com/yb66/tickle](@yb66)
39
+ * Moved library to [http://semver.org/](semver).
40
+ * Merged in some changes from @dan335 and @JesseAldridge, thanks to them.
41
+ * Moved rdocs to markdown for niceness.
42
+ * Updated licences with dates and correct spelling ;)
43
+ * Fix incorporated for "NameError: uninitialized constant Module::Numerizer"
44
+ * Moved library to Bundler to make it easier to set up and develop against.
45
+ * Started using Yardoc for more niceness with documentation.
46
+
47
+ ----
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "rspec"
7
+ end
8
+
9
+ gem "pry-byebug"
10
+ gem "pry-state"
@@ -1,4 +1,6 @@
1
1
  Copyright (c) 2010 Joshua Lippiner
2
+ Copyright (c) 2013 Iain Barnett
3
+
2
4
 
3
5
  Permission is hereby granted, free of charge, to any person obtaining
4
6
  a copy of this software and associated documentation files (the
@@ -1,82 +1,71 @@
1
- = tickle
2
- http://github.com/noctivityinc/tickle
3
- by Joshua Lippiner, Noctivity
1
+ ## Tickle ##
4
2
 
5
- == *LEGACY WARNING*
3
+ This is now the home of ***Tickle***, previously found at [github.com/noctivityinc/tickle](https://github.com/noctivityinc/tickle)
6
4
 
7
- If you starting using Tickle pre version 0.1.X, you will need to update your code to either include the :next_only => true option or read correctly from the options hash. Sorry.
5
+ If you wish to contribute then please take a look at the Contribution section further down the page, but I'd be really, *really* grateful if anyone wishes to contribute specs. Not unit tests, but specs. This library's internals will be changing a lot over the coming months, and it would be good to have integration tests - a black-box spec of the library - to work against. Even if you've never contributed to a library before, now is your chance! I'll help anyone through with what they may need, and I promise not to be the standard snarky Open Source dictator that a lot of projects have. We'll try and improve this library together.
8
6
 
9
- == DESCRIPTION
7
+ Take a look at the `develop` branch where all this stuff will be happening.
10
8
 
11
- Tickle is a natural language parser for recurring events.
12
-
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
-
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
9
 
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.
10
+ ### DESCRIPTION ###
18
11
 
19
- == INSTALLATION
20
-
21
- Tickle can be installed via RubyGems:
22
-
23
- $ gem install tickle
24
-
25
- == TINKERING
12
+ Tickle is a natural language parser for recurring events.
13
+
14
+ Tickle is designed to be a complement to [Chronic](https://rubygems.org/gems/chronic) and can interpret things such as "every 2 days, every Sunday, Sundays, Weekly, etc."
26
15
 
27
- Everything's at Github - http://github.com/noctivityinc/tickle
16
+ 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.
28
17
 
29
- == DEPENDENCIES
18
+ ### *LEGACY WARNING* ###
30
19
 
31
- chronic gem (gem install chronic)
20
+ If you starting using Tickle pre version 0.1.X, you will need to update your code to either include the `:next_only => true` option or read correctly from the options hash. Sorry.
32
21
 
33
- thoughtbot's shoulda (gem install shoulda)
34
22
 
35
- == USAGE
23
+ ### USAGE ###
36
24
 
37
- You can parse strings containing a natural language interval using the Tickle.parse method.
25
+ You can parse strings containing a natural language interval using the `Tickle.parse` method.
38
26
 
39
- You can either pass a string prefixed with the word "every, each or 'on the'" or simply the time frame.
27
+ You can either pass a string prefixed with the word "every", "each" or "on the" or simply the timeframe.
40
28
 
41
29
  Tickle.parse returns a hash containing the following keys:
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.
30
+ * `next` the next occurrence of the event. This is NEVER today as its always the next date in the future.
31
+ * `starting` the date all calculations as based on. If not passed as an option, the start date is right now.
32
+ * `until` the last date you want this event to run until.
33
+ * `expression` this is the natural language expression to store to run through tickle later to get the next occurrence.
46
34
 
47
- Tickle returns nil if it cannot parse the string cannot be parsed.
35
+ Tickle returns `nil` if it cannot parse the string.
48
36
 
49
- Tickle HEAVILY uses chronic for parsing but mostly the start and until phrases.
37
+ Tickle ***heavily*** uses Chronic for parsing both the event and the start date.
50
38
 
51
- === OPTIONS
39
+ ### OPTIONS ###
52
40
 
53
41
  There are two ways to pass options: natural language or an options hash.
54
42
 
55
43
  NATURAL LANGUAGE:
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")
44
+ * Pass a start date with the word "starting", "start", or "stars" e.g. `Tickle.parse('every 3 days starting next friday')`
45
+ * Pass an end date with the word "until", "end", "ends", or "ending" e.g. `Tickle.parse('every 3 days until next friday')`
46
+ * Pass both at the same time e.g. `"starting May 5th repeat every other week until December 1"`
59
47
 
60
48
  OPTIONS HASH
61
49
  Valid options are:
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
50
+ * `start` - must be a valid date or Chronic date expression. e.g. `Tickle.parse('every other day', {:start => Date.new(2010,8,1) })`
51
+ * `until` - must be a valid date or Chronic date expression. e.g. `Tickle.parse('every other day', {:until => Date.new(2010,10,1) })`
52
+ * `next_only` - legacy switch to *only* return the next occurrence as a date and not return a hash
65
53
 
66
- === SUPER IMPORTANT NOTE ABOUT NEXT OCCURRENCE & START DATE
54
+ ### SUPER IMPORTANT NOTE ABOUT NEXT OCCURRENCE & START DATE ###
67
55
 
68
- You may notice when parsing an expression with a start date that the next occurrence IS the start date passed. This is DESIGNED BEHAVIOR.
56
+ You may notice when parsing an expression with a start date that the next occurrence **is** the start date passed. This is **designed behaviour**.
69
57
 
70
58
  Here's why - assume your user says "remind me every 3 weeks starting Dec 1" and today is May 8th. Well the first reminder needs to be sent on Dec 1, not Dec 21 (three weeks later).
71
59
 
72
- If you don't like that, fork and have fun but don't say I didn't warn ya.
60
+ If you don't like that, fork and have fun but don't say you weren't warned.
73
61
 
74
- === EXAMPLES
75
62
 
76
- require 'rubygems'
77
- require 'tickle'
63
+ ### EXAMPLES ###
64
+
65
+ require 'tickle'
66
+
67
+ #### SIMPLE ####
78
68
 
79
- SIMPLE
80
69
  Tickle.parse('day')
81
70
  #=> {:next=>2010-05-10 20:57:36 -0400, :expression=>"day", :starting=>2010-05-09 20:57:36 -0400, :until=>nil}
82
71
 
@@ -230,7 +219,8 @@ SIMPLE
230
219
  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)>})
231
220
  #=> {: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}
232
221
 
233
- COMPLEX
222
+ #### COMPLEX ####
223
+
234
224
  Tickle.parse('starting today and ending one week from now')
235
225
  #=> {: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}
236
226
 
@@ -283,7 +273,8 @@ COMPLEX
283
273
  #=> {: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}
284
274
 
285
275
 
286
- OPTIONS HASH
276
+ #### OPTIONS HASH ####
277
+
287
278
  Tickle.parse('May 1st 2020', {:next_only=>true})
288
279
  #=> 2020-05-01 00:00:00 -0400
289
280
 
@@ -308,7 +299,7 @@ OPTIONS HASH
308
299
  Tickle.parse('3 months', {:until=>2010-10-09 00:00:00 -0400})
309
300
  #=> {: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}
310
301
 
311
- US HOLIDAYS
302
+ #### US HOLIDAYS ####
312
303
 
313
304
  Tickle.parse('New Years Day', {:start=>#<Date: 2020-01-01 (4917699/2,0,2299161)>, :now=>#<Date: 2020-01-01 (4917699/2,0,2299161)>})
314
305
  #=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
@@ -389,48 +380,73 @@ US HOLIDAYS
389
380
  #=> {:next=>2021-01-01 12:00:00 -0500, :expression=>"january 1, 2021", :starting=>2020-01-01 00:00:00 -0500, :until=>nil}
390
381
 
391
382
 
392
- == USING IN APP
383
+ ### USING IN APP ###
393
384
 
394
385
  To use in your app, we recommend adding two attributes to your database model:
395
- * next_occurrence
396
- * tickle_expression
397
386
 
398
- Then call Tickle.parse(date expression) when you need to and save the results accordingly. In your
399
- code, each day, simply check to see if today is >= next_occurrence and, if so, run your block.
387
+ * `next_occurrence`
388
+ * `tickle_expression`
400
389
 
401
- After it completes, call Tickle.parse(tickle_expression) again to update the next occurrence of the event.
390
+ Then call `Tickle.parse("date expression goes here")` when you need to and save the results accordingly. In your
391
+ code, each day, simply check to see if today is `>= next_occurrence` and, if so, run your block.
402
392
 
393
+ After it completes, call `next_occurrence = Tickle.parse(tickle_expression)` again to update the next occurrence of the event.
403
394
 
404
- == TESTING
405
395
 
406
- Tickle comes with a full testing suite for simple, complex, options hash and invalid arguments.
396
+ ### INSTALLATION ###
407
397
 
408
- You also have some command line options:
409
- --v verbose output like the examples above
410
- --d debug output showing the guts of a date expression
398
+ Tickle can be installed via RubyGems:
399
+
400
+ gem install tickle
411
401
 
412
- == LIMITATIONS
402
+ or if you're using Bundler, add this to the Gemfile:
403
+
404
+ gem "tickle"
405
+
406
+ ### DEPENDENCIES ###
407
+
408
+ Chronic gem:
409
+
410
+ `gem install gitlab-chronic`
411
+
412
+ thoughtbot's [shoulda](https://rubygems.org/gems/shoulda):
413
+
414
+ `gem install shoulda`
415
+
416
+ or just run `bundle install`.
417
+
418
+
419
+ ### LIMITATIONS ###
413
420
 
414
421
  Currently, Tickle only works for day intervals but feel free to fork and add time-based interval support or send me a note if you really want me to add it.
415
422
 
416
- == CREDIT
417
423
 
418
- HUGE shout-out to both the creator of Chronic, Tom Preston-Werner (http://chronic.rubyforge.org/) as well as Brian Brownling who maintains a github version at http://github.com/mojombo/chronic.
424
+ ### CONTRIBUTING ###
425
+
426
+ Fork it, create a new branch for your changes, and send in a pull request.
427
+
428
+ * Only tested code gets in.
429
+ * Document it.
430
+ * If you want to work on something but aren't sure whether it'll get in, create a new branch and open a pull request before you've done any code. That will open an issue and we can discuss it.
431
+ * Do not mess with the Rakefile, version, or history (if you want to have your own version, that is fine but do it on a separate branch from the one I'm going to merge.)
432
+
433
+ ### TESTING ###
434
+
435
+ Tickle comes with a full testing suite for simple, complex, options hash and invalid arguments.
436
+
437
+ You also have some command line options:
438
+
439
+ * --v verbose output like the examples above
440
+ * --d debug output showing the guts of a date expression
419
441
 
420
- Without their work and code structure I'd be lost.
442
+ ### CREDIT ###
421
443
 
422
- As always, BIG shout-out to the RVM Master himself, Wayne Seguin, for putting up with me and Ruby from day one. Ask Wayne to make you some Ciabatta bread next time you see him
444
+ The original work on the library was done by *Joshua Lippiner* a.k.a. [Noctivity](https://github.com/noctivityinc).
423
445
 
446
+ ***HUGE*** shout-out to both the creator of Chronic, *Tom Preston-Werner* as well as *Brian Brownling* who maintains a Github version at [github.com/mojombo/chronic](https://github.com/mojombo/chronic).
424
447
 
425
- == Note on Patches/Pull Requests
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.
448
+ As always, ***BIG*** shout-out to the RVM Master himself, *Wayne Seguin*, for putting up with me and Ruby from day one. Ask Wayne to make you some ciabatta bread next time you see him.
433
449
 
434
- == Copyright
450
+ ### LICENCE ###
435
451
 
436
- Copyright (c) 2010 Joshua Lippiner. See LICENSE for details.
452
+ See the LICENCE file.
data/Rakefile CHANGED
@@ -1,25 +1,3 @@
1
- require 'rubygems'
2
- require 'rake'
3
-
4
- begin
5
- require 'jeweler'
6
- Jeweler::Tasks.new do |gem|
7
- gem.name = "tickle"
8
- gem.summary = 'natural language parser for recurring events'
9
- gem.description = '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.'
10
- gem.email = "jlippiner@noctivity.com"
11
- gem.homepage = "http://github.com/noctivityinc/tickle"
12
- gem.authors = ["Joshua Lippiner"]
13
- gem.add_dependency('chronic', '>= 0.2.3')
14
- gem.add_development_dependency "shoulda", ">= 2.10.3"
15
-
16
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
- end
18
- Jeweler::GemcutterTasks.new
19
- rescue LoadError
20
- puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
21
- end
22
-
23
1
  require 'rake/testtask'
24
2
  Rake::TestTask.new(:test) do |test|
25
3
  test.libs << 'lib' << 'test'
@@ -27,29 +5,22 @@ Rake::TestTask.new(:test) do |test|
27
5
  test.verbose = true
28
6
  end
29
7
 
30
- begin
31
- require 'rcov/rcovtask'
32
- Rcov::RcovTask.new do |test|
33
- test.libs << 'test'
34
- test.pattern = 'test/**/test_*.rb'
35
- test.verbose = true
36
- end
37
- rescue LoadError
38
- task :rcov do
39
- abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
40
- end
41
- end
8
+ task :default => :test
42
9
 
43
- task :test => :check_dependencies
44
10
 
45
- task :default => :test
11
+ desc "(Re-) generate documentation and place it in the docs/ dir. Open the index.html file in there to read it."
12
+ task :docs => [:"docs:environment", :"docs:yard"]
13
+ namespace :docs do
14
+
15
+ task :environment do
16
+ ENV["RACK_ENV"] = "documentation"
17
+ end
18
+
19
+ require 'yard'
46
20
 
47
- require 'rake/rdoctask'
48
- Rake::RDocTask.new do |rdoc|
49
- version = File.exist?('VERSION') ? File.read('VERSION') : ""
21
+ YARD::Rake::YardocTask.new :yard do |t|
22
+ t.files = ['lib/**/*.rb']
23
+ t.options = ['-odoc/'] # optional
24
+ end
50
25
 
51
- rdoc.rdoc_dir = 'rdoc'
52
- rdoc.title = "tickle #{version}"
53
- rdoc.rdoc_files.include('README*')
54
- rdoc.rdoc_files.include('lib/**/*.rb')
55
26
  end
@@ -0,0 +1,29 @@
1
+
2
+ require File.join(File.dirname(__FILE__), 'lib', 'tickle')
3
+
4
+ =begin
5
+
6
+ Tickle creates standard Ruby Time objects.
7
+
8
+ Time is ignored if there's also a date, unless the date is 'tomorrow'(?)
9
+
10
+ Tickle creates times in the servers local time zone.
11
+ To go from server time to user's local time...
12
+ user_time = server_time + (user_time_offset - server_time_offset)
13
+ eg (5:00PM Central) = (6:00PM Eastern + (-6 - -5))
14
+
15
+ Tickle makes 'May 30th' at 0:00, but 'June 18, 2011' and 'Christmas' at 12:00.
16
+ =end
17
+
18
+
19
+ server_offset = Time.now.utc_offset / 60 / 60
20
+
21
+ ['May 30th', '6:30 PM',
22
+ 'tomorrow at 6:00', 'June 18, 2011', 'Christmas'].each {|s|
23
+ time = Tickle.parse(s)[:next]
24
+ if s == 'Christmas'
25
+ time -= 12 * 60 * 60
26
+ end
27
+ print s, " --> server date: ", time
28
+ puts
29
+ }
@@ -9,16 +9,22 @@
9
9
 
10
10
  $LOAD_PATH.unshift(File.dirname(__FILE__)) # For use/testing when no gem is installed
11
11
 
12
+ if ENV["DEBUG"]
13
+ warn "DEBUG MODE ON"
14
+ require 'pry-byebug'
15
+ require 'pry-state'
16
+ binding.pry
17
+ end
18
+
12
19
  require 'date'
13
20
  require 'time'
14
- require 'chronic'
21
+ require 'gitlab-chronic'
15
22
 
16
23
  require 'tickle/tickle'
17
24
  require 'tickle/handler'
18
25
  require 'tickle/repeater'
19
26
 
20
27
  module Tickle #:nodoc:
21
- VERSION = "0.1.7"
22
28
 
23
29
  def self.debug=(val); @debug = val; end
24
30
 
@@ -48,20 +54,20 @@ class Date #:nodoc:
48
54
  amount ||= 1
49
55
  case attr
50
56
  when :day then
51
- Date.civil(self.year, self.month, self.day + amount)
57
+ Date.civil(self.year, self.month, self.day).next_day(amount)
52
58
  when :wday then
53
59
  amount = Date::ABBR_DAYNAMES.index(amount) if amount.is_a?(String)
54
60
  raise Exception, "specified day of week invalid. Use #{Date::ABBR_DAYNAMES}" unless amount
55
61
  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
56
- Date.civil(self.year, self.month, self.day + diff)
62
+ Date.civil(self.year, self.month, self.day).next_day(diff)
57
63
  when :week then
58
- Date.civil(self.year, self.month, self.day + (7*amount))
64
+ Date.civil(self.year, self.month, self.day).next_day(7*amount)
59
65
  when :month then
60
- Date.civil(self.year, self.month+amount, self.day)
66
+ Date.civil(self.year, self.month, self.day).next_month(amount)
61
67
  when :year then
62
- Date.civil(self.year + amount, self.month, self.day)
68
+ Date.civil(self.year, self.month, self.day).next_year(amount)
63
69
  else
64
- raise Exception, "type \"#{attr}\" not supported."
70
+ raise Exception, "type \"#{attr}\" not supported."
65
71
  end
66
72
  end
67
73
  end
@@ -71,27 +77,27 @@ class Time #:nodoc:
71
77
  amount ||= 1
72
78
  case attr
73
79
  when :sec then
74
- Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec + amount)
80
+ Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + amount
75
81
  when :min then
76
- Time.local(self.year, self.month, self.day, self.hour, self.min + amount, self.sec)
82
+ Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60)
77
83
  when :hour then
78
- Time.local(self.year, self.month, self.day, self.hour + amount, self.min, self.sec)
84
+ Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60 * 60)
79
85
  when :day then
80
- Time.local(self.year, self.month, self.day + amount, self.hour, self.min, self.sec)
86
+ Time.local(self.year, self.month, self.day, self.hour, self.min, self.sec) + (amount * 60 * 60 * 24)
81
87
  when :wday then
82
88
  amount = Time::RFC2822_DAY_NAME.index(amount) if amount.is_a?(String)
83
89
  raise Exception, "specified day of week invalid. Use #{Time::RFC2822_DAY_NAME}" unless amount
84
90
  diff = (amount > self.wday) ? (amount - self.wday) : (7 - (self.wday - amount))
85
- Time.local(self.year, self.month, self.day + diff, self.hour, self.min, self.sec)
91
+ DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_day(diff)
86
92
  when :week then
87
- Time.local(self.year, self.month, self.day + (amount * 7), self.hour, self.min, self.sec)
93
+ DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_day(amount * 7)
88
94
  when :month then
89
- Time.local(self.year, self.month + amount, self.day, self.hour, self.min, self.sec)
95
+ DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_month(amount)
90
96
  when :year then
91
- Time.local(self.year + amount, self.month, self.day, self.hour, self.min, self.sec)
97
+ DateTime.civil(self.year, self.month, self.day, self.hour, self.min, self.sec, self.zone).next_year(amount)
92
98
  else
93
99
  raise Exception, "type \"#{attr}\" not supported."
94
- end
100
+ end.to_time.localtime
95
101
  end
96
102
  end
97
103
 
@@ -19,8 +19,10 @@
19
19
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
20
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
21
 
22
- module Tickle #:nodoc:
23
- class << self #:nodoc:
22
+ require 'numerizer'
23
+
24
+ module Tickle
25
+ class << self
24
26
  # == Configuration options
25
27
  #
26
28
  # * +start+ - start date for future occurrences. Must be in valid date format.
@@ -105,9 +107,25 @@ module Tickle #:nodoc:
105
107
  def scan_expression(text, options)
106
108
  starting = ending = nil
107
109
 
108
- start_every_regex = /^(start(?:s|ing)?)\s(.*)(\s(?:every|each|\bon\b|repeat)(?:s|ing)?)(.*)/i
110
+ start_every_regex = /^
111
+ (start(?:s|ing)?) # 0
112
+ \s
113
+ (.*)
114
+ (\s(?:every|each|\bon\b|repeat) # 1
115
+ (?:s|ing)?) # 2
116
+ (.*) # 3
117
+ /ix
109
118
  every_start_regex = /^(every|each|\bon\b|repeat(?:the)?)\s(.*)(\s(?:start)(?:s|ing)?)(.*)/i
110
- start_ending_regex = /^(start(?:s|ing)?)\s(.*)(\s(?:\bend|until)(?:s|ing)?)(.*)/i
119
+ start_ending_regex = /^
120
+ (start(?:s|ing)?) # 0
121
+ \s+
122
+ (.*?)(?:\s+and)? # 1
123
+ (\s
124
+ (?:\bend|until)
125
+ (?:s|ing)?
126
+ ) # 2
127
+ (.*) # 3
128
+ /ix
111
129
  if text =~ start_every_regex
112
130
  starting = text.match(start_every_regex)[2].strip
113
131
  text = text.match(start_every_regex)[4].strip
@@ -117,8 +135,9 @@ module Tickle #:nodoc:
117
135
  text = text.match(every_start_regex)[4].strip
118
136
  starting, ending = process_for_ending(text)
119
137
  elsif text =~ start_ending_regex
120
- starting = text.match(start_ending_regex)[2].strip
121
- ending = text.match(start_ending_regex)[4].strip
138
+ md = text.match start_ending_regex
139
+ starting = md.captures[1]
140
+ ending = md.captures.last.strip
122
141
  event = 'day'
123
142
  else
124
143
  event, ending = process_for_ending(text)
@@ -127,6 +146,7 @@ module Tickle #:nodoc:
127
146
  # they gave a phrase so if we can't interpret then we need to raise an error
128
147
  if starting
129
148
  Tickle.dwrite("starting: #{starting}")
149
+ @start ||= nil # initialize the variable to quell warnings
130
150
  @start = chronic_parse(pre_filter(starting))
131
151
  if @start
132
152
  @start.to_time
@@ -172,8 +192,7 @@ module Tickle #:nodoc:
172
192
  text.gsub!(/repeat(s|ing)?(\s)?/, '')
173
193
  text.gsub!(/on the(\s)?/, '')
174
194
  text.gsub!(/([^\w\d\s])+/, '')
175
- text.downcase.strip
176
- text = normalize_us_holidays(text)
195
+ normalize_us_holidays(text.downcase.strip)
177
196
  end
178
197
 
179
198
  # Split the text on spaces and convert each word into
@@ -254,8 +273,6 @@ module Tickle #:nodoc:
254
273
  @tokens.map(&:type)
255
274
  end
256
275
 
257
- protected
258
-
259
276
  # Returns the next available month based on the current day of the month.
260
277
  # For example, if get_next_month(15) is called and the start date is the 10th, then it will return the 15th of this month.
261
278
  # However, if get_next_month(15) is called and the start date is the 18th, it will return the 15th of next month.
@@ -264,7 +281,8 @@ module Tickle #:nodoc:
264
281
  end
265
282
 
266
283
  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
284
+ start = @start || Date.today
285
+ year = (Date.new(start.year.to_i, month.to_i, day.to_i) == start.to_date) ? start.year + 1 : start.year
268
286
  return year
269
287
  end
270
288
 
@@ -0,0 +1,5 @@
1
+ module Tickle
2
+
3
+ # This library's current version.
4
+ VERSION = "1.2.0"
5
+ end
@@ -1,6 +1,13 @@
1
- require 'rubygems'
1
+ require 'simplecov'
2
+ SimpleCov.start do
3
+ add_filter "/vendor/"
4
+ add_filter "/bin/"
5
+ end
6
+
2
7
  require 'test/unit'
3
8
  require 'shoulda'
9
+ require 'timecop'
10
+
4
11
 
5
12
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
6
13
  $LOAD_PATH.unshift(File.dirname(__FILE__))
@@ -1,19 +1,25 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/helper')
1
+ require_relative './helper.rb'
2
2
  require 'time'
3
3
  require 'test/unit'
4
4
 
5
5
  class TestParsing < Test::Unit::TestCase
6
6
 
7
+ Time_now = Time.parse "2010-05-09 20:57:36 +0000"
7
8
  def setup
8
9
  Tickle.debug = (ARGV.detect {|a| a == '--d'})
9
10
  @verbose = (ARGV.detect {|a| a == '--v'})
10
-
11
- puts "Time.now"
12
- p Time.now
11
+ Timecop.freeze Time_now
12
+ ENV["TZ"] = "UTC"
13
13
 
14
14
  @date = Date.today
15
+ @tz = ENV["TZ"]
15
16
  end
16
17
 
18
+ def teardown
19
+ Timecop.return
20
+ ENV["TZ"] = @tz
21
+ end
22
+
17
23
  def test_parse_best_guess_simple
18
24
  start = Date.new(2020, 04, 01)
19
25
 
@@ -85,11 +91,14 @@ class TestParsing < Test::Unit::TestCase
85
91
  assert_date_match(Date.new(2020, 04, 21), 'the twenty first of the month', {:start => start, :now => start})
86
92
  end
87
93
 
88
- def test_parse_best_guess_complex
89
- start = Date.new(2020, 04, 01)
90
-
94
+ def test_parse_best_guess_complex_and
91
95
  assert_tickle_match(@date.bump(:day, 1), @date, @date.bump(:week, 1), 'day', 'starting today and ending one week from now') if Time.now.hour < 21 # => demonstrates leaving out the actual time period and implying it as daily
92
96
  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.
97
+ end
98
+
99
+
100
+ def test_parse_best_guess_complex
101
+ start = Date.new(2020, 04, 01)
93
102
 
94
103
  assert_tickle_match(@date.bump(:wday, 'Mon'), @date.bump(:wday, 'Mon'), nil, 'month', 'starting Monday repeat every month')
95
104
 
@@ -165,30 +174,30 @@ class TestParsing < Test::Unit::TestCase
165
174
 
166
175
  def test_argument_validation
167
176
  assert_raise(Tickle::InvalidArgumentException) do
168
- time = Tickle.parse("may 27", :today => 'something odd')
177
+ Tickle.parse("may 27", :today => 'something odd')
169
178
  end
170
179
 
171
180
  assert_raise(Tickle::InvalidArgumentException) do
172
- time = Tickle.parse("may 27", :foo => :bar)
181
+ Tickle.parse("may 27", :foo => :bar)
173
182
  end
174
183
 
175
184
  assert_raise(Tickle::InvalidArgumentException) do
176
- time = Tickle.parse(nil)
185
+ Tickle.parse(nil)
177
186
  end
178
187
 
179
188
  assert_raise(Tickle::InvalidDateExpression) do
180
189
  past_date = Date.civil(Date.today.year, Date.today.month, Date.today.day - 1)
181
- time = Tickle.parse("every other day", {:start => past_date})
190
+ Tickle.parse("every other day", {:start => past_date})
182
191
  end
183
192
 
184
193
  assert_raise(Tickle::InvalidDateExpression) do
185
- start_date = Date.civil(Date.today.year, Date.today.month, Date.today.day + 10)
186
- end_date = Date.civil(Date.today.year, Date.today.month, Date.today.day + 5)
187
- time = Tickle.parse("every other day", :start => start_date, :until => end_date)
194
+ start_date = Date.civil(Date.today.year, Date.today.month).next_day(10)
195
+ end_date = Date.civil(Date.today.year, Date.today.month).next_day(5)
196
+ Tickle.parse("every other day", :start => start_date, :until => end_date)
188
197
  end
189
198
 
190
199
  assert_raise(Tickle::InvalidDateExpression) do
191
- end_date = Date.civil(Date.today.year, Date.today.month+2, Date.today.day)
200
+ end_date = Date.civil(Date.today.year, Date.today.month, Date.today.day).next_month(2)
192
201
  parse_now('every 3 months', {:until => end_date})
193
202
  end
194
203
  end
@@ -1,65 +1,34 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tickle/version'
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tickle}
8
- s.version = "0.1.7"
8
+ s.version = Tickle::VERSION
9
9
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Joshua Lippiner"]
12
- s.date = %q{2010-05-10}
10
+ s.authors = ["Joshua Lippiner", "Iain Barnett"]
11
+ s.email = %q{iainspeed@gmail.com}
13
12
  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
- s.email = %q{jlippiner@noctivity.com}
15
- s.extra_rdoc_files = [
16
- "LICENSE",
17
- "README.rdoc"
18
- ]
19
- s.files = [
20
- ".document",
21
- ".gitignore",
22
- ".rvmrc",
23
- "LICENSE",
24
- "README.rdoc",
25
- "Rakefile",
26
- "SCENARIOS.rdoc",
27
- "VERSION",
28
- "git-flow-version",
29
- "lib/numerizer/numerizer.rb",
30
- "lib/tickle.rb",
31
- "lib/tickle/handler.rb",
32
- "lib/tickle/repeater.rb",
33
- "lib/tickle/tickle.rb",
34
- "test/git-flow-version",
35
- "test/helper.rb",
36
- "test/test_parsing.rb",
37
- "tickle.gemspec"
38
- ]
39
- s.homepage = %q{http://github.com/noctivityinc/tickle}
40
- s.rdoc_options = ["--charset=UTF-8"]
41
- s.require_paths = ["lib"]
42
- s.rubygems_version = %q{1.3.6}
43
13
  s.summary = %q{natural language parser for recurring events}
44
- s.test_files = [
45
- "test/helper.rb",
46
- "test/test_parsing.rb"
47
- ]
14
+ s.homepage = %q{http://github.com/yb66/tickle}
15
+ s.license = "MIT"
48
16
 
49
- if s.respond_to? :specification_version then
50
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
51
- s.specification_version = 3
17
+ s.files = `git ls-files`.split($/)
18
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
+
21
+ s.require_paths = ["lib"]
52
22
 
53
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
54
- s.add_runtime_dependency(%q<chronic>, [">= 0.2.3"])
55
- s.add_development_dependency(%q<shoulda>, [">= 2.10.3"])
56
- else
57
- s.add_dependency(%q<chronic>, [">= 0.2.3"])
58
- s.add_dependency(%q<shoulda>, [">= 2.10.3"])
59
- end
60
- else
61
- s.add_dependency(%q<chronic>, [">= 0.2.3"])
62
- s.add_dependency(%q<shoulda>, [">= 2.10.3"])
63
- end
23
+ s.add_dependency "gitlab-chronic", "~> 0.10.6"
24
+ s.add_dependency "numerizer", "~> 0.2.0"
25
+ s.add_development_dependency "shoulda", "~> 2.10.3"
26
+ s.add_development_dependency "simplecov"
27
+ s.add_development_dependency "test-unit"
28
+ s.add_development_dependency "bundler"
29
+ s.add_development_dependency "rake"
30
+ s.add_development_dependency "yard"
31
+ s.add_development_dependency "maruku"
32
+ s.add_development_dependency "timecop"
64
33
  end
65
34
 
metadata CHANGED
@@ -1,108 +1,211 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: tickle
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 1
8
- - 7
9
- version: 0.1.7
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.2.0
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - Joshua Lippiner
8
+ - Iain Barnett
13
9
  autorequire:
14
10
  bindir: bin
15
11
  cert_chain: []
16
-
17
- date: 2010-05-10 00:00:00 -04:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: chronic
12
+ date: 2020-09-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: gitlab-chronic
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 0.10.6
21
+ type: :runtime
22
22
  prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- requirements:
25
- - - ">="
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- - 2
30
- - 3
31
- version: 0.2.3
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 0.10.6
28
+ - !ruby/object:Gem::Dependency
29
+ name: numerizer
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 0.2.0
32
35
  type: :runtime
33
- version_requirements: *id001
34
- - !ruby/object:Gem::Dependency
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: 0.2.0
42
+ - !ruby/object:Gem::Dependency
35
43
  name: shoulda
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 2.10.3
49
+ type: :development
36
50
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- requirements:
39
- - - ">="
40
- - !ruby/object:Gem::Version
41
- segments:
42
- - 2
43
- - 10
44
- - 3
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
45
55
  version: 2.10.3
56
+ - !ruby/object:Gem::Dependency
57
+ name: simplecov
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: test-unit
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
46
77
  type: :development
47
- version_requirements: *id002
48
- description: 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.
49
- email: jlippiner@noctivity.com
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: bundler
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: yard
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ version: '0'
126
+ - !ruby/object:Gem::Dependency
127
+ name: maruku
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: timecop
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ description: Tickle is a date/time helper gem to help parse natural language into
155
+ a recurring pattern. Tickle is designed to be a compliment of Chronic and can interpret
156
+ things such as "every 2 days, every Sunday, Sundays, Weekly, etc.
157
+ email: iainspeed@gmail.com
50
158
  executables: []
51
-
52
159
  extensions: []
53
-
54
- extra_rdoc_files:
55
- - LICENSE
56
- - README.rdoc
57
- files:
58
- - .document
59
- - .gitignore
60
- - .rvmrc
61
- - LICENSE
62
- - README.rdoc
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".document"
163
+ - ".gitignore"
164
+ - ".travis.yml"
165
+ - CHANGES.md
166
+ - Gemfile
167
+ - LICENCE
168
+ - README.md
63
169
  - Rakefile
64
170
  - SCENARIOS.rdoc
65
- - VERSION
171
+ - examples.rb
66
172
  - git-flow-version
67
- - lib/numerizer/numerizer.rb
68
173
  - lib/tickle.rb
69
174
  - lib/tickle/handler.rb
70
175
  - lib/tickle/repeater.rb
71
176
  - lib/tickle/tickle.rb
177
+ - lib/tickle/version.rb
178
+ - spec/spec_helper.rb
72
179
  - test/git-flow-version
73
180
  - test/helper.rb
74
181
  - test/test_parsing.rb
75
182
  - tickle.gemspec
76
- has_rdoc: true
77
- homepage: http://github.com/noctivityinc/tickle
78
- licenses: []
79
-
183
+ homepage: http://github.com/yb66/tickle
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
80
187
  post_install_message:
81
- rdoc_options:
82
- - --charset=UTF-8
83
- require_paths:
188
+ rdoc_options: []
189
+ require_paths:
84
190
  - lib
85
- required_ruby_version: !ruby/object:Gem::Requirement
86
- requirements:
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
87
193
  - - ">="
88
- - !ruby/object:Gem::Version
89
- segments:
90
- - 0
91
- version: "0"
92
- required_rubygems_version: !ruby/object:Gem::Requirement
93
- requirements:
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
94
198
  - - ">="
95
- - !ruby/object:Gem::Version
96
- segments:
97
- - 0
98
- version: "0"
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
99
201
  requirements: []
100
-
101
202
  rubyforge_project:
102
- rubygems_version: 1.3.6
203
+ rubygems_version: 2.5.2.3
103
204
  signing_key:
104
- specification_version: 3
205
+ specification_version: 4
105
206
  summary: natural language parser for recurring events
106
- test_files:
207
+ test_files:
208
+ - spec/spec_helper.rb
209
+ - test/git-flow-version
107
210
  - test/helper.rb
108
211
  - test/test_parsing.rb
data/.rvmrc DELETED
@@ -1,9 +0,0 @@
1
- #!/usr/bin/env bash
2
-
3
- # .rvmrc file for tdt application
4
-
5
- if [[ "Darwin" = "$(uname)" ]] ; then
6
- rvm ruby-1.9.1@tickle --symlink textmate
7
- else
8
- rvm ruby-1.9.1@tickle
9
- fi
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.1.7
@@ -1,103 +0,0 @@
1
- require 'strscan'
2
-
3
- class Numerizer
4
-
5
- DIRECT_NUMS = [
6
- ['eleven', '11'],
7
- ['twelve', '12'],
8
- ['thirteen', '13'],
9
- ['fourteen', '14'],
10
- ['fifteen', '15'],
11
- ['sixteen', '16'],
12
- ['seventeen', '17'],
13
- ['eighteen', '18'],
14
- ['nineteen', '19'],
15
- ['ninteen', '19'], # Common mis-spelling
16
- ['zero', '0'],
17
- ['one', '1'],
18
- ['two', '2'],
19
- ['three', '3'],
20
- ['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
21
- ['five', '5'],
22
- ['six(\W|$)', '6\1'],
23
- ['seven(\W|$)', '7\1'],
24
- ['eight(\W|$)', '8\1'],
25
- ['nine(\W|$)', '9\1'],
26
- ['ten', '10'],
27
- ['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
28
- ]
29
-
30
- TEN_PREFIXES = [ ['twenty', 20],
31
- ['thirty', 30],
32
- ['fourty', 40],
33
- ['fifty', 50],
34
- ['sixty', 60],
35
- ['seventy', 70],
36
- ['eighty', 80],
37
- ['ninety', 90]
38
- ]
39
-
40
- BIG_PREFIXES = [ ['hundred', 100],
41
- ['thousand', 1000],
42
- ['million', 1_000_000],
43
- ['billion', 1_000_000_000],
44
- ['trillion', 1_000_000_000_000],
45
- ]
46
-
47
- class << self
48
- def numerize(string)
49
- string = string.dup
50
-
51
- # preprocess
52
- string.gsub!(/ +|([^\d])-([^d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
53
- string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
54
-
55
- # easy/direct replacements
56
-
57
- DIRECT_NUMS.each do |dn|
58
- string.gsub!(/#{dn[0]}/i, dn[1])
59
- end
60
-
61
- # ten, twenty, etc.
62
-
63
- TEN_PREFIXES.each do |tp|
64
- string.gsub!(/(?:#{tp[0]})( *\d(?=[^\d]|$))*/i) { (tp[1] + $1.to_i).to_s }
65
- end
66
-
67
- # hundreds, thousands, millions, etc.
68
-
69
- BIG_PREFIXES.each do |bp|
70
- string.gsub!(/(\d*) *#{bp[0]}/i) { (bp[1] * $1.to_i).to_s}
71
- andition(string)
72
- #combine_numbers(string) # Should to be more efficient way to do this
73
- end
74
-
75
- # fractional addition
76
- # I'm not combining this with the previous block as using float addition complicates the strings
77
- # (with extraneous .0's and such )
78
- string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
79
-
80
- string
81
- end
82
-
83
- private
84
- def andition(string)
85
- sc = StringScanner.new(string)
86
- while(sc.scan_until(/(\d+)( | and )(\d+)(?=[^\w]|$)/i))
87
- if sc[2] =~ /and/ || sc[1].size > sc[3].size
88
- string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[3].to_i).to_s
89
- sc.reset
90
- end
91
- end
92
- end
93
-
94
- # def combine_numbers(string)
95
- # sc = StringScanner.new(string)
96
- # while(sc.scan_until(/(\d+)(?: | and |-)(\d+)(?=[^\w]|$)/i))
97
- # string[(sc.pos - sc.matched_size)..(sc.pos-1)] = (sc[1].to_i + sc[2].to_i).to_s
98
- # sc.reset
99
- # end
100
- # end
101
-
102
- end
103
- end