chronic 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. data/HISTORY.md +27 -0
  2. data/Manifest.txt +16 -5
  3. data/README.md +14 -8
  4. data/Rakefile +2 -8
  5. data/chronic.gemspec +8 -11
  6. data/lib/chronic.rb +21 -14
  7. data/lib/chronic/chronic.rb +38 -130
  8. data/lib/chronic/grabber.rb +11 -15
  9. data/lib/chronic/handlers.rb +63 -40
  10. data/lib/chronic/mini_date.rb +27 -0
  11. data/lib/chronic/numerizer.rb +120 -0
  12. data/lib/chronic/ordinal.rb +5 -10
  13. data/lib/chronic/pointer.rb +8 -10
  14. data/lib/chronic/repeater.rb +106 -109
  15. data/lib/chronic/repeaters/repeater_day.rb +43 -41
  16. data/lib/chronic/repeaters/repeater_day_name.rb +38 -36
  17. data/lib/chronic/repeaters/repeater_day_portion.rb +74 -73
  18. data/lib/chronic/repeaters/repeater_fortnight.rb +57 -55
  19. data/lib/chronic/repeaters/repeater_hour.rb +46 -44
  20. data/lib/chronic/repeaters/repeater_minute.rb +46 -44
  21. data/lib/chronic/repeaters/repeater_month.rb +52 -50
  22. data/lib/chronic/repeaters/repeater_month_name.rb +84 -80
  23. data/lib/chronic/repeaters/repeater_season.rb +97 -119
  24. data/lib/chronic/repeaters/repeater_season_name.rb +39 -39
  25. data/lib/chronic/repeaters/repeater_second.rb +32 -30
  26. data/lib/chronic/repeaters/repeater_time.rb +106 -101
  27. data/lib/chronic/repeaters/repeater_week.rb +60 -58
  28. data/lib/chronic/repeaters/repeater_weekday.rb +67 -58
  29. data/lib/chronic/repeaters/repeater_weekend.rb +54 -52
  30. data/lib/chronic/repeaters/repeater_year.rb +50 -48
  31. data/lib/chronic/scalar.rb +24 -16
  32. data/lib/chronic/separator.rb +15 -33
  33. data/lib/chronic/span.rb +31 -0
  34. data/lib/chronic/tag.rb +26 -0
  35. data/lib/chronic/time_zone.rb +7 -9
  36. data/lib/chronic/token.rb +35 -0
  37. data/test/helper.rb +5 -6
  38. data/test/test_Chronic.rb +5 -0
  39. data/test/test_Numerizer.rb +60 -39
  40. data/test/test_RepeaterHour.rb +4 -0
  41. data/test/test_parsing.rb +104 -13
  42. metadata +14 -20
  43. data/lib/chronic/numerizer/numerizer.rb +0 -97
@@ -1,26 +1,22 @@
1
- #module Chronic
2
-
3
- class Chronic::Grabber < Chronic::Tag #:nodoc:
4
- def self.scan(tokens)
1
+ module Chronic
2
+ class Grabber < Tag #:nodoc:
3
+ def self.scan(tokens, options)
5
4
  tokens.each_index do |i|
6
- if t = self.scan_for_all(tokens[i]) then tokens[i].tag(t); next end
5
+ if t = scan_for_all(tokens[i]) then tokens[i].tag(t); next end
7
6
  end
8
- tokens
9
7
  end
10
8
 
11
9
  def self.scan_for_all(token)
12
- scanner = {/last/ => :last,
13
- /this/ => :this,
14
- /next/ => :next}
15
- scanner.keys.each do |scanner_item|
16
- return self.new(scanner[scanner_item]) if scanner_item =~ token.word
17
- end
18
- return nil
10
+ scan_for token, self,
11
+ {
12
+ /last/ => :last,
13
+ /this/ => :this,
14
+ /next/ => :next
15
+ }
19
16
  end
20
17
 
21
18
  def to_s
22
19
  'grabber-' << @type.to_s
23
20
  end
24
21
  end
25
-
26
- #end
22
+ end
@@ -3,8 +3,7 @@ module Chronic
3
3
  class << self
4
4
 
5
5
  def definitions(options={}) #:nodoc:
6
- options[:endian_precedence] = [:middle, :little] if options[:endian_precedence].nil?
7
-
6
+ options[:endian_precedence] ||= [:middle, :little]
8
7
  # ensure the endian precedence is exactly two elements long
9
8
  raise ChronicPain, "More than two elements specified for endian precedence array" unless options[:endian_precedence].length == 2
10
9
 
@@ -19,36 +18,48 @@ module Chronic
19
18
  raise ChronicPain, "Unknown endian type: #{e.to_s}" unless instance_variable_defined?(endian_variable_name_for(e))
20
19
  end
21
20
 
22
- @definitions ||=
23
- {:time => [Handler.new([:repeater_time, :repeater_day_portion?], nil)],
24
-
25
- :date => [Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :separator_slash_or_dash?, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
26
- Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
27
- Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
28
- Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
29
- Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
30
- Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
31
- Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
32
- Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
33
- Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
34
- @middle_endian_handler,
35
- @little_endian_handler,
36
- Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
37
- Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)],
38
-
39
- # tonight at 7pm
40
- :anchor => [Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
41
- Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
42
- Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)],
43
-
44
- # 3 weeks from now, in 2 months
45
- :arrow => [Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
46
- Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
47
- Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)],
48
-
49
- # 3rd week in march
50
- :narrow => [Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
51
- Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)]
21
+ @definitions ||= {
22
+ :time => [
23
+ Handler.new([:repeater_time, :repeater_day_portion?], nil)
24
+ ],
25
+
26
+ :date => [
27
+ Handler.new([:repeater_day_name, :repeater_month_name, :scalar_day, :repeater_time, :separator_slash_or_dash?, :time_zone, :scalar_year], :handle_rdn_rmn_sd_t_tz_sy),
28
+ Handler.new([:repeater_month_name, :scalar_day, :scalar_year], :handle_rmn_sd_sy),
29
+ Handler.new([:repeater_month_name, :ordinal_day, :scalar_year], :handle_rmn_od_sy),
30
+ Handler.new([:repeater_month_name, :scalar_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_sd_sy),
31
+ Handler.new([:repeater_month_name, :ordinal_day, :scalar_year, :separator_at?, 'time?'], :handle_rmn_od_sy),
32
+ Handler.new([:repeater_month_name, :scalar_day, :separator_at?, 'time?'], :handle_rmn_sd),
33
+ Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :scalar_day], :handle_rmn_sd_on),
34
+ Handler.new([:repeater_month_name, :ordinal_day, :separator_at?, 'time?'], :handle_rmn_od),
35
+ Handler.new([:repeater_time, :repeater_day_portion?, :separator_on?, :repeater_month_name, :ordinal_day], :handle_rmn_od_on),
36
+ Handler.new([:repeater_month_name, :scalar_year], :handle_rmn_sy),
37
+ Handler.new([:scalar_day, :repeater_month_name, :scalar_year, :separator_at?, 'time?'], :handle_sd_rmn_sy),
38
+ @middle_endian_handler,
39
+ @little_endian_handler,
40
+ Handler.new([:scalar_year, :separator_slash_or_dash, :scalar_month, :separator_slash_or_dash, :scalar_day, :separator_at?, 'time?'], :handle_sy_sm_sd),
41
+ Handler.new([:scalar_month, :separator_slash_or_dash, :scalar_year], :handle_sm_sy)
42
+ ],
43
+
44
+ # tonight at 7pm
45
+ :anchor => [
46
+ Handler.new([:grabber?, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
47
+ Handler.new([:grabber?, :repeater, :repeater, :separator_at?, :repeater?, :repeater?], :handle_r),
48
+ Handler.new([:repeater, :grabber, :repeater], :handle_r_g_r)
49
+ ],
50
+
51
+ # 3 weeks from now, in 2 months
52
+ :arrow => [
53
+ Handler.new([:scalar, :repeater, :pointer], :handle_s_r_p),
54
+ Handler.new([:pointer, :scalar, :repeater], :handle_p_s_r),
55
+ Handler.new([:scalar, :repeater, :pointer, 'anchor'], :handle_s_r_p_a)
56
+ ],
57
+
58
+ # 3rd week in march
59
+ :narrow => [
60
+ Handler.new([:ordinal, :repeater, :separator_in, :repeater], :handle_o_r_s_r),
61
+ Handler.new([:ordinal, :repeater, :grabber, :repeater], :handle_o_r_g_r)
62
+ ]
52
63
  }
53
64
 
54
65
  apply_endian_precedences(options[:endian_precedence])
@@ -130,10 +141,9 @@ module Chronic
130
141
 
131
142
  if !time_tokens.empty?
132
143
  @now = outer_span.begin
133
- time = get_anchor(dealias_and_disambiguate_times(time_tokens, options), options)
134
- return time
144
+ get_anchor(dealias_and_disambiguate_times(time_tokens, options), options)
135
145
  else
136
- return outer_span
146
+ outer_span
137
147
  end
138
148
  end
139
149
 
@@ -211,6 +221,21 @@ module Chronic
211
221
  end
212
222
  end
213
223
 
224
+ def handle_rmn_od_sy(tokens, options) #:nodoc:
225
+ month = tokens[0].get_tag(RepeaterMonthName).index
226
+ day = tokens[1].get_tag(OrdinalDay).type
227
+ year = tokens[2].get_tag(ScalarYear).type
228
+
229
+ time_tokens = tokens.last(tokens.size - 3)
230
+
231
+ begin
232
+ day_start = Chronic.time_class.local(year, month, day)
233
+ day_or_time(day_start, time_tokens, options)
234
+ rescue ArgumentError
235
+ nil
236
+ end
237
+ end
238
+
214
239
  def handle_sd_rmn_sy(tokens, options) #:nodoc:
215
240
  new_tokens = [tokens[1], tokens[0], tokens[2]]
216
241
  time_tokens = tokens.last(tokens.size - 3)
@@ -363,7 +388,7 @@ module Chronic
363
388
  when :last
364
389
  outer_span = head.next(:past)
365
390
  when :this
366
- if repeaters.size > 0
391
+ if options[:context] != :past and repeaters.size > 0
367
392
  outer_span = head.this(:none)
368
393
  else
369
394
  outer_span = head.this(options[:context])
@@ -398,10 +423,8 @@ module Chronic
398
423
  head.start = pointer == :future ? span.begin : span.end
399
424
  h = head.this(:none)
400
425
 
401
- if span.include?(h.begin) || span.include?(h.end)
402
- return find_within(rest, h, pointer)
403
- else
404
- return nil
426
+ if span.cover?(h.begin) || span.cover?(h.end)
427
+ find_within(rest, h, pointer)
405
428
  end
406
429
  end
407
430
 
@@ -0,0 +1,27 @@
1
+ module Chronic
2
+ class MiniDate
3
+ attr_accessor :month, :day
4
+
5
+ def initialize(month, day)
6
+ @month = month
7
+ @day = day
8
+ end
9
+
10
+ def is_between?(md_start, md_end)
11
+ return true if (@month == md_start.month and @day >= md_start.day) ||
12
+ (@month == md_end.month and @day <= md_end.day)
13
+
14
+ i = md_start.month + 1
15
+ until i == md_end.month
16
+ return true if @month == i
17
+ i = (i+1) % 12
18
+ end
19
+
20
+ return false
21
+ end
22
+
23
+ def equals?(other)
24
+ @month == other.month and day == other.day
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,120 @@
1
+ require 'strscan'
2
+
3
+ module Chronic
4
+ class Numerizer
5
+
6
+ DIRECT_NUMS = [
7
+ ['eleven', '11'],
8
+ ['twelve', '12'],
9
+ ['thirteen', '13'],
10
+ ['fourteen', '14'],
11
+ ['fifteen', '15'],
12
+ ['sixteen', '16'],
13
+ ['seventeen', '17'],
14
+ ['eighteen', '18'],
15
+ ['nineteen', '19'],
16
+ ['ninteen', '19'], # Common mis-spelling
17
+ ['zero', '0'],
18
+ ['one', '1'],
19
+ ['two', '2'],
20
+ ['three', '3'],
21
+ ['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
22
+ ['five', '5'],
23
+ ['six(\W|$)', '6\1'],
24
+ ['seven(\W|$)', '7\1'],
25
+ ['eight(\W|$)', '8\1'],
26
+ ['nine(\W|$)', '9\1'],
27
+ ['ten', '10'],
28
+ ['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
29
+ ]
30
+
31
+ ORDINALS = [
32
+ ['first', '1'],
33
+ ['third', '3'],
34
+ ['fourth', '4'],
35
+ ['fifth', '5'],
36
+ ['sixth', '6'],
37
+ ['seventh', '7'],
38
+ ['eighth', '8'],
39
+ ['ninth', '9'],
40
+ ['tenth', '10']
41
+ ]
42
+
43
+ TEN_PREFIXES = [
44
+ ['twenty', 20],
45
+ ['thirty', 30],
46
+ ['forty', 40],
47
+ ['fourty', 40], # Common mis-spelling
48
+ ['fifty', 50],
49
+ ['sixty', 60],
50
+ ['seventy', 70],
51
+ ['eighty', 80],
52
+ ['ninety', 90]
53
+ ]
54
+
55
+ BIG_PREFIXES = [
56
+ ['hundred', 100],
57
+ ['thousand', 1000],
58
+ ['million', 1_000_000],
59
+ ['billion', 1_000_000_000],
60
+ ['trillion', 1_000_000_000_000],
61
+ ]
62
+
63
+ def self.numerize(string)
64
+ string = string.dup
65
+
66
+ # preprocess
67
+ string.gsub!(/ +|([^\d])-([^\d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
68
+ string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
69
+
70
+ # easy/direct replacements
71
+
72
+ DIRECT_NUMS.each do |dn|
73
+ string.gsub!(/#{dn[0]}/i, '<num>' + dn[1])
74
+ end
75
+
76
+ ORDINALS.each do |on|
77
+ string.gsub!(/#{on[0]}/i, '<num>' + on[1] + on[0][-2, 2])
78
+ end
79
+
80
+ # ten, twenty, etc.
81
+
82
+ TEN_PREFIXES.each do |tp|
83
+ string.gsub!(/(?:#{tp[0]}) *<num>(\d(?=[^\d]|$))*/i) { '<num>' + (tp[1] + $1.to_i).to_s }
84
+ end
85
+
86
+ TEN_PREFIXES.each do |tp|
87
+ string.gsub!(/#{tp[0]}/i) { '<num>' + tp[1].to_s }
88
+ end
89
+
90
+ # hundreds, thousands, millions, etc.
91
+
92
+ BIG_PREFIXES.each do |bp|
93
+ string.gsub!(/(?:<num>)?(\d*) *#{bp[0]}/i) { '<num>' + (bp[1] * $1.to_i).to_s}
94
+ andition(string)
95
+ end
96
+
97
+ # fractional addition
98
+ # I'm not combining this with the previous block as using float addition complicates the strings
99
+ # (with extraneous .0's and such )
100
+ string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
101
+
102
+ string.gsub(/<num>/, '')
103
+ end
104
+
105
+ class << self
106
+ private
107
+
108
+ def andition(string)
109
+ sc = StringScanner.new(string)
110
+ while(sc.scan_until(/<num>(\d+)( | and )<num>(\d+)(?=[^\w]|$)/i))
111
+ if sc[2] =~ /and/ || sc[1].size > sc[3].size
112
+ string[(sc.pos - sc.matched_size)..(sc.pos-1)] = '<num>' + (sc[1].to_i + sc[3].to_i).to_s
113
+ sc.reset
114
+ end
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
@@ -1,29 +1,24 @@
1
1
  module Chronic
2
2
 
3
3
  class Ordinal < Tag #:nodoc:
4
- def self.scan(tokens)
4
+ def self.scan(tokens, options)
5
5
  # for each token
6
6
  tokens.each_index do |i|
7
- if t = self.scan_for_ordinals(tokens[i]) then tokens[i].tag(t) end
8
- if t = self.scan_for_days(tokens[i]) then tokens[i].tag(t) end
7
+ if t = scan_for_ordinals(tokens[i]) then tokens[i].tag(t) end
8
+ if t = scan_for_days(tokens[i]) then tokens[i].tag(t) end
9
9
  end
10
- tokens
11
10
  end
12
11
 
13
12
  def self.scan_for_ordinals(token)
14
- if token.word =~ /^(\d*)(st|nd|rd|th)$/
15
- return Ordinal.new($1.to_i)
16
- end
17
- return nil
13
+ Ordinal.new($1.to_i) if token.word =~ /^(\d*)(st|nd|rd|th)$/
18
14
  end
19
15
 
20
16
  def self.scan_for_days(token)
21
17
  if token.word =~ /^(\d*)(st|nd|rd|th)$/
22
18
  unless $1.to_i > 31 || $1.to_i < 1
23
- return OrdinalDay.new(token.word.to_i)
19
+ OrdinalDay.new(token.word.to_i)
24
20
  end
25
21
  end
26
- return nil
27
22
  end
28
23
 
29
24
  def to_s
@@ -1,22 +1,20 @@
1
1
  module Chronic
2
2
 
3
3
  class Pointer < Tag #:nodoc:
4
- def self.scan(tokens)
4
+ def self.scan(tokens, options)
5
5
  # for each token
6
6
  tokens.each_index do |i|
7
- if t = self.scan_for_all(tokens[i]) then tokens[i].tag(t) end
7
+ if t = scan_for_all(tokens[i]) then tokens[i].tag(t) end
8
8
  end
9
- tokens
10
9
  end
11
10
 
12
11
  def self.scan_for_all(token)
13
- scanner = {/\bpast\b/ => :past,
14
- /\bfuture\b/ => :future,
15
- /\bin\b/ => :future}
16
- scanner.keys.each do |scanner_item|
17
- return self.new(scanner[scanner_item]) if scanner_item =~ token.word
18
- end
19
- return nil
12
+ scan_for token, self,
13
+ {
14
+ /\bpast\b/ => :past,
15
+ /\bfuture\b/ => :future,
16
+ /\bin\b/ => :future
17
+ }
20
18
  end
21
19
 
22
20
  def to_s
@@ -1,129 +1,126 @@
1
- class Chronic::Repeater < Chronic::Tag #:nodoc:
2
- def self.scan(tokens, options)
3
- # for each token
4
- tokens.each_index do |i|
5
- if t = self.scan_for_season_names(tokens[i]) then tokens[i].tag(t); next end
6
- if t = self.scan_for_month_names(tokens[i]) then tokens[i].tag(t); next end
7
- if t = self.scan_for_day_names(tokens[i]) then tokens[i].tag(t); next end
8
- if t = self.scan_for_day_portions(tokens[i]) then tokens[i].tag(t); next end
9
- if t = self.scan_for_times(tokens[i], options) then tokens[i].tag(t); next end
10
- if t = self.scan_for_units(tokens[i]) then tokens[i].tag(t); next end
1
+ module Chronic
2
+ class Repeater < Tag #:nodoc:
3
+ def self.scan(tokens, options)
4
+ # for each token
5
+ tokens.each_index do |i|
6
+ if t = scan_for_season_names(tokens[i]) then tokens[i].tag(t); next end
7
+ if t = scan_for_month_names(tokens[i]) then tokens[i].tag(t); next end
8
+ if t = scan_for_day_names(tokens[i]) then tokens[i].tag(t); next end
9
+ if t = scan_for_day_portions(tokens[i]) then tokens[i].tag(t); next end
10
+ if t = scan_for_times(tokens[i]) then tokens[i].tag(t); next end
11
+ if t = scan_for_units(tokens[i]) then tokens[i].tag(t); next end
12
+ end
11
13
  end
12
- tokens
13
- end
14
14
 
15
- def self.scan_for_season_names(token)
16
- scanner = {/^springs?$/ => :spring,
17
- /^summers?$/ => :summer,
18
- /^(autumn)|(fall)s?$/ => :autumn,
19
- /^winters?$/ => :winter}
20
- scanner.keys.each do |scanner_item|
21
- return Chronic::RepeaterSeasonName.new(scanner[scanner_item]) if scanner_item =~ token.word
15
+ def self.scan_for_season_names(token)
16
+ scan_for token, RepeaterSeasonName,
17
+ {
18
+ /^springs?$/ => :spring,
19
+ /^summers?$/ => :summer,
20
+ /^(autumn)|(fall)s?$/ => :autumn,
21
+ /^winters?$/ => :winter
22
+ }
22
23
  end
23
24
 
24
- return nil
25
- end
26
-
27
- def self.scan_for_month_names(token)
28
- scanner = {/^jan\.?(uary)?$/ => :january,
29
- /^feb\.?(ruary)?$/ => :february,
30
- /^mar\.?(ch)?$/ => :march,
31
- /^apr\.?(il)?$/ => :april,
32
- /^may$/ => :may,
33
- /^jun\.?e?$/ => :june,
34
- /^jul\.?y?$/ => :july,
35
- /^aug\.?(ust)?$/ => :august,
36
- /^sep\.?(t\.?|tember)?$/ => :september,
37
- /^oct\.?(ober)?$/ => :october,
38
- /^nov\.?(ember)?$/ => :november,
39
- /^dec\.?(ember)?$/ => :december}
40
- scanner.keys.each do |scanner_item|
41
- return Chronic::RepeaterMonthName.new(scanner[scanner_item]) if scanner_item =~ token.word
25
+ def self.scan_for_month_names(token)
26
+ scan_for token, RepeaterMonthName,
27
+ {
28
+ /^jan\.?(uary)?$/ => :january,
29
+ /^feb\.?(ruary)?$/ => :february,
30
+ /^mar\.?(ch)?$/ => :march,
31
+ /^apr\.?(il)?$/ => :april,
32
+ /^may$/ => :may,
33
+ /^jun\.?e?$/ => :june,
34
+ /^jul\.?y?$/ => :july,
35
+ /^aug\.?(ust)?$/ => :august,
36
+ /^sep\.?(t\.?|tember)?$/ => :september,
37
+ /^oct\.?(ober)?$/ => :october,
38
+ /^nov\.?(ember)?$/ => :november,
39
+ /^dec\.?(ember)?$/ => :december
40
+ }
42
41
  end
43
- return nil
44
- end
45
42
 
46
- def self.scan_for_day_names(token)
47
- scanner = {/^m[ou]n(day)?$/ => :monday,
48
- /^t(ue|eu|oo|u|)s(day)?$/ => :tuesday,
49
- /^tue$/ => :tuesday,
50
- /^we(dnes|nds|nns)day$/ => :wednesday,
51
- /^wed$/ => :wednesday,
52
- /^th(urs|ers)day$/ => :thursday,
53
- /^thu$/ => :thursday,
54
- /^fr[iy](day)?$/ => :friday,
55
- /^sat(t?[ue]rday)?$/ => :saturday,
56
- /^su[nm](day)?$/ => :sunday}
57
- scanner.keys.each do |scanner_item|
58
- return Chronic::RepeaterDayName.new(scanner[scanner_item]) if scanner_item =~ token.word
43
+ def self.scan_for_day_names(token)
44
+ scan_for token, RepeaterDayName,
45
+ {
46
+ /^m[ou]n(day)?$/ => :monday,
47
+ /^t(ue|eu|oo|u|)s(day)?$/ => :tuesday,
48
+ /^tue$/ => :tuesday,
49
+ /^we(dnes|nds|nns)day$/ => :wednesday,
50
+ /^wed$/ => :wednesday,
51
+ /^th(urs|ers)day$/ => :thursday,
52
+ /^thu(rs)?$/ => :thursday,
53
+ /^fr[iy](day)?$/ => :friday,
54
+ /^sat(t?[ue]rday)?$/ => :saturday,
55
+ /^su[nm](day)?$/ => :sunday
56
+ }
59
57
  end
60
- return nil
61
- end
62
58
 
63
- def self.scan_for_day_portions(token)
64
- scanner = {/^ams?$/ => :am,
65
- /^pms?$/ => :pm,
66
- /^mornings?$/ => :morning,
67
- /^afternoons?$/ => :afternoon,
68
- /^evenings?$/ => :evening,
69
- /^(night|nite)s?$/ => :night}
70
- scanner.keys.each do |scanner_item|
71
- return Chronic::RepeaterDayPortion.new(scanner[scanner_item]) if scanner_item =~ token.word
59
+ def self.scan_for_day_portions(token)
60
+ scan_for token, RepeaterDayPortion,
61
+ {
62
+ /^ams?$/ => :am,
63
+ /^pms?$/ => :pm,
64
+ /^mornings?$/ => :morning,
65
+ /^afternoons?$/ => :afternoon,
66
+ /^evenings?$/ => :evening,
67
+ /^(night|nite)s?$/ => :night
68
+ }
72
69
  end
73
- return nil
74
- end
75
70
 
76
- def self.scan_for_times(token, options)
77
- if token.word =~ /^\d{1,2}(:?\d{2})?([\.:]?\d{2})?$/
78
- return Chronic::RepeaterTime.new(token.word, options)
71
+ def self.scan_for_times(token)
72
+ if token.word =~ /^\d{1,2}(:?\d{2})?([\.:]?\d{2})?$/
73
+ return Chronic::RepeaterTime.new(token.word)
74
+ end
75
+ return nil
79
76
  end
80
- return nil
81
- end
82
77
 
83
- def self.scan_for_units(token)
84
- scanner = {/^years?$/ => :year,
85
- /^seasons?$/ => :season,
86
- /^months?$/ => :month,
87
- /^fortnights?$/ => :fortnight,
88
- /^weeks?$/ => :week,
89
- /^weekends?$/ => :weekend,
90
- /^(week|business)days?$/ => :weekday,
91
- /^days?$/ => :day,
92
- /^hours?$/ => :hour,
93
- /^minutes?$/ => :minute,
94
- /^seconds?$/ => :second}
95
- scanner.keys.each do |scanner_item|
96
- if scanner_item =~ token.word
97
- klass_name = 'Chronic::Repeater' + scanner[scanner_item].to_s.capitalize
98
- klass = eval(klass_name)
99
- return klass.new(scanner[scanner_item])
78
+ def self.scan_for_units(token)
79
+ {
80
+ /^years?$/ => :year,
81
+ /^seasons?$/ => :season,
82
+ /^months?$/ => :month,
83
+ /^fortnights?$/ => :fortnight,
84
+ /^weeks?$/ => :week,
85
+ /^weekends?$/ => :weekend,
86
+ /^(week|business)days?$/ => :weekday,
87
+ /^days?$/ => :day,
88
+ /^hours?$/ => :hour,
89
+ /^minutes?$/ => :minute,
90
+ /^seconds?$/ => :second
91
+ }.each do |item, symbol|
92
+ if item =~ token.word
93
+ klass_name = 'Repeater' + symbol.to_s.capitalize
94
+ klass = Chronic.const_get(klass_name)
95
+ return klass.new(symbol)
96
+ end
100
97
  end
98
+ return nil
101
99
  end
102
- return nil
103
- end
104
100
 
105
- def <=>(other)
106
- width <=> other.width
107
- end
101
+ def <=>(other)
102
+ width <=> other.width
103
+ end
108
104
 
109
- # returns the width (in seconds or months) of this repeatable.
110
- def width
111
- raise("Repeatable#width must be overridden in subclasses")
112
- end
105
+ # returns the width (in seconds or months) of this repeatable.
106
+ def width
107
+ raise("Repeatable#width must be overridden in subclasses")
108
+ end
113
109
 
114
- # returns the next occurance of this repeatable.
115
- def next(pointer)
116
- !@now.nil? || raise("Start point must be set before calling #next")
117
- [:future, :none, :past].include?(pointer) || raise("First argument 'pointer' must be one of :past or :future")
118
- #raise("Repeatable#next must be overridden in subclasses")
119
- end
110
+ # returns the next occurance of this repeatable.
111
+ def next(pointer)
112
+ !@now.nil? || raise("Start point must be set before calling #next")
113
+ [:future, :none, :past].include?(pointer) || raise("First argument 'pointer' must be one of :past or :future")
114
+ #raise("Repeatable#next must be overridden in subclasses")
115
+ end
120
116
 
121
- def this(pointer)
122
- !@now.nil? || raise("Start point must be set before calling #this")
123
- [:future, :past, :none].include?(pointer) || raise("First argument 'pointer' must be one of :past, :future, :none")
124
- end
117
+ def this(pointer)
118
+ !@now.nil? || raise("Start point must be set before calling #this")
119
+ [:future, :past, :none].include?(pointer) || raise("First argument 'pointer' must be one of :past, :future, :none")
120
+ end
125
121
 
126
- def to_s
127
- 'repeater'
122
+ def to_s
123
+ 'repeater'
124
+ end
128
125
  end
129
- end
126
+ end