tickle 0.1.3 → 0.1.5

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2009 Joshua Lippiner
1
+ Copyright (c) 2010 Joshua Lippiner
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -2,11 +2,11 @@
2
2
  http://github.com/noctivityinc/tickle
3
3
  by Joshua Lippiner, Noctivity
4
4
 
5
- ** LEGACY WARNING
5
+ == *LEGACY WARNING*
6
6
 
7
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.
8
8
 
9
- -- DESCRIPTION
9
+ == DESCRIPTION
10
10
 
11
11
  Tickle is a natural language parser for recurring events.
12
12
 
@@ -14,17 +14,17 @@ Tickle is designed to be a compliment of Chronic and can interpret things such a
14
14
 
15
15
  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
16
 
17
- -- INSTALLATION
17
+ == INSTALLATION
18
18
 
19
19
  Tickle can be installed via RubyGems:
20
20
 
21
21
  $ gem install tickle
22
22
 
23
- -- TINKERING
23
+ == TINKERING
24
24
 
25
25
  Everything's at Github - http://github.com/noctivityinc/tickle
26
26
 
27
- -- DEPENDENCIES
27
+ == DEPENDENCIES
28
28
 
29
29
  chronic gem (gem install chronic)
30
30
 
@@ -37,31 +37,31 @@ You can parse strings containing a natural language interval using the Tickle.pa
37
37
  You can either pass a string prefixed with the word "every, each or 'on the'" or simply the time frame.
38
38
 
39
39
  Tickle.parse returns a hash containing the following keys:
40
- * next = the next occurrence of the event. This is NEVER today as its always the next date in the future.
41
- * starting = the date all calculations as based on. If not passed as an option, the start date is right now.
42
- * until = the last date you want this event to run until.
43
- * expression = this is the natural language expression to store to run through tickle later to get the next occurrence.
40
+ * next = the next occurrence of the event. This is NEVER today as its always the next date in the future.
41
+ * starting = the date all calculations as based on. If not passed as an option, the start date is right now.
42
+ * until = the last date you want this event to run until.
43
+ * expression = this is the natural language expression to store to run through tickle later to get the next occurrence.
44
44
 
45
45
  Tickle returns nil if it cannot parse the string cannot be parsed.
46
46
 
47
47
  Tickle HEAVILY uses chronic for parsing both the event and the start date.
48
48
 
49
- -- OPTIONS
49
+ === OPTIONS
50
50
 
51
51
  There are two ways to pass options: natural language or an options hash.
52
52
 
53
53
  NATURAL LANGUAGE:
54
- Pass a start date with the word "starting, start, stars" (e.g. Tickle.parse('every 3 days starting next friday'))
55
- Pass an end date with the word "until, end, ends, ending" (e.g. Tickle.parse('every 3 days until next friday'))
56
- Pass both at the same time (e.g. "starting May 5th repeat every other week until December 1")
54
+ * Pass a start date with the word "starting, start, stars" (e.g. Tickle.parse('every 3 days starting next friday'))
55
+ * Pass an end date with the word "until, end, ends, ending" (e.g. Tickle.parse('every 3 days until next friday'))
56
+ * Pass both at the same time (e.g. "starting May 5th repeat every other week until December 1")
57
57
 
58
58
  OPTIONS HASH
59
59
  Valid options are:
60
- * start - must be a valid date. (e.g. Tickle.parse('every other day', {:start => Date.new(2010,8,1) }))
61
- * until - must be a valid date. (e.g. Tickle.parse('every other day', {:until => Date.new(2010,10,1) }))
62
- * next_only - legacy switch to ONLY return the next occurrence as a date and not return a hash
60
+ * start - must be a valid date. (e.g. Tickle.parse('every other day', {:start => Date.new(2010,8,1) }))
61
+ * until - must be a valid date. (e.g. Tickle.parse('every other day', {:until => Date.new(2010,10,1) }))
62
+ * next_only - legacy switch to ONLY return the next occurrence as a date and not return a hash
63
63
 
64
- -- SUPER IMPORTANT NOTE ABOUT NEXT OCCURRENCE & START DATE
64
+ === SUPER IMPORTANT NOTE ABOUT NEXT OCCURRENCE & START DATE
65
65
 
66
66
  You may notice when parsing an expression with a start date that the next occurrence IS the start date passed. This is DESIGNED BEHAVIOR.
67
67
 
@@ -69,7 +69,7 @@ Here's why - assume your user says "remind me every 3 weeks starting Dec 1" and
69
69
 
70
70
  If you don't like that, fork and have fun but don't say I didn't warn ya.
71
71
 
72
- -- EXAMPLES
72
+ === EXAMPLES
73
73
 
74
74
  require 'rubygems'
75
75
  require 'tickle'
@@ -153,7 +153,7 @@ WITH OPTIONS HASH
153
153
  Tickle.parse('3 months, {:until=>Thu, 07 Oct 2010}') #=> {:next=>2010-08-08 14:01:19 -0400, :recurrence_expression=>"3 months", :starting=>2010-05-07 14:01:19 -0400, :until=>2010-10-07 00:00:00 -0400}
154
154
  .
155
155
 
156
- -- USING IN APP
156
+ == USING IN APP
157
157
 
158
158
  To use in your app, we recommend adding two attributes to your database model:
159
159
  * next_occurrence
@@ -165,14 +165,14 @@ code, each day, simply check to see if today is >= next_occurrence and, if so, r
165
165
  After it completes, call Tickle.parse(tickle_expression) again to update the next occurrence of the event.
166
166
 
167
167
 
168
- -- TESTING
168
+ == TESTING
169
169
 
170
170
  Tickle comes with a full testing suite that tests and shows sample output for simple, complex, options hash and invalid arguments.
171
171
 
172
172
  Please note, the tests were designed to output the parsed expression and not return true. This allows (and sorry, forces you) to have to skim through the
173
173
  results and queries to ensure they are working correctly. You can also add your own for fun.
174
174
 
175
- -- LIMITATIONS
175
+ == LIMITATIONS
176
176
 
177
177
  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.
178
178
 
@@ -187,13 +187,13 @@ As always, BIG shout-out to the RVM Master himself, Wayne Seguin, for putting up
187
187
 
188
188
  == Note on Patches/Pull Requests
189
189
 
190
- * Fork the project.
191
- * Make your feature addition or bug fix.
192
- * Add tests for it. This is important so I don't break it in a
193
- future version unintentionally.
194
- * Commit, do not mess with rakefile, version, or history.
195
- (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)
196
- * Send me a pull request. Bonus points for time-based branches.
190
+ * Fork the project.
191
+ * Make your feature addition or bug fix.
192
+ * Add tests for it. This is important so I don't break it in a
193
+ future version unintentionally.
194
+ * Commit, do not mess with rakefile, version, or history.
195
+ (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)
196
+ * Send me a pull request. Bonus points for time-based branches.
197
197
 
198
198
  == Copyright
199
199
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.3
1
+ 0.1.5
data/git-flow-version CHANGED
@@ -1 +1 @@
1
- GITFLOW_VERSION=0.1.3
1
+ GITFLOW_VERSION=0.1.5
data/lib/tickle.rb CHANGED
@@ -17,8 +17,8 @@ require 'tickle/tickle'
17
17
  require 'tickle/handler'
18
18
  require 'tickle/repeater'
19
19
 
20
- module Tickle
21
- VERSION = "0.1.3"
20
+ module Tickle #:nodoc:
21
+ VERSION = "0.1.5"
22
22
 
23
23
  def self.debug; false; end
24
24
 
@@ -36,7 +36,8 @@ module Tickle
36
36
  end
37
37
  end
38
38
 
39
- class Date
39
+ class Date #:nodoc:
40
+ # returns the days in the sending month
40
41
  def days_in_month
41
42
  d,m,y = mday,month,year
42
43
  d += 1 while Date.valid_civil?(y,m,d)
@@ -44,7 +45,8 @@ class Date
44
45
  end
45
46
  end
46
47
 
47
- class String
48
+ class String #:nodoc:
49
+ # returns true if the sending string is a text or numeric ordinal (e.g. first or 1st)
48
50
  def is_ordinal?
49
51
  scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventeenth eighteenth nineteenth twenty thirty thirtieth}
50
52
  regex = /\b(\d*)(st|nd|rd|th)\b/
@@ -52,7 +54,8 @@ class String
52
54
  end
53
55
  end
54
56
 
55
- class Array
57
+ class Array #:nodoc:
58
+ # compares two arrays to determine if they both contain the same elements
56
59
  def same?(y)
57
60
  self.sort == y.sort
58
61
  end
@@ -1,6 +1,10 @@
1
- module Tickle
2
- class << self
1
+ module Tickle #:nodoc:
2
+ class << self #:nodoc:
3
3
 
4
+ # The heavy lifting. Goes through each token groupings to determine what natural language should either by
5
+ # parsed by Chronic or returned. This methodology makes extension fairly simple, as new token types can be
6
+ # easily added in repeater and then processed by the guess method
7
+ #
4
8
  def guess()
5
9
  guess_unit_types
6
10
  guess_weekday unless @next
data/lib/tickle/tickle.rb CHANGED
@@ -1,6 +1,38 @@
1
- module Tickle
2
- class << self
3
-
1
+ # Copyright (c) 2010 Joshua Lippiner
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+
22
+ module Tickle #:nodoc:
23
+ class << self #:nodoc:
24
+ # == Configuration options
25
+ #
26
+ # * +start+ - start date for future occurrences. Must be in valid date format.
27
+ # * +until+ - last date to run occurrences until. Must be in valid date format.
28
+ #
29
+ # Use by calling Tickle.parse and passing natural language with or without options.
30
+ #
31
+ # def get_next_occurrence
32
+ # results = Tickle.parse('every Wednesday starting June 1st until Dec 15th')
33
+ # return results[:next] if results
34
+ # end
35
+ #
4
36
  def parse(text, specified_options = {})
5
37
  # get options and set defaults if necessary
6
38
  default_options = {:start => Time.now, :next_only => false, :until => nil}
@@ -59,10 +91,7 @@ module Tickle
59
91
  if !best_guess
60
92
  return nil
61
93
  elsif options[:next_only] != true
62
- h = {:next => best_guess.to_time, :recurrence_expression => event.strip}
63
- h.merge!({:starting => @start.to_time}) if @start
64
- h.merge!({:until => @until.to_time}) if @until
65
- return h
94
+ return {:next => best_guess.to_time, :expression => event.strip, :starting => @start, :until => @until}
66
95
  else
67
96
  return best_guess
68
97
  end
@@ -86,16 +115,13 @@ module Tickle
86
115
  event, ending = process_for_ending(text)
87
116
  end
88
117
 
89
- @start = (starting && Tickle.parse(pre_filter(starting), {:next_only => true}) || options[:start])
118
+ @start = (starting && Tickle.parse(pre_filter(starting), {:next_only => true}) || options[:start]).to_time
90
119
  @until = (ending && Tickle.parse(pre_filter(ending), {:next_only => true}) || options[:until])
120
+ @until = @until.to_time if @until
91
121
  @next = nil
92
122
  return event
93
123
  end
94
124
 
95
- def inspect_matches
96
-
97
- end
98
-
99
125
  # process the remaining expression to see if an until, end, ending is specified
100
126
  def process_for_ending(text)
101
127
  regex = /^(.*)(\s(?:end|until)(?:s|ing)?)(.*)/i
@@ -179,10 +205,15 @@ module Tickle
179
205
 
180
206
  protected
181
207
 
208
+ # Returns the next available month based on the current day of the month.
209
+ # For example, if get_next_month(15) is called and today is the 10th, then it will return the 15th of this month.
210
+ # However, if get_next_month(15) is called and today is the 18th, it will return the 15th of next month.
182
211
  def get_next_month(number)
183
212
  month = number.to_i < Date.today.day ? (Date.today.month == 12 ? 1 : Date.today.month + 1) : Date.today.month
184
213
  end
185
214
 
215
+ # Return the number of days in a specified month.
216
+ # If no month is specified, current month is used.
186
217
  def days_in_month(month=nil)
187
218
  month ||= Date.today.month
188
219
  days_in_mon = Date.civil(Date.today.year, month, -1).day
@@ -200,6 +231,7 @@ module Tickle
200
231
  @start = start
201
232
  end
202
233
 
234
+ # Updates an existing token. Mostly used by the repeater class.
203
235
  def update(type, start=nil, interval=nil)
204
236
  @start = start
205
237
  @type = type
@@ -210,12 +242,10 @@ module Tickle
210
242
  # This exception is raised if an invalid argument is provided to
211
243
  # any of Tickle's methods
212
244
  class InvalidArgumentException < Exception
213
-
214
245
  end
215
246
 
216
247
  # This exception is raised if there is an issue with the parsing
217
248
  # output from the date expression provided
218
249
  class InvalidDateExpression < Exception
219
-
220
250
  end
221
251
  end
data/tickle.gemspec CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{tickle}
8
- s.version = "0.1.3"
8
+ s.version = "0.1.5"
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"]
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 1
8
- - 3
9
- version: 0.1.3
8
+ - 5
9
+ version: 0.1.5
10
10
  platform: ruby
11
11
  authors:
12
12
  - Joshua Lippiner