gforces-chronik 0.3.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 (47) hide show
  1. data/README +161 -0
  2. data/lib/chronik.rb +100 -0
  3. data/lib/chronik/chronik.rb +249 -0
  4. data/lib/chronik/grabber.rb +26 -0
  5. data/lib/chronik/handlers.rb +524 -0
  6. data/lib/chronik/ordinal.rb +40 -0
  7. data/lib/chronik/pointer.rb +27 -0
  8. data/lib/chronik/repeater.rb +129 -0
  9. data/lib/chronik/repeaters/repeater_day.rb +52 -0
  10. data/lib/chronik/repeaters/repeater_day_name.rb +51 -0
  11. data/lib/chronik/repeaters/repeater_day_portion.rb +94 -0
  12. data/lib/chronik/repeaters/repeater_fortnight.rb +70 -0
  13. data/lib/chronik/repeaters/repeater_hour.rb +57 -0
  14. data/lib/chronik/repeaters/repeater_minute.rb +57 -0
  15. data/lib/chronik/repeaters/repeater_month.rb +66 -0
  16. data/lib/chronik/repeaters/repeater_month_name.rb +98 -0
  17. data/lib/chronik/repeaters/repeater_season.rb +150 -0
  18. data/lib/chronik/repeaters/repeater_season_name.rb +45 -0
  19. data/lib/chronik/repeaters/repeater_second.rb +41 -0
  20. data/lib/chronik/repeaters/repeater_time.rb +124 -0
  21. data/lib/chronik/repeaters/repeater_week.rb +73 -0
  22. data/lib/chronik/repeaters/repeater_weekday.rb +77 -0
  23. data/lib/chronik/repeaters/repeater_weekend.rb +65 -0
  24. data/lib/chronik/repeaters/repeater_year.rb +64 -0
  25. data/lib/chronik/scalar.rb +76 -0
  26. data/lib/chronik/separator.rb +91 -0
  27. data/lib/chronik/time_zone.rb +23 -0
  28. data/lib/numerizer/numerizer.rb +100 -0
  29. data/test/suite.rb +9 -0
  30. data/test/test_Chronik.rb +50 -0
  31. data/test/test_Handler.rb +110 -0
  32. data/test/test_Numerizer.rb +38 -0
  33. data/test/test_RepeaterDayName.rb +52 -0
  34. data/test/test_RepeaterFortnight.rb +63 -0
  35. data/test/test_RepeaterHour.rb +65 -0
  36. data/test/test_RepeaterMonth.rb +47 -0
  37. data/test/test_RepeaterMonthName.rb +57 -0
  38. data/test/test_RepeaterTime.rb +72 -0
  39. data/test/test_RepeaterWeek.rb +63 -0
  40. data/test/test_RepeaterWeekday.rb +56 -0
  41. data/test/test_RepeaterWeekend.rb +75 -0
  42. data/test/test_RepeaterYear.rb +63 -0
  43. data/test/test_Span.rb +24 -0
  44. data/test/test_Time.rb +50 -0
  45. data/test/test_Token.rb +26 -0
  46. data/test/test_parsing.rb +711 -0
  47. metadata +103 -0
@@ -0,0 +1,57 @@
1
+ class Chronik::RepeaterHour < Chronik::Repeater #:nodoc:
2
+ HOUR_SECONDS = 3600 # 60 * 60
3
+
4
+ def initialize(type)
5
+ super
6
+ @current_hour_start = nil
7
+ end
8
+
9
+ def next(pointer)
10
+ super
11
+
12
+ if !@current_hour_start
13
+ case pointer
14
+ when :future
15
+ @current_hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
16
+ when :past
17
+ @current_hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour - 1)
18
+ end
19
+ else
20
+ direction = pointer == :future ? 1 : -1
21
+ @current_hour_start += direction * HOUR_SECONDS
22
+ end
23
+
24
+ Chronik::Span.new(@current_hour_start, @current_hour_start + HOUR_SECONDS)
25
+ end
26
+
27
+ def this(pointer = :future)
28
+ super
29
+
30
+ case pointer
31
+ when :future
32
+ hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min + 1)
33
+ hour_end = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
34
+ when :past
35
+ hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour)
36
+ hour_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
37
+ when :none
38
+ hour_start = Time.construct(@now.year, @now.month, @now.day, @now.hour)
39
+ hour_end = hour_begin + HOUR_SECONDS
40
+ end
41
+
42
+ Chronik::Span.new(hour_start, hour_end)
43
+ end
44
+
45
+ def offset(span, amount, pointer)
46
+ direction = pointer == :future ? 1 : -1
47
+ span + direction * amount * HOUR_SECONDS
48
+ end
49
+
50
+ def width
51
+ HOUR_SECONDS
52
+ end
53
+
54
+ def to_s
55
+ super << '-hour'
56
+ end
57
+ end
@@ -0,0 +1,57 @@
1
+ class Chronik::RepeaterMinute < Chronik::Repeater #:nodoc:
2
+ MINUTE_SECONDS = 60
3
+
4
+ def initialize(type)
5
+ super
6
+ @current_minute_start = nil
7
+ end
8
+
9
+ def next(pointer = :future)
10
+ super
11
+
12
+ if !@current_minute_start
13
+ case pointer
14
+ when :future
15
+ @current_minute_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min + 1)
16
+ when :past
17
+ @current_minute_start = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min - 1)
18
+ end
19
+ else
20
+ direction = pointer == :future ? 1 : -1
21
+ @current_minute_start += direction * MINUTE_SECONDS
22
+ end
23
+
24
+ Chronik::Span.new(@current_minute_start, @current_minute_start + MINUTE_SECONDS)
25
+ end
26
+
27
+ def this(pointer = :future)
28
+ super
29
+
30
+ case pointer
31
+ when :future
32
+ minute_begin = @now
33
+ minute_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
34
+ when :past
35
+ minute_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
36
+ minute_end = @now
37
+ when :none
38
+ minute_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min)
39
+ minute_end = Time.construct(@now.year, @now.month, @now.day, @now.hour, @now.min) + MINUTE_SECONDS
40
+ end
41
+
42
+ Chronik::Span.new(minute_begin, minute_end)
43
+ end
44
+
45
+ def offset(span, amount, pointer)
46
+ direction = pointer == :future ? 1 : -1
47
+ span + direction * amount * MINUTE_SECONDS
48
+ end
49
+
50
+ def width
51
+ MINUTE_SECONDS
52
+ end
53
+
54
+ def to_s
55
+ super << '-minute'
56
+ end
57
+ end
@@ -0,0 +1,66 @@
1
+ class Chronik::RepeaterMonth < Chronik::Repeater #:nodoc:
2
+ MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
3
+ YEAR_MONTHS = 12
4
+
5
+ def initialize(type)
6
+ super
7
+ @current_month_start = nil
8
+ end
9
+
10
+ def next(pointer)
11
+ super
12
+
13
+ if !@current_month_start
14
+ @current_month_start = offset_by(Time.construct(@now.year, @now.month), 1, pointer)
15
+ else
16
+ @current_month_start = offset_by(Time.construct(@current_month_start.year, @current_month_start.month), 1, pointer)
17
+ end
18
+
19
+ Chronik::Span.new(@current_month_start, Time.construct(@current_month_start.year, @current_month_start.month + 1))
20
+ end
21
+
22
+ def this(pointer = :future)
23
+ super
24
+
25
+ case pointer
26
+ when :future
27
+ month_start = Time.construct(@now.year, @now.month, @now.day + 1)
28
+ month_end = self.offset_by(Time.construct(@now.year, @now.month), 1, :future)
29
+ when :past
30
+ month_start = Time.construct(@now.year, @now.month)
31
+ month_end = Time.construct(@now.year, @now.month, @now.day)
32
+ when :none
33
+ month_start = Time.construct(@now.year, @now.month)
34
+ month_end = self.offset_by(Time.construct(@now.year, @now.month), 1, :future)
35
+ end
36
+
37
+ Chronik::Span.new(month_start, month_end)
38
+ end
39
+
40
+ def offset(span, amount, pointer)
41
+ Chronik::Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
42
+ end
43
+
44
+ def offset_by(time, amount, pointer)
45
+ direction = pointer == :future ? 1 : -1
46
+
47
+ amount_years = direction * amount / YEAR_MONTHS
48
+ amount_months = direction * amount % YEAR_MONTHS
49
+
50
+ new_year = time.year + amount_years
51
+ new_month = time.month + amount_months
52
+ if new_month > YEAR_MONTHS
53
+ new_year += 1
54
+ new_month -= YEAR_MONTHS
55
+ end
56
+ Time.construct(new_year, new_month, time.day, time.hour, time.min, time.sec)
57
+ end
58
+
59
+ def width
60
+ MONTH_SECONDS
61
+ end
62
+
63
+ def to_s
64
+ super << '-month'
65
+ end
66
+ end
@@ -0,0 +1,98 @@
1
+ class Chronik::RepeaterMonthName < Chronik::Repeater #:nodoc:
2
+ MONTH_SECONDS = 2_592_000 # 30 * 24 * 60 * 60
3
+
4
+ def initialize(type)
5
+ super
6
+ @current_month_begin = nil
7
+ end
8
+
9
+ def next(pointer)
10
+ super
11
+
12
+ if !@current_month_begin
13
+ target_month = symbol_to_number(@type)
14
+ case pointer
15
+ when :future
16
+ if @now.month < target_month
17
+ @current_month_begin = Time.construct(@now.year, target_month)
18
+ elsif @now.month > target_month
19
+ @current_month_begin = Time.construct(@now.year + 1, target_month)
20
+ end
21
+ when :none
22
+ if @now.month <= target_month
23
+ @current_month_begin = Time.construct(@now.year, target_month)
24
+ elsif @now.month > target_month
25
+ @current_month_begin = Time.construct(@now.year + 1, target_month)
26
+ end
27
+ when :past
28
+ if @now.month > target_month
29
+ @current_month_begin = Time.construct(@now.year, target_month)
30
+ elsif @now.month < target_month
31
+ @current_month_begin = Time.construct(@now.year - 1, target_month)
32
+ end
33
+ end
34
+ @current_month_begin || raise("Current month should be set by now")
35
+ else
36
+ case pointer
37
+ when :future
38
+ @current_month_begin = Time.construct(@current_month_begin.year + 1, @current_month_begin.month)
39
+ when :past
40
+ @current_month_begin = Time.construct(@current_month_begin.year - 1, @current_month_begin.month)
41
+ end
42
+ end
43
+
44
+ cur_month_year = @current_month_begin.year
45
+ cur_month_month = @current_month_begin.month
46
+
47
+ if cur_month_month == 12
48
+ next_month_year = cur_month_year + 1
49
+ next_month_month = 1
50
+ else
51
+ next_month_year = cur_month_year
52
+ next_month_month = cur_month_month + 1
53
+ end
54
+
55
+ Chronik::Span.new(@current_month_begin, Time.construct(next_month_year, next_month_month))
56
+ end
57
+
58
+ def this(pointer = :future)
59
+ super
60
+
61
+ case pointer
62
+ when :past
63
+ self.next(pointer)
64
+ when :future, :none
65
+ self.next(:none)
66
+ end
67
+ end
68
+
69
+ def width
70
+ MONTH_SECONDS
71
+ end
72
+
73
+ def index
74
+ symbol_to_number(@type)
75
+ end
76
+
77
+ def to_s
78
+ super << '-monthname-' << @type.to_s
79
+ end
80
+
81
+ private
82
+
83
+ def symbol_to_number(sym)
84
+ lookup = {:january => 1,
85
+ :february => 2,
86
+ :march => 3,
87
+ :april => 4,
88
+ :may => 5,
89
+ :june => 6,
90
+ :july => 7,
91
+ :august => 8,
92
+ :september => 9,
93
+ :october => 10,
94
+ :november => 11,
95
+ :december => 12}
96
+ lookup[sym] || raise("Invalid symbol specified")
97
+ end
98
+ end
@@ -0,0 +1,150 @@
1
+ class Time
2
+ def to_minidate
3
+ MiniDate.new(self.month, self.day)
4
+ end
5
+ end
6
+
7
+ class Season
8
+ attr_reader :start, :end
9
+
10
+ def initialize(myStart, myEnd)
11
+ @start = myStart
12
+ @end = myEnd
13
+ end
14
+
15
+ def self.find_next_season(season, pointer)
16
+ lookup = {:spring => 0, :summer => 1, :autumn => 2, :winter => 3}
17
+ next_season_num = (lookup[season]+1*pointer) % 4
18
+ lookup.invert[next_season_num]
19
+ end
20
+
21
+ def self.season_after(season); find_next_season(season, +1); end
22
+ def self.season_before(season); find_next_season(season, -1); end
23
+ end
24
+
25
+ class MiniDate
26
+ attr_accessor :month, :day
27
+
28
+ def initialize(month, day)
29
+ @month = month
30
+ @day = day
31
+ end
32
+
33
+ def is_between?(md_start, md_end)
34
+ return true if (@month == md_start.month and @day >= md_start.day) ||
35
+ (@month == md_end.month and @day <= md_end.day)
36
+
37
+ i = md_start.month + 1
38
+ until i == md_end.month
39
+ return true if @month == i
40
+ i = (i+1) % 12
41
+ end
42
+
43
+ return false
44
+ end
45
+
46
+ def equals?(other)
47
+ @month == other.month and day == other.day
48
+ end
49
+ end
50
+
51
+ class Chronik::RepeaterSeason < Chronik::Repeater #:nodoc:
52
+ YEAR_SEASONS = 4
53
+ SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
54
+ SEASONS = { :spring => Season.new( MiniDate.new(3,20),MiniDate.new(6,20) ),
55
+ :summer => Season.new( MiniDate.new(6,21),MiniDate.new(9,22) ),
56
+ :autumn => Season.new( MiniDate.new(9,23),MiniDate.new(12,21) ),
57
+ :winter => Season.new( MiniDate.new(12,22),MiniDate.new(3,19) ) }
58
+
59
+ def initialize(type)
60
+ super
61
+ @next_season_start = nil
62
+ end
63
+
64
+ def next(pointer)
65
+ super
66
+
67
+ direction = pointer == :future ? 1 : -1
68
+ next_season = Season.find_next_season(find_current_season(@now.to_minidate), direction)
69
+
70
+ find_next_season_span(direction, next_season)
71
+ end
72
+
73
+ def this(pointer = :future)
74
+ super
75
+
76
+ direction = pointer == :future ? 1 : -1
77
+
78
+ today = Time.construct(@now.year, @now.month, @now.day)
79
+ this_ssn = find_current_season(@now.to_minidate)
80
+ case pointer
81
+ when :past
82
+ this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
83
+ this_ssn_end = today
84
+ when :future
85
+ this_ssn_start = today + Chronik::RepeaterDay::DAY_SECONDS
86
+ this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
87
+ when :none
88
+ this_ssn_start = today + direction * num_seconds_til_start(this_ssn, direction)
89
+ this_ssn_end = today + direction * num_seconds_til_end(this_ssn, direction)
90
+ end
91
+
92
+ Chronik::Span.new(this_ssn_start, this_ssn_end)
93
+ end
94
+
95
+ def offset(span, amount, pointer)
96
+ Chronik::Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
97
+ end
98
+
99
+ def offset_by(time, amount, pointer)
100
+ direction = pointer == :future ? 1 : -1
101
+ time + amount * direction * SEASON_SECONDS
102
+ end
103
+
104
+ def width
105
+ SEASON_SECONDS
106
+ end
107
+
108
+ def to_s
109
+ super << '-season'
110
+ end
111
+
112
+ private
113
+
114
+ def find_next_season_span(direction, next_season)
115
+ if !@next_season_start or !@next_season_end
116
+ @next_season_start = Time.construct(@now.year, @now.month, @now.day)
117
+ @next_season_end = Time.construct(@now.year, @now.month, @now.day)
118
+ end
119
+
120
+ @next_season_start += direction * num_seconds_til_start(next_season, direction)
121
+ @next_season_end += direction * num_seconds_til_end(next_season, direction)
122
+
123
+ Chronik::Span.new(@next_season_start, @next_season_end)
124
+ end
125
+
126
+ def find_current_season(md)
127
+ [:spring, :summer, :autumn, :winter].each do |season|
128
+ return season if md.is_between?(SEASONS[season].start, SEASONS[season].end)
129
+ end
130
+ end
131
+
132
+ def num_seconds_til(goal, direction)
133
+ start = Time.construct(@now.year, @now.month, @now.day)
134
+ seconds = 0
135
+
136
+ until (start + direction * seconds).to_minidate.equals?(goal)
137
+ seconds += Chronik::RepeaterDay::DAY_SECONDS
138
+ end
139
+
140
+ seconds
141
+ end
142
+
143
+ def num_seconds_til_start(season_symbol, direction)
144
+ num_seconds_til(SEASONS[season_symbol].start, direction)
145
+ end
146
+
147
+ def num_seconds_til_end(season_symbol, direction)
148
+ num_seconds_til(SEASONS[season_symbol].end, direction)
149
+ end
150
+ end
@@ -0,0 +1,45 @@
1
+ require 'chronik/repeaters/repeater_season.rb'
2
+
3
+ class Chronik::RepeaterSeasonName < Chronik::RepeaterSeason #:nodoc:
4
+ SEASON_SECONDS = 7_862_400 # 91 * 24 * 60 * 60
5
+ DAY_SECONDS = 86_400 # (24 * 60 * 60)
6
+
7
+ def next(pointer)
8
+ direction = pointer == :future ? 1 : -1
9
+ find_next_season_span(direction, @type)
10
+ end
11
+
12
+ def this(pointer = :future)
13
+ # super
14
+
15
+ direction = pointer == :future ? 1 : -1
16
+
17
+ today = Time.construct(@now.year, @now.month, @now.day)
18
+ goal_ssn_start = today + direction * num_seconds_til_start(@type, direction)
19
+ goal_ssn_end = today + direction * num_seconds_til_end(@type, direction)
20
+ curr_ssn = find_current_season(@now.to_minidate)
21
+ case pointer
22
+ when :past
23
+ this_ssn_start = goal_ssn_start
24
+ this_ssn_end = (curr_ssn == @type) ? today : goal_ssn_end
25
+ when :future
26
+ this_ssn_start = (curr_ssn == @type) ? today + Chronik::RepeaterDay::DAY_SECONDS : goal_ssn_start
27
+ this_ssn_end = goal_ssn_end
28
+ when :none
29
+ this_ssn_start = goal_ssn_start
30
+ this_ssn_end = goal_ssn_end
31
+ end
32
+
33
+ Chronik::Span.new(this_ssn_start, this_ssn_end)
34
+ end
35
+
36
+ def offset(span, amount, pointer)
37
+ Chronik::Span.new(offset_by(span.begin, amount, pointer), offset_by(span.end, amount, pointer))
38
+ end
39
+
40
+ def offset_by(time, amount, pointer)
41
+ direction = pointer == :future ? 1 : -1
42
+ time + amount * direction * Chronik::RepeaterYear::YEAR_SECONDS
43
+ end
44
+
45
+ end