chronic 0.2.3 → 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 (63) hide show
  1. data/HISTORY.md +103 -0
  2. data/LICENSE +21 -0
  3. data/Manifest.txt +16 -5
  4. data/README.md +171 -0
  5. data/Rakefile +136 -15
  6. data/benchmark/benchmark.rb +13 -0
  7. data/chronic.gemspec +82 -0
  8. data/lib/chronic/chronic.rb +65 -147
  9. data/lib/chronic/grabber.rb +13 -17
  10. data/lib/chronic/handlers.rb +216 -138
  11. data/lib/chronic/mini_date.rb +27 -0
  12. data/lib/chronic/numerizer.rb +120 -0
  13. data/lib/chronic/ordinal.rb +11 -16
  14. data/lib/chronic/pointer.rb +11 -13
  15. data/lib/chronic/repeater.rb +117 -106
  16. data/lib/chronic/repeaters/repeater_day.rb +50 -43
  17. data/lib/chronic/repeaters/repeater_day_name.rb +49 -42
  18. data/lib/chronic/repeaters/repeater_day_portion.rb +82 -80
  19. data/lib/chronic/repeaters/repeater_fortnight.rb +60 -53
  20. data/lib/chronic/repeaters/repeater_hour.rb +50 -43
  21. data/lib/chronic/repeaters/repeater_minute.rb +50 -43
  22. data/lib/chronic/repeaters/repeater_month.rb +63 -56
  23. data/lib/chronic/repeaters/repeater_month_name.rb +91 -82
  24. data/lib/chronic/repeaters/repeater_season.rb +125 -20
  25. data/lib/chronic/repeaters/repeater_season_name.rb +43 -22
  26. data/lib/chronic/repeaters/repeater_second.rb +40 -33
  27. data/lib/chronic/repeaters/repeater_time.rb +118 -106
  28. data/lib/chronic/repeaters/repeater_week.rb +64 -57
  29. data/lib/chronic/repeaters/repeater_weekday.rb +86 -0
  30. data/lib/chronic/repeaters/repeater_weekend.rb +58 -51
  31. data/lib/chronic/repeaters/repeater_year.rb +58 -50
  32. data/lib/chronic/scalar.rb +37 -27
  33. data/lib/chronic/separator.rb +34 -37
  34. data/lib/chronic/span.rb +31 -0
  35. data/lib/chronic/tag.rb +26 -0
  36. data/lib/chronic/time_zone.rb +9 -10
  37. data/lib/chronic/token.rb +35 -0
  38. data/lib/chronic.rb +34 -25
  39. data/test/helper.rb +6 -0
  40. data/test/test_Chronic.rb +22 -18
  41. data/test/test_DaylightSavings.rb +118 -0
  42. data/test/test_Handler.rb +37 -38
  43. data/test/test_Numerizer.rb +66 -42
  44. data/test/test_RepeaterDayName.rb +15 -16
  45. data/test/test_RepeaterFortnight.rb +16 -17
  46. data/test/test_RepeaterHour.rb +22 -19
  47. data/test/test_RepeaterMinute.rb +34 -0
  48. data/test/test_RepeaterMonth.rb +16 -17
  49. data/test/test_RepeaterMonthName.rb +17 -18
  50. data/test/test_RepeaterTime.rb +20 -22
  51. data/test/test_RepeaterWeek.rb +16 -17
  52. data/test/test_RepeaterWeekday.rb +55 -0
  53. data/test/test_RepeaterWeekend.rb +21 -22
  54. data/test/test_RepeaterYear.rb +17 -18
  55. data/test/test_Span.rb +5 -6
  56. data/test/test_Time.rb +11 -12
  57. data/test/test_Token.rb +5 -6
  58. data/test/test_parsing.rb +395 -208
  59. metadata +68 -52
  60. data/History.txt +0 -53
  61. data/README.txt +0 -149
  62. data/lib/numerizer/numerizer.rb +0 -103
  63. data/test/suite.rb +0 -9
@@ -1,58 +1,66 @@
1
- class Chronic::RepeaterYear < Chronic::Repeater #:nodoc:
2
-
3
- def next(pointer)
4
- super
5
-
6
- if !@current_year_start
1
+ module Chronic
2
+ class RepeaterYear < Repeater #:nodoc:
3
+ YEAR_SECONDS = 31536000 # 365 * 24 * 60 * 60
4
+
5
+ def initialize(type)
6
+ super
7
+ @current_year_start = nil
8
+ end
9
+
10
+ def next(pointer)
11
+ super
12
+
13
+ if !@current_year_start
14
+ case pointer
15
+ when :future
16
+ @current_year_start = Time.construct(@now.year + 1)
17
+ when :past
18
+ @current_year_start = Time.construct(@now.year - 1)
19
+ end
20
+ else
21
+ diff = pointer == :future ? 1 : -1
22
+ @current_year_start = Time.construct(@current_year_start.year + diff)
23
+ end
24
+
25
+ Span.new(@current_year_start, Time.construct(@current_year_start.year + 1))
26
+ end
27
+
28
+ def this(pointer = :future)
29
+ super
30
+
7
31
  case pointer
8
32
  when :future
9
- @current_year_start = Time.construct(@now.year + 1)
33
+ this_year_start = Time.construct(@now.year, @now.month, @now.day) + RepeaterDay::DAY_SECONDS
34
+ this_year_end = Time.construct(@now.year + 1, 1, 1)
10
35
  when :past
11
- @current_year_start = Time.construct(@now.year - 1)
36
+ this_year_start = Time.construct(@now.year, 1, 1)
37
+ this_year_end = Time.construct(@now.year, @now.month, @now.day)
38
+ when :none
39
+ this_year_start = Time.construct(@now.year, 1, 1)
40
+ this_year_end = Time.construct(@now.year + 1, 1, 1)
12
41
  end
13
- else
14
- diff = pointer == :future ? 1 : -1
15
- @current_year_start = Time.construct(@current_year_start.year + diff)
42
+
43
+ Span.new(this_year_start, this_year_end)
16
44
  end
17
-
18
- Chronic::Span.new(@current_year_start, Time.construct(@current_year_start.year + 1))
19
- end
20
-
21
- def this(pointer = :future)
22
- super
23
-
24
- case pointer
25
- when :future
26
- this_year_start = Time.construct(@now.year, @now.month, @now.day) + Chronic::RepeaterDay::DAY_SECONDS
27
- this_year_end = Time.construct(@now.year + 1, 1, 1)
28
- when :past
29
- this_year_start = Time.construct(@now.year, 1, 1)
30
- this_year_end = Time.construct(@now.year, @now.month, @now.day)
31
- when :none
32
- this_year_start = Time.construct(@now.year, 1, 1)
33
- this_year_end = Time.construct(@now.year + 1, 1, 1)
45
+
46
+ def offset(span, amount, pointer)
47
+ direction = pointer == :future ? 1 : -1
48
+
49
+ sb = span.begin
50
+ new_begin = Time.construct(sb.year + (amount * direction), sb.month, sb.day, sb.hour, sb.min, sb.sec)
51
+
52
+ se = span.end
53
+ new_end = Time.construct(se.year + (amount * direction), se.month, se.day, se.hour, se.min, se.sec)
54
+
55
+ Span.new(new_begin, new_end)
56
+ end
57
+
58
+ def width
59
+ (365 * 24 * 60 * 60)
60
+ end
61
+
62
+ def to_s
63
+ super << '-year'
34
64
  end
35
-
36
- Chronic::Span.new(this_year_start, this_year_end)
37
- end
38
-
39
- def offset(span, amount, pointer)
40
- direction = pointer == :future ? 1 : -1
41
-
42
- sb = span.begin
43
- new_begin = Time.construct(sb.year + (amount * direction), sb.month, sb.day, sb.hour, sb.min, sb.sec)
44
-
45
- se = span.end
46
- new_end = Time.construct(se.year + (amount * direction), se.month, se.day, se.hour, se.min, se.sec)
47
-
48
- Chronic::Span.new(new_begin, new_end)
49
- end
50
-
51
- def width
52
- (365 * 24 * 60 * 60)
53
- end
54
-
55
- def to_s
56
- super << '-year'
57
65
  end
58
66
  end
@@ -1,74 +1,84 @@
1
1
  module Chronic
2
2
 
3
3
  class Scalar < Tag #:nodoc:
4
- def self.scan(tokens)
4
+ DAY_PORTIONS = %w( am pm morning afternoon evening night )
5
+
6
+ def self.scan(tokens, options)
5
7
  # for each token
6
8
  tokens.each_index do |i|
7
- if t = self.scan_for_scalars(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
8
- if t = self.scan_for_days(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
9
- if t = self.scan_for_months(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
10
- if t = self.scan_for_years(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
9
+ if t = scan_for_scalars(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
10
+ if t = scan_for_days(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
11
+ if t = scan_for_months(tokens[i], tokens[i + 1]) then tokens[i].tag(t) end
12
+ if t = scan_for_years(tokens[i], tokens[i + 1], options) then tokens[i].tag(t) end
11
13
  end
12
- tokens
13
14
  end
14
-
15
+
15
16
  def self.scan_for_scalars(token, post_token)
16
17
  if token.word =~ /^\d*$/
17
- unless post_token && %w{am pm morning afternoon evening night}.include?(post_token)
18
+ unless post_token && DAY_PORTIONS.include?(post_token.word)
18
19
  return Scalar.new(token.word.to_i)
19
20
  end
20
21
  end
21
- return nil
22
22
  end
23
-
23
+
24
24
  def self.scan_for_days(token, post_token)
25
25
  if token.word =~ /^\d\d?$/
26
- unless token.word.to_i > 31 || (post_token && %w{am pm morning afternoon evening night}.include?(post_token))
27
- return ScalarDay.new(token.word.to_i)
26
+ toi = token.word.to_i
27
+ unless toi > 31 || toi < 1 || (post_token && DAY_PORTIONS.include?(post_token.word))
28
+ return ScalarDay.new(toi)
28
29
  end
29
30
  end
30
- return nil
31
31
  end
32
-
32
+
33
33
  def self.scan_for_months(token, post_token)
34
34
  if token.word =~ /^\d\d?$/
35
- unless token.word.to_i > 12 || (post_token && %w{am pm morning afternoon evening night}.include?(post_token))
36
- return ScalarMonth.new(token.word.to_i)
35
+ toi = token.word.to_i
36
+ unless toi > 12 || toi < 1 || (post_token && DAY_PORTIONS.include?(post_token.word))
37
+ return ScalarMonth.new(toi)
37
38
  end
38
39
  end
39
- return nil
40
40
  end
41
-
42
- def self.scan_for_years(token, post_token)
41
+
42
+ def self.scan_for_years(token, post_token, options)
43
43
  if token.word =~ /^([1-9]\d)?\d\d?$/
44
- unless post_token && %w{am pm morning afternoon evening night}.include?(post_token)
45
- return ScalarYear.new(token.word.to_i)
44
+ unless post_token && DAY_PORTIONS.include?(post_token.word)
45
+ year = make_year(token.word.to_i, options[:ambiguous_year_future_bias])
46
+ return ScalarYear.new(year.to_i)
46
47
  end
47
48
  end
48
- return nil
49
49
  end
50
-
50
+
51
+ # Build a year from a 2 digit suffix
52
+ def self.make_year(year, bias)
53
+ return year if year.to_s.size > 2
54
+ start_year = Chronic.time_class.now.year - bias
55
+ century = (start_year / 100) * 100
56
+ full_year = century + year
57
+ full_year += 100 if full_year < start_year
58
+ full_year
59
+ end
60
+
51
61
  def to_s
52
62
  'scalar'
53
63
  end
54
64
  end
55
-
65
+
56
66
  class ScalarDay < Scalar #:nodoc:
57
67
  def to_s
58
68
  super << '-day-' << @type.to_s
59
69
  end
60
70
  end
61
-
71
+
62
72
  class ScalarMonth < Scalar #:nodoc:
63
73
  def to_s
64
74
  super << '-month-' << @type.to_s
65
75
  end
66
76
  end
67
-
77
+
68
78
  class ScalarYear < Scalar #:nodoc:
69
79
  def to_s
70
80
  super << '-year-' << @type.to_s
71
81
  end
72
82
  end
73
83
 
74
- end
84
+ end
@@ -1,76 +1,73 @@
1
1
  module Chronic
2
2
 
3
3
  class Separator < Tag #:nodoc:
4
- def self.scan(tokens)
4
+ def self.scan(tokens, options)
5
5
  tokens.each_index do |i|
6
- if t = self.scan_for_commas(tokens[i]) then tokens[i].tag(t); next end
7
- if t = self.scan_for_slash_or_dash(tokens[i]) then tokens[i].tag(t); next end
8
- if t = self.scan_for_at(tokens[i]) then tokens[i].tag(t); next end
9
- if t = self.scan_for_in(tokens[i]) then tokens[i].tag(t); next end
6
+ if t = scan_for_commas(tokens[i]) then tokens[i].tag(t); next end
7
+ if t = scan_for_slash_or_dash(tokens[i]) then tokens[i].tag(t); next end
8
+ if t = scan_for_at(tokens[i]) then tokens[i].tag(t); next end
9
+ if t = scan_for_in(tokens[i]) then tokens[i].tag(t); next end
10
+ if t = scan_for_on(tokens[i]) then tokens[i].tag(t); next end
10
11
  end
11
- tokens
12
12
  end
13
-
13
+
14
14
  def self.scan_for_commas(token)
15
- scanner = {/^,$/ => :comma}
16
- scanner.keys.each do |scanner_item|
17
- return SeparatorComma.new(scanner[scanner_item]) if scanner_item =~ token.word
18
- end
19
- return nil
15
+ scan_for token, SeparatorComma, { /^,$/ => :comma }
20
16
  end
21
-
17
+
22
18
  def self.scan_for_slash_or_dash(token)
23
- scanner = {/^-$/ => :dash,
24
- /^\/$/ => :slash}
25
- scanner.keys.each do |scanner_item|
26
- return SeparatorSlashOrDash.new(scanner[scanner_item]) if scanner_item =~ token.word
27
- end
28
- return nil
19
+ scan_for token, SeparatorSlashOrDash,
20
+ {
21
+ /^-$/ => :dash,
22
+ /^\/$/ => :slash
23
+ }
29
24
  end
30
-
25
+
31
26
  def self.scan_for_at(token)
32
- scanner = {/^(at|@)$/ => :at}
33
- scanner.keys.each do |scanner_item|
34
- return SeparatorAt.new(scanner[scanner_item]) if scanner_item =~ token.word
35
- end
36
- return nil
27
+ scan_for token, SeparatorAt, { /^(at|@)$/ => :at }
37
28
  end
38
-
29
+
39
30
  def self.scan_for_in(token)
40
- scanner = {/^in$/ => :in}
41
- scanner.keys.each do |scanner_item|
42
- return SeparatorIn.new(scanner[scanner_item]) if scanner_item =~ token.word
43
- end
44
- return nil
31
+ scan_for token, SeparatorIn, { /^in$/ => :in }
32
+ end
33
+
34
+ def self.scan_for_on(token)
35
+ scan_for token, SeparatorOn, { /^on$/ => :on }
45
36
  end
46
-
37
+
47
38
  def to_s
48
39
  'separator'
49
40
  end
50
41
  end
51
-
42
+
52
43
  class SeparatorComma < Separator #:nodoc:
53
44
  def to_s
54
45
  super << '-comma'
55
46
  end
56
47
  end
57
-
48
+
58
49
  class SeparatorSlashOrDash < Separator #:nodoc:
59
50
  def to_s
60
51
  super << '-slashordash-' << @type.to_s
61
52
  end
62
53
  end
63
-
54
+
64
55
  class SeparatorAt < Separator #:nodoc:
65
56
  def to_s
66
57
  super << '-at'
67
58
  end
68
59
  end
69
-
60
+
70
61
  class SeparatorIn < Separator #:nodoc:
71
62
  def to_s
72
63
  super << '-in'
73
64
  end
74
65
  end
75
66
 
76
- end
67
+ class SeparatorOn < Separator #:nodoc:
68
+ def to_s
69
+ super << '-on'
70
+ end
71
+ end
72
+
73
+ end
@@ -0,0 +1,31 @@
1
+ module Chronic
2
+ # A Span represents a range of time. Since this class extends
3
+ # Range, you can use #begin and #end to get the beginning and
4
+ # ending times of the span (they will be of class Time)
5
+ class Span < Range
6
+ # Returns the width of this span in seconds
7
+ def width
8
+ (self.end - self.begin).to_i
9
+ end
10
+
11
+ # Add a number of seconds to this span, returning the
12
+ # resulting Span
13
+ def +(seconds)
14
+ Span.new(self.begin + seconds, self.end + seconds)
15
+ end
16
+
17
+ # Subtract a number of seconds to this span, returning the
18
+ # resulting Span
19
+ def -(seconds)
20
+ self + -seconds
21
+ end
22
+
23
+ # Prints this span in a nice fashion
24
+ def to_s
25
+ '(' << self.begin.to_s << '..' << self.end.to_s << ')'
26
+ end
27
+
28
+ alias :cover? :include? unless RUBY_VERSION =~ /^1.9/
29
+
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ module Chronic
2
+ # Tokens are tagged with subclassed instances of this class when
3
+ # they match specific criteria
4
+ class Tag #:nodoc:
5
+ attr_accessor :type
6
+
7
+ def initialize(type)
8
+ @type = type
9
+ end
10
+
11
+ def start=(s)
12
+ @now = s
13
+ end
14
+
15
+ class << self
16
+ private
17
+
18
+ def scan_for(token, klass, items={})
19
+ items.each do |item, symbol|
20
+ return klass.new(symbol) if item =~ token.word
21
+ end
22
+ nil
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,22 +1,21 @@
1
1
  module Chronic
2
- class TimeZone < Tag #:nodoc:
3
- def self.scan(tokens)
2
+ class TimeZone < Tag #:nodoc:
3
+ def self.scan(tokens, options)
4
4
  tokens.each_index do |i|
5
- 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
6
6
  end
7
- tokens
8
7
  end
9
8
 
10
9
  def self.scan_for_all(token)
11
- scanner = {/[PMCE][DS]T/i => :tz}
12
- scanner.keys.each do |scanner_item|
13
- return self.new(scanner[scanner_item]) if scanner_item =~ token.word
14
- end
15
- return nil
10
+ scan_for token, self,
11
+ {
12
+ /[PMCE][DS]T/i => :tz,
13
+ /(tzminus)?\d{4}/ => :tz
14
+ }
16
15
  end
17
16
 
18
17
  def to_s
19
18
  'timezone'
20
19
  end
21
20
  end
22
- end
21
+ end
@@ -0,0 +1,35 @@
1
+ module Chronic
2
+ class Token #:nodoc:
3
+ attr_accessor :word, :tags
4
+
5
+ def initialize(word)
6
+ @word = word
7
+ @tags = []
8
+ end
9
+
10
+ # Tag this token with the specified tag
11
+ def tag(new_tag)
12
+ @tags << new_tag
13
+ end
14
+
15
+ # Remove all tags of the given class
16
+ def untag(tag_class)
17
+ @tags.delete_if { |m| m.kind_of? tag_class }
18
+ end
19
+
20
+ # Return true if this token has any tags
21
+ def tagged?
22
+ @tags.size > 0
23
+ end
24
+
25
+ # Return the Tag that matches the given class
26
+ def get_tag(tag_class)
27
+ @tags.find { |m| m.kind_of? tag_class }
28
+ end
29
+
30
+ # Print this Token in a pretty way
31
+ def to_s
32
+ @word << '(' << @tags.join(', ') << ') '
33
+ end
34
+ end
35
+ end
data/lib/chronic.rb CHANGED
@@ -7,10 +7,27 @@
7
7
  #
8
8
  #=============================================================================
9
9
 
10
- $:.unshift File.dirname(__FILE__) # For use/testing when no gem is installed
10
+ module Chronic
11
+ VERSION = "0.4.0"
12
+
13
+ class << self
14
+ attr_accessor :debug
15
+ attr_accessor :time_class
16
+ end
17
+
18
+ self.debug = false
19
+ self.time_class = Time
20
+ end
21
+
22
+ require 'time'
23
+ require 'date'
11
24
 
12
25
  require 'chronic/chronic'
13
26
  require 'chronic/handlers'
27
+ require 'chronic/mini_date'
28
+ require 'chronic/tag'
29
+ require 'chronic/span'
30
+ require 'chronic/token'
14
31
 
15
32
  require 'chronic/repeater'
16
33
  require 'chronic/repeaters/repeater_year'
@@ -21,6 +38,7 @@ require 'chronic/repeaters/repeater_month_name'
21
38
  require 'chronic/repeaters/repeater_fortnight'
22
39
  require 'chronic/repeaters/repeater_week'
23
40
  require 'chronic/repeaters/repeater_weekend'
41
+ require 'chronic/repeaters/repeater_weekday'
24
42
  require 'chronic/repeaters/repeater_day'
25
43
  require 'chronic/repeaters/repeater_day_name'
26
44
  require 'chronic/repeaters/repeater_day_portion'
@@ -36,28 +54,15 @@ require 'chronic/ordinal'
36
54
  require 'chronic/separator'
37
55
  require 'chronic/time_zone'
38
56
 
39
- require 'numerizer/numerizer'
40
-
41
- module Chronic
42
- VERSION = "0.2.3"
43
-
44
- def self.debug; false; end
45
- end
46
-
47
- alias p_orig p
48
-
49
- def p(val)
50
- p_orig val
51
- puts
52
- end
57
+ require 'chronic/numerizer'
53
58
 
54
59
  # class Time
55
60
  # def self.construct(year, month = 1, day = 1, hour = 0, minute = 0, second = 0)
56
61
  # # extra_seconds = second > 60 ? second - 60 : 0
57
62
  # # extra_minutes = minute > 59 ? minute - 59 : 0
58
63
  # # extra_hours = hour > 23 ? hour - 23 : 0
59
- # # extra_days = day >
60
- #
64
+ # # extra_days = day >
65
+ #
61
66
  # if month > 12
62
67
  # if month % 12 == 0
63
68
  # year += (month - 12) / 12
@@ -67,7 +72,7 @@ end
67
72
  # month = month % 12
68
73
  # end
69
74
  # end
70
- #
75
+ #
71
76
  # base = Time.local(year, month)
72
77
  # puts base
73
78
  # offset = ((day - 1) * 24 * 60 * 60) + (hour * 60 * 60) + (minute * 60) + second
@@ -84,17 +89,17 @@ class Time
84
89
  minute += second / 60
85
90
  second = second % 60
86
91
  end
87
-
92
+
88
93
  if minute >= 60
89
94
  hour += minute / 60
90
95
  minute = minute % 60
91
96
  end
92
-
97
+
93
98
  if hour >= 24
94
99
  day += hour / 24
95
100
  hour = hour % 24
96
101
  end
97
-
102
+
98
103
  # determine if there is a day overflow. this is complicated by our crappy calendar
99
104
  # system (non-constant number of days per month)
100
105
  day <= 56 || raise("day must be no more than 56 (makes month resolution easier)")
@@ -109,7 +114,7 @@ class Time
109
114
  day = day % days_this_month
110
115
  end
111
116
  end
112
-
117
+
113
118
  if month > 12
114
119
  if month % 12 == 0
115
120
  year += (month - 12) / 12
@@ -119,7 +124,11 @@ class Time
119
124
  month = month % 12
120
125
  end
121
126
  end
122
-
123
- Time.local(year, month, day, hour, minute, second)
127
+
128
+ Chronic.time_class.local(year, month, day, hour, minute, second)
124
129
  end
125
- end
130
+
131
+ def to_minidate
132
+ Chronic::MiniDate.new(self.month, self.day)
133
+ end
134
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,6 @@
1
+ unless defined? Chronic
2
+ $:.unshift File.expand_path('../../lib')
3
+ require 'chronic'
4
+ end
5
+
6
+ require 'test/unit'
data/test/test_Chronic.rb CHANGED
@@ -1,50 +1,54 @@
1
- require 'chronic'
2
- require 'test/unit'
1
+ require File.join(File.dirname(__FILE__), *%w[helper])
3
2
 
4
3
  class TestChronic < Test::Unit::TestCase
5
-
4
+
6
5
  def setup
7
6
  # Wed Aug 16 14:00:00 UTC 2006
8
7
  @now = Time.local(2006, 8, 16, 14, 0, 0, 0)
9
8
  end
10
-
9
+
10
+ def test_pre_normalize_numerized_string
11
+ string = 'two and a half years'
12
+ assert_equal Chronic::Numerizer.numerize(string), Chronic.pre_normalize(string)
13
+ end
14
+
11
15
  def test_post_normalize_am_pm_aliases
12
16
  # affect wanted patterns
13
-
17
+
14
18
  tokens = [Chronic::Token.new("5:00"), Chronic::Token.new("morning")]
15
19
  tokens[0].tag(Chronic::RepeaterTime.new("5:00"))
16
20
  tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
17
-
21
+
18
22
  assert_equal :morning, tokens[1].tags[0].type
19
-
23
+
20
24
  tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
21
-
25
+
22
26
  assert_equal :am, tokens[1].tags[0].type
23
27
  assert_equal 2, tokens.size
24
-
28
+
25
29
  # don't affect unwanted patterns
26
-
30
+
27
31
  tokens = [Chronic::Token.new("friday"), Chronic::Token.new("morning")]
28
32
  tokens[0].tag(Chronic::RepeaterDayName.new(:friday))
29
33
  tokens[1].tag(Chronic::RepeaterDayPortion.new(:morning))
30
-
34
+
31
35
  assert_equal :morning, tokens[1].tags[0].type
32
-
36
+
33
37
  tokens = Chronic.dealias_and_disambiguate_times(tokens, {})
34
-
38
+
35
39
  assert_equal :morning, tokens[1].tags[0].type
36
40
  assert_equal 2, tokens.size
37
41
  end
38
-
42
+
39
43
  def test_guess
40
44
  span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0))
41
45
  assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
42
-
46
+
43
47
  span = Chronic::Span.new(Time.local(2006, 8, 16, 0), Time.local(2006, 8, 17, 0, 0, 1))
44
48
  assert_equal Time.local(2006, 8, 16, 12), Chronic.guess(span)
45
-
49
+
46
50
  span = Chronic::Span.new(Time.local(2006, 11), Time.local(2006, 12))
47
51
  assert_equal Time.local(2006, 11, 16), Chronic.guess(span)
48
52
  end
49
-
50
- end
53
+
54
+ end