chronic 0.6.7 → 0.7.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 +10 -0
  2. data/README.md +5 -0
  3. data/chronic.gemspec +3 -0
  4. data/lib/chronic.rb +49 -43
  5. data/lib/chronic/chronic.rb +72 -62
  6. data/lib/chronic/grabber.rb +9 -7
  7. data/lib/chronic/handler.rb +10 -12
  8. data/lib/chronic/handlers.rb +33 -1
  9. data/lib/chronic/ordinal.rb +12 -9
  10. data/lib/chronic/pointer.rb +9 -7
  11. data/lib/chronic/repeater.rb +28 -18
  12. data/lib/chronic/repeaters/repeater_day_portion.rb +25 -11
  13. data/lib/chronic/scalar.rb +30 -23
  14. data/lib/chronic/season.rb +1 -12
  15. data/lib/chronic/separator.rb +21 -15
  16. data/lib/chronic/tag.rb +5 -11
  17. data/lib/chronic/time_zone.rb +9 -7
  18. data/lib/chronic/token.rb +12 -10
  19. data/test/helper.rb +7 -1
  20. data/test/{test_Chronic.rb → test_chronic.rb} +6 -6
  21. data/test/{test_DaylightSavings.rb → test_daylight_savings.rb} +1 -1
  22. data/test/{test_Handler.rb → test_handler.rb} +1 -1
  23. data/test/{test_MiniDate.rb → test_mini_date.rb} +9 -9
  24. data/test/{test_Numerizer.rb → test_numerizer.rb} +1 -1
  25. data/test/test_parsing.rb +68 -10
  26. data/test/{test_RepeaterDayName.rb → test_repeater_day_name.rb} +1 -1
  27. data/test/test_repeater_day_portion.rb +254 -0
  28. data/test/{test_RepeaterFortnight.rb → test_repeater_fortnight.rb} +1 -1
  29. data/test/{test_RepeaterHour.rb → test_repeater_hour.rb} +1 -1
  30. data/test/{test_RepeaterMinute.rb → test_repeater_minute.rb} +1 -1
  31. data/test/{test_RepeaterMonth.rb → test_repeater_month.rb} +1 -1
  32. data/test/{test_RepeaterMonthName.rb → test_repeater_month_name.rb} +1 -1
  33. data/test/{test_RepeaterSeason.rb → test_repeater_season.rb} +1 -1
  34. data/test/{test_RepeaterTime.rb → test_repeater_time.rb} +1 -1
  35. data/test/{test_RepeaterWeek.rb → test_repeater_week.rb} +1 -1
  36. data/test/{test_RepeaterWeekday.rb → test_repeater_weekday.rb} +1 -1
  37. data/test/{test_RepeaterWeekend.rb → test_repeater_weekend.rb} +1 -1
  38. data/test/{test_RepeaterYear.rb → test_repeater_year.rb} +1 -1
  39. data/test/{test_Span.rb → test_span.rb} +1 -1
  40. data/test/{test_Token.rb → test_token.rb} +1 -1
  41. metadata +76 -44
  42. data/.gemtest +0 -0
  43. data/.yardopts +0 -3
@@ -1,12 +1,13 @@
1
1
  module Chronic
2
2
  class Separator < Tag
3
3
 
4
- # Scan an Array of {Token}s and apply any necessary Separator tags to
5
- # each token
4
+ # Scan an Array of Token objects and apply any necessary Separator
5
+ # tags to each token.
6
6
  #
7
- # @param [Array<Token>] tokens Array of tokens to scan
8
- # @param [Hash] options Options specified in {Chronic.parse}
9
- # @return [Array] list of tokens
7
+ # tokens - An Array of tokens to scan.
8
+ # options - The Hash of options specified in Chronic::parse.
9
+ #
10
+ # Returns an Array of tokens.
10
11
  def self.scan(tokens, options)
11
12
  tokens.each do |token|
12
13
  if t = scan_for_commas(token) then token.tag(t); next end
@@ -17,14 +18,16 @@ module Chronic
17
18
  end
18
19
  end
19
20
 
20
- # @param [Token] token
21
- # @return [SeparatorComma, nil]
21
+ # token - The Token object we want to scan.
22
+ #
23
+ # Returns a new SeparatorComma object.
22
24
  def self.scan_for_commas(token)
23
25
  scan_for token, SeparatorComma, { /^,$/ => :comma }
24
26
  end
25
27
 
26
- # @param [Token] token
27
- # @return [SeparatorSlashOrDash, nil]
28
+ # token - The Token object we want to scan.
29
+ #
30
+ # Returns a new SeparatorSlashOrDash object.
28
31
  def self.scan_for_slash_or_dash(token)
29
32
  scan_for token, SeparatorSlashOrDash,
30
33
  {
@@ -33,20 +36,23 @@ module Chronic
33
36
  }
34
37
  end
35
38
 
36
- # @param [Token] token
37
- # @return [SeparatorAt, nil]
39
+ # token - The Token object we want to scan.
40
+ #
41
+ # Returns a new SeparatorAt object.
38
42
  def self.scan_for_at(token)
39
43
  scan_for token, SeparatorAt, { /^(at|@)$/ => :at }
40
44
  end
41
45
 
42
- # @param [Token] token
43
- # @return [SeparatorIn, nil]
46
+ # token - The Token object we want to scan.
47
+ #
48
+ # Returns a new SeparatorIn object.
44
49
  def self.scan_for_in(token)
45
50
  scan_for token, SeparatorIn, { /^in$/ => :in }
46
51
  end
47
52
 
48
- # @param [Token] token
49
- # @return [SeparatorOn, nil]
53
+ # token - The Token object we want to scan.
54
+ #
55
+ # Returns a new SeparatorOn object.
50
56
  def self.scan_for_on(token)
51
57
  scan_for token, SeparatorOn, { /^on$/ => :on }
52
58
  end
@@ -1,29 +1,23 @@
1
1
  module Chronic
2
2
  # Tokens are tagged with subclassed instances of this class when
3
- # they match specific criteria
3
+ # they match specific criteria.
4
4
  class Tag
5
5
 
6
- # @return [Symbol]
7
6
  attr_accessor :type
8
7
 
9
- # @param [Symbol] type
8
+ # type - The Symbol type of this tag.
10
9
  def initialize(type)
11
10
  @type = type
12
11
  end
13
12
 
14
- # @param [Time] s Set the start timestamp for this Tag
15
- def start=(s)
16
- @now = s
13
+ # time - Set the start Time for this Tag.
14
+ def start=(time)
15
+ @now = time
17
16
  end
18
17
 
19
18
  class << self
20
19
  private
21
20
 
22
- # @param [Token] token
23
- # @param [Class] klass The class instance to create
24
- # @param [Regexp, Hash] items
25
- # @return [Object, nil] either a new instance of `klass` or `nil` if
26
- # no match is found
27
21
  def scan_for(token, klass, items={})
28
22
  case items
29
23
  when Regexp
@@ -1,20 +1,22 @@
1
1
  module Chronic
2
2
  class TimeZone < Tag
3
3
 
4
- # Scan an Array of {Token}s and apply any necessary TimeZone tags to
5
- # each token
4
+ # Scan an Array of Token objects and apply any necessary TimeZone
5
+ # tags to each token.
6
6
  #
7
- # @param [Array<Token>] tokens Array of tokens to scan
8
- # @param [Hash] options Options specified in {Chronic.parse}
9
- # @return [Array] list of tokens
7
+ # tokens - An Array of tokens to scan.
8
+ # options - The Hash of options specified in Chronic::parse.
9
+ #
10
+ # Returns an Array of tokens.
10
11
  def self.scan(tokens, options)
11
12
  tokens.each do |token|
12
13
  if t = scan_for_all(token) then token.tag(t); next end
13
14
  end
14
15
  end
15
16
 
16
- # @param [Token] token
17
- # @return [TimeZone, nil]
17
+ # token - The Token object we want to scan.
18
+ #
19
+ # Returns a new Pointer object.
18
20
  def self.scan_for_all(token)
19
21
  scan_for token, self,
20
22
  {
@@ -1,10 +1,7 @@
1
1
  module Chronic
2
2
  class Token
3
3
 
4
- # @return [String] The word this Token represents
5
4
  attr_accessor :word
6
-
7
- # @return [Array] A list of tag associated with this Token
8
5
  attr_accessor :tags
9
6
 
10
7
  def initialize(word)
@@ -12,27 +9,32 @@ module Chronic
12
9
  @tags = []
13
10
  end
14
11
 
15
- # Tag this token with the specified tag
12
+ # Tag this token with the specified tag.
13
+ #
14
+ # new_tag - The new Tag object.
16
15
  #
17
- # @param [Tag] new_tag An instance of {Tag} or one of its subclasses
16
+ # Returns nothing.
18
17
  def tag(new_tag)
19
18
  @tags << new_tag
20
19
  end
21
20
 
22
- # Remove all tags of the given class
21
+ # Remove all tags of the given class.
23
22
  #
24
- # @param [Class] The tag class to remove
23
+ # tag_class - The tag Class to remove.
24
+ #
25
+ # Returns nothing.
25
26
  def untag(tag_class)
26
27
  @tags.delete_if { |m| m.kind_of? tag_class }
27
28
  end
28
29
 
29
- # @return [Boolean] true if this token has any tags
30
+ # Returns true if this token has any tags.
30
31
  def tagged?
31
32
  @tags.size > 0
32
33
  end
33
34
 
34
- # @param [Class] tag_class The tag class to search for
35
- # @return [Tag] The first Tag that matches the given class
35
+ # tag_class - The tag Class to search for.
36
+ #
37
+ # Returns The first Tag that matches the given class.
36
38
  def get_tag(tag_class)
37
39
  @tags.find { |m| m.kind_of? tag_class }
38
40
  end
@@ -3,4 +3,10 @@ unless defined? Chronic
3
3
  require 'chronic'
4
4
  end
5
5
 
6
- require 'test/unit'
6
+ require 'minitest/autorun'
7
+
8
+ class TestCase < MiniTest::Unit::TestCase
9
+ def self.test(name, &block)
10
+ define_method("test_#{name.gsub(/\W/, '_')}", &block) if block
11
+ end
12
+ end
@@ -1,12 +1,16 @@
1
1
  require 'helper'
2
2
 
3
- class TestChronic < Test::Unit::TestCase
3
+ class TestChronic < TestCase
4
4
 
5
5
  def setup
6
6
  # Wed Aug 16 14:00:00 UTC 2006
7
7
  @now = Time.local(2006, 8, 16, 14, 0, 0, 0)
8
8
  end
9
9
 
10
+ def test_pre_normalize
11
+ assert_equal Chronic.pre_normalize('12:55 pm'), Chronic.pre_normalize('12.55 pm')
12
+ end
13
+
10
14
  def test_pre_normalize_numerized_string
11
15
  string = 'two and a half years'
12
16
  assert_equal Chronic::Numerizer.numerize(string), Chronic.pre_normalize(string)
@@ -131,11 +135,7 @@ class TestChronic < Test::Unit::TestCase
131
135
  assert_equal Time.local(2004, 3, 4), Chronic.construct(2004, 2, 33)
132
136
  assert_equal Time.local(2000, 3, 4), Chronic.construct(2000, 2, 33)
133
137
 
134
- assert_nothing_raised do
135
- Chronic.construct(2006, 1, 56)
136
- end
137
-
138
- assert_raise(RuntimeError) do
138
+ assert_raises(RuntimeError) do
139
139
  Chronic.construct(2006, 1, 57)
140
140
  end
141
141
  end
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class TestDaylightSavings < Test::Unit::TestCase
3
+ class TestDaylightSavings < TestCase
4
4
 
5
5
  def setup
6
6
  @begin_daylight_savings = Time.local(2008, 3, 9, 5, 0, 0, 0)
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class TestHandler < Test::Unit::TestCase
3
+ class TestHandler < TestCase
4
4
 
5
5
  def setup
6
6
  # Wed Aug 16 14:00:00 UTC 2006
@@ -1,32 +1,32 @@
1
1
  require 'helper'
2
2
 
3
- class TestMiniDate < Test::Unit::TestCase
3
+ class TestMiniDate < TestCase
4
4
  def test_valid_month
5
- assert_raise(ArgumentError){ Chronic::MiniDate.new(0,12) }
6
- assert_raise(ArgumentError){ Chronic::MiniDate.new(13,1) }
5
+ assert_raises(ArgumentError){ Chronic::MiniDate.new(0,12) }
6
+ assert_raises(ArgumentError){ Chronic::MiniDate.new(13,1) }
7
7
  end
8
-
8
+
9
9
  def test_is_between
10
10
  m=Chronic::MiniDate.new(3,2)
11
11
  assert m.is_between?(Chronic::MiniDate.new(2,4), Chronic::MiniDate.new(4,7))
12
- assert !m.is_between?(Chronic::MiniDate.new(1,5), Chronic::MiniDate.new(2,7))
13
-
12
+ assert !m.is_between?(Chronic::MiniDate.new(1,5), Chronic::MiniDate.new(2,7))
13
+
14
14
  #There was a hang if date tested is in december and outside the testing range
15
15
  m=Chronic::MiniDate.new(12,24)
16
16
  assert !m.is_between?(Chronic::MiniDate.new(10,1), Chronic::MiniDate.new(12,21))
17
17
  end
18
-
18
+
19
19
  def test_is_between_short_range
20
20
  m=Chronic::MiniDate.new(5,10)
21
21
  assert m.is_between?(Chronic::MiniDate.new(5,3), Chronic::MiniDate.new(5,12))
22
22
  assert !m.is_between?(Chronic::MiniDate.new(5,11), Chronic::MiniDate.new(5,15))
23
23
  end
24
-
24
+
25
25
  def test_is_between_wrapping_range
26
26
  m=Chronic::MiniDate.new(1,1)
27
27
  assert m.is_between?(Chronic::MiniDate.new(11,11), Chronic::MiniDate.new(2,2))
28
28
  m=Chronic::MiniDate.new(12,12)
29
29
  assert m.is_between?(Chronic::MiniDate.new(11,11), Chronic::MiniDate.new(1,5))
30
30
  end
31
-
31
+
32
32
  end
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class ParseNumbersTest < Test::Unit::TestCase
3
+ class ParseNumbersTest < TestCase
4
4
 
5
5
  def test_straight_parsing
6
6
  strings = {
@@ -1,6 +1,6 @@
1
1
  require 'helper'
2
2
 
3
- class TestParsing < Test::Unit::TestCase
3
+ class TestParsing < TestCase
4
4
  # Wed Aug 16 14:00:00 UTC 2006
5
5
  TIME_2006_08_16_14_00_00 = Time.local(2006, 8, 16, 14, 0, 0, 0)
6
6
 
@@ -252,6 +252,9 @@ class TestParsing < Test::Unit::TestCase
252
252
 
253
253
  time = parse_now("27/5/1979 @ 0700")
254
254
  assert_equal Time.local(1979, 5, 27, 7), time
255
+
256
+ time = parse_now("03/18/2012 09:26 pm")
257
+ assert_equal Time.local(2012, 3, 18, 21, 26), time
255
258
  end
256
259
 
257
260
  def test_handle_sy_sm_sd
@@ -278,19 +281,34 @@ class TestParsing < Test::Unit::TestCase
278
281
 
279
282
  time = parse_now("1902-08-20")
280
283
  assert_equal Time.local(1902, 8, 20, 12, 0, 0), time
284
+
285
+ # exif date time original
286
+ time = parse_now("2012:05:25 22:06:50")
287
+ assert_equal Time.local(2012, 5, 25, 22, 6, 50), time
281
288
  end
282
289
 
283
- def test_handle_sm_sy
290
+ def test_handle_sm_sd
284
291
  time = parse_now("05/06")
285
- assert_equal Time.local(2006, 5, 16, 12), time
292
+ assert_equal Time.local(2006, 5, 6, 12), time
286
293
 
287
- time = parse_now("12/06")
288
- assert_equal Time.local(2006, 12, 16, 12), time
294
+ time = parse_now("05/06", :endian_precedence => [:little, :medium])
295
+ assert_equal Time.local(2006, 6, 5, 12), time
289
296
 
290
- time = parse_now("13/06")
291
- assert_equal nil, time
297
+ time = parse_now("13/01")
298
+ assert_nil time
292
299
  end
293
300
 
301
+ # def test_handle_sm_sy
302
+ # time = parse_now("05/06")
303
+ # assert_equal Time.local(2006, 5, 16, 12), time
304
+ #
305
+ # time = parse_now("12/06")
306
+ # assert_equal Time.local(2006, 12, 16, 12), time
307
+ #
308
+ # time = parse_now("13/06")
309
+ # assert_equal nil, time
310
+ # end
311
+
294
312
  def test_handle_r
295
313
  end
296
314
 
@@ -354,6 +372,11 @@ class TestParsing < Test::Unit::TestCase
354
372
  assert_equal Time.local(2006, 8, 9, 12), time
355
373
  end
356
374
 
375
+ def test_handle_sm_rmn_sy
376
+ time = parse_now('30-Mar-11')
377
+ assert_equal Time.local(2011, 3, 30, 12), time
378
+ end
379
+
357
380
  # end of testing handlers
358
381
 
359
382
  def test_parse_guess_r
@@ -575,13 +598,33 @@ class TestParsing < Test::Unit::TestCase
575
598
  time = parse_now("tonight")
576
599
  assert_equal Time.local(2006, 8, 16, 22), time
577
600
 
601
+ # hour
602
+
603
+ time = parse_now("next hr")
604
+ assert_equal Time.local(2006, 8, 16, 15, 30, 0), time
605
+
606
+ time = parse_now("next hrs")
607
+ assert_equal Time.local(2006, 8, 16, 15, 30, 0), time
608
+
578
609
  # minute
579
610
 
611
+ time = parse_now("next min")
612
+ assert_equal Time.local(2006, 8, 16, 14, 1, 30), time
613
+
614
+ time = parse_now("next mins")
615
+ assert_equal Time.local(2006, 8, 16, 14, 1, 30), time
616
+
580
617
  time = parse_now("next minute")
581
618
  assert_equal Time.local(2006, 8, 16, 14, 1, 30), time
582
619
 
583
620
  # second
584
621
 
622
+ time = parse_now("next sec")
623
+ assert_equal Time.local(2006, 8, 16, 14, 0, 1), time
624
+
625
+ time = parse_now("next secs")
626
+ assert_equal Time.local(2006, 8, 16, 14, 0, 1), time
627
+
585
628
  time = parse_now("this second")
586
629
  assert_equal Time.local(2006, 8, 16, 14), time
587
630
 
@@ -674,6 +717,20 @@ class TestParsing < Test::Unit::TestCase
674
717
  assert_equal Time.local(2006, 8, 8, 12), time
675
718
  end
676
719
 
720
+ def test_parse_guess_a_ago
721
+ time = parse_now("AN hour ago")
722
+ assert_equal Time.local(2006, 8, 16, 13), time
723
+
724
+ time = parse_now("A day ago")
725
+ assert_equal Time.local(2006, 8, 15, 14), time
726
+
727
+ time = parse_now("a month ago")
728
+ assert_equal Time.local(2006, 7, 16, 14), time
729
+
730
+ time = parse_now("a year ago")
731
+ assert_equal Time.local(2005, 8, 16, 14), time
732
+ end
733
+
677
734
  def test_parse_guess_s_r_p
678
735
  # past
679
736
 
@@ -836,6 +893,7 @@ class TestParsing < Test::Unit::TestCase
836
893
  assert_equal parse_now("33 days from now"), parse_now("thirty-three days from now")
837
894
  assert_equal parse_now("2867532 seconds from now"), parse_now("two million eight hundred and sixty seven thousand five hundred and thirty two seconds from now")
838
895
  assert_equal parse_now("may 10th"), parse_now("may tenth")
896
+ assert_equal parse_now("second monday in january"), parse_now("2nd monday in january")
839
897
  end
840
898
 
841
899
  def test_parse_only_complete_pointers
@@ -855,11 +913,11 @@ class TestParsing < Test::Unit::TestCase
855
913
  end
856
914
 
857
915
  def test_argument_validation
858
- assert_raise(ArgumentError) do
916
+ assert_raises(ArgumentError) do
859
917
  time = Chronic.parse("may 27", :foo => :bar)
860
918
  end
861
919
 
862
- assert_raise(ArgumentError) do
920
+ assert_raises(ArgumentError) do
863
921
  time = Chronic.parse("may 27", :context => :bar)
864
922
  end
865
923
  end
@@ -915,7 +973,7 @@ class TestParsing < Test::Unit::TestCase
915
973
  t1 = Chronic.parse("now")
916
974
  sleep 0.1
917
975
  t2 = Chronic.parse("now")
918
- assert_not_equal t1, t2
976
+ refute_equal t1, t2
919
977
  end
920
978
 
921
979
  def test_noon