slaxor-chronic 0.3.1
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.
- data/HISTORY.md +76 -0
- data/LICENSE +21 -0
- data/Manifest.txt +47 -0
- data/README.md +165 -0
- data/Rakefile +146 -0
- data/benchmark/benchmark.rb +13 -0
- data/lib/chronic.rb +127 -0
- data/lib/chronic/chronic.rb +249 -0
- data/lib/chronic/grabber.rb +26 -0
- data/lib/chronic/handlers.rb +524 -0
- data/lib/chronic/numerizer/numerizer.rb +97 -0
- data/lib/chronic/ordinal.rb +40 -0
- data/lib/chronic/pointer.rb +27 -0
- data/lib/chronic/repeater.rb +129 -0
- data/lib/chronic/repeaters/repeater_day.rb +52 -0
- data/lib/chronic/repeaters/repeater_day_name.rb +51 -0
- data/lib/chronic/repeaters/repeater_day_portion.rb +94 -0
- data/lib/chronic/repeaters/repeater_fortnight.rb +70 -0
- data/lib/chronic/repeaters/repeater_hour.rb +57 -0
- data/lib/chronic/repeaters/repeater_minute.rb +57 -0
- data/lib/chronic/repeaters/repeater_month.rb +66 -0
- data/lib/chronic/repeaters/repeater_month_name.rb +98 -0
- data/lib/chronic/repeaters/repeater_season.rb +150 -0
- data/lib/chronic/repeaters/repeater_season_name.rb +45 -0
- data/lib/chronic/repeaters/repeater_second.rb +41 -0
- data/lib/chronic/repeaters/repeater_time.rb +124 -0
- data/lib/chronic/repeaters/repeater_week.rb +73 -0
- data/lib/chronic/repeaters/repeater_weekday.rb +77 -0
- data/lib/chronic/repeaters/repeater_weekend.rb +65 -0
- data/lib/chronic/repeaters/repeater_year.rb +64 -0
- data/lib/chronic/scalar.rb +76 -0
- data/lib/chronic/separator.rb +91 -0
- data/lib/chronic/time_zone.rb +23 -0
- data/slaxor-chronic.gemspec +85 -0
- data/test/helper.rb +7 -0
- data/test/test_Chronic.rb +49 -0
- data/test/test_DaylightSavings.rb +118 -0
- data/test/test_Handler.rb +109 -0
- data/test/test_Numerizer.rb +51 -0
- data/test/test_RepeaterDayName.rb +51 -0
- data/test/test_RepeaterFortnight.rb +62 -0
- data/test/test_RepeaterHour.rb +64 -0
- data/test/test_RepeaterMinute.rb +34 -0
- data/test/test_RepeaterMonth.rb +46 -0
- data/test/test_RepeaterMonthName.rb +56 -0
- data/test/test_RepeaterTime.rb +70 -0
- data/test/test_RepeaterWeek.rb +62 -0
- data/test/test_RepeaterWeekday.rb +55 -0
- data/test/test_RepeaterWeekend.rb +74 -0
- data/test/test_RepeaterYear.rb +62 -0
- data/test/test_Span.rb +23 -0
- data/test/test_Time.rb +49 -0
- data/test/test_Token.rb +25 -0
- data/test/test_parsing.rb +710 -0
- metadata +138 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
|
3
|
+
class Numerizer
|
4
|
+
|
5
|
+
DIRECT_NUMS = [
|
6
|
+
['eleven', '11'],
|
7
|
+
['twelve', '12'],
|
8
|
+
['thirteen', '13'],
|
9
|
+
['fourteen', '14'],
|
10
|
+
['fifteen', '15'],
|
11
|
+
['sixteen', '16'],
|
12
|
+
['seventeen', '17'],
|
13
|
+
['eighteen', '18'],
|
14
|
+
['nineteen', '19'],
|
15
|
+
['ninteen', '19'], # Common mis-spelling
|
16
|
+
['zero', '0'],
|
17
|
+
['one', '1'],
|
18
|
+
['two', '2'],
|
19
|
+
['three', '3'],
|
20
|
+
['four(\W|$)', '4\1'], # The weird regex is so that it matches four but not fourty
|
21
|
+
['five', '5'],
|
22
|
+
['six(\W|$)', '6\1'],
|
23
|
+
['seven(\W|$)', '7\1'],
|
24
|
+
['eight(\W|$)', '8\1'],
|
25
|
+
['nine(\W|$)', '9\1'],
|
26
|
+
['ten', '10'],
|
27
|
+
['\ba[\b^$]', '1'] # doesn't make sense for an 'a' at the end to be a 1
|
28
|
+
]
|
29
|
+
|
30
|
+
TEN_PREFIXES = [ ['twenty', 20],
|
31
|
+
['thirty', 30],
|
32
|
+
['fourty', 40],
|
33
|
+
['fifty', 50],
|
34
|
+
['sixty', 60],
|
35
|
+
['seventy', 70],
|
36
|
+
['eighty', 80],
|
37
|
+
['ninety', 90]
|
38
|
+
]
|
39
|
+
|
40
|
+
BIG_PREFIXES = [ ['hundred', 100],
|
41
|
+
['thousand', 1000],
|
42
|
+
['million', 1_000_000],
|
43
|
+
['billion', 1_000_000_000],
|
44
|
+
['trillion', 1_000_000_000_000],
|
45
|
+
]
|
46
|
+
|
47
|
+
def self.numerize(string)
|
48
|
+
string = string.dup
|
49
|
+
|
50
|
+
# preprocess
|
51
|
+
string.gsub!(/ +|([^\d])-([^\d])/, '\1 \2') # will mutilate hyphenated-words but shouldn't matter for date extraction
|
52
|
+
string.gsub!(/a half/, 'haAlf') # take the 'a' out so it doesn't turn into a 1, save the half for the end
|
53
|
+
|
54
|
+
# easy/direct replacements
|
55
|
+
|
56
|
+
DIRECT_NUMS.each do |dn|
|
57
|
+
string.gsub!(/#{dn[0]}/i, '<num>' + dn[1])
|
58
|
+
end
|
59
|
+
|
60
|
+
# ten, twenty, etc.
|
61
|
+
|
62
|
+
TEN_PREFIXES.each do |tp|
|
63
|
+
string.gsub!(/(?:#{tp[0]}) *<num>(\d(?=[^\d]|$))*/i) { '<num>' + (tp[1] + $1.to_i).to_s }
|
64
|
+
end
|
65
|
+
|
66
|
+
TEN_PREFIXES.each do |tp|
|
67
|
+
string.gsub!(/#{tp[0]}/i) { '<num>' + tp[1].to_s }
|
68
|
+
end
|
69
|
+
|
70
|
+
# hundreds, thousands, millions, etc.
|
71
|
+
|
72
|
+
BIG_PREFIXES.each do |bp|
|
73
|
+
string.gsub!(/(?:<num>)?(\d*) *#{bp[0]}/i) { '<num>' + (bp[1] * $1.to_i).to_s}
|
74
|
+
andition(string)
|
75
|
+
end
|
76
|
+
|
77
|
+
# fractional addition
|
78
|
+
# I'm not combining this with the previous block as using float addition complicates the strings
|
79
|
+
# (with extraneous .0's and such )
|
80
|
+
string.gsub!(/(\d+)(?: | and |-)*haAlf/i) { ($1.to_f + 0.5).to_s }
|
81
|
+
|
82
|
+
string.gsub(/<num>/, '')
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def self.andition(string)
|
88
|
+
sc = StringScanner.new(string)
|
89
|
+
while(sc.scan_until(/<num>(\d+)( | and )<num>(\d+)(?=[^\w]|$)/i))
|
90
|
+
if sc[2] =~ /and/ || sc[1].size > sc[3].size
|
91
|
+
string[(sc.pos - sc.matched_size)..(sc.pos-1)] = '<num>' + (sc[1].to_i + sc[3].to_i).to_s
|
92
|
+
sc.reset
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Chronic
|
2
|
+
|
3
|
+
class Ordinal < Tag #:nodoc:
|
4
|
+
def self.scan(tokens)
|
5
|
+
# for each token
|
6
|
+
tokens.each_index do |i|
|
7
|
+
if t = self.scan_for_ordinals(tokens[i]) then tokens[i].tag(t) end
|
8
|
+
if t = self.scan_for_days(tokens[i]) then tokens[i].tag(t) end
|
9
|
+
end
|
10
|
+
tokens
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.scan_for_ordinals(token)
|
14
|
+
if token.word =~ /^(\d*)(st|nd|rd|th)$/
|
15
|
+
return Ordinal.new($1.to_i)
|
16
|
+
end
|
17
|
+
return nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.scan_for_days(token)
|
21
|
+
if token.word =~ /^(\d*)(st|nd|rd|th)$/
|
22
|
+
unless $1.to_i > 31 || $1.to_i < 1
|
23
|
+
return OrdinalDay.new(token.word.to_i)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
return nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
'ordinal'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class OrdinalDay < Ordinal #:nodoc:
|
35
|
+
def to_s
|
36
|
+
super << '-day-' << @type.to_s
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Chronic
|
2
|
+
|
3
|
+
class Pointer < Tag #:nodoc:
|
4
|
+
def self.scan(tokens)
|
5
|
+
# for each token
|
6
|
+
tokens.each_index do |i|
|
7
|
+
if t = self.scan_for_all(tokens[i]) then tokens[i].tag(t) end
|
8
|
+
end
|
9
|
+
tokens
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.scan_for_all(token)
|
13
|
+
scanner = {/\bpast\b/ => :past,
|
14
|
+
/\bfuture\b/ => :future,
|
15
|
+
/\bin\b/ => :future}
|
16
|
+
scanner.keys.each do |scanner_item|
|
17
|
+
return self.new(scanner[scanner_item]) if scanner_item =~ token.word
|
18
|
+
end
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
'pointer-' << @type.to_s
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
class Chronic::Repeater < Chronic::Tag #:nodoc:
|
2
|
+
def self.scan(tokens, options)
|
3
|
+
# for each token
|
4
|
+
tokens.each_index do |i|
|
5
|
+
if t = self.scan_for_season_names(tokens[i]) then tokens[i].tag(t); next end
|
6
|
+
if t = self.scan_for_month_names(tokens[i]) then tokens[i].tag(t); next end
|
7
|
+
if t = self.scan_for_day_names(tokens[i]) then tokens[i].tag(t); next end
|
8
|
+
if t = self.scan_for_day_portions(tokens[i]) then tokens[i].tag(t); next end
|
9
|
+
if t = self.scan_for_times(tokens[i], options) then tokens[i].tag(t); next end
|
10
|
+
if t = self.scan_for_units(tokens[i]) then tokens[i].tag(t); next end
|
11
|
+
end
|
12
|
+
tokens
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.scan_for_season_names(token)
|
16
|
+
scanner = {/^springs?$/ => :spring,
|
17
|
+
/^summers?$/ => :summer,
|
18
|
+
/^(autumn)|(fall)s?$/ => :autumn,
|
19
|
+
/^winters?$/ => :winter}
|
20
|
+
scanner.keys.each do |scanner_item|
|
21
|
+
return Chronic::RepeaterSeasonName.new(scanner[scanner_item]) if scanner_item =~ token.word
|
22
|
+
end
|
23
|
+
|
24
|
+
return nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.scan_for_month_names(token)
|
28
|
+
scanner = {/^jan\.?(uary)?$/ => :january,
|
29
|
+
/^feb\.?(ruary)?$/ => :february,
|
30
|
+
/^mar\.?(ch)?$/ => :march,
|
31
|
+
/^apr\.?(il)?$/ => :april,
|
32
|
+
/^may$/ => :may,
|
33
|
+
/^jun\.?e?$/ => :june,
|
34
|
+
/^jul\.?y?$/ => :july,
|
35
|
+
/^aug\.?(ust)?$/ => :august,
|
36
|
+
/^sep\.?(t\.?|tember)?$/ => :september,
|
37
|
+
/^oct\.?(ober)?$/ => :october,
|
38
|
+
/^nov\.?(ember)?$/ => :november,
|
39
|
+
/^dec\.?(ember)?$/ => :december}
|
40
|
+
scanner.keys.each do |scanner_item|
|
41
|
+
return Chronic::RepeaterMonthName.new(scanner[scanner_item]) if scanner_item =~ token.word
|
42
|
+
end
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.scan_for_day_names(token)
|
47
|
+
scanner = {/^m[ou]n(day)?$/ => :monday,
|
48
|
+
/^t(ue|eu|oo|u|)s(day)?$/ => :tuesday,
|
49
|
+
/^tue$/ => :tuesday,
|
50
|
+
/^we(dnes|nds|nns)day$/ => :wednesday,
|
51
|
+
/^wed$/ => :wednesday,
|
52
|
+
/^th(urs|ers)day$/ => :thursday,
|
53
|
+
/^thu$/ => :thursday,
|
54
|
+
/^fr[iy](day)?$/ => :friday,
|
55
|
+
/^sat(t?[ue]rday)?$/ => :saturday,
|
56
|
+
/^su[nm](day)?$/ => :sunday}
|
57
|
+
scanner.keys.each do |scanner_item|
|
58
|
+
return Chronic::RepeaterDayName.new(scanner[scanner_item]) if scanner_item =~ token.word
|
59
|
+
end
|
60
|
+
return nil
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.scan_for_day_portions(token)
|
64
|
+
scanner = {/^ams?$/ => :am,
|
65
|
+
/^pms?$/ => :pm,
|
66
|
+
/^mornings?$/ => :morning,
|
67
|
+
/^afternoons?$/ => :afternoon,
|
68
|
+
/^evenings?$/ => :evening,
|
69
|
+
/^(night|nite)s?$/ => :night}
|
70
|
+
scanner.keys.each do |scanner_item|
|
71
|
+
return Chronic::RepeaterDayPortion.new(scanner[scanner_item]) if scanner_item =~ token.word
|
72
|
+
end
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.scan_for_times(token, options)
|
77
|
+
if token.word =~ /^\d{1,2}(:?\d{2})?([\.:]?\d{2})?$/
|
78
|
+
return Chronic::RepeaterTime.new(token.word, options)
|
79
|
+
end
|
80
|
+
return nil
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.scan_for_units(token)
|
84
|
+
scanner = {/^years?$/ => :year,
|
85
|
+
/^seasons?$/ => :season,
|
86
|
+
/^months?$/ => :month,
|
87
|
+
/^fortnights?$/ => :fortnight,
|
88
|
+
/^weeks?$/ => :week,
|
89
|
+
/^weekends?$/ => :weekend,
|
90
|
+
/^(week|business)days?$/ => :weekday,
|
91
|
+
/^days?$/ => :day,
|
92
|
+
/^hours?$/ => :hour,
|
93
|
+
/^minutes?$/ => :minute,
|
94
|
+
/^seconds?$/ => :second}
|
95
|
+
scanner.keys.each do |scanner_item|
|
96
|
+
if scanner_item =~ token.word
|
97
|
+
klass_name = 'Chronic::Repeater' + scanner[scanner_item].to_s.capitalize
|
98
|
+
klass = eval(klass_name)
|
99
|
+
return klass.new(scanner[scanner_item])
|
100
|
+
end
|
101
|
+
end
|
102
|
+
return nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def <=>(other)
|
106
|
+
width <=> other.width
|
107
|
+
end
|
108
|
+
|
109
|
+
# returns the width (in seconds or months) of this repeatable.
|
110
|
+
def width
|
111
|
+
raise("Repeatable#width must be overridden in subclasses")
|
112
|
+
end
|
113
|
+
|
114
|
+
# returns the next occurance of this repeatable.
|
115
|
+
def next(pointer)
|
116
|
+
!@now.nil? || raise("Start point must be set before calling #next")
|
117
|
+
[:future, :none, :past].include?(pointer) || raise("First argument 'pointer' must be one of :past or :future")
|
118
|
+
#raise("Repeatable#next must be overridden in subclasses")
|
119
|
+
end
|
120
|
+
|
121
|
+
def this(pointer)
|
122
|
+
!@now.nil? || raise("Start point must be set before calling #this")
|
123
|
+
[:future, :past, :none].include?(pointer) || raise("First argument 'pointer' must be one of :past, :future, :none")
|
124
|
+
end
|
125
|
+
|
126
|
+
def to_s
|
127
|
+
'repeater'
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Chronic::RepeaterDay < Chronic::Repeater #:nodoc:
|
2
|
+
DAY_SECONDS = 86_400 # (24 * 60 * 60)
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@current_day_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer)
|
10
|
+
super
|
11
|
+
|
12
|
+
if !@current_day_start
|
13
|
+
@current_day_start = Chronic.time_class.local(@now.year, @now.month, @now.day)
|
14
|
+
end
|
15
|
+
|
16
|
+
direction = pointer == :future ? 1 : -1
|
17
|
+
@current_day_start += direction * DAY_SECONDS
|
18
|
+
|
19
|
+
Chronic::Span.new(@current_day_start, @current_day_start + DAY_SECONDS)
|
20
|
+
end
|
21
|
+
|
22
|
+
def this(pointer = :future)
|
23
|
+
super
|
24
|
+
|
25
|
+
case pointer
|
26
|
+
when :future
|
27
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day, @now.hour + 1)
|
28
|
+
day_end = Time.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
29
|
+
when :past
|
30
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day)
|
31
|
+
day_end = Time.construct(@now.year, @now.month, @now.day, @now.hour)
|
32
|
+
when :none
|
33
|
+
day_begin = Time.construct(@now.year, @now.month, @now.day)
|
34
|
+
day_end = Time.construct(@now.year, @now.month, @now.day) + DAY_SECONDS
|
35
|
+
end
|
36
|
+
|
37
|
+
Chronic::Span.new(day_begin, day_end)
|
38
|
+
end
|
39
|
+
|
40
|
+
def offset(span, amount, pointer)
|
41
|
+
direction = pointer == :future ? 1 : -1
|
42
|
+
span + direction * amount * DAY_SECONDS
|
43
|
+
end
|
44
|
+
|
45
|
+
def width
|
46
|
+
DAY_SECONDS
|
47
|
+
end
|
48
|
+
|
49
|
+
def to_s
|
50
|
+
super << '-day'
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Chronic::RepeaterDayName < Chronic::Repeater #:nodoc:
|
2
|
+
DAY_SECONDS = 86400 # (24 * 60 * 60)
|
3
|
+
|
4
|
+
def initialize(type)
|
5
|
+
super
|
6
|
+
@current_day_start = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def next(pointer)
|
10
|
+
super
|
11
|
+
|
12
|
+
direction = pointer == :future ? 1 : -1
|
13
|
+
|
14
|
+
if !@current_day_start
|
15
|
+
@current_day_start = Time.construct(@now.year, @now.month, @now.day)
|
16
|
+
@current_day_start += direction * DAY_SECONDS
|
17
|
+
|
18
|
+
day_num = symbol_to_number(@type)
|
19
|
+
|
20
|
+
while @current_day_start.wday != day_num
|
21
|
+
@current_day_start += direction * DAY_SECONDS
|
22
|
+
end
|
23
|
+
else
|
24
|
+
@current_day_start += direction * 7 * DAY_SECONDS
|
25
|
+
end
|
26
|
+
|
27
|
+
Chronic::Span.new(@current_day_start, @current_day_start + DAY_SECONDS)
|
28
|
+
end
|
29
|
+
|
30
|
+
def this(pointer = :future)
|
31
|
+
super
|
32
|
+
|
33
|
+
pointer = :future if pointer == :none
|
34
|
+
self.next(pointer)
|
35
|
+
end
|
36
|
+
|
37
|
+
def width
|
38
|
+
DAY_SECONDS
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_s
|
42
|
+
super << '-dayname-' << @type.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def symbol_to_number(sym)
|
48
|
+
lookup = {:sunday => 0, :monday => 1, :tuesday => 2, :wednesday => 3, :thursday => 4, :friday => 5, :saturday => 6}
|
49
|
+
lookup[sym] || raise("Invalid symbol specified")
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
class Chronic::RepeaterDayPortion < Chronic::Repeater #:nodoc:
|
2
|
+
@@morning = (6 * 60 * 60)..(12 * 60 * 60) # 6am-12am
|
3
|
+
@@afternoon = (13 * 60 * 60)..(17 * 60 * 60) # 1pm-5pm
|
4
|
+
@@evening = (17 * 60 * 60)..(20 * 60 * 60) # 5pm-8pm
|
5
|
+
@@night = (20 * 60 * 60)..(24 * 60 * 60) # 8pm-12pm
|
6
|
+
|
7
|
+
def initialize(type)
|
8
|
+
super
|
9
|
+
@current_span = nil
|
10
|
+
|
11
|
+
if type.kind_of? Integer
|
12
|
+
@range = (@type * 60 * 60)..((@type + 12) * 60 * 60)
|
13
|
+
else
|
14
|
+
lookup = {:am => 0..(12 * 60 * 60 - 1),
|
15
|
+
:pm => (12 * 60 * 60)..(24 * 60 * 60 - 1),
|
16
|
+
:morning => @@morning,
|
17
|
+
:afternoon => @@afternoon,
|
18
|
+
:evening => @@evening,
|
19
|
+
:night => @@night}
|
20
|
+
@range = lookup[type]
|
21
|
+
lookup[type] || raise("Invalid type '#{type}' for RepeaterDayPortion")
|
22
|
+
end
|
23
|
+
@range || raise("Range should have been set by now")
|
24
|
+
end
|
25
|
+
|
26
|
+
def next(pointer)
|
27
|
+
super
|
28
|
+
|
29
|
+
full_day = 60 * 60 * 24
|
30
|
+
|
31
|
+
if !@current_span
|
32
|
+
now_seconds = @now - Time.construct(@now.year, @now.month, @now.day)
|
33
|
+
if now_seconds < @range.begin
|
34
|
+
case pointer
|
35
|
+
when :future
|
36
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
37
|
+
when :past
|
38
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) - full_day + @range.begin
|
39
|
+
end
|
40
|
+
elsif now_seconds > @range.end
|
41
|
+
case pointer
|
42
|
+
when :future
|
43
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + full_day + @range.begin
|
44
|
+
when :past
|
45
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
46
|
+
end
|
47
|
+
else
|
48
|
+
case pointer
|
49
|
+
when :future
|
50
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + full_day + @range.begin
|
51
|
+
when :past
|
52
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) - full_day + @range.begin
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@current_span = Chronic::Span.new(range_start, range_start + (@range.end - @range.begin))
|
57
|
+
else
|
58
|
+
case pointer
|
59
|
+
when :future
|
60
|
+
@current_span += full_day
|
61
|
+
when :past
|
62
|
+
@current_span -= full_day
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def this(context = :future)
|
68
|
+
super
|
69
|
+
|
70
|
+
range_start = Time.construct(@now.year, @now.month, @now.day) + @range.begin
|
71
|
+
@current_span = Chronic::Span.new(range_start, range_start + (@range.end - @range.begin))
|
72
|
+
end
|
73
|
+
|
74
|
+
def offset(span, amount, pointer)
|
75
|
+
@now = span.begin
|
76
|
+
portion_span = self.next(pointer)
|
77
|
+
direction = pointer == :future ? 1 : -1
|
78
|
+
portion_span + (direction * (amount - 1) * Chronic::RepeaterDay::DAY_SECONDS)
|
79
|
+
end
|
80
|
+
|
81
|
+
def width
|
82
|
+
@range || raise("Range has not been set")
|
83
|
+
return @current_span.width if @current_span
|
84
|
+
if @type.kind_of? Integer
|
85
|
+
return (12 * 60 * 60)
|
86
|
+
else
|
87
|
+
@range.end - @range.begin
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def to_s
|
92
|
+
super << '-dayportion-' << @type.to_s
|
93
|
+
end
|
94
|
+
end
|