tickle 0.0.3 → 0.0.4
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 +32 -22
- data/SCENARIOS.rdoc +3 -0
- data/VERSION +1 -1
- data/git-flow-version +1 -0
- data/lib/tickle.rb +26 -9
- data/lib/tickle/handler.rb +30 -7
- data/lib/tickle/repeater.rb +44 -6
- data/lib/tickle/tickle.rb +49 -19
- data/test/git-flow-version +1 -0
- data/test/test_parsing.rb +55 -42
- data/tickle.gemspec +4 -2
- metadata +5 -3
data/README.rdoc
CHANGED
@@ -43,42 +43,52 @@ Tickle HEAVILY uses chronic for parsing both the event and the start date.
|
|
43
43
|
require 'rubygems'
|
44
44
|
require 'tickle'
|
45
45
|
|
46
|
-
|
47
|
-
2010-04-
|
48
|
-
|
49
|
-
Tickle.parse('each day') #=> 2010-04-
|
50
|
-
Tickle.parse('every day') #=> 2010-04-
|
51
|
-
Tickle.parse('every week') #=> 2010-
|
52
|
-
Tickle.parse('every Month') #=> 2010-05-
|
53
|
-
Tickle.parse('every year') #=> 2011-04-
|
54
|
-
Tickle.parse('daily') #=> 2010-04-
|
55
|
-
Tickle.parse('weekly') #=> 2010-
|
56
|
-
Tickle.parse('monthly') #=> 2010-05-
|
57
|
-
Tickle.parse('yearly') #=> 2011-04-
|
58
|
-
Tickle.parse('every 3 days') #=> 2010-04-
|
59
|
-
Tickle.parse('every 3 weeks') #=> 2010-05-
|
60
|
-
Tickle.parse('every 3 months') #=> 2010-07-
|
61
|
-
Tickle.parse('every 3 years') #=> 2013-04-
|
62
|
-
Tickle.parse('every other day') #=> 2010-04-
|
63
|
-
Tickle.parse('every other week') #=> 2010-05-
|
64
|
-
Tickle.parse('every other month') #=> 2010-06-
|
65
|
-
Tickle.parse('every other year') #=> 2012-04-
|
46
|
+
Time.now
|
47
|
+
2010-04-24 12:05:51 -0400
|
48
|
+
|
49
|
+
Tickle.parse('each day') #=> 2010-04-24 12:05:51 -0400
|
50
|
+
Tickle.parse('every day') #=> 2010-04-24 12:05:51 -0400
|
51
|
+
Tickle.parse('every week') #=> 2010-05-01 12:05:51 -0400
|
52
|
+
Tickle.parse('every Month') #=> 2010-05-24 12:05:51 -0400
|
53
|
+
Tickle.parse('every year') #=> 2011-04-24 12:05:51 -0400
|
54
|
+
Tickle.parse('daily') #=> 2010-04-24 12:05:51 -0400
|
55
|
+
Tickle.parse('weekly') #=> 2010-05-01 12:05:51 -0400
|
56
|
+
Tickle.parse('monthly') #=> 2010-05-24 12:05:51 -0400
|
57
|
+
Tickle.parse('yearly') #=> 2011-04-24 12:05:51 -0400
|
58
|
+
Tickle.parse('every 3 days') #=> 2010-04-27 12:05:51 -0400
|
59
|
+
Tickle.parse('every 3 weeks') #=> 2010-05-15 12:05:51 -0400
|
60
|
+
Tickle.parse('every 3 months') #=> 2010-07-23 12:05:51 -0400
|
61
|
+
Tickle.parse('every 3 years') #=> 2013-04-23 12:05:51 -0400
|
62
|
+
Tickle.parse('every other day') #=> 2010-04-26 12:05:51 -0400
|
63
|
+
Tickle.parse('every other week') #=> 2010-05-08 12:05:51 -0400
|
64
|
+
Tickle.parse('every other month') #=> 2010-06-24 12:05:51 -0400
|
65
|
+
Tickle.parse('every other year') #=> 2012-04-24 12:05:51 -0400
|
66
66
|
Tickle.parse('every other day starting May 1st') #=> 2010-05-01 12:00:00 -0400
|
67
67
|
Tickle.parse('every other week starting this Sunday') #=> 2010-04-25 12:00:00 -0400
|
68
68
|
Tickle.parse('every Monday') #=> 2010-04-26 12:00:00 -0400
|
69
69
|
Tickle.parse('every Wednesday') #=> 2010-04-28 12:00:00 -0400
|
70
|
-
Tickle.parse('every Friday') #=> 2010-04-
|
70
|
+
Tickle.parse('every Friday') #=> 2010-04-30 12:00:00 -0400
|
71
71
|
Tickle.parse('every May') #=> 2010-05-01 12:00:00 -0400
|
72
72
|
Tickle.parse('every june') #=> 2010-06-01 12:00:00 -0400
|
73
73
|
Tickle.parse('beginning of the week') #=> 2010-04-25 12:00:00 -0400
|
74
74
|
Tickle.parse('middle of the week') #=> 2010-04-28 12:00:00 -0400
|
75
|
-
Tickle.parse('end of the week') #=> 2010-
|
75
|
+
Tickle.parse('end of the week') #=> 2010-05-01 12:00:00 -0400
|
76
76
|
Tickle.parse('beginning of the month') #=> 2010-05-01 12:00:00 -0400
|
77
77
|
Tickle.parse('middle of the month') #=> 2010-05-15 12:00:00 -0400
|
78
78
|
Tickle.parse('end of the month') #=> 2010-04-30 00:00:00 -0400
|
79
79
|
Tickle.parse('beginning of the year') #=> 2011-01-01 12:00:00 -0500
|
80
80
|
Tickle.parse('middle of the year') #=> 2010-06-15 00:00:00 -0400
|
81
81
|
Tickle.parse('end of the year') #=> 2010-12-31 00:00:00 -0500
|
82
|
+
Tickle.parse('the 3rd of May') #=> 2010-05-03 12:00:00 -0400
|
83
|
+
Tickle.parse('the 3rd of February') #=> 2011-02-03 12:00:00 -0500
|
84
|
+
Tickle.parse('the 10th of the month') #=> 2010-05-10 12:00:00 -0400
|
85
|
+
Tickle.parse('the tenth of the month') #=> 2010-05-10 12:00:00 -0400
|
86
|
+
Tickle.parse('the first of the month') #=> 2010-05-01 12:00:00 -0400
|
87
|
+
Tickle.parse('the thirtieth') #=> 2010-04-30 12:00:00 -0400
|
88
|
+
Tickle.parse('the fifth') #=> 2010-05-05 12:00:00 -0400
|
89
|
+
Tickle.parse('the 3rd Sunday of May') #=> 2010-05-16 12:00:00 -0400
|
90
|
+
Tickle.parse('the 3rd Sunday of the month') #=> 2010-05-16 12:00:00 -0400
|
91
|
+
|
82
92
|
|
83
93
|
|
84
94
|
-- USING IN APP
|
data/SCENARIOS.rdoc
CHANGED
@@ -10,3 +10,6 @@ every November 15th => month found with number. interval = 365, start_date = Ch
|
|
10
10
|
every day => word 'day' found without a number. interval = 1. start_day = today
|
11
11
|
every week => word 'week' found without a number. interval = 7. start_day = today
|
12
12
|
every month => word 'month' found without a number. interval = 30. start_day = today
|
13
|
+
|
14
|
+
|
15
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.4
|
data/git-flow-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
GITFLOW_VERSION=0.0.4
|
data/lib/tickle.rb
CHANGED
@@ -18,24 +18,41 @@ require 'tickle/repeater'
|
|
18
18
|
|
19
19
|
module Tickle
|
20
20
|
VERSION = "0.0.3"
|
21
|
-
|
21
|
+
|
22
22
|
def self.debug; false; end
|
23
|
-
|
23
|
+
|
24
24
|
def self.dwrite(msg)
|
25
25
|
puts msg if Tickle.debug
|
26
26
|
end
|
27
|
+
|
28
|
+
def self.is_date(str)
|
29
|
+
begin
|
30
|
+
Date.parse(str.to_s)
|
31
|
+
return true
|
32
|
+
rescue Exception => e
|
33
|
+
return false
|
34
|
+
end
|
35
|
+
end
|
27
36
|
end
|
28
37
|
|
29
|
-
class Date
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
38
|
+
class Date
|
39
|
+
def days_in_month
|
40
|
+
d,m,y = mday,month,year
|
41
|
+
d += 1 while Date.valid_civil?(y,m,d)
|
42
|
+
d - 1
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class String
|
47
|
+
def is_ordinal?
|
48
|
+
scanner = %w{first second third fourth fifth sixth seventh eighth ninth tenth eleventh twelfth thirteenth fourteenth fifteenth sixteenth seventieth eighteenth nineteenth twenty thirty thirtieth}
|
49
|
+
regex = /\b(\d*)(st|nd|rd|th)\b/
|
50
|
+
!(self =~ regex).nil? || scanner.include?(self.downcase)
|
51
|
+
end
|
35
52
|
end
|
36
53
|
|
37
54
|
class Array
|
38
55
|
def same?(y)
|
39
56
|
self.sort == y.sort
|
40
57
|
end
|
41
|
-
end
|
58
|
+
end
|
data/lib/tickle/handler.rb
CHANGED
@@ -4,23 +4,24 @@ module Tickle
|
|
4
4
|
def guess()
|
5
5
|
interval = guess_unit_types
|
6
6
|
interval ||= guess_weekday
|
7
|
-
interval ||= guess_weekday
|
8
7
|
interval ||= guess_month_names
|
9
8
|
interval ||= guess_number_and_unit
|
9
|
+
interval ||= guess_ordinal
|
10
|
+
interval ||= guess_ordinal_and_unit
|
10
11
|
interval ||= guess_special
|
11
12
|
|
12
13
|
# defines the next occurrence of this tickle if not set in a guess routine
|
13
14
|
@next ||= @start + (interval * 60 * 60 * 24) if interval
|
14
|
-
|
15
|
+
|
15
16
|
# check to see if the start date is > NOW and, if so, set the next occurrence = start
|
16
17
|
@next = @start if @start.to_time > Time.now
|
17
|
-
|
18
|
+
|
18
19
|
# return the next occurrence
|
19
20
|
return @next.to_time if interval
|
20
21
|
end
|
21
22
|
|
22
23
|
def guess_unit_types
|
23
|
-
interval =
|
24
|
+
interval = 0 if token_types.same?([:day])
|
24
25
|
interval = 7 if token_types.same?([:week])
|
25
26
|
interval = 30 if token_types.same?([:month])
|
26
27
|
interval = 365 if token_types.same?([:year])
|
@@ -51,6 +52,20 @@ module Tickle
|
|
51
52
|
interval
|
52
53
|
end
|
53
54
|
|
55
|
+
def guess_ordinal
|
56
|
+
if token_types.same?([:ordinal]) then interval = 365; @next = Chronic.parse("#{token_of_type(:ordinal).start} day in #{Date::MONTHNAMES[get_next_month(token_of_type(:ordinal).start)]}"); end
|
57
|
+
interval
|
58
|
+
end
|
59
|
+
|
60
|
+
def guess_ordinal_and_unit
|
61
|
+
parse_text = ''
|
62
|
+
if token_types.same?([:ordinal, :month_name]) then interval = 365; @next = Chronic.parse("#{token_of_type(:ordinal).original} day in #{token_of_type(:month_name).start.to_s}"); end
|
63
|
+
if token_types.same?([:ordinal, :month]) then interval = 365; @next = Chronic.parse("#{token_of_type(:ordinal).start} day in #{Date::MONTHNAMES[get_next_month(token_of_type(:ordinal).start)]}"); end
|
64
|
+
if token_types.same?([:ordinal, :weekday, :month_name]) then interval = 365; @next = Chronic.parse("#{token_of_type(:ordinal).original} #{token_of_type(:weekday).start.to_s} in #{token_of_type(:month_name).start.to_s}"); end
|
65
|
+
if token_types.same?([:ordinal, :weekday, :month]) then interval = 365; @next = Chronic.parse("#{token_of_type(:ordinal).original} #{token_of_type(:weekday).start.to_s} in #{Date::MONTHNAMES[get_next_month(token_of_type(:ordinal).start)]}"); end
|
66
|
+
interval
|
67
|
+
end
|
68
|
+
|
54
69
|
def guess_special
|
55
70
|
interval = guess_special_other
|
56
71
|
interval ||= guess_special_beginning
|
@@ -81,16 +96,16 @@ module Tickle
|
|
81
96
|
if token_types.same?([:special, :year]) && token_of_type(:special).start == :end then interval = 365; @start = Date.new(Date.today.year, 12, 31); end
|
82
97
|
interval
|
83
98
|
end
|
84
|
-
|
99
|
+
|
85
100
|
def guess_special_middle
|
86
101
|
if token_types.same?([:special, :week]) && token_of_type(:special).start == :middle then interval = 7; @start = Chronic.parse('Wednesday'); end
|
87
102
|
if token_types.same?([:special, :month]) && token_of_type(:special).start == :middle then
|
88
103
|
interval = 30;
|
89
|
-
@start = (Date.today.day
|
104
|
+
@start = (Date.today.day > 15 ? Chronic.parse('15th day of next month') : Date.new(Date.today.year, Date.today.month, 15))
|
90
105
|
end
|
91
106
|
if token_types.same?([:special, :year]) && token_of_type(:special).start == :middle then
|
92
107
|
interval = 365;
|
93
|
-
@start = (Date.today.day
|
108
|
+
@start = (Date.today.day > 15 && Date.today.month > 6 ? Date.new(Date.today.year+1, 6, 15) : Date.new(Date.today.year, 6, 15))
|
94
109
|
end
|
95
110
|
interval
|
96
111
|
end
|
@@ -99,5 +114,13 @@ module Tickle
|
|
99
114
|
@tokens.detect {|token| token.type == type}
|
100
115
|
end
|
101
116
|
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
def get_next_month(ordinal)
|
121
|
+
ord_to_int = ordinal.gsub(/\b(\d*)(st|nd|rd|th)\b/,'\1').to_i
|
122
|
+
month = (ord_to_int < Date.today.day ? Date.today.month + 1 : Date.today.month)
|
123
|
+
end
|
124
|
+
|
102
125
|
end
|
103
126
|
end
|
data/lib/tickle/repeater.rb
CHANGED
@@ -4,10 +4,12 @@ class Tickle::Repeater < Chronic::Tag #:nodoc:
|
|
4
4
|
# for each token
|
5
5
|
tokens.each do |token|
|
6
6
|
token = self.scan_for_numbers(token)
|
7
|
-
token = self.
|
8
|
-
token = self.
|
9
|
-
token = self.
|
10
|
-
token = self.
|
7
|
+
token = self.scan_for_ordinal_names(token)
|
8
|
+
token = self.scan_for_ordinals(token)
|
9
|
+
token = self.scan_for_month_names(token) unless token.type
|
10
|
+
token = self.scan_for_day_names(token) unless token.type
|
11
|
+
token = self.scan_for_special_text(token) unless token.type
|
12
|
+
token = self.scan_for_units(token) unless token.type
|
11
13
|
end
|
12
14
|
tokens
|
13
15
|
end
|
@@ -18,6 +20,42 @@ class Tickle::Repeater < Chronic::Tag #:nodoc:
|
|
18
20
|
token
|
19
21
|
end
|
20
22
|
|
23
|
+
def self.scan_for_ordinal_names(token)
|
24
|
+
scanner = {/first/ => '1st',
|
25
|
+
/second/ => '2nd',
|
26
|
+
/third/ => '3rd',
|
27
|
+
/fourth/ => '4th',
|
28
|
+
/fifth/ => '5th',
|
29
|
+
/sixth/ => '6th',
|
30
|
+
/seventh/ => '7th',
|
31
|
+
/eighth/ => '8th',
|
32
|
+
/ninth/ => '9th',
|
33
|
+
/tenth/ => '10th',
|
34
|
+
/eleventh/ => '11th',
|
35
|
+
/twelfth/ => '12th',
|
36
|
+
/thirteenth/ => '13th',
|
37
|
+
/fourteenth/ => '14th',
|
38
|
+
/fifteenth/ => '15th',
|
39
|
+
/sixteenth/ => '16th',
|
40
|
+
/seventeenth/ => '17th',
|
41
|
+
/eighteenth/ => '18th',
|
42
|
+
/nineteenth/ => '19th',
|
43
|
+
/twenty/ => '20th',
|
44
|
+
/thirty/ => '30th',
|
45
|
+
/thirtieth/ => '30th',
|
46
|
+
}
|
47
|
+
scanner.keys.each do |scanner_item|
|
48
|
+
token.update(:ordinal, scanner[scanner_item], 365) if scanner_item =~ token.original
|
49
|
+
end
|
50
|
+
token
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.scan_for_ordinals(token)
|
54
|
+
regex = /\b(\d*)(st|nd|rd|th)\b/
|
55
|
+
token.update(:ordinal, token.original, 365) if !(token.original =~ regex).nil?
|
56
|
+
token
|
57
|
+
end
|
58
|
+
|
21
59
|
def self.scan_for_month_names(token)
|
22
60
|
scanner = {/^jan\.?(uary)?$/ => :january,
|
23
61
|
/^feb\.?(ruary)?$/ => :february,
|
@@ -59,7 +97,7 @@ class Tickle::Repeater < Chronic::Tag #:nodoc:
|
|
59
97
|
/^begin(ing|ning)?$/ => :beginning,
|
60
98
|
/^start$/ => :beginning,
|
61
99
|
/^end$/ => :end,
|
62
|
-
|
100
|
+
/^mid(d)?le$/ => :middle}
|
63
101
|
scanner.keys.each do |scanner_item|
|
64
102
|
token.update(:special, scanner[scanner_item], 7) if scanner_item =~ token.word
|
65
103
|
end
|
@@ -72,7 +110,7 @@ class Tickle::Repeater < Chronic::Tag #:nodoc:
|
|
72
110
|
/^fortnights?$/ => {:type => :fortnight, :interval => 365, :start => :today},
|
73
111
|
/^week(ly)?s?$/ => {:type => :week, :interval => 7, :start => :today},
|
74
112
|
/^weekends?$/ => {:type => :weekend, :interval => 7, :start => :saturday},
|
75
|
-
|
113
|
+
/^days?$/ => {:type => :day, :interval => 1, :start => :today},
|
76
114
|
/^daily?$/ => {:type => :day, :interval => 1, :start => :today}}
|
77
115
|
scanner.keys.each do |scanner_item|
|
78
116
|
if scanner_item =~ token.word
|
data/lib/tickle/tickle.rb
CHANGED
@@ -8,43 +8,39 @@ module Tickle
|
|
8
8
|
|
9
9
|
# ensure the specified options are valid
|
10
10
|
specified_options.keys.each do |key|
|
11
|
-
|
11
|
+
raise(InvalidArgumentException, "#{key} is not a valid option key.") unless default_options.keys.include?(key)
|
12
12
|
end
|
13
|
-
|
14
|
-
|
15
|
-
# remove every is specified
|
16
|
-
text = text.gsub(/^every\s\b/, '')
|
17
|
-
|
18
|
-
# put the text into a normal format to ease scanning using Chronic
|
19
|
-
text = pre_normalize(text)
|
20
|
-
text = Chronic.pre_normalize(text)
|
21
|
-
text = numericize_ordinals(text)
|
13
|
+
raise(InvalidArgumentException, ':start specified is not a valid datetime.') unless (is_date(specified_options[:start]) || Chronic.parse(specified_options[:start])) if specified_options[:start]
|
22
14
|
|
23
15
|
# check to see if this event starts some other time and reset now
|
24
16
|
event, starting = text.split('starting')
|
25
17
|
@start = (Chronic.parse(starting) || options[:start])
|
26
18
|
@next = nil
|
27
19
|
|
20
|
+
# put the text into a normal format to ease scanning using Chronic
|
21
|
+
event = pre_tokenize(event)
|
22
|
+
|
28
23
|
# split into tokens
|
29
24
|
@tokens = base_tokenize(event)
|
30
25
|
|
26
|
+
# process each original word for implied word
|
27
|
+
post_tokenize
|
28
|
+
|
31
29
|
# scan the tokens with each token scanner
|
32
30
|
@tokens = Repeater.scan(@tokens)
|
33
31
|
|
34
32
|
# remove all tokens without a type
|
35
33
|
@tokens.reject! {|token| token.type.nil? }
|
36
34
|
|
37
|
-
# dwrite @tokens.inspect
|
38
|
-
|
39
35
|
return guess
|
40
36
|
end
|
41
37
|
|
42
38
|
# Normalize natural string removing prefix language
|
43
|
-
def
|
39
|
+
def pre_tokenize(text)
|
44
40
|
normalized_text = text.gsub(/^every\s\b/, '')
|
45
41
|
normalized_text = text.gsub(/^each\s\b/, '')
|
46
42
|
normalized_text = text.gsub(/^on the\s\b/, '')
|
47
|
-
normalized_text
|
43
|
+
normalized_text.downcase
|
48
44
|
end
|
49
45
|
|
50
46
|
# Split the text on spaces and convert each word into
|
@@ -53,11 +49,45 @@ module Tickle
|
|
53
49
|
text.split(' ').map { |word| Token.new(word) }
|
54
50
|
end
|
55
51
|
|
52
|
+
# normalizes each token
|
53
|
+
def post_tokenize
|
54
|
+
@tokens.each do |token|
|
55
|
+
token.word = normalize(token.original)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Clean up the specified input text by stripping unwanted characters,
|
60
|
+
# converting idioms to their canonical form, converting number words
|
61
|
+
# to numbers (three => 3), and converting ordinal words to numeric
|
62
|
+
# ordinals (third => 3rd)
|
63
|
+
def normalize(text) #:nodoc:
|
64
|
+
normalized_text = text.to_s.downcase
|
65
|
+
normalized_text = Numerizer.numerize(normalized_text)
|
66
|
+
normalized_text.gsub!(/['"\.]/, '')
|
67
|
+
normalized_text.gsub!(/([\/\-\,\@])/) { ' ' + $1 + ' ' }
|
68
|
+
normalized_text.gsub!(/\btoday\b/, 'this day')
|
69
|
+
normalized_text.gsub!(/\btomm?orr?ow\b/, 'next day')
|
70
|
+
normalized_text.gsub!(/\byesterday\b/, 'last day')
|
71
|
+
normalized_text.gsub!(/\bnoon\b/, '12:00')
|
72
|
+
normalized_text.gsub!(/\bmidnight\b/, '24:00')
|
73
|
+
normalized_text.gsub!(/\bbefore now\b/, 'past')
|
74
|
+
normalized_text.gsub!(/\bnow\b/, 'this second')
|
75
|
+
normalized_text.gsub!(/\b(ago|before)\b/, 'past')
|
76
|
+
normalized_text.gsub!(/\bthis past\b/, 'last')
|
77
|
+
normalized_text.gsub!(/\bthis last\b/, 'last')
|
78
|
+
normalized_text.gsub!(/\b(?:in|during) the (morning)\b/, '\1')
|
79
|
+
normalized_text.gsub!(/\b(?:in the|during the|at) (afternoon|evening|night)\b/, '\1')
|
80
|
+
normalized_text.gsub!(/\btonight\b/, 'this night')
|
81
|
+
normalized_text.gsub!(/(?=\w)([ap]m|oclock)\b/, ' \1')
|
82
|
+
normalized_text.gsub!(/\b(hence|after|from)\b/, 'future')
|
83
|
+
normalized_text = numericize_ordinals(normalized_text)
|
84
|
+
end
|
85
|
+
|
56
86
|
# Convert ordinal words to numeric ordinals (third => 3rd)
|
57
87
|
def numericize_ordinals(text) #:nodoc:
|
58
88
|
text = text.gsub(/\b(\d*)(st|nd|rd|th)\b/, '\1')
|
59
89
|
end
|
60
|
-
|
90
|
+
|
61
91
|
# Returns an array of types for all tokens
|
62
92
|
def token_types
|
63
93
|
@tokens.map(&:type)
|
@@ -65,11 +95,11 @@ module Tickle
|
|
65
95
|
end
|
66
96
|
|
67
97
|
class Token #:nodoc:
|
68
|
-
attr_accessor :word, :type, :interval, :start
|
98
|
+
attr_accessor :original, :word, :type, :interval, :start
|
69
99
|
|
70
|
-
def initialize(
|
71
|
-
@
|
72
|
-
@type = @interval = @start = nil
|
100
|
+
def initialize(original)
|
101
|
+
@original = original
|
102
|
+
@word = @type = @interval = @start = nil
|
73
103
|
end
|
74
104
|
|
75
105
|
def update(type, start=nil, interval=nil)
|
@@ -0,0 +1 @@
|
|
1
|
+
GITFLOW_VERSION=0.1.0
|
data/test/test_parsing.rb
CHANGED
@@ -11,49 +11,62 @@ class TestParsing < Test::Unit::TestCase
|
|
11
11
|
def test_parse_best_guess
|
12
12
|
puts "Time.now"
|
13
13
|
p Time.now
|
14
|
-
|
15
|
-
parse_now('each day')
|
16
|
-
|
17
|
-
parse_now('every day')
|
18
|
-
parse_now('every week')
|
19
|
-
parse_now('every Month')
|
20
|
-
parse_now('every year')
|
21
|
-
|
22
|
-
parse_now('daily')
|
23
|
-
parse_now('weekly')
|
24
|
-
parse_now('monthly')
|
25
|
-
parse_now('yearly')
|
26
|
-
|
27
|
-
parse_now('every 3 days')
|
28
|
-
parse_now('every 3 weeks')
|
29
|
-
parse_now('every 3 months')
|
30
|
-
parse_now('every 3 years')
|
31
|
-
|
32
|
-
parse_now('every other day')
|
33
|
-
parse_now('every other week')
|
34
|
-
parse_now('every other month')
|
35
|
-
parse_now('every other year')
|
36
|
-
parse_now('every other day starting May 1st')
|
37
|
-
parse_now('every other week starting this Sunday')
|
38
14
|
|
39
|
-
parse_now('
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
15
|
+
parse_now('each day')
|
16
|
+
|
17
|
+
parse_now('every day')
|
18
|
+
parse_now('every week')
|
19
|
+
parse_now('every Month')
|
20
|
+
parse_now('every year')
|
21
|
+
|
22
|
+
parse_now('daily')
|
23
|
+
parse_now('weekly')
|
24
|
+
parse_now('monthly')
|
25
|
+
parse_now('yearly')
|
26
|
+
|
27
|
+
parse_now('every 3 days')
|
28
|
+
parse_now('every 3 weeks')
|
29
|
+
parse_now('every 3 months')
|
30
|
+
parse_now('every 3 years')
|
31
|
+
|
32
|
+
parse_now('every other day')
|
33
|
+
parse_now('every other week')
|
34
|
+
parse_now('every other month')
|
35
|
+
parse_now('every other year')
|
36
|
+
parse_now('every other day starting May 1st')
|
37
|
+
parse_now('every other week starting this Sunday')
|
38
|
+
|
39
|
+
parse_now('every Monday')
|
40
|
+
parse_now('every Wednesday')
|
41
|
+
parse_now('every Friday')
|
42
|
+
|
43
|
+
parse_now('every May')
|
44
|
+
parse_now('every june')
|
45
|
+
|
46
|
+
parse_now('beginning of the week')
|
47
|
+
parse_now('middle of the week')
|
48
|
+
parse_now('end of the week')
|
49
|
+
|
50
|
+
parse_now('beginning of the month')
|
51
|
+
parse_now('middle of the month')
|
52
|
+
parse_now('end of the month')
|
53
|
+
|
54
|
+
parse_now('beginning of the year')
|
55
|
+
parse_now('middle of the year')
|
56
|
+
parse_now('end of the year')
|
57
|
+
|
58
|
+
parse_now('the 3rd of May')
|
59
|
+
parse_now('the 3rd of February', {:start => Date.new(2010, 03, 01).to_time})
|
60
|
+
|
61
|
+
parse_now('the 10th of the month')
|
62
|
+
parse_now('the tenth of the month')
|
63
|
+
|
64
|
+
parse_now('the first of the month')
|
65
|
+
parse_now('the thirtieth')
|
66
|
+
parse_now('the fifth', {:start => Date.new(2010, 03, 15)})
|
67
|
+
|
68
|
+
parse_now('the 3rd Sunday of May')
|
69
|
+
parse_now('the 3rd Sunday of the month')
|
57
70
|
end
|
58
71
|
|
59
72
|
def test_argument_validation
|
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.0.
|
8
|
+
s.version = "0.0.4"
|
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-04-
|
12
|
+
s.date = %q{2010-04-24}
|
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 = [
|
@@ -25,11 +25,13 @@ Gem::Specification.new do |s|
|
|
25
25
|
"Rakefile",
|
26
26
|
"SCENARIOS.rdoc",
|
27
27
|
"VERSION",
|
28
|
+
"git-flow-version",
|
28
29
|
"lib/numerizer/numerizer.rb",
|
29
30
|
"lib/tickle.rb",
|
30
31
|
"lib/tickle/handler.rb",
|
31
32
|
"lib/tickle/repeater.rb",
|
32
33
|
"lib/tickle/tickle.rb",
|
34
|
+
"test/git-flow-version",
|
33
35
|
"test/helper.rb",
|
34
36
|
"test/test_parsing.rb",
|
35
37
|
"tickle.gemspec"
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 4
|
9
|
+
version: 0.0.4
|
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-04-
|
17
|
+
date: 2010-04-24 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -63,11 +63,13 @@ files:
|
|
63
63
|
- Rakefile
|
64
64
|
- SCENARIOS.rdoc
|
65
65
|
- VERSION
|
66
|
+
- git-flow-version
|
66
67
|
- lib/numerizer/numerizer.rb
|
67
68
|
- lib/tickle.rb
|
68
69
|
- lib/tickle/handler.rb
|
69
70
|
- lib/tickle/repeater.rb
|
70
71
|
- lib/tickle/tickle.rb
|
72
|
+
- test/git-flow-version
|
71
73
|
- test/helper.rb
|
72
74
|
- test/test_parsing.rb
|
73
75
|
- tickle.gemspec
|