chronic 0.2.2 → 0.10.2
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.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.travis.yml +8 -0
- data/HISTORY.md +243 -0
- data/LICENSE +21 -0
- data/README.md +182 -0
- data/Rakefile +62 -15
- data/chronic.gemspec +23 -0
- data/lib/chronic/date.rb +82 -0
- data/lib/chronic/grabber.rb +24 -17
- data/lib/chronic/handler.rb +97 -0
- data/lib/chronic/handlers.rb +490 -312
- data/lib/chronic/mini_date.rb +38 -0
- data/lib/chronic/numerizer.rb +130 -0
- data/lib/chronic/ordinal.rb +33 -24
- data/lib/chronic/parser.rb +268 -0
- data/lib/chronic/pointer.rb +22 -17
- data/lib/chronic/repeater.rb +137 -107
- data/lib/chronic/repeaters/repeater_day.rb +51 -44
- data/lib/chronic/repeaters/repeater_day_name.rb +50 -43
- data/lib/chronic/repeaters/repeater_day_portion.rb +97 -81
- data/lib/chronic/repeaters/repeater_fortnight.rb +61 -54
- data/lib/chronic/repeaters/repeater_hour.rb +51 -44
- data/lib/chronic/repeaters/repeater_minute.rb +51 -44
- data/lib/chronic/repeaters/repeater_month.rb +79 -60
- data/lib/chronic/repeaters/repeater_month_name.rb +85 -83
- data/lib/chronic/repeaters/repeater_season.rb +110 -22
- data/lib/chronic/repeaters/repeater_season_name.rb +41 -22
- data/lib/chronic/repeaters/repeater_second.rb +41 -34
- data/lib/chronic/repeaters/repeater_time.rb +128 -104
- data/lib/chronic/repeaters/repeater_week.rb +65 -58
- data/lib/chronic/repeaters/repeater_weekday.rb +86 -0
- data/lib/chronic/repeaters/repeater_weekend.rb +59 -52
- data/lib/chronic/repeaters/repeater_year.rb +72 -52
- data/lib/chronic/scalar.rb +53 -46
- data/lib/chronic/season.rb +26 -0
- data/lib/chronic/separator.rb +174 -43
- data/lib/chronic/sign.rb +49 -0
- data/lib/chronic/span.rb +31 -0
- data/lib/chronic/tag.rb +37 -0
- data/lib/chronic/time.rb +40 -0
- data/lib/chronic/time_zone.rb +21 -11
- data/lib/chronic/token.rb +51 -0
- data/lib/chronic.rb +94 -69
- data/test/helper.rb +12 -0
- data/test/test_chronic.rb +183 -0
- data/test/test_daylight_savings.rb +118 -0
- data/test/{test_Handler.rb → test_handler.rb} +73 -55
- data/test/test_mini_date.rb +32 -0
- data/test/test_numerizer.rb +86 -0
- data/test/test_parsing.rb +891 -248
- data/test/{test_RepeaterDayName.rb → test_repeater_day_name.rb} +16 -17
- data/test/test_repeater_day_portion.rb +254 -0
- data/test/{test_RepeaterFortnight.rb → test_repeater_fortnight.rb} +17 -18
- data/test/{test_RepeaterHour.rb → test_repeater_hour.rb} +23 -20
- data/test/test_repeater_minute.rb +34 -0
- data/test/{test_RepeaterMonth.rb → test_repeater_month.rb} +21 -18
- data/test/{test_RepeaterMonthName.rb → test_repeater_month_name.rb} +18 -19
- data/test/test_repeater_season.rb +40 -0
- data/test/{test_RepeaterTime.rb → test_repeater_time.rb} +39 -23
- data/test/{test_RepeaterWeek.rb → test_repeater_week.rb} +17 -18
- data/test/test_repeater_weekday.rb +55 -0
- data/test/{test_RepeaterWeekend.rb → test_repeater_weekend.rb} +22 -23
- data/test/{test_RepeaterYear.rb → test_repeater_year.rb} +25 -19
- data/test/{test_Span.rb → test_span.rb} +7 -8
- data/test/{test_Token.rb → test_token.rb} +6 -7
- metadata +163 -85
- data/History.txt +0 -49
- data/Manifest.txt +0 -47
- data/README.txt +0 -149
- data/lib/chronic/chronic.rb +0 -239
- data/lib/numerizer/numerizer.rb +0 -103
- data/test/suite.rb +0 -9
- data/test/test_Chronic.rb +0 -50
- data/test/test_Numerizer.rb +0 -48
- data/test/test_Time.rb +0 -50
data/lib/chronic/repeater.rb
CHANGED
|
@@ -1,115 +1,145 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
module Chronic
|
|
2
|
+
class Repeater < Tag
|
|
3
|
+
|
|
4
|
+
# Scan an Array of Token objects and apply any necessary Repeater
|
|
5
|
+
# tags to each token.
|
|
6
|
+
#
|
|
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.
|
|
11
|
+
def self.scan(tokens, options)
|
|
12
|
+
tokens.each do |token|
|
|
13
|
+
if t = scan_for_season_names(token, options) then token.tag(t); next end
|
|
14
|
+
if t = scan_for_month_names(token, options) then token.tag(t); next end
|
|
15
|
+
if t = scan_for_day_names(token, options) then token.tag(t); next end
|
|
16
|
+
if t = scan_for_day_portions(token, options) then token.tag(t); next end
|
|
17
|
+
if t = scan_for_times(token, options) then token.tag(t); next end
|
|
18
|
+
if t = scan_for_units(token, options) then token.tag(t); next end
|
|
19
|
+
end
|
|
10
20
|
end
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/^sep\.?(t\.?|tember)?$/ => :september,
|
|
24
|
-
/^oct\.?(ober)?$/ => :october,
|
|
25
|
-
/^nov\.?(ember)?$/ => :november,
|
|
26
|
-
/^dec\.?(ember)?$/ => :december}
|
|
27
|
-
scanner.keys.each do |scanner_item|
|
|
28
|
-
return Chronic::RepeaterMonthName.new(scanner[scanner_item]) if scanner_item =~ token.word
|
|
21
|
+
|
|
22
|
+
# token - The Token object we want to scan.
|
|
23
|
+
#
|
|
24
|
+
# Returns a new Repeater object.
|
|
25
|
+
def self.scan_for_season_names(token, options = {})
|
|
26
|
+
scan_for token, RepeaterSeasonName,
|
|
27
|
+
{
|
|
28
|
+
/^springs?$/ => :spring,
|
|
29
|
+
/^summers?$/ => :summer,
|
|
30
|
+
/^(autumn)|(fall)s?$/ => :autumn,
|
|
31
|
+
/^winters?$/ => :winter
|
|
32
|
+
}, options
|
|
29
33
|
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
34
|
+
|
|
35
|
+
# token - The Token object we want to scan.
|
|
36
|
+
#
|
|
37
|
+
# Returns a new Repeater object.
|
|
38
|
+
def self.scan_for_month_names(token, options = {})
|
|
39
|
+
scan_for token, RepeaterMonthName,
|
|
40
|
+
{
|
|
41
|
+
/^jan[:\.]?(uary)?$/ => :january,
|
|
42
|
+
/^feb[:\.]?(ruary)?$/ => :february,
|
|
43
|
+
/^mar[:\.]?(ch)?$/ => :march,
|
|
44
|
+
/^apr[:\.]?(il)?$/ => :april,
|
|
45
|
+
/^may$/ => :may,
|
|
46
|
+
/^jun[:\.]?e?$/ => :june,
|
|
47
|
+
/^jul[:\.]?y?$/ => :july,
|
|
48
|
+
/^aug[:\.]?(ust)?$/ => :august,
|
|
49
|
+
/^sep[:\.]?(t[:\.]?|tember)?$/ => :september,
|
|
50
|
+
/^oct[:\.]?(ober)?$/ => :october,
|
|
51
|
+
/^nov[:\.]?(ember)?$/ => :november,
|
|
52
|
+
/^dec[:\.]?(ember)?$/ => :december
|
|
53
|
+
}, options
|
|
46
54
|
end
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
|
|
56
|
+
# token - The Token object we want to scan.
|
|
57
|
+
#
|
|
58
|
+
# Returns a new Repeater object.
|
|
59
|
+
def self.scan_for_day_names(token, options = {})
|
|
60
|
+
scan_for token, RepeaterDayName,
|
|
61
|
+
{
|
|
62
|
+
/^m[ou]n(day)?$/ => :monday,
|
|
63
|
+
/^t(ue|eu|oo|u|)s?(day)?$/ => :tuesday,
|
|
64
|
+
/^we(d|dnes|nds|nns)(day)?$/ => :wednesday,
|
|
65
|
+
/^th(u|ur|urs|ers)(day)?$/ => :thursday,
|
|
66
|
+
/^fr[iy](day)?$/ => :friday,
|
|
67
|
+
/^sat(t?[ue]rday)?$/ => :saturday,
|
|
68
|
+
/^su[nm](day)?$/ => :sunday
|
|
69
|
+
}, options
|
|
59
70
|
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
71
|
+
|
|
72
|
+
# token - The Token object we want to scan.
|
|
73
|
+
#
|
|
74
|
+
# Returns a new Repeater object.
|
|
75
|
+
def self.scan_for_day_portions(token, options = {})
|
|
76
|
+
scan_for token, RepeaterDayPortion,
|
|
77
|
+
{
|
|
78
|
+
/^ams?$/ => :am,
|
|
79
|
+
/^pms?$/ => :pm,
|
|
80
|
+
/^mornings?$/ => :morning,
|
|
81
|
+
/^afternoons?$/ => :afternoon,
|
|
82
|
+
/^evenings?$/ => :evening,
|
|
83
|
+
/^(night|nite)s?$/ => :night
|
|
84
|
+
}, options
|
|
66
85
|
end
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
+
|
|
87
|
+
# token - The Token object we want to scan.
|
|
88
|
+
#
|
|
89
|
+
# Returns a new Repeater object.
|
|
90
|
+
def self.scan_for_times(token, options = {})
|
|
91
|
+
scan_for token, RepeaterTime, /^\d{1,2}(:?\d{1,2})?([\.:]?\d{1,2}([\.:]\d{1,6})?)?$/, options
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# token - The Token object we want to scan.
|
|
95
|
+
#
|
|
96
|
+
# Returns a new Repeater object.
|
|
97
|
+
def self.scan_for_units(token, options = {})
|
|
98
|
+
{
|
|
99
|
+
/^years?$/ => :year,
|
|
100
|
+
/^seasons?$/ => :season,
|
|
101
|
+
/^months?$/ => :month,
|
|
102
|
+
/^fortnights?$/ => :fortnight,
|
|
103
|
+
/^weeks?$/ => :week,
|
|
104
|
+
/^weekends?$/ => :weekend,
|
|
105
|
+
/^(week|business)days?$/ => :weekday,
|
|
106
|
+
/^days?$/ => :day,
|
|
107
|
+
/^hrs?$/ => :hour,
|
|
108
|
+
/^hours?$/ => :hour,
|
|
109
|
+
/^mins?$/ => :minute,
|
|
110
|
+
/^minutes?$/ => :minute,
|
|
111
|
+
/^secs?$/ => :second,
|
|
112
|
+
/^seconds?$/ => :second
|
|
113
|
+
}.each do |item, symbol|
|
|
114
|
+
if item =~ token.word
|
|
115
|
+
klass_name = 'Repeater' + symbol.to_s.capitalize
|
|
116
|
+
klass = Chronic.const_get(klass_name)
|
|
117
|
+
return klass.new(symbol, options)
|
|
118
|
+
end
|
|
86
119
|
end
|
|
120
|
+
return nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def <=>(other)
|
|
124
|
+
width <=> other.width
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# returns the width (in seconds or months) of this repeatable.
|
|
128
|
+
def width
|
|
129
|
+
raise("Repeater#width must be overridden in subclasses")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# returns the next occurance of this repeatable.
|
|
133
|
+
def next(pointer)
|
|
134
|
+
raise("Start point must be set before calling #next") unless @now
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def this(pointer)
|
|
138
|
+
raise("Start point must be set before calling #this") unless @now
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def to_s
|
|
142
|
+
'repeater'
|
|
87
143
|
end
|
|
88
|
-
return nil
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
def <=>(other)
|
|
92
|
-
width <=> other.width
|
|
93
|
-
end
|
|
94
|
-
|
|
95
|
-
# returns the width (in seconds or months) of this repeatable.
|
|
96
|
-
def width
|
|
97
|
-
raise("Repeatable#width must be overridden in subclasses")
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# returns the next occurance of this repeatable.
|
|
101
|
-
def next(pointer)
|
|
102
|
-
!@now.nil? || raise("Start point must be set before calling #next")
|
|
103
|
-
[:future, :none, :past].include?(pointer) || raise("First argument 'pointer' must be one of :past or :future")
|
|
104
|
-
#raise("Repeatable#next must be overridden in subclasses")
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def this(pointer)
|
|
108
|
-
!@now.nil? || raise("Start point must be set before calling #this")
|
|
109
|
-
[:future, :past, :none].include?(pointer) || raise("First argument 'pointer' must be one of :past, :future, :none")
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def to_s
|
|
113
|
-
'repeater'
|
|
114
144
|
end
|
|
115
|
-
end
|
|
145
|
+
end
|
|
@@ -1,47 +1,54 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@current_day_start = Time.local(@now.year, @now.month, @now.day)
|
|
1
|
+
module Chronic
|
|
2
|
+
class RepeaterDay < Repeater #:nodoc:
|
|
3
|
+
DAY_SECONDS = 86_400 # (24 * 60 * 60)
|
|
4
|
+
|
|
5
|
+
def initialize(type, options = {})
|
|
6
|
+
super
|
|
7
|
+
@current_day_start = nil
|
|
9
8
|
end
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
9
|
+
|
|
10
|
+
def next(pointer)
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
unless @current_day_start
|
|
14
|
+
@current_day_start = Chronic.time_class.local(@now.year, @now.month, @now.day)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
direction = pointer == :future ? 1 : -1
|
|
18
|
+
@current_day_start += direction * DAY_SECONDS
|
|
19
|
+
|
|
20
|
+
Span.new(@current_day_start, @current_day_start + DAY_SECONDS)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def this(pointer = :future)
|
|
24
|
+
super
|
|
25
|
+
|
|
26
|
+
case pointer
|
|
27
|
+
when :future
|
|
28
|
+
day_begin = Chronic.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
29
|
+
day_end = Chronic.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
|
30
|
+
when :past
|
|
31
|
+
day_begin = Chronic.construct(@now.year, @now.month, @now.day)
|
|
32
|
+
day_end = Chronic.construct(@now.year, @now.month, @now.day, @now.hour)
|
|
33
|
+
when :none
|
|
34
|
+
day_begin = Chronic.construct(@now.year, @now.month, @now.day)
|
|
35
|
+
day_end = Chronic.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
Span.new(day_begin, day_end)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def offset(span, amount, pointer)
|
|
42
|
+
direction = pointer == :future ? 1 : -1
|
|
43
|
+
span + direction * amount * DAY_SECONDS
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def width
|
|
47
|
+
DAY_SECONDS
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def to_s
|
|
51
|
+
super << '-day'
|
|
30
52
|
end
|
|
31
|
-
|
|
32
|
-
Chronic::Span.new(day_begin, day_end)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def offset(span, amount, pointer)
|
|
36
|
-
direction = pointer == :future ? 1 : -1
|
|
37
|
-
span + direction * amount * DAY_SECONDS
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def width
|
|
41
|
-
DAY_SECONDS
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def to_s
|
|
45
|
-
super << '-day'
|
|
46
53
|
end
|
|
47
|
-
end
|
|
54
|
+
end
|
|
@@ -1,46 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
@
|
|
1
|
+
module Chronic
|
|
2
|
+
class RepeaterDayName < Repeater #:nodoc:
|
|
3
|
+
DAY_SECONDS = 86400 # (24 * 60 * 60)
|
|
4
|
+
|
|
5
|
+
def initialize(type, options = {})
|
|
6
|
+
super
|
|
7
|
+
@current_date = nil
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def next(pointer)
|
|
11
|
+
super
|
|
12
|
+
|
|
13
|
+
direction = pointer == :future ? 1 : -1
|
|
14
|
+
|
|
15
|
+
unless @current_date
|
|
16
|
+
@current_date = ::Date.new(@now.year, @now.month, @now.day)
|
|
17
|
+
@current_date += direction
|
|
18
|
+
|
|
19
|
+
day_num = symbol_to_number(@type)
|
|
20
|
+
|
|
21
|
+
while @current_date.wday != day_num
|
|
22
|
+
@current_date += direction
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
@current_date += direction * 7
|
|
17
26
|
end
|
|
18
|
-
|
|
19
|
-
@
|
|
27
|
+
next_date = @current_date.succ
|
|
28
|
+
Span.new(Chronic.construct(@current_date.year, @current_date.month, @current_date.day), Chronic.construct(next_date.year, next_date.month, next_date.day))
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def this(pointer = :future)
|
|
32
|
+
super
|
|
33
|
+
|
|
34
|
+
pointer = :future if pointer == :none
|
|
35
|
+
self.next(pointer)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def width
|
|
39
|
+
DAY_SECONDS
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def to_s
|
|
43
|
+
super << '-dayname-' << @type.to_s
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def symbol_to_number(sym)
|
|
49
|
+
lookup = {:sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3, :thursday => 4, :friday => 5, :saturday => 6}
|
|
50
|
+
lookup[sym] || raise("Invalid symbol specified")
|
|
20
51
|
end
|
|
21
|
-
|
|
22
|
-
Chronic::Span.new(@current_day_start, @current_day_start + DAY_SECONDS)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def this(pointer = :future)
|
|
26
|
-
super
|
|
27
|
-
|
|
28
|
-
pointer = :future if pointer == :none
|
|
29
|
-
self.next(pointer)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def width
|
|
33
|
-
DAY_SECONDS
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
def to_s
|
|
37
|
-
super << '-dayname-' << @type.to_s
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
private
|
|
41
|
-
|
|
42
|
-
def symbol_to_number(sym)
|
|
43
|
-
lookup = {:sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3, :thursday => 4, :friday => 5, :saturday => 6}
|
|
44
|
-
lookup[sym] || raise("Invalid symbol specified")
|
|
45
52
|
end
|
|
46
|
-
end
|
|
53
|
+
end
|
|
@@ -1,93 +1,109 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
1
|
+
module Chronic
|
|
2
|
+
class RepeaterDayPortion < Repeater #:nodoc:
|
|
3
|
+
PORTIONS = {
|
|
4
|
+
:am => 0..(12 * 60 * 60 - 1),
|
|
5
|
+
:pm => (12 * 60 * 60)..(24 * 60 * 60 - 1),
|
|
6
|
+
:morning => (6 * 60 * 60)..(12 * 60 * 60), # 6am-12am,
|
|
7
|
+
:afternoon => (13 * 60 * 60)..(17 * 60 * 60), # 1pm-5pm,
|
|
8
|
+
:evening => (17 * 60 * 60)..(20 * 60 * 60), # 5pm-8pm,
|
|
9
|
+
:night => (20 * 60 * 60)..(24 * 60 * 60), # 8pm-12pm
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
def initialize(type, options = {})
|
|
13
|
+
super
|
|
14
|
+
@current_span = nil
|
|
15
|
+
|
|
16
|
+
if type.kind_of? Integer
|
|
17
|
+
@range = (@type * 60 * 60)..((@type + 12) * 60 * 60)
|
|
18
|
+
else
|
|
19
|
+
@range = PORTIONS[type]
|
|
20
|
+
@range || raise("Invalid type '#{type}' for RepeaterDayPortion")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@range || raise("Range should have been set by now")
|
|
21
24
|
end
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
25
|
+
|
|
26
|
+
def next(pointer)
|
|
27
|
+
super
|
|
28
|
+
|
|
29
|
+
unless @current_span
|
|
30
|
+
now_seconds = @now - Chronic.construct(@now.year, @now.month, @now.day)
|
|
31
|
+
if now_seconds < @range.begin
|
|
32
|
+
case pointer
|
|
33
|
+
when :future
|
|
34
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
35
|
+
when :past
|
|
36
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day - 1) + @range.begin
|
|
37
|
+
end
|
|
38
|
+
elsif now_seconds > @range.end
|
|
39
|
+
case pointer
|
|
40
|
+
when :future
|
|
41
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day + 1) + @range.begin
|
|
42
|
+
when :past
|
|
43
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
case pointer
|
|
47
|
+
when :future
|
|
48
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day + 1) + @range.begin
|
|
49
|
+
when :past
|
|
50
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day - 1) + @range.begin
|
|
51
|
+
end
|
|
45
52
|
end
|
|
53
|
+
offset = (@range.end - @range.begin)
|
|
54
|
+
range_end = construct_date_from_reference_and_offset(range_start, offset)
|
|
55
|
+
@current_span = Span.new(range_start, range_end)
|
|
46
56
|
else
|
|
57
|
+
days_to_shift_window =
|
|
47
58
|
case pointer
|
|
48
59
|
when :future
|
|
49
|
-
|
|
60
|
+
1
|
|
50
61
|
when :past
|
|
51
|
-
|
|
62
|
+
-1
|
|
52
63
|
end
|
|
64
|
+
|
|
65
|
+
new_begin = Chronic.construct(@current_span.begin.year, @current_span.begin.month, @current_span.begin.day + days_to_shift_window, @current_span.begin.hour, @current_span.begin.min, @current_span.begin.sec)
|
|
66
|
+
new_end = Chronic.construct(@current_span.end.year, @current_span.end.month, @current_span.end.day + days_to_shift_window, @current_span.end.hour, @current_span.end.min, @current_span.end.sec)
|
|
67
|
+
@current_span = Span.new(new_begin, new_end)
|
|
53
68
|
end
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def this(context = :future)
|
|
72
|
+
super
|
|
73
|
+
|
|
74
|
+
range_start = Chronic.construct(@now.year, @now.month, @now.day) + @range.begin
|
|
75
|
+
range_end = construct_date_from_reference_and_offset(range_start)
|
|
76
|
+
@current_span = Span.new(range_start, range_end)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def offset(span, amount, pointer)
|
|
80
|
+
@now = span.begin
|
|
81
|
+
portion_span = self.next(pointer)
|
|
82
|
+
direction = pointer == :future ? 1 : -1
|
|
83
|
+
portion_span + (direction * (amount - 1) * RepeaterDay::DAY_SECONDS)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def width
|
|
87
|
+
@range || raise("Range has not been set")
|
|
88
|
+
return @current_span.width if @current_span
|
|
89
|
+
if @type.kind_of? Integer
|
|
90
|
+
return (12 * 60 * 60)
|
|
91
|
+
else
|
|
92
|
+
@range.end - @range.begin
|
|
62
93
|
end
|
|
63
94
|
end
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
direction = pointer == :future ? 1 : -1
|
|
77
|
-
portion_span + (direction * (amount - 1) * Chronic::RepeaterDay::DAY_SECONDS)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def width
|
|
81
|
-
@range || raise("Range has not been set")
|
|
82
|
-
return @current_span.width if @current_span
|
|
83
|
-
if @type.kind_of? Integer
|
|
84
|
-
return (12 * 60 * 60)
|
|
85
|
-
else
|
|
86
|
-
@range.end - @range.begin
|
|
95
|
+
|
|
96
|
+
def to_s
|
|
97
|
+
super << '-dayportion-' << @type.to_s
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
private
|
|
101
|
+
def construct_date_from_reference_and_offset(reference, offset = nil)
|
|
102
|
+
elapsed_seconds_for_range = offset || (@range.end - @range.begin)
|
|
103
|
+
second_hand = ((elapsed_seconds_for_range - (12 * 60))) % 60
|
|
104
|
+
minute_hand = (elapsed_seconds_for_range - second_hand) / (60) % 60
|
|
105
|
+
hour_hand = (elapsed_seconds_for_range - minute_hand - second_hand) / (60 * 60) + reference.hour % 24
|
|
106
|
+
Chronic.construct(reference.year, reference.month, reference.day, hour_hand, minute_hand, second_hand)
|
|
87
107
|
end
|
|
88
108
|
end
|
|
89
|
-
|
|
90
|
-
def to_s
|
|
91
|
-
super << '-dayportion-' << @type.to_s
|
|
92
|
-
end
|
|
93
|
-
end
|
|
109
|
+
end
|