nickel 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,9 +2,7 @@ require_relative 'occurrence'
2
2
  require_relative 'construct'
3
3
 
4
4
  module Nickel
5
-
6
5
  class ConstructInterpreter
7
-
8
6
  attr_reader :occurrences, :constructs, :curdate
9
7
 
10
8
  def initialize(constructs, curdate)
@@ -31,19 +29,20 @@ module Nickel
31
29
  end
32
30
 
33
31
  private
32
+
34
33
  def initialize_index_to_type_map
35
34
  # The @index_to_type_map hash looks like this: {0 => :date, 1 => :timespan, ...}
36
35
  # Each key represents the index in @constructs and the value represents that constructs class.
37
36
  @index_to_type_map = {}
38
- @constructs.each_with_index do |c,i|
37
+ @constructs.each_with_index do |c, i|
39
38
  @index_to_type_map[i] = case c.class.name
40
- when "Nickel::DateConstruct" then :date
41
- when "Nickel::TimeConstruct" then :time
42
- when "Nickel::DateSpanConstruct" then :datespan
43
- when "Nickel::TimeSpanConstruct" then :timespan
44
- when "Nickel::RecurrenceConstruct" then :recurrence
45
- when "Nickel::WrapperConstruct" then :wrapper
46
- end
39
+ when 'Nickel::DateConstruct' then :date
40
+ when 'Nickel::TimeConstruct' then :time
41
+ when 'Nickel::DateSpanConstruct' then :datespan
42
+ when 'Nickel::TimeSpanConstruct' then :timespan
43
+ when 'Nickel::RecurrenceConstruct' then :recurrence
44
+ when 'Nickel::WrapperConstruct' then :wrapper
45
+ end
47
46
  end
48
47
  end
49
48
 
@@ -52,27 +51,27 @@ module Nickel
52
51
  # Determine user input style, i.e. "DATE TIME DATE TIME" OR "TIME DATE TIME DATE".
53
52
  # Determine user input style, i.e. "DATE TIME DATE TIME" OR "TIME DATE TIME DATE".
54
53
  case (@index_to_type_map[0] == :wrapper ? @index_to_type_map[1] : @index_to_type_map[0])
55
- when :date then @user_input_style = :datetime
56
- when :time then @user_input_style = :timedate
57
- when :datespan then @user_input_style = :datetime
58
- when :timespan then @user_input_style = :timedate
59
- when :recurrence then @user_input_style = :datetime
60
- else
61
- # We only have wrappers. It doesn't matter which user style we choose.
62
- @user_input_style = :datetime
54
+ when :date then @user_input_style = :datetime
55
+ when :time then @user_input_style = :timedate
56
+ when :datespan then @user_input_style = :datetime
57
+ when :timespan then @user_input_style = :timedate
58
+ when :recurrence then @user_input_style = :datetime
59
+ else
60
+ # We only have wrappers. It doesn't matter which user style we choose.
61
+ @user_input_style = :datetime
63
62
  end
64
63
  end
65
64
 
66
65
  def initialize_arrays_of_construct_indices
67
- @dci,@tci,@dsci,@tsci,@rci,@wci = [],[],[],[],[],[]
66
+ @dci, @tci, @dsci, @tsci, @rci, @wci = [], [], [], [], [], []
68
67
  @index_to_type_map.each do |i, type|
69
68
  case type
70
- when :date then @dci << i
71
- when :time then @tci << i
72
- when :datespan then @dsci << i
73
- when :timespan then @tsci << i
74
- when :recurrence then @rci << i
75
- when :wrapper then @wci << i
69
+ when :date then @dci << i
70
+ when :time then @tci << i
71
+ when :datespan then @dsci << i
72
+ when :timespan then @tsci << i
73
+ when :recurrence then @rci << i
74
+ when :wrapper then @wci << i
76
75
  end
77
76
  end
78
77
  end
@@ -127,7 +126,7 @@ module Nickel
127
126
  # meaning move forward.
128
127
  if @user_input_style == :datetime then index + 1
129
128
  elsif @user_input_style == :timedate then index - 1
130
- else raise "ConstructInterpreter#move_time_map_index says: @user_input_style is not valid"
129
+ else fail 'ConstructInterpreter#move_time_map_index says: @user_input_style is not valid'
131
130
  end
132
131
  end
133
132
 
@@ -138,7 +137,7 @@ module Nickel
138
137
  else
139
138
  # There are times for this date, use them for any indices marked as inherit_on.
140
139
  # Then clear the inherit_on array.
141
- inherit_on.each {|k| @sorted_time_map[k] = @sorted_time_map[date_index]}
140
+ inherit_on.each { |k| @sorted_time_map[k] = @sorted_time_map[date_index] }
142
141
  inherit_on = []
143
142
  end
144
143
  inherit_on
@@ -169,7 +168,7 @@ module Nickel
169
168
  elsif index_references_timespan(tindex)
170
169
  return @constructs[tindex].start_time
171
170
  else
172
- raise "ConstructInterpreter#start_time_from_tindex says: tindex does not reference a time or time span"
171
+ fail 'ConstructInterpreter#start_time_from_tindex says: tindex does not reference a time or time span'
173
172
  end
174
173
  end
175
174
 
@@ -193,7 +192,6 @@ module Nickel
193
192
  # One of this methods functions will be to assign proper am/pm values to time
194
193
  # and timespan constructs if they were not specified.
195
194
  def finalize_constructs
196
-
197
195
  # First assign am/pm values to timespan constructs independent of
198
196
  # other times in timemap.
199
197
  finalize_timespan_constructs
@@ -205,7 +203,7 @@ module Nickel
205
203
  # The time_indices array holds TimeConstruct and TimeSpanConstruct indices.
206
204
  # The time_array will hold an array of ZTime objects to modify (potentially)
207
205
  time_array = []
208
- time_indices.each {|tindex| time_array << start_time_from_tindex(tindex)}
206
+ time_indices.each { |tindex| time_array << start_time_from_tindex(tindex) }
209
207
  ZTime.am_pm_modifier(*time_array)
210
208
  end
211
209
 
@@ -247,8 +245,8 @@ module Nickel
247
245
 
248
246
  def occurrences_from_dates
249
247
  @dci.each do |dindex|
250
- occ_base = Occurrence.new(:type => :single, :start_date => @constructs[dindex].date)
251
- create_occurrence_for_each_time_in_time_map(occ_base, dindex) {|occ| @occurrences << occ}
248
+ occ_base = Occurrence.new(type: :single, start_date: @constructs[dindex].date)
249
+ create_occurrence_for_each_time_in_time_map(occ_base, dindex) { |occ| @occurrences << occ }
252
250
  end
253
251
  end
254
252
 
@@ -257,11 +255,11 @@ module Nickel
257
255
  end
258
256
 
259
257
  def occurrences_from_one_date_span
260
- occ_base = Occurrence.new(:type => :daily,
261
- :start_date => @constructs[@dsci[0]].start_date,
262
- :end_date => @constructs[@dsci[0]].end_date,
263
- :interval => 1)
264
- create_occurrence_for_each_time_in_time_map(occ_base, @dsci[0]) {|occ| @occurrences << occ}
258
+ occ_base = Occurrence.new(type: :daily,
259
+ start_date: @constructs[@dsci[0]].start_date,
260
+ end_date: @constructs[@dsci[0]].end_date,
261
+ interval: 1)
262
+ create_occurrence_for_each_time_in_time_map(occ_base, @dsci[0]) { |occ| @occurrences << occ }
265
263
  end
266
264
 
267
265
  def found_recurrences_and_optional_date_span
@@ -271,7 +269,7 @@ module Nickel
271
269
  def occurrences_from_recurrences_and_optional_date_span
272
270
  if @dsci.size == 1
273
271
  # If a date span exists, it functions as wrapper.
274
- occ_base_opts = {:start_date => @constructs[@dsci[0]].start_date, :end_date => @constructs[@dsci[0]].end_date}
272
+ occ_base_opts = { start_date: @constructs[@dsci[0]].start_date, end_date: @constructs[@dsci[0]].end_date }
275
273
  else
276
274
  # Perhaps there are type 0 or type 1 wrappers to provide start/end dates.
277
275
  occ_base_opts = occ_base_opts_from_wrappers
@@ -284,7 +282,7 @@ module Nickel
284
282
  # but they must be merged with start/end dates, if supplied.
285
283
  occ_base = Occurrence.new(rec_occ_base_opts.merge(occ_base_opts))
286
284
  # Attach times:
287
- create_occurrence_for_each_time_in_time_map(occ_base, rcindex) {|occ| @occurrences << occ}
285
+ create_occurrence_for_each_time_in_time_map(occ_base, rcindex) { |occ| @occurrences << occ }
288
286
  end
289
287
  end
290
288
  end
@@ -296,7 +294,7 @@ module Nickel
296
294
  end
297
295
 
298
296
  def occurrences_from_wrappers_only
299
- occ_base = {:type => :daily, :interval => 1}
297
+ occ_base = { type: :daily, interval: 1 }
300
298
  @occurrences << Occurrence.new(occ_base.merge(occ_base_opts_from_wrappers))
301
299
  end
302
300
 
@@ -319,22 +317,22 @@ module Nickel
319
317
  if base_opts[:start_date].nil? && base_opts[:end_date].nil? # span must start today
320
318
  base_opts[:start_date] = @curdate.dup
321
319
  base_opts[:end_date] = case @constructs[wi].wrapper_type
322
- when 2 then @curdate.add_days(@constructs[wi].wrapper_length)
323
- when 3 then @curdate.add_weeks(@constructs[wi].wrapper_length)
324
- when 4 then @curdate.add_months(@constructs[wi].wrapper_length)
325
- end
320
+ when 2 then @curdate.add_days(@constructs[wi].wrapper_length)
321
+ when 3 then @curdate.add_weeks(@constructs[wi].wrapper_length)
322
+ when 4 then @curdate.add_months(@constructs[wi].wrapper_length)
323
+ end
326
324
  elsif base_opts[:start_date] && base_opts[:end_date].nil?
327
325
  base_opts[:end_date] = case @constructs[wi].wrapper_type
328
- when 2 then base_opts[:start_date].add_days(@constructs[wi].wrapper_length)
329
- when 3 then base_opts[:start_date].add_weeks(@constructs[wi].wrapper_length)
330
- when 4 then base_opts[:start_date].add_months(@constructs[wi].wrapper_length)
331
- end
326
+ when 2 then base_opts[:start_date].add_days(@constructs[wi].wrapper_length)
327
+ when 3 then base_opts[:start_date].add_weeks(@constructs[wi].wrapper_length)
328
+ when 4 then base_opts[:start_date].add_months(@constructs[wi].wrapper_length)
329
+ end
332
330
  elsif base_opts[:start_date].nil? && base_opts[:end_date] # for 6 months until jan 3rd
333
331
  base_opts[:start_date] = case @constructs[wi].wrapper_type
334
- when 2 then base_opts[:end_date].sub_days(@constructs[wi].wrapper_length)
335
- when 3 then base_opts[:end_date].sub_weeks(@constructs[wi].wrapper_length)
336
- when 4 then base_opts[:end_date].sub_months(@constructs[wi].wrapper_length)
337
- end
332
+ when 2 then base_opts[:end_date].sub_days(@constructs[wi].wrapper_length)
333
+ when 3 then base_opts[:end_date].sub_weeks(@constructs[wi].wrapper_length)
334
+ when 4 then base_opts[:end_date].sub_months(@constructs[wi].wrapper_length)
335
+ end
338
336
  end
339
337
  end
340
338
  end
@@ -6,16 +6,14 @@ require_relative 'construct_finder'
6
6
  require_relative 'construct_interpreter'
7
7
 
8
8
  module Nickel
9
-
10
9
  class NLP
11
-
12
10
  attr_reader :query, :input_date, :input_time, :nlp_query
13
11
  attr_reader :construct_finder, :construct_interpreter
14
12
  attr_reader :occurrences, :message
15
13
 
16
14
  def initialize(query, date_time = Time.now)
17
- raise InvalidDateTimeError unless [DateTime, Time].include?(date_time.class)
18
- str_time = date_time.strftime("%Y%m%dT%H%M%S")
15
+ fail InvalidDateTimeError unless [DateTime, Time].include?(date_time.class)
16
+ str_time = date_time.strftime('%Y%m%dT%H%M%S')
19
17
  validate_input query, str_time
20
18
  @query = query.dup
21
19
  @input_date = ZDate.new str_time[0..7] # up to T, note format is already verified
@@ -33,8 +31,8 @@ module Nickel
33
31
  @construct_interpreter = ConstructInterpreter.new(@construct_finder.constructs, @input_date) # input_date only needed for wrappers
34
32
  @construct_interpreter.run
35
33
 
36
- @occurrences = @construct_interpreter.occurrences.each {|occ| occ.finalize(@input_date) } # finds start and end dates
37
- @occurrences.sort! {|x,y| if x.start_date > y.start_date then 1 elsif x.start_date < y.start_date then -1 else 0 end} # sorts occurrences by start dat
34
+ @occurrences = @construct_interpreter.occurrences.each { |occ| occ.finalize(@input_date) } # finds start and end dates
35
+ @occurrences.sort_by(&:start_date)
38
36
  @occurrences
39
37
  end
40
38
 
@@ -52,16 +50,16 @@ module Nickel
52
50
  # now iterate through constructs, blow away any words between positions comp_start and comp_end
53
51
  constructs.each do |c|
54
52
  # create a range between comp_start and comp_end, iterate through it and wipe out words between them
55
- (c.comp_start..c.comp_end).each {|x| message_array[x] = nil}
53
+ (c.comp_start..c.comp_end).each { |x| message_array[x] = nil }
56
54
  # also wipe out words before comp start if it is something like in, at, on, or the
57
55
  if c.comp_start - 1 >= 0 && message_array[c.comp_start - 1] =~ /\b(from|in|at|on|the|are|is|for)\b/
58
56
  message_array[c.comp_start - 1] = nil
59
- if $1 == "the" && c.comp_start - 2 >= 0 && message_array[c.comp_start - 2] =~ /\b(for|on)\b/ # for the next three days; on the 27th;
57
+ if Regexp.last_match(1) == 'the' && c.comp_start - 2 >= 0 && message_array[c.comp_start - 2] =~ /\b(for|on)\b/ # for the next three days; on the 27th;
60
58
  message_array[c.comp_start - 2] = nil
61
- if $1 == "on" && c.comp_start - 3 >= 0 && message_array[c.comp_start - 3] =~ /\b(is|are)\b/ # is on the 28th; are on the 21st and 22nd;
59
+ if Regexp.last_match(1) == 'on' && c.comp_start - 3 >= 0 && message_array[c.comp_start - 3] =~ /\b(is|are)\b/ # is on the 28th; are on the 21st and 22nd;
62
60
  message_array[c.comp_start - 3] = nil
63
61
  end
64
- elsif $1 == "on" && c.comp_start - 2 >= 0 && message_array[c.comp_start - 2] =~ /\b(is|are)\b/ # is on tuesday; are on tuesday and wed;
62
+ elsif Regexp.last_match(1) == 'on' && c.comp_start - 2 >= 0 && message_array[c.comp_start - 2] =~ /\b(is|are)\b/ # is on tuesday; are on tuesday and wed;
65
63
  message_array[c.comp_start - 2] = nil
66
64
  end
67
65
  end
@@ -70,40 +68,39 @@ module Nickel
70
68
  # reloop and wipe out words after end of constructs, if they are followed by another construct
71
69
  # note we already wiped out terms ahead of the constructs, so be sure to check for nil values, these indicate that a construct is followed by the nil
72
70
  constructs.each_with_index do |c, i|
73
- if message_array[c.comp_end+1] && message_array[c.comp_end + 1] == "and" # do something tomorrow and on friday
74
- if message_array[c.comp_end + 2].nil? || (constructs[i+1] && constructs[i+1].comp_start == c.comp_end + 2)
71
+ if message_array[c.comp_end + 1] && message_array[c.comp_end + 1] == 'and' # do something tomorrow and on friday
72
+ if message_array[c.comp_end + 2].nil? || (constructs[i + 1] && constructs[i + 1].comp_start == c.comp_end + 2)
75
73
  message_array[c.comp_end + 1] = nil
76
- elsif message_array[c.comp_end + 2] == "also" && message_array[c.comp_end + 3].nil? || (constructs[i+1] && constructs[i+1].comp_start == c.comp_end + 3) # do something tomorrow and also on friday
74
+ elsif message_array[c.comp_end + 2] == 'also' && message_array[c.comp_end + 3].nil? || (constructs[i + 1] && constructs[i + 1].comp_start == c.comp_end + 3) # do something tomorrow and also on friday
77
75
  message_array[c.comp_end + 1] = nil
78
76
  message_array[c.comp_end + 2] = nil
79
77
  end
80
78
  end
81
79
  end
82
- @message = message_array.compact.join(" ") # remove nils and join the words with spaces
80
+ @message = message_array.compact.join(' ') # remove nils and join the words with spaces
83
81
  end
84
82
 
85
83
  # returns any words in the query that appeared as input to their original case
86
84
  def correct_case
87
85
  orig = @query.split
88
86
  latest = @message.split
89
- orig.each_with_index do |original_word,j|
87
+ orig.each_with_index do |original_word, j|
90
88
  if i = latest.index(original_word.downcase)
91
89
  latest[i] = original_word
92
90
  end
93
91
  end
94
- @message = latest.join(" ")
92
+ @message = latest.join(' ')
95
93
  end
96
94
 
97
- def validate_input query, date_time
98
- raise "Empty NLP query" unless query.length > 0
99
- raise "NLP says: date_time is not in the correct format" unless date_time =~ /^\d{8}T\d{6}$/
95
+ def validate_input(query, date_time)
96
+ fail 'Empty NLP query' unless query.length > 0
97
+ fail 'NLP says: date_time is not in the correct format' unless date_time =~ /^\d{8}T\d{6}$/
100
98
  end
101
99
  end
102
100
 
103
101
  class InvalidDateTimeError < StandardError
104
102
  def message
105
- "You must pass in a ruby DateTime or Time class object"
103
+ 'You must pass in a ruby DateTime or Time class object'
106
104
  end
107
105
  end
108
106
  end
109
-
@@ -3,7 +3,6 @@ require_relative 'ztime'
3
3
  require_relative 'nlp_query_constants'
4
4
 
5
5
  module Nickel
6
-
7
6
  class NLPQuery
8
7
  include NLPQueryConstants
9
8
 
@@ -21,7 +20,7 @@ module Nickel
21
20
  end
22
21
 
23
22
  def query_formatting
24
- query_str.gsub!(/\n/,'')
23
+ query_str.gsub!(/\n/, '')
25
24
  query_str.downcase!
26
25
  remove_unused_punctuation
27
26
  replace_backslashes
@@ -54,14 +53,14 @@ module Nickel
54
53
  if block_given?
55
54
  # query_str.gsub!(args[0]) {yield(*m.to_a[1..-1])} # There is a bug here: If gsub matches more than once,
56
55
  # then the first set of referenced matches will be passed to the block
57
- ret_str = m.pre_match + m[0].sub(args[0]) {yield(*m.to_a[1..-1])} # this will take care of the first set of matches
56
+ ret_str = m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) } # this will take care of the first set of matches
58
57
  while (m_old = m.dup) && (m = m.post_match.match(args[0]))
59
- ret_str << m.pre_match + m[0].sub(args[0]) {yield(*m.to_a[1..-1])}
58
+ ret_str << m.pre_match + m[0].sub(args[0]) { yield(*m.to_a[1..-1]) }
60
59
  end
61
60
  ret_str << m_old.post_match
62
- query_str.sub!(/.*/,ret_str)
61
+ query_str.sub!(/.*/, ret_str)
63
62
  else
64
- query_str.gsub!(args[0],args[1])
63
+ query_str.gsub!(args[0], args[1])
65
64
  end
66
65
  end
67
66
  end
@@ -71,338 +70,338 @@ module Nickel
71
70
  end
72
71
 
73
72
  def remove_unused_punctuation
74
- nsub!(/,/,' ')
75
- nsub!(/\./,'')
76
- nsub!(/;/,'')
77
- nsub!(/['`]/,'')
73
+ nsub!(/,/, ' ')
74
+ nsub!(/\./, '')
75
+ nsub!(/;/, '')
76
+ nsub!(/['`]/, '')
78
77
  end
79
78
 
80
79
  def replace_backslashes
81
- nsub!(/\\/,'/')
80
+ nsub!(/\\/, '/')
82
81
  end
83
82
 
84
83
  def run_spell_check
85
- nsub!(/tomm?orr?ow|romorrow/,'tomorrow')
86
- nsub!(/weeknd/,'weekend')
87
- nsub!(/weekends/,'every sat sun')
88
- nsub!(/everyother/,'every other')
89
- nsub!(/weak/,'week')
90
- nsub!(/everyweek/,'every week')
91
- nsub!(/everymonth/,'every month')
92
- nsub!(/c?h[oa]nn?[aui][ck][ck]?[ua]h?/,'hannukkah')
93
- nsub!(/frist/,'1st')
94
- nsub!(/eveyr|evrey/,'every')
95
- nsub!(/fridya|friady|fridy/,'friday')
96
- nsub!(/thurdsday/,'thursday')
97
- nsub!(/x-?mas/,'christmas')
98
- nsub!(/st\s+(patrick|patty|pat)s?(\s+day)?/,'st patricks day')
99
- nsub!(/frouth/,'fourth')
100
- nsub!(/\btill\b/,'through')
101
- nsub!(/\bthru\b|\bthrouh\b|\bthough\b|\bthrew\b|\bthrow\b|\bthroug\b|\bthuogh\b/,'through')
102
- nsub!(/weekdays|every\s+weekday/,'every monday through friday')
103
- nsub!(/\bevery?day\b/,'every day')
104
- nsub!(/eigth/,'eighth')
105
- nsub!(/bi[-\s]monthly/,'bimonthly')
106
- nsub!(/tri[-\s]monthly/,'trimonthly')
84
+ nsub!(/tomm?orr?ow|romorrow/, 'tomorrow')
85
+ nsub!(/weeknd/, 'weekend')
86
+ nsub!(/weekends/, 'every sat sun')
87
+ nsub!(/everyother/, 'every other')
88
+ nsub!(/weak/, 'week')
89
+ nsub!(/everyweek/, 'every week')
90
+ nsub!(/everymonth/, 'every month')
91
+ nsub!(/c?h[oa]nn?[aui][ck][ck]?[ua]h?/, 'hannukkah')
92
+ nsub!(/frist/, '1st')
93
+ nsub!(/eveyr|evrey/, 'every')
94
+ nsub!(/fridya|friady|fridy/, 'friday')
95
+ nsub!(/thurdsday/, 'thursday')
96
+ nsub!(/x-?mas/, 'christmas')
97
+ nsub!(/st\s+(patrick|patty|pat)s?(\s+day)?/, 'st patricks day')
98
+ nsub!(/frouth/, 'fourth')
99
+ nsub!(/\btill\b/, 'through')
100
+ nsub!(/\bthru\b|\bthrouh\b|\bthough\b|\bthrew\b|\bthrow\b|\bthroug\b|\bthuogh\b/, 'through')
101
+ nsub!(/weekdays|every\s+weekday/, 'every monday through friday')
102
+ nsub!(/\bevery?day\b/, 'every day')
103
+ nsub!(/eigth/, 'eighth')
104
+ nsub!(/bi[-\s]monthly/, 'bimonthly')
105
+ nsub!(/tri[-\s]monthly/, 'trimonthly')
107
106
  end
108
107
 
109
108
  def remove_unnecessary_words
110
- nsub!(/coming/,'')
111
- nsub!(/o'?clock/,'')
112
- nsub!(/\btom\b/,'tomorrow')
113
- nsub!(/\s*in\s+(the\s+)?(morning|am)/,' am')
114
- nsub!(/\s*in\s+(the\s+)?(afternoon|pm|evenn?ing)/,' pm')
115
- nsub!(/\s*at\s+night/,'pm')
116
- nsub!(/(after\s*)?noon(ish)?/,'12:00pm')
117
- nsub!(/\bmi(dn|nd)ight\b/,'12:00am')
118
- nsub!(/final/,'last')
119
- nsub!(/recur(s|r?ing)?/,'repeats')
120
- nsub!(/\beach\b/,'every')
121
- nsub!(/running\s+(until|through)/,'through')
122
- nsub!(/runn?(s|ing)|go(ing|e?s)/,'for')
123
- nsub!(/next\s+occ?urr?[ae]nce(\s+is)?/,'start')
124
- nsub!(/next\s+date(\s+it)?(\s+occ?urr?s)?(\s+is)?/,'start')
125
- nsub!(/forever/,'repeats daily')
126
- nsub!(/\bany(?:\s*)day\b/,'every day')
127
- nsub!(/^anytime$/,'every day') # user entered anytime by itself, not 'dayname anytime', caught next
128
- nsub!(/any(\s)?time|whenever/,'all day')
109
+ nsub!(/coming/, '')
110
+ nsub!(/o'?clock/, '')
111
+ nsub!(/\btom\b/, 'tomorrow')
112
+ nsub!(/\s*in\s+(the\s+)?(morning|am)/, ' am')
113
+ nsub!(/\s*in\s+(the\s+)?(afternoon|pm|evenn?ing)/, ' pm')
114
+ nsub!(/\s*at\s+night/, 'pm')
115
+ nsub!(/(after\s*)?noon(ish)?/, '12:00pm')
116
+ nsub!(/\bmi(dn|nd)ight\b/, '12:00am')
117
+ nsub!(/final/, 'last')
118
+ nsub!(/recur(s|r?ing)?/, 'repeats')
119
+ nsub!(/\beach\b/, 'every')
120
+ nsub!(/running\s+(until|through)/, 'through')
121
+ nsub!(/runn?(s|ing)|go(ing|e?s)/, 'for')
122
+ nsub!(/next\s+occ?urr?[ae]nce(\s+is)?/, 'start')
123
+ nsub!(/next\s+date(\s+it)?(\s+occ?urr?s)?(\s+is)?/, 'start')
124
+ nsub!(/forever/, 'repeats daily')
125
+ nsub!(/\bany(?:\s*)day\b/, 'every day')
126
+ nsub!(/^anytime$/, 'every day') # user entered anytime by itself, not 'dayname anytime', caught next
127
+ nsub!(/any(\s)?time|whenever/, 'all day')
129
128
  end
130
129
 
131
130
  def standardize_days
132
- nsub!(/mondays/,'every mon')
133
- nsub!(/monday/,'mon')
134
- nsub!(/tuesdays/,'every tue')
135
- nsub!(/tuesadys/,'every tue')
136
- nsub!(/tuesday/,'tue')
137
- nsub!(/tuesady/,'tue')
138
- nsub!(/wednesdays/,'every wed')
139
- nsub!(/wednesday/,'wed')
140
- nsub!(/thursdays/,'every thu')
141
- nsub!(/thurdsays/,'every thu')
142
- nsub!(/thursadys/,'every thu')
143
- nsub!(/thursday/,'thu')
144
- nsub!(/thurdsay/,'thu')
145
- nsub!(/thursady/,'thu')
146
- nsub!(/\bthurd?\b/,'thu')
147
- nsub!(/\bthurs?d?\b/,'thu')
148
- nsub!(/fridays/,'every fri')
149
- nsub!(/firdays/,'every fri')
150
- nsub!(/friday/,'fri')
151
- nsub!(/firday/,'fri')
152
- nsub!(/saturdays/,'every sat')
153
- nsub!(/saturday/,'sat')
154
- nsub!(/sundays/,'every sun')
155
- nsub!(/sunday/,'sun')
131
+ nsub!(/mondays/, 'every mon')
132
+ nsub!(/monday/, 'mon')
133
+ nsub!(/tuesdays/, 'every tue')
134
+ nsub!(/tuesadys/, 'every tue')
135
+ nsub!(/tuesday/, 'tue')
136
+ nsub!(/tuesady/, 'tue')
137
+ nsub!(/wednesdays/, 'every wed')
138
+ nsub!(/wednesday/, 'wed')
139
+ nsub!(/thursdays/, 'every thu')
140
+ nsub!(/thurdsays/, 'every thu')
141
+ nsub!(/thursadys/, 'every thu')
142
+ nsub!(/thursday/, 'thu')
143
+ nsub!(/thurdsay/, 'thu')
144
+ nsub!(/thursady/, 'thu')
145
+ nsub!(/\bthurd?\b/, 'thu')
146
+ nsub!(/\bthurs?d?\b/, 'thu')
147
+ nsub!(/fridays/, 'every fri')
148
+ nsub!(/firdays/, 'every fri')
149
+ nsub!(/friday/, 'fri')
150
+ nsub!(/firday/, 'fri')
151
+ nsub!(/saturdays/, 'every sat')
152
+ nsub!(/saturday/, 'sat')
153
+ nsub!(/sundays/, 'every sun')
154
+ nsub!(/sunday/, 'sun')
156
155
  end
157
156
 
158
157
  def standardize_months
159
- nsub!(/january/,'jan')
160
- nsub!(/february/,'feb')
158
+ nsub!(/january/, 'jan')
159
+ nsub!(/february/, 'feb')
161
160
  nsub!(/febr/, 'feb')
162
- nsub!(/march/,'mar')
163
- nsub!(/april/,'apr')
164
- nsub!(/may/,'may')
165
- nsub!(/june/,'jun')
166
- nsub!(/july/,'jul')
167
- nsub!(/august/,'aug')
168
- nsub!(/september/,'sep')
169
- nsub!(/sept/,'sep')
170
- nsub!(/october/,'oct')
171
- nsub!(/november/,'nov')
172
- nsub!(/novermber/,'nov')
173
- nsub!(/novem/,'nov')
174
- nsub!(/decemb?e?r?/,'dec')
161
+ nsub!(/march/, 'mar')
162
+ nsub!(/april/, 'apr')
163
+ nsub!(/may/, 'may')
164
+ nsub!(/june/, 'jun')
165
+ nsub!(/july/, 'jul')
166
+ nsub!(/august/, 'aug')
167
+ nsub!(/september/, 'sep')
168
+ nsub!(/sept/, 'sep')
169
+ nsub!(/october/, 'oct')
170
+ nsub!(/november/, 'nov')
171
+ nsub!(/novermber/, 'nov')
172
+ nsub!(/novem/, 'nov')
173
+ nsub!(/decemb?e?r?/, 'dec')
175
174
  end
176
175
 
177
176
  def standardize_numbers
178
- nsub!(/\bone\s*-?\s*hundred\b/,'100')
179
- nsub!(/\bone\s*-?\s*hundredth\b/,'100th')
180
- nsub!(/\bninety\s*-?\s*nine\b/,'99')
181
- nsub!(/\bninety\s*-?\s*ninth\b/,'99th')
182
- nsub!(/\bninety\s*-?\s*eight\b/,'98')
183
- nsub!(/\bninety\s*-?\s*eighth\b/,'98th')
184
- nsub!(/\bninety\s*-?\s*seven\b/,'97')
185
- nsub!(/\bninety\s*-?\s*seventh\b/,'97th')
186
- nsub!(/\bninety\s*-?\s*six\b/,'96')
187
- nsub!(/\bninety\s*-?\s*sixth\b/,'96th')
188
- nsub!(/\bninety\s*-?\s*five\b/,'95')
189
- nsub!(/\bninety\s*-?\s*fifth\b/,'95th')
190
- nsub!(/\bninety\s*-?\s*four\b/,'94')
191
- nsub!(/\bninety\s*-?\s*fourth\b/,'94th')
192
- nsub!(/\bninety\s*-?\s*three\b/,'93')
193
- nsub!(/\bninety\s*-?\s*third\b/,'93rd')
194
- nsub!(/\bninety\s*-?\s*two\b/,'92')
195
- nsub!(/\bninety\s*-?\s*second\b/,'92nd')
196
- nsub!(/\bninety\s*-?\s*one\b/,'91')
197
- nsub!(/\bninety\s*-?\s*first\b/,'91st')
198
- nsub!(/\bninety\b/,'90')
199
- nsub!(/\bninetieth\b/,'90th')
200
- nsub!(/\beighty\s*-?\s*nine\b/,'89')
201
- nsub!(/\beighty\s*-?\s*ninth\b/,'89th')
202
- nsub!(/\beighty\s*-?\s*eight\b/,'88')
203
- nsub!(/\beighty\s*-?\s*eighth\b/,'88th')
204
- nsub!(/\beighty\s*-?\s*seven\b/,'87')
205
- nsub!(/\beighty\s*-?\s*seventh\b/,'87th')
206
- nsub!(/\beighty\s*-?\s*six\b/,'86')
207
- nsub!(/\beighty\s*-?\s*sixth\b/,'86th')
208
- nsub!(/\beighty\s*-?\s*five\b/,'85')
209
- nsub!(/\beighty\s*-?\s*fifth\b/,'85th')
210
- nsub!(/\beighty\s*-?\s*four\b/,'84')
211
- nsub!(/\beighty\s*-?\s*fourth\b/,'84th')
212
- nsub!(/\beighty\s*-?\s*three\b/,'83')
213
- nsub!(/\beighty\s*-?\s*third\b/,'83rd')
214
- nsub!(/\beighty\s*-?\s*two\b/,'82')
215
- nsub!(/\beighty\s*-?\s*second\b/,'82nd')
216
- nsub!(/\beighty\s*-?\s*one\b/,'81')
217
- nsub!(/\beighty\s*-?\s*first\b/,'81st')
218
- nsub!(/\beighty\b/,'80')
219
- nsub!(/\beightieth\b/,'80th')
220
- nsub!(/\bseventy\s*-?\s*nine\b/,'79')
221
- nsub!(/\bseventy\s*-?\s*ninth\b/,'79th')
222
- nsub!(/\bseventy\s*-?\s*eight\b/,'78')
223
- nsub!(/\bseventy\s*-?\s*eighth\b/,'78th')
224
- nsub!(/\bseventy\s*-?\s*seven\b/,'77')
225
- nsub!(/\bseventy\s*-?\s*seventh\b/,'77th')
226
- nsub!(/\bseventy\s*-?\s*six\b/,'76')
227
- nsub!(/\bseventy\s*-?\s*sixth\b/,'76th')
228
- nsub!(/\bseventy\s*-?\s*five\b/,'75')
229
- nsub!(/\bseventy\s*-?\s*fifth\b/,'75th')
230
- nsub!(/\bseventy\s*-?\s*four\b/,'74')
231
- nsub!(/\bseventy\s*-?\s*fourth\b/,'74th')
232
- nsub!(/\bseventy\s*-?\s*three\b/,'73')
233
- nsub!(/\bseventy\s*-?\s*third\b/,'73rd')
234
- nsub!(/\bseventy\s*-?\s*two\b/,'72')
235
- nsub!(/\bseventy\s*-?\s*second\b/,'72nd')
236
- nsub!(/\bseventy\s*-?\s*one\b/,'71')
237
- nsub!(/\bseventy\s*-?\s*first\b/,'71st')
238
- nsub!(/\bseventy\b/,'70')
239
- nsub!(/\bseventieth\b/,'70th')
240
- nsub!(/\bsixty\s*-?\s*nine\b/,'69')
241
- nsub!(/\bsixty\s*-?\s*ninth\b/,'69th')
242
- nsub!(/\bsixty\s*-?\s*eight\b/,'68')
243
- nsub!(/\bsixty\s*-?\s*eighth\b/,'68th')
244
- nsub!(/\bsixty\s*-?\s*seven\b/,'67')
245
- nsub!(/\bsixty\s*-?\s*seventh\b/,'67th')
246
- nsub!(/\bsixty\s*-?\s*six\b/,'66')
247
- nsub!(/\bsixty\s*-?\s*sixth\b/,'66th')
248
- nsub!(/\bsixty\s*-?\s*five\b/,'65')
249
- nsub!(/\bsixty\s*-?\s*fifth\b/,'65th')
250
- nsub!(/\bsixty\s*-?\s*four\b/,'64')
251
- nsub!(/\bsixty\s*-?\s*fourth\b/,'64th')
252
- nsub!(/\bsixty\s*-?\s*three\b/,'63')
253
- nsub!(/\bsixty\s*-?\s*third\b/,'63rd')
254
- nsub!(/\bsixty\s*-?\s*two\b/,'62')
255
- nsub!(/\bsixty\s*-?\s*second\b/,'62nd')
256
- nsub!(/\bsixty\s*-?\s*one\b/,'61')
257
- nsub!(/\bsixty\s*-?\s*first\b/,'61st')
258
- nsub!(/\bsixty\b/,'60')
259
- nsub!(/\bsixtieth\b/,'60th')
260
- nsub!(/\bfifty\s*-?\s*nine\b/,'59')
261
- nsub!(/\bfifty\s*-?\s*ninth\b/,'59th')
262
- nsub!(/\bfifty\s*-?\s*eight\b/,'58')
263
- nsub!(/\bfifty\s*-?\s*eighth\b/,'58th')
264
- nsub!(/\bfifty\s*-?\s*seven\b/,'57')
265
- nsub!(/\bfifty\s*-?\s*seventh\b/,'57th')
266
- nsub!(/\bfifty\s*-?\s*six\b/,'56')
267
- nsub!(/\bfifty\s*-?\s*sixth\b/,'56th')
268
- nsub!(/\bfifty\s*-?\s*five\b/,'55')
269
- nsub!(/\bfifty\s*-?\s*fifth\b/,'55th')
270
- nsub!(/\bfifty\s*-?\s*four\b/,'54')
271
- nsub!(/\bfifty\s*-?\s*fourth\b/,'54th')
272
- nsub!(/\bfifty\s*-?\s*three\b/,'53')
273
- nsub!(/\bfifty\s*-?\s*third\b/,'53rd')
274
- nsub!(/\bfifty\s*-?\s*two\b/,'52')
275
- nsub!(/\bfifty\s*-?\s*second\b/,'52nd')
276
- nsub!(/\bfifty\s*-?\s*one\b/,'51')
277
- nsub!(/\bfifty\s*-?\s*first\b/,'51st')
278
- nsub!(/\bfifty\b/,'50')
279
- nsub!(/\bfiftieth\b/,'50th')
280
- nsub!(/\bfourty\s*-?\s*nine\b/,'49')
281
- nsub!(/\bfourty\s*-?\s*ninth\b/,'49th')
282
- nsub!(/\bfourty\s*-?\s*eight\b/,'48')
283
- nsub!(/\bfourty\s*-?\s*eighth\b/,'48th')
284
- nsub!(/\bfourty\s*-?\s*seven\b/,'47')
285
- nsub!(/\bfourty\s*-?\s*seventh\b/,'47th')
286
- nsub!(/\bfourty\s*-?\s*six\b/,'46')
287
- nsub!(/\bfourty\s*-?\s*sixth\b/,'46th')
288
- nsub!(/\bfourty\s*-?\s*five\b/,'45')
289
- nsub!(/\bfourty\s*-?\s*fifth\b/,'45th')
290
- nsub!(/\bfourty\s*-?\s*four\b/,'44')
291
- nsub!(/\bfourty\s*-?\s*fourth\b/,'44th')
292
- nsub!(/\bfourty\s*-?\s*three\b/,'43')
293
- nsub!(/\bfourty\s*-?\s*third\b/,'43rd')
294
- nsub!(/\bfourty\s*-?\s*two\b/,'42')
295
- nsub!(/\bfourty\s*-?\s*second\b/,'42nd')
296
- nsub!(/\bfourty\s*-?\s*one\b/,'41')
297
- nsub!(/\bfourty\s*-?\s*first\b/,'41st')
298
- nsub!(/\bfourty\b/,'40')
299
- nsub!(/\bfourtieth\b/,'40th')
300
- nsub!(/\bthirty\s*-?\s*nine\b/,'39')
301
- nsub!(/\bthirty\s*-?\s*ninth\b/,'39th')
302
- nsub!(/\bthirty\s*-?\s*eight\b/,'38')
303
- nsub!(/\bthirty\s*-?\s*eighth\b/,'38th')
304
- nsub!(/\bthirty\s*-?\s*seven\b/,'37')
305
- nsub!(/\bthirty\s*-?\s*seventh\b/,'37th')
306
- nsub!(/\bthirty\s*-?\s*six\b/,'36')
307
- nsub!(/\bthirty\s*-?\s*sixth\b/,'36th')
308
- nsub!(/\bthirty\s*-?\s*five\b/,'35')
309
- nsub!(/\bthirty\s*-?\s*fifth\b/,'35th')
310
- nsub!(/\bthirty\s*-?\s*four\b/,'34')
311
- nsub!(/\bthirty\s*-?\s*fourth\b/,'34th')
312
- nsub!(/\bthirty\s*-?\s*three\b/,'33')
313
- nsub!(/\bthirty\s*-?\s*third\b/,'33rd')
314
- nsub!(/\bthirty\s*-?\s*two\b/,'32')
315
- nsub!(/\bthirty\s*-?\s*second\b/,'32nd')
316
- nsub!(/\bthirty\s*-?\s*one\b/,'31')
317
- nsub!(/\bthirty\s*-?\s*first\b/,'31st')
318
- nsub!(/\bthirty\b/,'30')
319
- nsub!(/\bthirtieth\b/,'30th')
320
- nsub!(/\btwenty\s*-?\s*nine\b/,'29')
321
- nsub!(/\btwenty\s*-?\s*ninth\b/,'29th')
322
- nsub!(/\btwenty\s*-?\s*eight\b/,'28')
323
- nsub!(/\btwenty\s*-?\s*eighth\b/,'28th')
324
- nsub!(/\btwenty\s*-?\s*seven\b/,'27')
325
- nsub!(/\btwenty\s*-?\s*seventh\b/,'27th')
326
- nsub!(/\btwenty\s*-?\s*six\b/,'26')
327
- nsub!(/\btwenty\s*-?\s*sixth\b/,'26th')
328
- nsub!(/\btwenty\s*-?\s*five\b/,'25')
329
- nsub!(/\btwenty\s*-?\s*fifth\b/,'25th')
330
- nsub!(/\btwenty\s*-?\s*four\b/,'24')
331
- nsub!(/\btwenty\s*-?\s*fourth\b/,'24th')
332
- nsub!(/\btwenty\s*-?\s*three\b/,'23')
333
- nsub!(/\btwenty\s*-?\s*third\b/,'23rd')
334
- nsub!(/\btwenty\s*-?\s*two\b/,'22')
335
- nsub!(/\btwenty\s*-?\s*second\b/,'22nd')
336
- nsub!(/\btwenty\s*-?\s*one\b/,'21')
337
- nsub!(/\btwenty\s*-?\s*first\b/,'21st')
338
- nsub!(/\btwenty\b/,'20')
339
- nsub!(/\btwentieth\b/,'20th')
340
- nsub!(/\bnineteen\b/,'19')
341
- nsub!(/\bnineteenth\b/,'19th')
342
- nsub!(/\beighteen\b/,'18')
343
- nsub!(/\beighteenth\b/,'18th')
344
- nsub!(/\bseventeen\b/,'17')
345
- nsub!(/\bseventeenth\b/,'17th')
346
- nsub!(/\bsixteen\b/,'16')
347
- nsub!(/\bsixteenth\b/,'16th')
348
- nsub!(/\bfifteen\b/,'15')
349
- nsub!(/\bfifteenth\b/,'15th')
350
- nsub!(/\bfourteen\b/,'14')
351
- nsub!(/\bfourteenth\b/,'14th')
352
- nsub!(/\bthirteen/,'13')
353
- nsub!(/\bthirteenth/,'13th')
354
- nsub!(/\btwelve\b/,'12')
355
- nsub!(/\btwelfth\b/,'12th')
356
- nsub!(/\beleven\b/,'11')
357
- nsub!(/\beleventh\b/,'11th')
358
- nsub!(/\bten\b/,'10')
359
- nsub!(/\btenth\b/,'10th')
360
- nsub!(/\bnine\b/,'9')
361
- nsub!(/\bninth\b/,'9th')
362
- nsub!(/\beight\b/,'8')
363
- nsub!(/\beighth\b/,'8th')
364
- nsub!(/\bseven\b/,'7')
365
- nsub!(/\bseventh\b/,'7th')
366
- nsub!(/\bsix\b/,'6')
367
- nsub!(/\bsixth\b/,'6th')
368
- nsub!(/\bfive\b/,'5')
369
- nsub!(/\bfifth\b/,'5th')
370
- nsub!(/\bfour\b/,'4')
371
- nsub!(/\bfourth\b/,'4th')
372
- nsub!(/\bthree\b/,'3')
373
- nsub!(/\bthird\b/,'3rd')
374
- nsub!(/\btwo\b/,'2')
375
- nsub!(/\bsecond\b/,'2nd')
376
- nsub!(/\bone\b/,'1')
377
- nsub!(/\bfirst\b/,'1st')
378
- nsub!(/\bzero\b/,'0')
379
- nsub!(/\bzeroth\b/,'0th')
177
+ nsub!(/\bone\s*-?\s*hundred\b/, '100')
178
+ nsub!(/\bone\s*-?\s*hundredth\b/, '100th')
179
+ nsub!(/\bninety\s*-?\s*nine\b/, '99')
180
+ nsub!(/\bninety\s*-?\s*ninth\b/, '99th')
181
+ nsub!(/\bninety\s*-?\s*eight\b/, '98')
182
+ nsub!(/\bninety\s*-?\s*eighth\b/, '98th')
183
+ nsub!(/\bninety\s*-?\s*seven\b/, '97')
184
+ nsub!(/\bninety\s*-?\s*seventh\b/, '97th')
185
+ nsub!(/\bninety\s*-?\s*six\b/, '96')
186
+ nsub!(/\bninety\s*-?\s*sixth\b/, '96th')
187
+ nsub!(/\bninety\s*-?\s*five\b/, '95')
188
+ nsub!(/\bninety\s*-?\s*fifth\b/, '95th')
189
+ nsub!(/\bninety\s*-?\s*four\b/, '94')
190
+ nsub!(/\bninety\s*-?\s*fourth\b/, '94th')
191
+ nsub!(/\bninety\s*-?\s*three\b/, '93')
192
+ nsub!(/\bninety\s*-?\s*third\b/, '93rd')
193
+ nsub!(/\bninety\s*-?\s*two\b/, '92')
194
+ nsub!(/\bninety\s*-?\s*second\b/, '92nd')
195
+ nsub!(/\bninety\s*-?\s*one\b/, '91')
196
+ nsub!(/\bninety\s*-?\s*first\b/, '91st')
197
+ nsub!(/\bninety\b/, '90')
198
+ nsub!(/\bninetieth\b/, '90th')
199
+ nsub!(/\beighty\s*-?\s*nine\b/, '89')
200
+ nsub!(/\beighty\s*-?\s*ninth\b/, '89th')
201
+ nsub!(/\beighty\s*-?\s*eight\b/, '88')
202
+ nsub!(/\beighty\s*-?\s*eighth\b/, '88th')
203
+ nsub!(/\beighty\s*-?\s*seven\b/, '87')
204
+ nsub!(/\beighty\s*-?\s*seventh\b/, '87th')
205
+ nsub!(/\beighty\s*-?\s*six\b/, '86')
206
+ nsub!(/\beighty\s*-?\s*sixth\b/, '86th')
207
+ nsub!(/\beighty\s*-?\s*five\b/, '85')
208
+ nsub!(/\beighty\s*-?\s*fifth\b/, '85th')
209
+ nsub!(/\beighty\s*-?\s*four\b/, '84')
210
+ nsub!(/\beighty\s*-?\s*fourth\b/, '84th')
211
+ nsub!(/\beighty\s*-?\s*three\b/, '83')
212
+ nsub!(/\beighty\s*-?\s*third\b/, '83rd')
213
+ nsub!(/\beighty\s*-?\s*two\b/, '82')
214
+ nsub!(/\beighty\s*-?\s*second\b/, '82nd')
215
+ nsub!(/\beighty\s*-?\s*one\b/, '81')
216
+ nsub!(/\beighty\s*-?\s*first\b/, '81st')
217
+ nsub!(/\beighty\b/, '80')
218
+ nsub!(/\beightieth\b/, '80th')
219
+ nsub!(/\bseventy\s*-?\s*nine\b/, '79')
220
+ nsub!(/\bseventy\s*-?\s*ninth\b/, '79th')
221
+ nsub!(/\bseventy\s*-?\s*eight\b/, '78')
222
+ nsub!(/\bseventy\s*-?\s*eighth\b/, '78th')
223
+ nsub!(/\bseventy\s*-?\s*seven\b/, '77')
224
+ nsub!(/\bseventy\s*-?\s*seventh\b/, '77th')
225
+ nsub!(/\bseventy\s*-?\s*six\b/, '76')
226
+ nsub!(/\bseventy\s*-?\s*sixth\b/, '76th')
227
+ nsub!(/\bseventy\s*-?\s*five\b/, '75')
228
+ nsub!(/\bseventy\s*-?\s*fifth\b/, '75th')
229
+ nsub!(/\bseventy\s*-?\s*four\b/, '74')
230
+ nsub!(/\bseventy\s*-?\s*fourth\b/, '74th')
231
+ nsub!(/\bseventy\s*-?\s*three\b/, '73')
232
+ nsub!(/\bseventy\s*-?\s*third\b/, '73rd')
233
+ nsub!(/\bseventy\s*-?\s*two\b/, '72')
234
+ nsub!(/\bseventy\s*-?\s*second\b/, '72nd')
235
+ nsub!(/\bseventy\s*-?\s*one\b/, '71')
236
+ nsub!(/\bseventy\s*-?\s*first\b/, '71st')
237
+ nsub!(/\bseventy\b/, '70')
238
+ nsub!(/\bseventieth\b/, '70th')
239
+ nsub!(/\bsixty\s*-?\s*nine\b/, '69')
240
+ nsub!(/\bsixty\s*-?\s*ninth\b/, '69th')
241
+ nsub!(/\bsixty\s*-?\s*eight\b/, '68')
242
+ nsub!(/\bsixty\s*-?\s*eighth\b/, '68th')
243
+ nsub!(/\bsixty\s*-?\s*seven\b/, '67')
244
+ nsub!(/\bsixty\s*-?\s*seventh\b/, '67th')
245
+ nsub!(/\bsixty\s*-?\s*six\b/, '66')
246
+ nsub!(/\bsixty\s*-?\s*sixth\b/, '66th')
247
+ nsub!(/\bsixty\s*-?\s*five\b/, '65')
248
+ nsub!(/\bsixty\s*-?\s*fifth\b/, '65th')
249
+ nsub!(/\bsixty\s*-?\s*four\b/, '64')
250
+ nsub!(/\bsixty\s*-?\s*fourth\b/, '64th')
251
+ nsub!(/\bsixty\s*-?\s*three\b/, '63')
252
+ nsub!(/\bsixty\s*-?\s*third\b/, '63rd')
253
+ nsub!(/\bsixty\s*-?\s*two\b/, '62')
254
+ nsub!(/\bsixty\s*-?\s*second\b/, '62nd')
255
+ nsub!(/\bsixty\s*-?\s*one\b/, '61')
256
+ nsub!(/\bsixty\s*-?\s*first\b/, '61st')
257
+ nsub!(/\bsixty\b/, '60')
258
+ nsub!(/\bsixtieth\b/, '60th')
259
+ nsub!(/\bfifty\s*-?\s*nine\b/, '59')
260
+ nsub!(/\bfifty\s*-?\s*ninth\b/, '59th')
261
+ nsub!(/\bfifty\s*-?\s*eight\b/, '58')
262
+ nsub!(/\bfifty\s*-?\s*eighth\b/, '58th')
263
+ nsub!(/\bfifty\s*-?\s*seven\b/, '57')
264
+ nsub!(/\bfifty\s*-?\s*seventh\b/, '57th')
265
+ nsub!(/\bfifty\s*-?\s*six\b/, '56')
266
+ nsub!(/\bfifty\s*-?\s*sixth\b/, '56th')
267
+ nsub!(/\bfifty\s*-?\s*five\b/, '55')
268
+ nsub!(/\bfifty\s*-?\s*fifth\b/, '55th')
269
+ nsub!(/\bfifty\s*-?\s*four\b/, '54')
270
+ nsub!(/\bfifty\s*-?\s*fourth\b/, '54th')
271
+ nsub!(/\bfifty\s*-?\s*three\b/, '53')
272
+ nsub!(/\bfifty\s*-?\s*third\b/, '53rd')
273
+ nsub!(/\bfifty\s*-?\s*two\b/, '52')
274
+ nsub!(/\bfifty\s*-?\s*second\b/, '52nd')
275
+ nsub!(/\bfifty\s*-?\s*one\b/, '51')
276
+ nsub!(/\bfifty\s*-?\s*first\b/, '51st')
277
+ nsub!(/\bfifty\b/, '50')
278
+ nsub!(/\bfiftieth\b/, '50th')
279
+ nsub!(/\bfourty\s*-?\s*nine\b/, '49')
280
+ nsub!(/\bfourty\s*-?\s*ninth\b/, '49th')
281
+ nsub!(/\bfourty\s*-?\s*eight\b/, '48')
282
+ nsub!(/\bfourty\s*-?\s*eighth\b/, '48th')
283
+ nsub!(/\bfourty\s*-?\s*seven\b/, '47')
284
+ nsub!(/\bfourty\s*-?\s*seventh\b/, '47th')
285
+ nsub!(/\bfourty\s*-?\s*six\b/, '46')
286
+ nsub!(/\bfourty\s*-?\s*sixth\b/, '46th')
287
+ nsub!(/\bfourty\s*-?\s*five\b/, '45')
288
+ nsub!(/\bfourty\s*-?\s*fifth\b/, '45th')
289
+ nsub!(/\bfourty\s*-?\s*four\b/, '44')
290
+ nsub!(/\bfourty\s*-?\s*fourth\b/, '44th')
291
+ nsub!(/\bfourty\s*-?\s*three\b/, '43')
292
+ nsub!(/\bfourty\s*-?\s*third\b/, '43rd')
293
+ nsub!(/\bfourty\s*-?\s*two\b/, '42')
294
+ nsub!(/\bfourty\s*-?\s*second\b/, '42nd')
295
+ nsub!(/\bfourty\s*-?\s*one\b/, '41')
296
+ nsub!(/\bfourty\s*-?\s*first\b/, '41st')
297
+ nsub!(/\bfourty\b/, '40')
298
+ nsub!(/\bfourtieth\b/, '40th')
299
+ nsub!(/\bthirty\s*-?\s*nine\b/, '39')
300
+ nsub!(/\bthirty\s*-?\s*ninth\b/, '39th')
301
+ nsub!(/\bthirty\s*-?\s*eight\b/, '38')
302
+ nsub!(/\bthirty\s*-?\s*eighth\b/, '38th')
303
+ nsub!(/\bthirty\s*-?\s*seven\b/, '37')
304
+ nsub!(/\bthirty\s*-?\s*seventh\b/, '37th')
305
+ nsub!(/\bthirty\s*-?\s*six\b/, '36')
306
+ nsub!(/\bthirty\s*-?\s*sixth\b/, '36th')
307
+ nsub!(/\bthirty\s*-?\s*five\b/, '35')
308
+ nsub!(/\bthirty\s*-?\s*fifth\b/, '35th')
309
+ nsub!(/\bthirty\s*-?\s*four\b/, '34')
310
+ nsub!(/\bthirty\s*-?\s*fourth\b/, '34th')
311
+ nsub!(/\bthirty\s*-?\s*three\b/, '33')
312
+ nsub!(/\bthirty\s*-?\s*third\b/, '33rd')
313
+ nsub!(/\bthirty\s*-?\s*two\b/, '32')
314
+ nsub!(/\bthirty\s*-?\s*second\b/, '32nd')
315
+ nsub!(/\bthirty\s*-?\s*one\b/, '31')
316
+ nsub!(/\bthirty\s*-?\s*first\b/, '31st')
317
+ nsub!(/\bthirty\b/, '30')
318
+ nsub!(/\bthirtieth\b/, '30th')
319
+ nsub!(/\btwenty\s*-?\s*nine\b/, '29')
320
+ nsub!(/\btwenty\s*-?\s*ninth\b/, '29th')
321
+ nsub!(/\btwenty\s*-?\s*eight\b/, '28')
322
+ nsub!(/\btwenty\s*-?\s*eighth\b/, '28th')
323
+ nsub!(/\btwenty\s*-?\s*seven\b/, '27')
324
+ nsub!(/\btwenty\s*-?\s*seventh\b/, '27th')
325
+ nsub!(/\btwenty\s*-?\s*six\b/, '26')
326
+ nsub!(/\btwenty\s*-?\s*sixth\b/, '26th')
327
+ nsub!(/\btwenty\s*-?\s*five\b/, '25')
328
+ nsub!(/\btwenty\s*-?\s*fifth\b/, '25th')
329
+ nsub!(/\btwenty\s*-?\s*four\b/, '24')
330
+ nsub!(/\btwenty\s*-?\s*fourth\b/, '24th')
331
+ nsub!(/\btwenty\s*-?\s*three\b/, '23')
332
+ nsub!(/\btwenty\s*-?\s*third\b/, '23rd')
333
+ nsub!(/\btwenty\s*-?\s*two\b/, '22')
334
+ nsub!(/\btwenty\s*-?\s*second\b/, '22nd')
335
+ nsub!(/\btwenty\s*-?\s*one\b/, '21')
336
+ nsub!(/\btwenty\s*-?\s*first\b/, '21st')
337
+ nsub!(/\btwenty\b/, '20')
338
+ nsub!(/\btwentieth\b/, '20th')
339
+ nsub!(/\bnineteen\b/, '19')
340
+ nsub!(/\bnineteenth\b/, '19th')
341
+ nsub!(/\beighteen\b/, '18')
342
+ nsub!(/\beighteenth\b/, '18th')
343
+ nsub!(/\bseventeen\b/, '17')
344
+ nsub!(/\bseventeenth\b/, '17th')
345
+ nsub!(/\bsixteen\b/, '16')
346
+ nsub!(/\bsixteenth\b/, '16th')
347
+ nsub!(/\bfifteen\b/, '15')
348
+ nsub!(/\bfifteenth\b/, '15th')
349
+ nsub!(/\bfourteen\b/, '14')
350
+ nsub!(/\bfourteenth\b/, '14th')
351
+ nsub!(/\bthirteen/, '13')
352
+ nsub!(/\bthirteenth/, '13th')
353
+ nsub!(/\btwelve\b/, '12')
354
+ nsub!(/\btwelfth\b/, '12th')
355
+ nsub!(/\beleven\b/, '11')
356
+ nsub!(/\beleventh\b/, '11th')
357
+ nsub!(/\bten\b/, '10')
358
+ nsub!(/\btenth\b/, '10th')
359
+ nsub!(/\bnine\b/, '9')
360
+ nsub!(/\bninth\b/, '9th')
361
+ nsub!(/\beight\b/, '8')
362
+ nsub!(/\beighth\b/, '8th')
363
+ nsub!(/\bseven\b/, '7')
364
+ nsub!(/\bseventh\b/, '7th')
365
+ nsub!(/\bsix\b/, '6')
366
+ nsub!(/\bsixth\b/, '6th')
367
+ nsub!(/\bfive\b/, '5')
368
+ nsub!(/\bfifth\b/, '5th')
369
+ nsub!(/\bfour\b/, '4')
370
+ nsub!(/\bfourth\b/, '4th')
371
+ nsub!(/\bthree\b/, '3')
372
+ nsub!(/\bthird\b/, '3rd')
373
+ nsub!(/\btwo\b/, '2')
374
+ nsub!(/\bsecond\b/, '2nd')
375
+ nsub!(/\bone\b/, '1')
376
+ nsub!(/\bfirst\b/, '1st')
377
+ nsub!(/\bzero\b/, '0')
378
+ nsub!(/\bzeroth\b/, '0th')
380
379
  end
381
380
 
382
381
  def standardize_am_pm
383
- nsub!(/([0-9])(?:\s*)a\b/,'\1am') # allows 5a as 5am
384
- nsub!(/([0-9])(?:\s*)p\b/,'\1pm') # allows 5p as 5pm
385
- nsub!(/\s+am\b/,'am') # removes any spaces before am, shouldn't I check for preceeding digits?
386
- nsub!(/\s+pm\b/,'pm') # removes any spaces before pm, shouldn't I check for preceeding digits?
382
+ nsub!(/([0-9])(?:\s*)a\b/, '\1am') # allows 5a as 5am
383
+ nsub!(/([0-9])(?:\s*)p\b/, '\1pm') # allows 5p as 5pm
384
+ nsub!(/\s+am\b/, 'am') # removes any spaces before am, shouldn't I check for preceeding digits?
385
+ nsub!(/\s+pm\b/, 'pm') # removes any spaces before pm, shouldn't I check for preceeding digits?
387
386
  end
388
387
 
389
388
  def replace_hyphens
390
- nsub!(/--?/,' through ')
389
+ nsub!(/--?/, ' through ')
391
390
  end
392
391
 
393
392
  def insert_repeats_before_words_indicating_recurrence_lame
394
393
  comps = query_str.split
395
- (daily_index = comps.index("daily")) && comps[daily_index - 1] != "repeats" && comps[daily_index] = "repeats daily"
396
- (weekly_index = comps.index("weekly")) && comps[weekly_index - 1] != "repeats" && comps[weekly_index] = "repeats weekly"
397
- (monthly_index = comps.index("monthly")) && comps[monthly_index - 1] != "repeats" && comps[monthly_index] = "repeats monthly"
394
+ (daily_index = comps.index('daily')) && comps[daily_index - 1] != 'repeats' && comps[daily_index] = 'repeats daily'
395
+ (weekly_index = comps.index('weekly')) && comps[weekly_index - 1] != 'repeats' && comps[weekly_index] = 'repeats weekly'
396
+ (monthly_index = comps.index('monthly')) && comps[monthly_index - 1] != 'repeats' && comps[monthly_index] = 'repeats monthly'
398
397
  if (rejoin = comps.join(' ')) != query_str
399
- nsub!(/.+/,rejoin)
398
+ nsub!(/.+/, rejoin)
400
399
  end
401
400
  end
402
401
 
403
402
  def insert_space_at_end_of_string_lame
404
403
  # nsub!(/(.+)/,'\1 ') # I don't really want to be notified about this
405
- query_str.gsub!(/(.+)/,'\1 ')
404
+ query_str.gsub!(/(.+)/, '\1 ')
406
405
  end
407
406
 
408
407
  def to_s
@@ -410,63 +409,64 @@ module Nickel
410
409
  end
411
410
 
412
411
  private
412
+
413
413
  attr_accessor :query_str
414
414
 
415
415
  def standardize_input
416
- nsub!(/last\s+#{DAY_OF_WEEK}/,'5th \1') # last dayname => 5th dayname
416
+ nsub!(/last\s+#{DAY_OF_WEEK}/, '5th \1') # last dayname => 5th dayname
417
417
  nsub!(/\ba\s+(week|month|day)/, '1 \1') # a month|week|day => 1 month|week|day
418
- nsub!(/^(through|until)/,'today through') # ^through => today through
419
- nsub!(/every\s*(night|morning)/,'every day')
420
- nsub!(/tonight/,'today')
421
- nsub!(/this(?:\s*)morning/,'today')
422
- nsub!(/before\s+12pm/,'6am to 12pm') # arbitrary
418
+ nsub!(/^(through|until)/, 'today through') # ^through => today through
419
+ nsub!(/every\s*(night|morning)/, 'every day')
420
+ nsub!(/tonight/, 'today')
421
+ nsub!(/this(?:\s*)morning/, 'today')
422
+ nsub!(/before\s+12pm/, '6am to 12pm') # arbitrary
423
423
 
424
424
  # Handle 'THE' Cases
425
425
  # Attempt to pick out where a user entered 'the' when they really mean 'every'.
426
426
  # For example,
427
427
  # The first of every month and the 22nd of THE month => repeats monthly first xxxxxx repeats monthly 22nd xxxxxxx
428
- nsub!(/(?:the\s+)?#{DATE_DD_WITH_SUFFIX}\s+(?:of\s+)?(?:every|each)\s+month((?:.*)of\s+the\s+month(?:.*))/) do |m1,m2|
429
- ret_str = " repeats monthly " + m1
428
+ nsub!(/(?:the\s+)?#{DATE_DD_WITH_SUFFIX}\s+(?:of\s+)?(?:every|each)\s+month((?:.*)of\s+the\s+month(?:.*))/) do |m1, m2|
429
+ ret_str = ' repeats monthly ' + m1
430
430
  ret_str << m2.gsub(/(?:and\s+)?(?:the\s+)?#{DATE_DD_WITH_SUFFIX}\s+of\s+the\s+month/, ' repeats monthly \1 ')
431
431
  end
432
432
 
433
433
  # Every first sunday of the month and the last tuesday => repeats monthly first sunday xxxxxxxxx repeats monthly last tuesday xxxxxxx
434
- nsub!(/every\s+#{WEEK_OF_MONTH}\s+#{DAY_OF_WEEK}\s+of\s+(?:the\s+)?month((?:.*)and\s+(?:the\s+)?#{WEEK_OF_MONTH}\s+#{DAY_OF_WEEK}(?:.*))/) do |m1,m2,m3|
435
- ret_str = " repeats monthly " + m1 + " " + m2 + " "
434
+ nsub!(/every\s+#{WEEK_OF_MONTH}\s+#{DAY_OF_WEEK}\s+of\s+(?:the\s+)?month((?:.*)and\s+(?:the\s+)?#{WEEK_OF_MONTH}\s+#{DAY_OF_WEEK}(?:.*))/) do |m1, m2, m3|
435
+ ret_str = ' repeats monthly ' + m1 + ' ' + m2 + ' '
436
436
  ret_str << m3.gsub(/and\s+(?:the\s+)?#{WEEK_OF_MONTH}\s+#{DAY_OF_WEEK}(?:\s*)(?:of\s+)?(?:the\s+)?(?:month\s+)?/, ' repeats monthly \1 \2 ')
437
437
  end
438
438
 
439
439
  # The x through the y of oct z => 10/x/z through 10/y/z
440
- nsub!(/(?:the\s+)?#{DATE_DD}\s+(?:through|to|until)\s+(?:the\s+)?#{DATE_DD}\s(?:of\s+)#{MONTH_OF_YEAR}\s+(?:of\s+)?#{YEAR}/) do |m1,m2,m3,m4|
440
+ nsub!(/(?:the\s+)?#{DATE_DD}\s+(?:through|to|until)\s+(?:the\s+)?#{DATE_DD}\s(?:of\s+)#{MONTH_OF_YEAR}\s+(?:of\s+)?#{YEAR}/) do |m1, m2, m3, m4|
441
441
  (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m1 + '/' + m4 + ' through ' + (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m2 + '/' + m4
442
442
  end
443
443
 
444
444
  # The x through the y of oct => 10/x through 10/y
445
- nsub!(/(?:the\s+)?#{DATE_DD}\s+(?:through|to|until)\s+(?:the\s+)#{DATE_DD}\s(?:of\s+)?#{MONTH_OF_YEAR}/) do |m1,m2,m3|
445
+ nsub!(/(?:the\s+)?#{DATE_DD}\s+(?:through|to|until)\s+(?:the\s+)#{DATE_DD}\s(?:of\s+)?#{MONTH_OF_YEAR}/) do |m1, m2, m3|
446
446
  (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m1 + ' through ' + (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m2
447
447
  end
448
448
 
449
449
  # January 1 - February 15
450
- nsub!(/#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:through|to|until)\s+#{MONTH_OF_YEAR}\s#{DATE_DD_NB_ON_SUFFIX}/) do |m1,m2,m3,m4|
451
- (ZDate.months_of_year.index(m1) + 1).to_s + '/' + m2.gsub(/(st|nd|rd|th)/, "") + ' through ' + (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m4.gsub(/(st|nd|rd|th)/, "")
450
+ nsub!(/#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:through|to|until)\s+#{MONTH_OF_YEAR}\s#{DATE_DD_NB_ON_SUFFIX}/) do |m1, m2, m3, m4|
451
+ (ZDate.months_of_year.index(m1) + 1).to_s + '/' + m2.gsub(/(st|nd|rd|th)/, '') + ' through ' + (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m4.gsub(/(st|nd|rd|th)/, '')
452
452
  end
453
453
 
454
- #Tuesday, january 1 - friday, february 15, 2013
455
- nsub!(/(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}\s+(?:through|to|until)\s+(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}(?:[\s,]+)#{YEAR}/) do |m1,m2,m3,m4,m5,m6,m7|
454
+ # Tuesday, january 1 - friday, february 15, 2013
455
+ nsub!(/(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}\s+(?:through|to|until)\s+(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}(?:[\s,]+)#{YEAR}/) do |m1, m2, m3, m4, m5, m6, m7|
456
456
  if m7.nil?
457
- (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3.gsub(/(st|nd|rd|th)/, "") + ' through ' + (ZDate.months_of_year.index(m5) + 1).to_s + '/' + m6
457
+ (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3.gsub(/(st|nd|rd|th)/, '') + ' through ' + (ZDate.months_of_year.index(m5) + 1).to_s + '/' + m6
458
458
  else
459
- (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3.gsub(/(st|nd|rd|th)/, "") + '/' + m7 + ' through ' + (ZDate.months_of_year.index(m5) + 1).to_s + '/' + m6.gsub(/(st|nd|rd|th)/, "") + "/" + m7
459
+ (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3.gsub(/(st|nd|rd|th)/, '') + '/' + m7 + ' through ' + (ZDate.months_of_year.index(m5) + 1).to_s + '/' + m6.gsub(/(st|nd|rd|th)/, '') + '/' + m7
460
460
  end
461
461
  end
462
462
 
463
- #Tuesday, january 1 2013 - friday, february 15, 2013
464
- nsub!(/(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}\s+#{YEAR}\s+(?:through|to|until)\s+(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}(?:[\s,]+)#{YEAR}/) do |m1,m2,m3,m4,m5,m6,m7,m8|
465
- (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3 + '/' + m4 + ' through ' + (ZDate.months_of_year.index(m6) + 1).to_s + '/' + m7 + "/" + m8
463
+ # Tuesday, january 1 2013 - friday, february 15, 2013
464
+ nsub!(/(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}\s+#{YEAR}\s+(?:through|to|until)\s+(?:#{DAY_OF_WEEK})?(?:[\s,]+)#{MONTH_OF_YEAR}(?:[\s,]+)#{DATE_DD}(?:[\s,]+)#{YEAR}/) do |m1, m2, m3, m4, m5, m6, m7, m8|
465
+ (ZDate.months_of_year.index(m2) + 1).to_s + '/' + m3 + '/' + m4 + ' through ' + (ZDate.months_of_year.index(m6) + 1).to_s + '/' + m7 + '/' + m8
466
466
  end
467
467
 
468
468
  # Monthname x through y
469
- nsub!(/#{MONTH_OF_YEAR}\s+(?:the\s+)?#{DATE_DD_NB_ON_SUFFIX}\s+(?:of\s+)?(?:#{YEAR}\s+)?(?:through|to|until)\s+(?:the\s+)?#{DATE_DD_NB_ON_SUFFIX}(?:\s+of)?(?:\s+#{YEAR})?/) do |m1,m2,m3,m4,m5|
469
+ nsub!(/#{MONTH_OF_YEAR}\s+(?:the\s+)?#{DATE_DD_NB_ON_SUFFIX}\s+(?:of\s+)?(?:#{YEAR}\s+)?(?:through|to|until)\s+(?:the\s+)?#{DATE_DD_NB_ON_SUFFIX}(?:\s+of)?(?:\s+#{YEAR})?/) do |m1, m2, m3, m4, m5|
470
470
  if m3 # $3 holds first occurrence of year
471
471
  (ZDate.months_of_year.index(m1) + 1).to_s + '/' + m2 + '/' + m3 + ' through ' + (ZDate.months_of_year.index(m1) + 1).to_s + '/' + m4 + '/' + m3
472
472
  elsif m5 # $5 holds second occurrence of year
@@ -479,7 +479,7 @@ module Nickel
479
479
  # Monthname x through monthname y
480
480
  # Jan 14 through jan 18 => 1/14 through 1/18
481
481
  # Oct 2 until oct 5
482
- nsub!(/#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:to|through|until)\s+#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:of\s+)?(?:#{YEAR})?/) do |m1,m2,m3,m4,m5|
482
+ nsub!(/#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:to|through|until)\s+#{MONTH_OF_YEAR}\s+#{DATE_DD_NB_ON_SUFFIX}\s+(?:of\s+)?(?:#{YEAR})?/) do |m1, m2, m3, m4, m5|
483
483
  if m5
484
484
  (ZDate.months_of_year.index(m1) + 1).to_s + '/' + m2 + '/' + m5 + ' through ' + (ZDate.months_of_year.index(m3) + 1).to_s + '/' + m4 + '/' + m5 + ' '
485
485
  else
@@ -488,12 +488,12 @@ module Nickel
488
488
  end
489
489
 
490
490
  # Mnday the 23rd, tuesday the 24th and wed the 25th of oct => 11/23 11/24 11/25
491
- nsub!(/((?:#{DAY_OF_WEEK_NB}\s+the\s+#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?){1,31})of\s+#{MONTH_OF_YEAR}\s*(#{YEAR})?/) do |m1,m2,m3|
491
+ nsub!(/((?:#{DAY_OF_WEEK_NB}\s+the\s+#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?){1,31})of\s+#{MONTH_OF_YEAR}\s*(#{YEAR})?/) do |m1, m2, m3|
492
492
  month_str = (ZDate.months_of_year.index(m2) + 1).to_s
493
493
  if m3
494
- m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
494
+ m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
495
495
  else
496
- m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1')
496
+ m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1')
497
497
  end
498
498
  end
499
499
 
@@ -501,12 +501,12 @@ module Nickel
501
501
  # the 23rd, 24th, and 25th of october => 11/23 11/24 11/25
502
502
  # the 23rd, 24th, and 25th of october 2010 => 11/23/2010 11/24/2010 11/25/2010
503
503
  # monday and tuesday, the 23rd and 24th of july => 7/23 7/24
504
- nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:day\s+)?(?:in\s+)?(?:of\s+)#{MONTH_OF_YEAR}\s*(#{YEAR})?/) do |m1,m2,m3|
504
+ nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:day\s+)?(?:in\s+)?(?:of\s+)#{MONTH_OF_YEAR}\s*(#{YEAR})?/) do |m1, m2, m3|
505
505
  month_str = (ZDate.months_of_year.index(m2) + 1).to_s
506
506
  if m3
507
- m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
507
+ m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
508
508
  else
509
- m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1')
509
+ m1.gsub(/\b(and|the)\b|#{DAY_OF_WEEK}/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1')
510
510
  end
511
511
  end
512
512
 
@@ -515,21 +515,21 @@ module Nickel
515
515
  # Dec 2nd, 3rd, and 5th 2008 => 12/2/2008 12/2/2008 12/5/2008
516
516
  # Mon nov 23rd 08
517
517
  # Dec 2, 3, 5, 2008 => 12/2/2008 12/3/2008 12/5/2008
518
- nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+((?:(?:the\s+)?#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?){1,31})#{YEAR}/) do |m1,m2,m3|
518
+ nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+((?:(?:the\s+)?#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?){1,31})#{YEAR}/) do |m1, m2, m3|
519
519
  month_str = (ZDate.months_of_year.index(m1) + 1).to_s
520
- m2.gsub(/\b(and|the)\b/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
520
+ m2.gsub(/\b(and|the)\b/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/, month_str + '/\1/' + m3)
521
521
  end
522
522
 
523
- nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+((?:(?:the\s+)?#{DATE_DD_WITHOUT_SUFFIX_NB}\s+(?:and\s+)?){1,31})#{YEAR}/) do |m1,m2,m3|
523
+ nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+((?:(?:the\s+)?#{DATE_DD_WITHOUT_SUFFIX_NB}\s+(?:and\s+)?){1,31})#{YEAR}/) do |m1, m2, m3|
524
524
  month_str = (ZDate.months_of_year.index(m1) + 1).to_s
525
- m2.gsub(/\b(and|the)\b/,'').gsub(/#{DATE_DD_WITHOUT_SUFFIX}/, month_str + '/\1/' + m3)
525
+ m2.gsub(/\b(and|the)\b/, '').gsub(/#{DATE_DD_WITHOUT_SUFFIX}/, month_str + '/\1/' + m3)
526
526
  end
527
527
 
528
528
  # Dec 2nd, 3rd, and 4th => 12/2, 12/3, 12/4
529
529
  # Note: dec 5 9 to 5 will give an error, need to find these and convert to dec 5 from 9 to 5; also dec 3,4, 9 to|through 5 --> dec 3, 4 from 9 through 5
530
- nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) do |m1,m2|
530
+ nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) do |m1, m2|
531
531
  month_str = (ZDate.months_of_year.index(m1) + 1).to_s
532
- m2.gsub(/(and|the)/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/) {month_str + '/' + $1} # that $1 is from the nested match!
532
+ m2.gsub(/(and|the)/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/) { month_str + '/' + Regexp.last_match(1) } # last match is from the nested match!
533
533
  end
534
534
 
535
535
  # Apr 29, 5 - 8pm
@@ -544,13 +544,13 @@ module Nickel
544
544
  # "dec 2, 3, and 4" --> 12/2, 12/3, 12/4
545
545
  # "mon, tue, wed, dec 2, 3, and 4" --> 12/2, 12/3, 12/4
546
546
  nsub!(/(#{MONTH_OF_YEAR_NB}\s+(?:the\s+)?(?:(?:#{DATE_DD_WITHOUT_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:to|through|until)\s+#{DATE_DD_WITHOUT_SUFFIX_NB})/) { |m1| m1.gsub(/#{DATE_DD_WITHOUT_SUFFIX}\s+(to|through|until)/, 'from \1 through ') }
547
- nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+(?:the\s+)?((?:#{DATE_DD_WITHOUT_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) do |m1,m2|
547
+ nsub!(/(?:(?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})?#{MONTH_OF_YEAR}\s+(?:the\s+)?((?:#{DATE_DD_WITHOUT_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) do |m1, m2|
548
548
  month_str = (ZDate.months_of_year.index(m1) + 1).to_s
549
- m2.gsub(/(and|the)/,'').gsub(/#{DATE_DD_NB_ON_SUFFIX}/) {month_str + '/' + $1} # $1 from nested match
549
+ m2.gsub(/(and|the)/, '').gsub(/#{DATE_DD_NB_ON_SUFFIX}/) { month_str + '/' + Regexp.last_match(1) } # last match is from nested match
550
550
  end
551
551
 
552
552
  # "monday 12/6" --> 12/6
553
- nsub!(/#{DAY_OF_WEEK_NB}\s+(#{DATE_MM_SLASH_DD})/,'\1')
553
+ nsub!(/#{DAY_OF_WEEK_NB}\s+(#{DATE_MM_SLASH_DD})/, '\1')
554
554
 
555
555
  # "next friday to|until|through the following tuesday" --> 10/12 through 10/16
556
556
  # "next friday through sunday" --> 10/12 through 10/14
@@ -558,9 +558,9 @@ module Nickel
558
558
  # we are not going to do date calculations here anymore, so instead:
559
559
  # next friday to|until|through the following tuesday" --> next friday through tuesday
560
560
  # next friday and the following sunday --> next friday and sunday
561
- nsub!(/next\s+#{DAY_OF_WEEK}\s+(to|until|through|and)\s+(?:the\s+)?(?:following|next)?(?:\s*)#{DAY_OF_WEEK}/) do |m1,m2,m3|
561
+ nsub!(/next\s+#{DAY_OF_WEEK}\s+(to|until|through|and)\s+(?:the\s+)?(?:following|next)?(?:\s*)#{DAY_OF_WEEK}/) do |m1, m2, m3|
562
562
  connector = (m2 =~ /and/ ? ' ' : ' through ')
563
- "next " + m1 + connector + m3
563
+ 'next ' + m1 + connector + m3
564
564
  end
565
565
 
566
566
  # "this friday to|until|through the following tuesday" --> 10/5 through 10/9
@@ -569,63 +569,63 @@ module Nickel
569
569
  # No longer performing date calculation
570
570
  # this friday and the following monday --> fri mon
571
571
  # this friday through the following tuesday --> fri through tues
572
- nsub!(/(?:this\s+)?#{DAY_OF_WEEK}\s+(to|until|through|and)\s+(?:the\s+)?(?:this|following)(?:\s*)#{DAY_OF_WEEK}/) do |m1,m2,m3|
572
+ nsub!(/(?:this\s+)?#{DAY_OF_WEEK}\s+(to|until|through|and)\s+(?:the\s+)?(?:this|following)(?:\s*)#{DAY_OF_WEEK}/) do |m1, m2, m3|
573
573
  connector = (m2 =~ /and/ ? ' ' : ' through ')
574
574
  m1 + connector + m3
575
575
  end
576
576
 
577
577
  # "the wed after next" --> 2 wed from today
578
- nsub!(/(?:the\s+)?#{DAY_OF_WEEK}\s+(?:after|following)\s+(?:the\s+)?next/,'2 \1 from today')
578
+ nsub!(/(?:the\s+)?#{DAY_OF_WEEK}\s+(?:after|following)\s+(?:the\s+)?next/, '2 \1 from today')
579
579
 
580
580
  # "mon and tue" --> mon tue
581
- nsub!(/(#{DAY_OF_WEEK}\s+and\s+#{DAY_OF_WEEK})(?:\s+and)?/,'\2 \3')
581
+ nsub!(/(#{DAY_OF_WEEK}\s+and\s+#{DAY_OF_WEEK})(?:\s+and)?/, '\2 \3')
582
582
 
583
583
  # "mon wed every week" --> every mon wed
584
- nsub!(/((#{DAY_OF_WEEK}(?:\s*)){1,7})(?:of\s+)?(?:every|each)(\s+other)?\s+week/,'every \4 \1')
584
+ nsub!(/((#{DAY_OF_WEEK}(?:\s*)){1,7})(?:of\s+)?(?:every|each)(\s+other)?\s+week/, 'every \4 \1')
585
585
 
586
586
  # "every 2|3 weeks" --> every 2nd|3rd week
587
- nsub!(/(?:repeats\s+)?every\s+(2|3)\s+weeks/) {|m1| "every " + m1.to_i.ordinalize + " week"}
587
+ nsub!(/(?:repeats\s+)?every\s+(2|3)\s+weeks/) { |m1| 'every ' + m1.to_i.ordinalize + ' week' }
588
588
 
589
589
  # "every week on mon tue fri" --> every mon tue fri
590
- nsub!(/(?:repeats\s+)?every\s+(?:(other|3rd|2nd)\s+)?weeks?\s+(?:\bon\s+)?((?:#{DAY_OF_WEEK_NB}\s+){1,7})/,'every \1 \2')
590
+ nsub!(/(?:repeats\s+)?every\s+(?:(other|3rd|2nd)\s+)?weeks?\s+(?:\bon\s+)?((?:#{DAY_OF_WEEK_NB}\s+){1,7})/, 'every \1 \2')
591
591
 
592
592
  # "every mon and every tue and.... " --> every mon tue ...
593
- nsub!(/every\s+#{DAY_OF_WEEK}\s+(?:and\s+)?every\s+#{DAY_OF_WEEK}(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?/,'every \1 \2 \3 \4 \5')
593
+ nsub!(/every\s+#{DAY_OF_WEEK}\s+(?:and\s+)?every\s+#{DAY_OF_WEEK}(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?(?:\s+(?:and\s+)?every\s+#{DAY_OF_WEEK})?/, 'every \1 \2 \3 \4 \5')
594
594
 
595
595
  # monday, wednesday, and friday next week at 8
596
596
  nsub!(/((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){1,7})(?:of\s+)?(this|next)\s+week/, '\2 \1')
597
597
 
598
598
  # "every day this|next week" --> returns monday through friday of the closest week, kinda stupid
599
599
  # doesn't do that anymore, no date calculations allowed here, instead just formats it nicely for construct finders --> every day this|next week
600
- nsub!(/every\s+day\s+(?:of\s+)?(this|the|next)\s+week\b./) {|m1| m1 == 'next' ? "every day next week" : "every day this week"}
600
+ nsub!(/every\s+day\s+(?:of\s+)?(this|the|next)\s+week\b./) { |m1| m1 == 'next' ? 'every day next week' : 'every day this week' }
601
601
 
602
602
  # "every day for the next week" --> "every day this week"
603
603
  nsub!(/every\s+day\s+for\s+(the\s+)?(next|this)\s+week/, 'every day this week')
604
604
 
605
605
  # "this weekend" --> sat sun
606
- nsub!(/(every\s+day\s+|both\s+days\s+)?this\s+weekend(\s+on)?(\s+both\s+days|\s+every\s+day|\s+sat\s+sun)?/,'sat sun')
606
+ nsub!(/(every\s+day\s+|both\s+days\s+)?this\s+weekend(\s+on)?(\s+both\s+days|\s+every\s+day|\s+sat\s+sun)?/, 'sat sun')
607
607
 
608
608
  # "this weekend including mon" --> sat sun mon
609
- nsub!(/sat\s+sun\s+(and|includ(es?|ing))\s+mon/,'sat sun mon')
610
- nsub!(/sat\s+sun\s+(and|includ(es?|ing))\s+fri/,'fri sat sun')
609
+ nsub!(/sat\s+sun\s+(and|includ(es?|ing))\s+mon/, 'sat sun mon')
610
+ nsub!(/sat\s+sun\s+(and|includ(es?|ing))\s+fri/, 'fri sat sun')
611
611
 
612
612
  # Note: next weekend including monday will now fail. Need to make constructors find "next sat sun mon"
613
613
  # "next weekend" --> next weekend
614
- nsub!(/(every\s+day\s+|both\s+days\s+)?next\s+weekend(\s+on)?(\s+both\s+days|\s+every\s+day|\s+sat\s+sun)?/,'next weekend')
614
+ nsub!(/(every\s+day\s+|both\s+days\s+)?next\s+weekend(\s+on)?(\s+both\s+days|\s+every\s+day|\s+sat\s+sun)?/, 'next weekend')
615
615
 
616
616
  # "next weekend including mon" --> next sat sun mon
617
- nsub!(/next\s+weekend\s+(and|includ(es?|ing))\s+mon/,'next sat sun mon')
618
- nsub!(/next\s+weekend\s+(and|includ(es?|ing))\s+fri/,'next fri sat sun')
617
+ nsub!(/next\s+weekend\s+(and|includ(es?|ing))\s+mon/, 'next sat sun mon')
618
+ nsub!(/next\s+weekend\s+(and|includ(es?|ing))\s+fri/, 'next fri sat sun')
619
619
 
620
620
  # "every weekend" --> every sat sun
621
- nsub!(/every\s+weekend(?:\s+(?:and|includ(?:es?|ing))\s+(mon|fri))?/,'every sat sun' + ' \1') # regarding "every sat sun fri", order should not matter after "every" keyword
621
+ nsub!(/every\s+weekend(?:\s+(?:and|includ(?:es?|ing))\s+(mon|fri))?/, 'every sat sun' + ' \1') # regarding "every sat sun fri", order should not matter after "every" keyword
622
622
 
623
623
  # "weekend" --> sat sun !!! catch all
624
- nsub!(/weekend/,'sat sun')
624
+ nsub!(/weekend/, 'sat sun')
625
625
 
626
626
  # "mon through wed" -- > mon tue wed
627
627
  # CATCH ALL FOR SPANS, TRY NOT TO USE THIS
628
- nsub!(/#{DAY_OF_WEEK}\s+(?:through|to|until)\s+#{DAY_OF_WEEK}/) do |m1,m2|
628
+ nsub!(/#{DAY_OF_WEEK}\s+(?:through|to|until)\s+#{DAY_OF_WEEK}/) do |m1, m2|
629
629
  index1 = ZDate.days_of_week.index(m1)
630
630
  index2 = ZDate.days_of_week.index(m2)
631
631
  i = index1
@@ -636,10 +636,11 @@ module Nickel
636
636
  i += 1
637
637
  end
638
638
  elsif index2 < index1
639
- begin
639
+ loop do
640
640
  ret_string << ZDate.days_of_week[i] + ' '
641
641
  i = (i + 1) % 7
642
- end while i != index2 + 1 # wrap until it hits index2
642
+ break if i != index2 + 1 # wrap until it hits index2
643
+ end
643
644
  else
644
645
  # indices are the same, one week event
645
646
  8.times do
@@ -651,132 +652,132 @@ module Nickel
651
652
  end
652
653
 
653
654
  # "every day" --> repeats daily
654
- nsub!(/\b(repeat(?:s|ing)?|every|each)\s+da(ily|y)\b/,'repeats daily')
655
+ nsub!(/\b(repeat(?:s|ing)?|every|each)\s+da(ily|y)\b/, 'repeats daily')
655
656
 
656
657
  # "every other week starting this|next fri" --> every other friday starting this friday
657
- nsub!(/every\s+(3rd|other)\s+week\s+(?:start(?:s|ing)?|begin(?:s|ning)?)\s+(this|next)\s+#{DAY_OF_WEEK}/,'every \1 \3 start \2 \3')
658
+ nsub!(/every\s+(3rd|other)\s+week\s+(?:start(?:s|ing)?|begin(?:s|ning)?)\s+(this|next)\s+#{DAY_OF_WEEK}/, 'every \1 \3 start \2 \3')
658
659
 
659
660
  # "every other|3rd friday starting this|next week" --> every other|3rd friday starting this|next friday
660
- nsub!(/every\s+(3rd|other)\s+#{DAY_OF_WEEK}\s+(?:start(?:s|ing)?|begin(?:s|ning)?)\s+(this|next)\s+week/,'every \1 \2 start \3 \2')
661
+ nsub!(/every\s+(3rd|other)\s+#{DAY_OF_WEEK}\s+(?:start(?:s|ing)?|begin(?:s|ning)?)\s+(this|next)\s+week/, 'every \1 \2 start \3 \2')
661
662
 
662
663
  # "repeats monthly on the 1st and 2nd friday" --> repeats monthly 1st friday 2nd friday
663
664
  # "repeats every other month on the 1st and 2nd friday" --> repeats monthly 1st friday 2nd friday
664
665
  # "repeats every three months on the 1st and 2nd friday" --> repeats threemonthly 1st friday 2nd friday
665
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
666
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
667
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
668
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
669
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
670
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1,m2| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
666
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
667
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
668
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
669
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
670
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
671
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+months?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}/) { |m1, m2| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
671
672
 
672
673
  # "repeats monthly on the 1st friday" --> repeats monthly 1st friday
673
674
  # "repeats monthly on the 1st friday, second tuesday, and third friday" --> repeats monthly 1st friday 2nd tuesday 3rd friday
674
675
  # "repeats every other month on the 1st friday, second tuesday, and third friday" --> repeats monthly 1st friday 2nd tuesday 3rd friday
675
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
676
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
677
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
678
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
679
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
680
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
676
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
677
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
678
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
679
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
680
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
681
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
681
682
 
682
683
  # "repeats monthly on the 1st friday saturday" --> repeats monthly 1st friday 1st saturday
683
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats monthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
684
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats altmonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
685
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats threemonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
686
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats monthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
687
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats altmonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
688
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1,m2| "repeats threemonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
684
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats monthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
685
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats altmonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
686
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats threemonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
687
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats monthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
688
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats altmonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
689
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:ly|s)?\s+(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})/) { |m1, m2| 'repeats threemonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
689
690
 
690
691
  # "21st of each month" --> repeats monthly 21st
691
692
  # "on the 21st, 22nd and 25th of each month" --> repeats monthly 21st 22nd 25th
692
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+\bmonths?/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
693
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+(?:other|2n?d?)\s+months?/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
694
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+3r?d?\s+months?/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
693
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+\bmonths?/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
694
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+(?:other|2n?d?)\s+months?/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
695
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,31})(?:days?\s+)?(?:of\s+)?(?:each|all|every)\s+3r?d?\s+months?/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
695
696
 
696
697
  # "repeats each month on the 22nd" --> repeats monthly 22nd
697
698
  # "repeats monthly on the 22nd 23rd and 24th" --> repeats monthly 22nd 23rd 24th
698
699
  # This can ONLY handle multi-day recurrence WITHOUT independent times for each, i.e. "repeats monthly on the 22nd at noon and 24th from 1 to 9" won't work; that's going to be a tricky one.
699
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
700
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
701
- #nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?\bmonth(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
702
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?\bmonthly\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
703
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
704
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
705
- #nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
706
- nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
707
- nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
708
- #nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?3r?d?\s+month(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
700
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)\bmonth(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
701
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?\bmonth(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
702
+ # nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?\bmonth(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
703
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?\bmonthly\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
704
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)(?:other|2n?d?)\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
705
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
706
+ # nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?(?:other|2n?d?)\s+month(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
707
+ nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)3r?d?\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
708
+ nsub!(/(?:repeats\s+)(?:(?:each|every|all)\s+)?3r?d?\s+month(?:s|ly)?\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
709
+ # nsub!(/(?:repeats\s+)?(?:(?:each|every|all)\s+)?3r?d?\s+month(?:s|ly)\s+(?:on\s+)?(?:the\s+)?((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
709
710
 
710
711
  # "on day 4 of every month" --> repeats monthly 4
711
712
  # "on days 4 9 and 14 of every month" --> repeats monthly 4 9 14
712
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+\bmonths?/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
713
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+(?:other|2n?d?)\s+months?/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
714
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+3r?d?\s+months?/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " " }
713
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+\bmonths?/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
714
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+(?:other|2n?d?)\s+months?/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
715
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:day|date)s?\s+((?:#{DATE_DD_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)(every|all|each)\s+3r?d?\s+months?/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
715
716
 
716
717
  # "every 22nd of the month" --> repeats monthly 22
717
718
  # "every 22nd 23rd and 25th of the month" --> repeats monthly 22 23 25
718
- nsub!(/(?:repeats\s+)?(?:every|each)\s+((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:day\s+)?(?:of\s+)?(?:the\s+)?\bmonth/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
719
- nsub!(/(?:repeats\s+)?(?:every|each)\s+other\s+((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:day\s+)?(?:of\s+)?(?:the\s+)?\bmonth/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
719
+ nsub!(/(?:repeats\s+)?(?:every|each)\s+((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:day\s+)?(?:of\s+)?(?:the\s+)?\bmonth/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
720
+ nsub!(/(?:repeats\s+)?(?:every|each)\s+other\s+((?:#{DATE_DD_WITH_SUFFIX_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:day\s+)?(?:of\s+)?(?:the\s+)?\bmonth/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
720
721
 
721
722
  # "every 1st and 2nd fri of the month" --> repeats monthly 1st fri 2nd fri
722
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
723
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1,m2| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
723
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
724
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1, m2| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
724
725
 
725
726
  # "every 1st friday of the month" --> repeats monthly 1st friday
726
727
  # "every 1st friday and 2nd tuesday of the month" --> repeats monthly 1st friday 2nd tuesday
727
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
728
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
728
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
729
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
729
730
 
730
731
  # "every 1st fri sat of the month" --> repeats monthly 1st fri 1st sat
731
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1,m2| "repeats monthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
732
- nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1,m2| "repeats altmonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
732
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1, m2| 'repeats monthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
733
+ nsub!(/(?:repeats\s+)?(?:each|every|all)\s+other\s+(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:the\s+)?(?:(?:each|every|all)\s+)?\bmonths?/) { |m1, m2| 'repeats altmonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
733
734
 
734
735
  # "the 1st and 2nd friday of every month" --> repeats monthly 1st friday 2nd friday
735
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
736
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1,m2| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
737
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1,m2| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
736
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
737
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1, m2| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
738
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1, m2| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
738
739
 
739
740
  # "the 1st friday of every month" --> repeats monthly 1st friday
740
741
  # "the 1st friday and the 2nd tuesday of every month" --> repeats monthly 1st friday 2nd tuesday
741
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
742
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
743
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
742
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
743
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
744
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
744
745
 
745
746
  # "the 1st friday saturday of every month" --> repeats monthly 1st friday 1st saturday
746
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1,m2| "repeats monthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
747
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1,m2| "repeats altmonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
748
- nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1,m2| "repeats threemonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
747
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)\bmonths?/) { |m1, m2| 'repeats monthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
748
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)(?:other|2n?d?)\s+months?/) { |m1, m2| 'repeats altmonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
749
+ nsub!(/(?:repeats\s+)?(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all)\s+)3r?d?\s+months?/) { |m1, m2| 'repeats threemonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
749
750
 
750
751
  # "repeats on the 1st and second friday of the month" --> repeats monthly 1st friday 2nd friday
751
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
752
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1,m2| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
753
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1,m2| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'').split.join(" " + m2 + " ") + " " + m2 + " " }
752
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
753
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1, m2| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
754
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,5})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1, m2| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '').split.join(' ' + m2 + ' ') + ' ' + m2 + ' ' }
754
755
 
755
756
  # "repeats on the 1st friday of the month --> repeats monthly 1st friday
756
757
  # "repeats on the 1st friday and second tuesday of the month" --> repeats monthly 1st friday 2nd tuesday
757
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
758
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1| "repeats altmonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
759
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1| "repeats threemonthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
758
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
759
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1| 'repeats altmonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
760
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1| 'repeats threemonthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
760
761
 
761
762
  # "repeats on the 1st friday saturday of the month" --> repeats monthly 1st friday 1st saturday
762
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1,m2| "repeats monthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
763
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1,m2| "repeats altmonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
764
- nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1,m2| "repeats threemonthly " + m1 + " " + m2.split.join(" " + m1 + " ") + " "}
763
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?\bmonths?/) { |m1, m2| 'repeats monthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
764
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?(?:other|2n?d?)\s+months?/) { |m1, m2| 'repeats altmonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
765
+ nsub!(/(?:repeats\s+)(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+){2,7})(?:of\s+)?(?:(?:every|each|all|the)\s+)?3r?d?\s+months?/) { |m1, m2| 'repeats threemonthly ' + m1 + ' ' + m2.split.join(' ' + m1 + ' ') + ' ' }
765
766
 
766
767
  # "repeats each month" --> every month
767
- nsub!(/(repeats\s+)?(each|every)\s+\bmonth(ly)?/,'every month ')
768
- nsub!(/all\s+months/,'every month')
768
+ nsub!(/(repeats\s+)?(each|every)\s+\bmonth(ly)?/, 'every month ')
769
+ nsub!(/all\s+months/, 'every month')
769
770
 
770
771
  # "repeats every other month" --> every other month
771
- nsub!(/(repeats\s+)?(each|every)\s+(other|2n?d?)\s+month(ly)?/,'every other month ')
772
- nsub!(/(repeats\s+)?bimonthly/,'every other month ') # hyphens have already been replaced in spell check (bi-monthly)
772
+ nsub!(/(repeats\s+)?(each|every)\s+(other|2n?d?)\s+month(ly)?/, 'every other month ')
773
+ nsub!(/(repeats\s+)?bimonthly/, 'every other month ') # hyphens have already been replaced in spell check (bi-monthly)
773
774
 
774
775
  # "repeats every three months" --> every third month
775
- nsub!(/(repeats\s+)?(each|every)\s+3r?d?\s+month/,'every third month ')
776
- nsub!(/(repeats\s+)?trimonthly/,'every third month ')
776
+ nsub!(/(repeats\s+)?(each|every)\s+3r?d?\s+month/, 'every third month ')
777
+ nsub!(/(repeats\s+)?trimonthly/, 'every third month ')
777
778
 
778
779
  # All months
779
- nsub!(/(repeats\s+)?all\s+months/,'every month ')
780
+ nsub!(/(repeats\s+)?all\s+months/, 'every month ')
780
781
  nsub!(/(repeats\s+)?all\s+other\+months/, 'every other month ')
781
782
 
782
783
  # All month
@@ -785,16 +786,16 @@ module Nickel
785
786
 
786
787
  # "repeats 2nd mon" --> repeats monthly 2nd mon
787
788
  # "repeats 2nd mon, 3rd fri, and the last sunday" --> repeats monthly 2nd mon 3rd fri 5th sun
788
- nsub!(/repeats\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') + " "}
789
+ nsub!(/repeats\s+(?:\bon\s+)?(?:the\s+)?((?:(?:1|2|3|4|5)(?:st|nd|rd|th)?\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') + ' ' }
789
790
 
790
791
  # "starting at x, ending at y" --> from x to y
791
- nsub!(/(?:begin|start)(?:s|ing|ning)?\s+(?:at\s+)?#{TIME}\s+(?:and\s+)?end(?:s|ing)?\s+(?:at\s+)#{TIME}/,'from \1 to \2')
792
+ nsub!(/(?:begin|start)(?:s|ing|ning)?\s+(?:at\s+)?#{TIME}\s+(?:and\s+)?end(?:s|ing)?\s+(?:at\s+)#{TIME}/, 'from \1 to \2')
792
793
 
793
794
  # "the x through the y"
794
- nsub!(/^(?:the\s+)?#{DATE_DD_WITH_SUFFIX}\s+(?:through|to|until)\s+(?:the\s+)?#{DATE_DD_WITH_SUFFIX}$/,'\1 through \2 ')
795
+ nsub!(/^(?:the\s+)?#{DATE_DD_WITH_SUFFIX}\s+(?:through|to|until)\s+(?:the\s+)?#{DATE_DD_WITH_SUFFIX}$/, '\1 through \2 ')
795
796
 
796
797
  # "x week(s) away" --> x week(s) from now
797
- nsub!(/([0-9]+)\s+(day|week|month)s?\s+away/,'\1 \2s from now')
798
+ nsub!(/([0-9]+)\s+(day|week|month)s?\s+away/, '\1 \2s from now')
798
799
 
799
800
  # "x days from now" --> "x days from now"
800
801
  # "in 2 weeks|days|months" --> 2 days|weeks|months from now"
@@ -813,22 +814,22 @@ module Nickel
813
814
  nsub!(/^(?:\s*)(?:right\s+)?now(?:\s*)$/, '0 minutes from now')
814
815
 
815
816
  # "a week/month from yesterday|tomorrow" --> 1 week from yesterday|tomorrow
816
- nsub!(/(?:(?:a|1)\s+)?(week|month)\s+from\s+(yesterday|tomorrow)/,'1 \1 from \2')
817
+ nsub!(/(?:(?:a|1)\s+)?(week|month)\s+from\s+(yesterday|tomorrow)/, '1 \1 from \2')
817
818
 
818
819
  # "a week/month from yesterday|tomorrow" --> 1 week from monday
819
- nsub!(/(?:(?:a|1)\s+)?(week|month)\s+from\s+#{DAY_OF_WEEK}/,'1 \1 from \2')
820
+ nsub!(/(?:(?:a|1)\s+)?(week|month)\s+from\s+#{DAY_OF_WEEK}/, '1 \1 from \2')
820
821
 
821
822
  # "every 2|3 days" --> every 2nd|3rd day
822
- nsub!(/every\s+(2|3)\s+days?/) {|m1| "every " + m1.to_i.ordinalize + " day"}
823
+ nsub!(/every\s+(2|3)\s+days?/) { |m1| 'every ' + m1.to_i.ordinalize + ' day' }
823
824
 
824
825
  # "the following" --> following
825
- nsub!(/the\s+following/,'following')
826
+ nsub!(/the\s+following/, 'following')
826
827
 
827
828
  # "friday the 12th to sunday the 14th" --> 12th through 14th
828
- nsub!(/#{DAY_OF_WEEK}\s+the\s+#{DATE_DD_WITH_SUFFIX}\s+(?:to|through|until)\s+#{DAY_OF_WEEK}\s+the\s+#{DATE_DD_WITH_SUFFIX}/,'\2 through \4')
829
+ nsub!(/#{DAY_OF_WEEK}\s+the\s+#{DATE_DD_WITH_SUFFIX}\s+(?:to|through|until)\s+#{DAY_OF_WEEK}\s+the\s+#{DATE_DD_WITH_SUFFIX}/, '\2 through \4')
829
830
 
830
831
  # "between 1 and 4" --> from 1 to 4
831
- nsub!(/between\s+#{TIME}\s+and\s+#{TIME}/,'from \1 to \2')
832
+ nsub!(/between\s+#{TIME}\s+and\s+#{TIME}/, 'from \1 to \2')
832
833
 
833
834
  # "on the 3rd sat of this month" --> "3rd sat this month"
834
835
  # "on the 3rd sat and 5th tuesday of this month" --> "3rd sat this month 5th tuesday this month"
@@ -836,45 +837,45 @@ module Nickel
836
837
  # "on the 2nd and 3rd sat of this month" --> "2nd sat this month 3rd sat this month"
837
838
  # This is going to be dicey, I'm going to remove 'the' from the following regexprsns:
838
839
  # The 'the' case will be handled AFTER wrapper substitution at end of this method
839
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:this|of)\s+month/) { |m1,m2| m2.gsub(/\band\b/,'').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 this month') }
840
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:this|of)\s+month/) { |m1,m2| m1.gsub(/\b(and|the)\b/,'').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' this month') }
841
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:this|of)\s+month/) { |m1| m1.gsub(/\b(and|the)\b/,'').gsub(/#{DAY_OF_WEEK}/,'\1 this month') }
840
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:this|of)\s+month/) { |m1, m2| m2.gsub(/\band\b/, '').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 this month') }
841
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:this|of)\s+month/) { |m1, m2| m1.gsub(/\b(and|the)\b/, '').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' this month') }
842
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:this|of)\s+month/) { |m1| m1.gsub(/\b(and|the)\b/, '').gsub(/#{DAY_OF_WEEK}/, '\1 this month') }
842
843
 
843
844
  # "on the 3rd sat of next month" --> "3rd sat next month"
844
845
  # "on the 3rd sat and 5th tuesday of next month" --> "3rd sat next month 5th tuesday next month"
845
846
  # "on the 3rd sat and sunday of next month" --> "3rd sat this month 3rd sun next month"
846
847
  # "on the 2nd and 3rd sat of next month" --> "2nd sat this month 3rd sat next month"
847
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?next\s+month/) { |m1,m2| m2.gsub(/\band\b/,'').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 next month') }
848
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?next\s+month/) { |m1,m2| m1.gsub(/\b(and|the)\b/,'').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' next month') }
849
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?next\s+month/) { |m1| m1.gsub(/\b(and|the)\b/,'').gsub(/#{DAY_OF_WEEK}/,'\1 next month') }
848
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?next\s+month/) { |m1, m2| m2.gsub(/\band\b/, '').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 next month') }
849
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?next\s+month/) { |m1, m2| m1.gsub(/\b(and|the)\b/, '').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' next month') }
850
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?next\s+month/) { |m1| m1.gsub(/\b(and|the)\b/, '').gsub(/#{DAY_OF_WEEK}/, '\1 next month') }
850
851
 
851
852
  # "on the 3rd sat of nov" --> "3rd sat nov"
852
853
  # "on the 3rd sat and 5th tuesday of nov" --> "3rd sat nov 5th tuesday nov !!!!!!! walking a fine line here, 'nov 5th', but then again the entire nlp walks a pretty fine line
853
854
  # "on the 3rd sat and sunday of nov" --> "3rd sat nov 3rd sun nov"
854
855
  # "on the 2nd and 3rd sat of nov" --> "2nd sat nov 3rd sat nov"
855
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1,m2,m3| m2.gsub(/\band\b/,'').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 ' + m3) }
856
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1,m2,m3| m1.gsub(/\b(and|the)\b/,'').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' ' + m3) }
857
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1,m2| m1.gsub(/\b(and|the)\b/,'').gsub(/#{DAY_OF_WEEK}/,'\1 ' + m2) }
856
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1, m2, m3| m2.gsub(/\band\b/, '').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 ' + m3) }
857
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1, m2, m3| m1.gsub(/\b(and|the)\b/, '').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' ' + m3) }
858
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/) { |m1, m2| m1.gsub(/\b(and|the)\b/, '').gsub(/#{DAY_OF_WEEK}/, '\1 ' + m2) }
858
859
 
859
860
  # "on the last day of nov" --> "last day nov"
860
- nsub!(/(?:\bon\s+)?(?:the\s+)?last\s+day\s+(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/,'last day \1')
861
+ nsub!(/(?:\bon\s+)?(?:the\s+)?last\s+day\s+(?:of\s+)?(?:in\s+)?#{MONTH_OF_YEAR}/, 'last day \1')
861
862
  # "on the 1st|last day of this|the month" --> "1st|last day this month"
862
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|last)\s+day\s+(?:of\s+)?(?:this|the)?(?:\s*)month/,'\1 day this month')
863
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|last)\s+day\s+(?:of\s+)?(?:this|the)?(?:\s*)month/, '\1 day this month')
863
864
  # "on the 1st|last day of next month" --> "1st|last day next month"
864
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|last)\s+day\s+(?:of\s+)?next\s+month/,'\1 day next month')
865
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|last)\s+day\s+(?:of\s+)?next\s+month/, '\1 day next month')
865
866
 
866
867
  # "every other weekend" --> every other sat sun
867
- nsub!(/every\s+other\s+weekend/,'every other sat sun')
868
+ nsub!(/every\s+other\s+weekend/, 'every other sat sun')
868
869
 
869
870
  # "this week on mon "--> this mon
870
- nsub!(/this\s+week\s+(?:on\s+)?#{DAY_OF_WEEK}/,'this \1')
871
+ nsub!(/this\s+week\s+(?:on\s+)?#{DAY_OF_WEEK}/, 'this \1')
871
872
  # "mon of this week " --> this mon
872
- nsub!(/#{DAY_OF_WEEK}\s+(?:of\s+)?this\s+week/,'this \1')
873
+ nsub!(/#{DAY_OF_WEEK}\s+(?:of\s+)?this\s+week/, 'this \1')
873
874
 
874
875
  # "next week on mon "--> next mon
875
- nsub!(/next\s+week\s+(?:on\s+)?#{DAY_OF_WEEK}/,'next \1')
876
+ nsub!(/next\s+week\s+(?:on\s+)?#{DAY_OF_WEEK}/, 'next \1')
876
877
  # "mon of next week " --> next mon
877
- nsub!(/#{DAY_OF_WEEK}\s+(?:of\s+)?next\s+week/,'next \1')
878
+ nsub!(/#{DAY_OF_WEEK}\s+(?:of\s+)?next\s+week/, 'next \1')
878
879
 
879
880
  # Ordinal this month:
880
881
  # this will slip by now
@@ -897,7 +898,7 @@ module Nickel
897
898
  nsub!(/(?:next|the\s+following)\s+month\s+(?:(?:on|the)\s+)?(?:(?:on|the)\s+)?#{DATE_DD}/, '\1 next month')
898
899
 
899
900
  # "for the next 3 days|weeks|months" --> for 3 days|weeks|months
900
- nsub!(/for\s+(?:the\s+)?(?:next|following)\s+(\d+)\s+(days|weeks|months)/,'for \1 \2')
901
+ nsub!(/for\s+(?:the\s+)?(?:next|following)\s+(\d+)\s+(days|weeks|months)/, 'for \1 \2')
901
902
 
902
903
  # This monthname -> monthname
903
904
  nsub!(/this\s+#{MONTH_OF_YEAR}/, '\1')
@@ -915,41 +916,40 @@ module Nickel
915
916
 
916
917
  # clean up wrapper terminology
917
918
  # This should always be at end of pre-process
918
- nsub!(/(begin(s|ning)?|start(s|ing)?)(\s+(at|on))?/,'start')
919
- nsub!(/(\bend(s|ing)?|through|until)(\s+(at|on))?/,'through')
920
- nsub!(/start\s+(?:(?:this|in)\s+)?#{MONTH_OF_YEAR}/,'start \1')
919
+ nsub!(/(begin(s|ning)?|start(s|ing)?)(\s+(at|on))?/, 'start')
920
+ nsub!(/(\bend(s|ing)?|through|until)(\s+(at|on))?/, 'through')
921
+ nsub!(/start\s+(?:(?:this|in)\s+)?#{MONTH_OF_YEAR}/, 'start \1')
921
922
 
922
923
  # 'the' cases; what this is all about is if someone enters "first sunday of the month" they mean one date. But if someone enters "first sunday of the month until december 2nd" they mean recurring
923
924
  # Do these actually do ANYTHING anymore?
924
925
  # "on the 3rd sat and sunday of the month" --> "repeats monthly 3rd sat 3rd sun" OR "3rd sat this month 3rd sun this month"
925
926
  if query_str =~ /(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:the)\s+month/
926
927
  if query_str =~ /(start|through)\s+#{DATE_MM_SLASH_DD}/
927
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:the)\s+month/) {|m1,m2| "repeats monthly " + m2.gsub(/\band\b/,'').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1') }
928
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:the)\s+month/) { |m1, m2| 'repeats monthly ' + m2.gsub(/\band\b/, '').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1') }
928
929
  else
929
- nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:the)\s+month/) {|m1,m2| m2.gsub(/\band\b/,'').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 this month') }
930
+ nsub!(/(?:\bon\s+)?(?:the\s+)?(1st|2nd|3rd|4th|5th)\s+((?:#{DAY_OF_WEEK_NB}\s+(?:and\s+)?){2,7})(?:of\s+)?(?:the)\s+month/) { |m1, m2| m2.gsub(/\band\b/, '').gsub(/#{DAY_OF_WEEK}/, m1 + ' \1 this month') }
930
931
  end
931
932
  end
932
933
 
933
934
  # "on the 2nd and 3rd sat of this month" --> "repeats monthly 2nd sat 3rd sat" OR "2nd sat this month 3rd sat this month"
934
935
  if query_str =~ /(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the)\s+month/
935
936
  if query_str =~ /(start|through)\s+#{DATE_MM_SLASH_DD}/
936
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the)\s+month/) {|m1,m2| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2) }
937
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the)\s+month/) { |m1, m2| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2) }
937
938
  else
938
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the)\s+month/) {|m1,m2| m1.gsub(/\b(and|the)\b/,'').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' this month') }
939
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+(?:and\s+)?(?:the\s+)?){2,7})#{DAY_OF_WEEK}\s+(?:of\s+)?(?:the)\s+month/) { |m1, m2| m1.gsub(/\b(and|the)\b/, '').gsub(/(1st|2nd|3rd|4th|5th)/, '\1 ' + m2 + ' this month') }
939
940
  end
940
941
  end
941
942
 
942
943
  # "on the 3rd sat and 5th tuesday of this month" --> "repeats monthly 3rd sat 5th tue" OR "3rd sat this month 5th tuesday this month"
943
944
  if query_str =~ /(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the)\s+month/
944
945
  if query_str =~ /(start|through)\s+#{DATE_MM_SLASH_DD}/
945
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the)\s+month/) { |m1| "repeats monthly " + m1.gsub(/\b(and|the)\b/,'') }
946
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the)\s+month/) { |m1| 'repeats monthly ' + m1.gsub(/\b(and|the)\b/, '') }
946
947
  else
947
- nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the)\s+month/) { |m1| m1.gsub(/\b(and|the)\b/,'').gsub(/#{DAY_OF_WEEK}/,'\1 this month') }
948
+ nsub!(/(?:\bon\s+)?(?:the\s+)?((?:(?:1st|2nd|3rd|4th|5th)\s+#{DAY_OF_WEEK_NB}\s+(?:and\s+)?(?:the\s+)?){1,10})(?:of\s+)?(?:the)\s+month/) { |m1| m1.gsub(/\b(and|the)\b/, '').gsub(/#{DAY_OF_WEEK}/, '\1 this month') }
948
949
  end
949
950
  end
950
951
 
951
- nsub!(/from\s+now\s+(through|to|until)/,'now through')
952
+ nsub!(/from\s+now\s+(through|to|until)/, 'now through')
952
953
  end
953
954
  end
954
955
  end
955
-