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,93 +1,102 @@
1
- class Chronic::RepeaterMonthName < Chronic::Repeater #:nodoc:
2
- MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
3
-
4
- def next(pointer)
5
- super
6
-
7
- if !@current_month_begin
8
- target_month = symbol_to_number(@type)
9
- case pointer
10
- when :future
11
- if @now.month < target_month
12
- @current_month_begin = Time.construct(@now.year, target_month)
13
- else @now.month > target_month
14
- @current_month_begin = Time.construct(@now.year + 1, target_month)
15
- end
16
- when :none
17
- if @now.month <= target_month
18
- @current_month_begin = Time.construct(@now.year, target_month)
19
- else @now.month > target_month
20
- @current_month_begin = Time.construct(@now.year + 1, target_month)
1
+ module Chronic
2
+ class RepeaterMonthName < Repeater #:nodoc:
3
+ MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
4
+ MONTHS = {
5
+ :january => 1,
6
+ :february => 2,
7
+ :march => 3,
8
+ :april => 4,
9
+ :may => 5,
10
+ :june => 6,
11
+ :july => 7,
12
+ :august => 8,
13
+ :september => 9,
14
+ :october => 10,
15
+ :november => 11,
16
+ :december => 12
17
+ }
18
+
19
+ def initialize(type)
20
+ super
21
+ @current_month_begin = nil
22
+ end
23
+
24
+ def next(pointer)
25
+ super
26
+
27
+ if !@current_month_begin
28
+ target_month = symbol_to_number(@type)
29
+ case pointer
30
+ when :future
31
+ if @now.month < target_month
32
+ @current_month_begin = Time.construct(@now.year, target_month)
33
+ elsif @now.month > target_month
34
+ @current_month_begin = Time.construct(@now.year + 1, target_month)
35
+ end
36
+ when :none
37
+ if @now.month <= target_month
38
+ @current_month_begin = Time.construct(@now.year, target_month)
39
+ elsif @now.month > target_month
40
+ @current_month_begin = Time.construct(@now.year + 1, target_month)
41
+ end
42
+ when :past
43
+ if @now.month >= target_month
44
+ @current_month_begin = Time.construct(@now.year, target_month)
45
+ elsif @now.month < target_month
46
+ @current_month_begin = Time.construct(@now.year - 1, target_month)
47
+ end
21
48
  end
22
- when :past
23
- if @now.month > target_month
24
- @current_month_begin = Time.construct(@now.year, target_month)
25
- else @now.month < target_month
26
- @current_month_begin = Time.construct(@now.year - 1, target_month)
49
+ @current_month_begin || raise("Current month should be set by now")
50
+ else
51
+ case pointer
52
+ when :future
53
+ @current_month_begin = Time.construct(@current_month_begin.year + 1, @current_month_begin.month)
54
+ when :past
55
+ @current_month_begin = Time.construct(@current_month_begin.year - 1, @current_month_begin.month)
27
56
  end
28
57
  end
29
- @current_month_begin || raise("Current month should be set by now")
30
- else
58
+
59
+ cur_month_year = @current_month_begin.year
60
+ cur_month_month = @current_month_begin.month
61
+
62
+ if cur_month_month == 12
63
+ next_month_year = cur_month_year + 1
64
+ next_month_month = 1
65
+ else
66
+ next_month_year = cur_month_year
67
+ next_month_month = cur_month_month + 1
68
+ end
69
+
70
+ Span.new(@current_month_begin, Time.construct(next_month_year, next_month_month))
71
+ end
72
+
73
+ def this(pointer = :future)
74
+ super
75
+
31
76
  case pointer
32
- when :future
33
- @current_month_begin = Time.construct(@current_month_begin.year + 1, @current_month_begin.month)
34
77
  when :past
35
- @current_month_begin = Time.construct(@current_month_begin.year - 1, @current_month_begin.month)
78
+ self.next(pointer)
79
+ when :future, :none
80
+ self.next(:none)
36
81
  end
37
82
  end
38
-
39
- cur_month_year = @current_month_begin.year
40
- cur_month_month = @current_month_begin.month
41
-
42
- if cur_month_month == 12
43
- next_month_year = cur_month_year + 1
44
- next_month_month = 1
45
- else
46
- next_month_year = cur_month_year
47
- next_month_month = cur_month_month + 1
83
+
84
+ def width
85
+ MONTH_SECONDS
48
86
  end
49
-
50
- Chronic::Span.new(@current_month_begin, Time.construct(next_month_year, next_month_month))
51
- end
52
-
53
- def this(pointer = :future)
54
- super
55
-
56
- case pointer
57
- when :past
58
- self.next(pointer)
59
- when :future, :none
60
- self.next(:none)
87
+
88
+ def index
89
+ symbol_to_number(@type)
90
+ end
91
+
92
+ def to_s
93
+ super << '-monthname-' << @type.to_s
94
+ end
95
+
96
+ private
97
+
98
+ def symbol_to_number(sym)
99
+ MONTHS[sym] || raise("Invalid symbol specified")
61
100
  end
62
- end
63
-
64
- def width
65
- MONTH_SECONDS
66
- end
67
-
68
- def index
69
- symbol_to_number(@type)
70
- end
71
-
72
- def to_s
73
- super << '-monthname-' << @type.to_s
74
- end
75
-
76
- private
77
-
78
- def symbol_to_number(sym)
79
- lookup = {:january => 1,
80
- :february => 2,
81
- :march => 3,
82
- :april => 4,
83
- :may => 5,
84
- :june => 6,
85
- :july => 7,
86
- :august => 8,
87
- :september => 9,
88
- :october => 10,
89
- :november => 11,
90
- :december => 12}
91
- lookup[sym] || raise("Invalid symbol specified")
92
101
  end
93
102
  end
@@ -1,23 +1,128 @@
1
- class Chronic::RepeaterSeason < Chronic::Repeater #:nodoc:
2
- SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
3
-
4
- def next(pointer)
5
- super
6
-
7
- raise 'Not implemented'
1
+ module Chronic
2
+ class Season
3
+ attr_reader :start, :end
4
+
5
+ def initialize(myStart, myEnd)
6
+ @start = myStart
7
+ @end = myEnd
8
+ end
9
+
10
+ def self.find_next_season(season, pointer)
11
+ lookup = {:spring => 0, :summer => 1, :autumn => 2, :winter => 3}
12
+ next_season_num = (lookup[season]+1*pointer) % 4
13
+ lookup.invert[next_season_num]
14
+ end
15
+
16
+ def self.season_after(season); find_next_season(season, +1); end
17
+ def self.season_before(season); find_next_season(season, -1); end
8
18
  end
9
-
10
- def this(pointer = :future)
11
- super
12
-
13
- raise 'Not implemented'
14
- end
15
-
16
- def width
17
- SEASON_SECONDS
18
- end
19
-
20
- def to_s
21
- super << '-season'
19
+
20
+ class RepeaterSeason < Repeater #:nodoc:
21
+ SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
22
+ SEASONS = {
23
+ :spring => Season.new(MiniDate.new(3,20), MiniDate.new(6,20)),
24
+ :summer => Season.new(MiniDate.new(6,21), MiniDate.new(9,22)),
25
+ :autumn => Season.new(MiniDate.new(9,23), MiniDate.new(12,21)),
26
+ :winter => Season.new(MiniDate.new(12,22), MiniDate.new(3,19))
27
+ }
28
+
29
+ def initialize(type)
30
+ super
31
+ @next_season_start = nil
32
+ end
33
+
34
+ def next(pointer)
35
+ super
36
+
37
+ direction = pointer == :future ? 1 : -1
38
+ next_season = Season.find_next_season(find_current_season(@now.to_minidate), direction)
39
+
40
+ find_next_season_span(direction, next_season)
41
+ end
42
+
43
+ def this(pointer = :future)
44
+ super
45
+
46
+ direction = pointer == :future ? 1 : -1
47
+
48
+ today = Time.construct(@now.year, @now.month, @now.day)
49
+ this_ssn = find_current_season(@now.to_minidate)
50
+ case pointer
51
+ when :past
52
+ this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
53
+ this_ssn_end = today
54
+ when :future
55
+ this_ssn_start = today + RepeaterDay::DAY_SECONDS
56
+ this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
57
+ when :none
58
+ this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
59
+ this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
60
+ end
61
+
62
+ construct_season(this_ssn_start, this_ssn_end)
63
+ end
64
+
65
+ def offset(span, amount, pointer)
66
+ Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
67
+ end
68
+
69
+ def offset_by(time, amount, pointer)
70
+ direction = pointer == :future ? 1 : -1
71
+ time + amount * direction * SEASON_SECONDS
72
+ end
73
+
74
+ def width
75
+ SEASON_SECONDS
76
+ end
77
+
78
+ def to_s
79
+ super << '-season'
80
+ end
81
+
82
+ private
83
+
84
+ def find_next_season_span(direction, next_season)
85
+ if !@next_season_start or !@next_season_end
86
+ @next_season_start = Time.construct(@now.year, @now.month, @now.day)
87
+ @next_season_end = Time.construct(@now.year, @now.month, @now.day)
88
+ end
89
+
90
+ @next_season_start += direction * num_seconds_til_start(next_season, direction)
91
+ @next_season_end += direction * num_seconds_til_end(next_season, direction)
92
+
93
+ construct_season(@next_season_start, @next_season_end)
94
+ end
95
+
96
+ def find_current_season(md)
97
+ [:spring, :summer, :autumn, :winter].find do |season|
98
+ md.is_between?(SEASONS[season].start, SEASONS[season].end)
99
+ end
100
+ end
101
+
102
+ def num_seconds_til(goal, direction)
103
+ start = Time.construct(@now.year, @now.month, @now.day)
104
+ seconds = 0
105
+
106
+ until (start + direction * seconds).to_minidate.equals?(goal)
107
+ seconds += RepeaterDay::DAY_SECONDS
108
+ end
109
+
110
+ seconds
111
+ end
112
+
113
+ def num_seconds_til_start(season_symbol, direction)
114
+ num_seconds_til(SEASONS[season_symbol].start, direction)
115
+ end
116
+
117
+ def num_seconds_til_end(season_symbol, direction)
118
+ num_seconds_til(SEASONS[season_symbol].end, direction)
119
+ end
120
+
121
+ def construct_season(start, finish)
122
+ Span.new(
123
+ Time.construct(start.year, start.month, start.day),
124
+ Time.construct(finish.year, finish.month, finish.day)
125
+ )
126
+ end
22
127
  end
23
128
  end
@@ -1,24 +1,45 @@
1
- class Chronic::RepeaterSeasonName < Chronic::RepeaterSeason #:nodoc:
2
- @summer = ['jul 21', 'sep 22']
3
- @autumn = ['sep 23', 'dec 21']
4
- @winter = ['dec 22', 'mar 19']
5
- @spring = ['mar 20', 'jul 20']
6
-
7
- def next(pointer)
8
- super
9
- raise 'Not implemented'
10
- end
11
-
12
- def this(pointer = :future)
13
- super
14
- raise 'Not implemented'
15
- end
16
-
17
- def width
18
- (91 * 24 * 60 * 60)
19
- end
20
-
21
- def to_s
22
- super << '-season-' << @type.to_s
1
+ module Chronic
2
+ class RepeaterSeasonName < RepeaterSeason #:nodoc:
3
+ SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
4
+ DAY_SECONDS = 86_400 # (24 * 60 * 60)
5
+
6
+ def next(pointer)
7
+ direction = pointer == :future ? 1 : -1
8
+ find_next_season_span(direction, @type)
9
+ end
10
+
11
+ def this(pointer = :future)
12
+ # super
13
+
14
+ direction = pointer == :future ? 1 : -1
15
+
16
+ today = Time.construct(@now.year, @now.month, @now.day)
17
+ goal_ssn_start = today + direction * num_seconds_til_start(@type, direction)
18
+ goal_ssn_end = today + direction * num_seconds_til_end(@type, direction)
19
+ curr_ssn = find_current_season(@now.to_minidate)
20
+ case pointer
21
+ when :past
22
+ this_ssn_start = goal_ssn_start
23
+ this_ssn_end = (curr_ssn == @type) ? today : goal_ssn_end
24
+ when :future
25
+ this_ssn_start = (curr_ssn == @type) ? today + RepeaterDay::DAY_SECONDS : goal_ssn_start
26
+ this_ssn_end = goal_ssn_end
27
+ when :none
28
+ this_ssn_start = goal_ssn_start
29
+ this_ssn_end = goal_ssn_end
30
+ end
31
+
32
+ construct_season(this_ssn_start, this_ssn_end)
33
+ end
34
+
35
+ def offset(span, amount, pointer)
36
+ Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
37
+ end
38
+
39
+ def offset_by(time, amount, pointer)
40
+ direction = pointer == :future ? 1 : -1
41
+ time + amount * direction * RepeaterYear::YEAR_SECONDS
42
+ end
43
+
23
44
  end
24
45
  end
@@ -1,36 +1,43 @@
1
- class Chronic::RepeaterSecond < Chronic::Repeater #:nodoc:
2
- SECOND_SECONDS = 1 # haha, awesome
3
-
4
- def next(pointer = :future)
5
- super
6
-
7
- direction = pointer == :future ? 1 : -1
8
-
9
- if !@second_start
10
- @second_start = @now + (direction * SECOND_SECONDS)
11
- else
12
- @second_start += SECOND_SECONDS * direction
1
+ module Chronic
2
+ class RepeaterSecond < Repeater #:nodoc:
3
+ SECOND_SECONDS = 1 # haha, awesome
4
+
5
+ def initialize(type)
6
+ super
7
+ @second_start = nil
8
+ end
9
+
10
+ def next(pointer = :future)
11
+ super
12
+
13
+ direction = pointer == :future ? 1 : -1
14
+
15
+ if !@second_start
16
+ @second_start = @now + (direction * SECOND_SECONDS)
17
+ else
18
+ @second_start += SECOND_SECONDS * direction
19
+ end
20
+
21
+ Span.new(@second_start, @second_start + SECOND_SECONDS)
22
+ end
23
+
24
+ def this(pointer = :future)
25
+ super
26
+
27
+ Span.new(@now, @now + 1)
28
+ end
29
+
30
+ def offset(span, amount, pointer)
31
+ direction = pointer == :future ? 1 : -1
32
+ span + direction * amount * SECOND_SECONDS
33
+ end
34
+
35
+ def width
36
+ SECOND_SECONDS
37
+ end
38
+
39
+ def to_s
40
+ super << '-second'
13
41
  end
14
-
15
- Chronic::Span.new(@second_start, @second_start + SECOND_SECONDS)
16
- end
17
-
18
- def this(pointer = :future)
19
- super
20
-
21
- Chronic::Span.new(@now, @now + 1)
22
- end
23
-
24
- def offset(span, amount, pointer)
25
- direction = pointer == :future ? 1 : -1
26
- span + direction * amount * SECOND_SECONDS
27
- end
28
-
29
- def width
30
- SECOND_SECONDS
31
- end
32
-
33
- def to_s
34
- super << '-second'
35
42
  end
36
43
  end