scheduled_resource 0.0.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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +136 -0
- data/Rakefile +2 -0
- data/bin/schedulize +173 -0
- data/lib/assets/javascripts/blank.jpg +0 -0
- data/lib/assets/javascripts/justify_tweaks.js +186 -0
- data/lib/assets/javascripts/time_pix.js.coffee +103 -0
- data/lib/assets/javascripts/use_block.js.coffee +131 -0
- data/lib/assets/stylesheets/scheduled_resource.css.scss +250 -0
- data/lib/scheduled_resource.rb +262 -0
- data/lib/scheduled_resource/helper.rb +65 -0
- data/lib/scheduled_resource/resource_use_block.rb +33 -0
- data/lib/scheduled_resource/version.rb +3 -0
- data/lib/z_time_header.rb +20 -0
- data/lib/z_time_header_day.rb +16 -0
- data/lib/z_time_header_hour.rb +15 -0
- data/lib/z_time_label.rb +88 -0
- data/lib/z_time_label_day.rb +23 -0
- data/lib/z_time_label_hour.rb +26 -0
- data/scheduled_resource.gemspec +25 -0
- metadata +178 -0
@@ -0,0 +1,262 @@
|
|
1
|
+
# scheduled_resource.rb
|
2
|
+
# Copyright (c) 2008-2015 Mike Cannon (michael.j.cannon@gmail.com)
|
3
|
+
# (http://github.com/emeyekayee/scheduled_resource)
|
4
|
+
# MIT License.
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'scheduled_resource/version'
|
8
|
+
require 'scheduled_resource/resource_use_block'
|
9
|
+
require 'scheduled_resource/helper'
|
10
|
+
|
11
|
+
require 'z_time_header'
|
12
|
+
require 'z_time_header_day'
|
13
|
+
require 'z_time_header_hour'
|
14
|
+
require 'z_time_label'
|
15
|
+
require 'z_time_label_day'
|
16
|
+
require 'z_time_label_hour'
|
17
|
+
|
18
|
+
# A "scheduled resource" is something that can be used for one thing at a time.
|
19
|
+
#
|
20
|
+
# Example: A Room (resource) is scheduled for a meeting (resource use block)
|
21
|
+
# titled "Weekly Staff Meeting" tomorrow from 9am to 11am.
|
22
|
+
#
|
23
|
+
# Class SchedResource manages class names, id's and labels for a
|
24
|
+
# schedule. An instance ties together:
|
25
|
+
#
|
26
|
+
# 1. A resource class (eg Room),
|
27
|
+
# 2. An id, and
|
28
|
+
# 3. Strings / html snippets (eg, label, title) for the DOM.
|
29
|
+
#
|
30
|
+
# The id (2 above) is used to
|
31
|
+
#
|
32
|
+
# a) select a resource <em>instance</em> and
|
33
|
+
#
|
34
|
+
# b) select instances of the <em>resource use block</em> class (eg Meeting).
|
35
|
+
#
|
36
|
+
# The id <em>may</em> be a database id but need not be.
|
37
|
+
# It is used by class methods
|
38
|
+
# <tt>get_all_blocks()</tt> of model use-block classes.
|
39
|
+
# Not tying this to a database id allows a little extra flexibility in
|
40
|
+
# configuration.
|
41
|
+
#
|
42
|
+
# Items 1 and 2 are are combined (with a '_') to form "tags" (ids) for the DOM.
|
43
|
+
#
|
44
|
+
# See also: ResourceUseBlock.
|
45
|
+
#
|
46
|
+
#--
|
47
|
+
# Config is loaded from config/schedule.yml:
|
48
|
+
# all_resources:: Resources in display order.
|
49
|
+
# rsrcs_by_kind:: A hash with resources grouped by kind (resource class).
|
50
|
+
# rsrc_of_tag:: Indexed by text tag: kind_subid.
|
51
|
+
# \visible_time:: Span of time window.
|
52
|
+
#++
|
53
|
+
#
|
54
|
+
# When queried with an array of ids and a time interval, the class
|
55
|
+
# method <tt>get_all_blocks(ids, t1, t2)</tt> of a <em>resource use</em>
|
56
|
+
# model returns a list of "use blocks", each with a starttime, endtime
|
57
|
+
# and descriptions of that use.
|
58
|
+
#
|
59
|
+
# This method invokes that method on each of the <em>resource use</em>
|
60
|
+
# classes. It returns a hash where:
|
61
|
+
# Key is a Resource (rsrc);
|
62
|
+
# Value is an array of use-block instances (rubs).
|
63
|
+
#
|
64
|
+
class ScheduledResource
|
65
|
+
|
66
|
+
CONFIG_FILE = "config/resource_schedule.yml"
|
67
|
+
|
68
|
+
class_attribute :config
|
69
|
+
|
70
|
+
# (SchedResource protocol) Returns a hash where each key is an
|
71
|
+
# <tt>rid</tt> and the value is an array of resource use
|
72
|
+
# blocks in the interval <tt>t1...t2</tt>, ordered by
|
73
|
+
# <tt>starttime</tt>.
|
74
|
+
#
|
75
|
+
# What <em>in</em> means depends on <em>inc</em>. If inc(remental) is
|
76
|
+
# false, the client is building the interval from scratch. If "hi", it is
|
77
|
+
# an addition to an existing interval on the high side. Similarly
|
78
|
+
# for "lo". This is to avoid re-transmitting blocks that span the
|
79
|
+
# current time boundaries on the client.
|
80
|
+
#
|
81
|
+
# Here the resource is a channel and the use blocks are programs.
|
82
|
+
#
|
83
|
+
# ==== Parameters
|
84
|
+
# * <tt>rids</tt> - A list of schedules resource ids (strings).
|
85
|
+
# * <tt>t1</tt> - Start time.
|
86
|
+
# * <tt>t2</tt> - End time.
|
87
|
+
# * <tt>inc</tt> - One of nil, "lo", "hi" (See above).
|
88
|
+
#
|
89
|
+
# ==== Returns
|
90
|
+
# * <tt>Hash</tt> - Each key is an <tt>rid</tt> and the value is an array of resource use blocks in the interval, ordered by <tt>starttime</tt>.
|
91
|
+
def self.get_all_blocks(t1, t2, inc)
|
92
|
+
blockss = {}
|
93
|
+
|
94
|
+
config[:rsrcs_by_kind].each do |kind, rsrcs|
|
95
|
+
rub_class = block_class_for_resource_name kind
|
96
|
+
rids = rsrcs.map{ |r| r.sub_id }
|
97
|
+
ru_blkss = rub_class.get_all_blocks rids, t1, t2, inc
|
98
|
+
|
99
|
+
add_rubs_of_kind kind, ru_blkss, blockss
|
100
|
+
end
|
101
|
+
|
102
|
+
blockss
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
# ==== Parameters
|
107
|
+
# * <tt>name</tt> - The class name (string) of a schedule resource.
|
108
|
+
#
|
109
|
+
# ==== Returns
|
110
|
+
# * <tt>Class</tt> - The class representing the <em>use</em> of that resource for an interval of time.
|
111
|
+
def self.block_class_for_resource_name( name )
|
112
|
+
config[:block_class_for_resource_kind][name]
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# ==== Returns
|
117
|
+
# * <tt>Array[SchedResource]</tt> - List of all configured SchedResources .
|
118
|
+
def self.resource_list; config[:all_resources] end
|
119
|
+
|
120
|
+
# ==== Returns
|
121
|
+
# * <tt>Time</tt> - The configured width of the visible time window.
|
122
|
+
def self.visible_time; config[:visible_time] end
|
123
|
+
|
124
|
+
|
125
|
+
#--
|
126
|
+
# Restore configuration from session.
|
127
|
+
#
|
128
|
+
# When we depend on data in the configuration to satisfy a query we are not
|
129
|
+
# being RESTful. On the other hand we are not maintaining changeable state
|
130
|
+
# here -- it's just a cache. If there <em>were</em> changeable state it
|
131
|
+
# would likely be kept, eg, in a per-user table in the database.
|
132
|
+
#++
|
133
|
+
def self.ensure_config( session ) # :nodoc:
|
134
|
+
return if (self.config ||= session[:schedule_config])
|
135
|
+
|
136
|
+
config_from_yaml( session )
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# ToDo: Generalize this so configuration can be loaded on per-user.
|
141
|
+
# Process configuration file.
|
142
|
+
def self.config_from_yaml( session )
|
143
|
+
config_from_yaml1
|
144
|
+
config_from_yaml2 session
|
145
|
+
config
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
private
|
150
|
+
# A caching one-of-each-sort constructor.
|
151
|
+
#
|
152
|
+
# ==== Parameters
|
153
|
+
# * <tt>kind</tt> - Class name (string) of a scheduled resource.
|
154
|
+
# * <tt>sub_id</tt> - Id (string), selecting a resource instance. The two are combined and used as a unique tag in the DOM as id and class attributes as well as in server code.
|
155
|
+
def self.get_for( kind, sub_id )
|
156
|
+
tag = compose_tag( kind, sub_id )
|
157
|
+
config[:rsrc_of_tag][ tag ] || self.new( kind, sub_id )
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.compose_tag( kind, sub_id ); "#{kind}_#{sub_id}" end
|
161
|
+
|
162
|
+
def self.config_from_yaml1()
|
163
|
+
self.config = { all_resources: [],
|
164
|
+
rsrc_of_tag: {},
|
165
|
+
block_class_for_resource_kind: {}
|
166
|
+
}
|
167
|
+
yml = YAML.load_file CONFIG_FILE
|
168
|
+
|
169
|
+
yml['ResourceKinds'].each do |key, val| # {"Channel" => <#Class Program>...}
|
170
|
+
config[:block_class_for_resource_kind][key] = eval val
|
171
|
+
end
|
172
|
+
|
173
|
+
if (rkls = yml['Resources']) # Resource Kind Lists, eg
|
174
|
+
rkls.each do |rkl| # ["TimeheaderHour", "Hour0"]
|
175
|
+
rkl = rkl.split(/[, ]+/) # ["Channel", "702", "703",... ]
|
176
|
+
rk = rkl.shift
|
177
|
+
add_resources rkl.map{ |sub_id| make_resource_of_kind(rk, sub_id) }
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
vt = yml['visibleTime']
|
182
|
+
config[:visible_time] = vt ? (eval vt) : 3.hours
|
183
|
+
|
184
|
+
t0 = yml['timeRangeMin']
|
185
|
+
config[:time_range_min] = t0 ? (eval t0) : (Time.now - 1.week)
|
186
|
+
|
187
|
+
tn = yml['timeRangeMax']
|
188
|
+
config[:time_range_max] = tn ? (eval tn) : (Time.now - 1.week)
|
189
|
+
|
190
|
+
config
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
def self.add_resources(rsrcs)
|
195
|
+
rs = config[:all_resources]
|
196
|
+
rsrcs.each{ |rsrc| rs.include?( rsrc ) || rs << rsrc }
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
def self.config_from_yaml2( session )
|
201
|
+
config[:rsrcs_by_kind] = resource_list.group_by{ |r| r.kind }
|
202
|
+
|
203
|
+
config[:rsrcs_by_kind].each do |kind, rsrcs|
|
204
|
+
klass = kind.constantize
|
205
|
+
rsrcs.each {|rsrc| klass.decorate_resource rsrc }
|
206
|
+
end
|
207
|
+
|
208
|
+
session[:schedule_config] = config
|
209
|
+
end
|
210
|
+
|
211
|
+
def self.make_resource_of_kind( klass, rid )
|
212
|
+
klass = eval klass if klass.class == String
|
213
|
+
get_for( klass.name, rid )
|
214
|
+
end
|
215
|
+
|
216
|
+
def self.add_rubs_of_kind( kind, ru_blkss, blockss )
|
217
|
+
ru_blkss.each do |rid, blks|
|
218
|
+
rsrc = get_for( kind, rid )
|
219
|
+
rubs = blks.map{ |blk| ResourceUseBlock.new rsrc, blk }
|
220
|
+
blockss[ rsrc ] = rubs
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
public
|
226
|
+
|
227
|
+
# Instance methods
|
228
|
+
def initialize( kind, sub_id ) # :nodoc:
|
229
|
+
@tag = self.class.send( :compose_tag, kind, sub_id )
|
230
|
+
@label = @title = nil
|
231
|
+
config[:rsrc_of_tag][@tag] = self
|
232
|
+
end
|
233
|
+
|
234
|
+
# ==== Returns
|
235
|
+
# * <tt>String</tt> - The class name of the scheduled resource.
|
236
|
+
def kind() @tag.sub( /_.*/, '' ) end
|
237
|
+
|
238
|
+
# ==== Returns
|
239
|
+
# * <tt>String</tt> - The <tt>rid</tt> (abstract id) of the SchedResource.
|
240
|
+
def sub_id() @tag.sub( /.*_/, '' ) end
|
241
|
+
|
242
|
+
def to_s() # :nodoc:
|
243
|
+
@tag
|
244
|
+
end
|
245
|
+
|
246
|
+
def inspect() # :nodoc:
|
247
|
+
"<#SchedResource \"#{@tag}\">"
|
248
|
+
end
|
249
|
+
|
250
|
+
attr_accessor :label, :title
|
251
|
+
def label(); @label || @tag end
|
252
|
+
|
253
|
+
def label=(val)
|
254
|
+
@label = val
|
255
|
+
end
|
256
|
+
|
257
|
+
def title(); @title || @tag end
|
258
|
+
|
259
|
+
# ==== Returns
|
260
|
+
# * <tt>String</tt> - CSS classes automatically generated for the DOM row representing this SchedResource.
|
261
|
+
def css_classes_for_row(); "rsrcRow #{self.kind}row #{@tag}row #{self.kind}Row #{@tag}Row" end # Row + row -- really?
|
262
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# Using ScheduledResource as a module here for namespacing (in transition).
|
2
|
+
class ScheduledResource
|
3
|
+
|
4
|
+
module Helper
|
5
|
+
|
6
|
+
def ensure_schedule_config
|
7
|
+
meth = params[:reset] ? :config_from_yaml : :ensure_config
|
8
|
+
ScheduledResource.send( meth, session )
|
9
|
+
end
|
10
|
+
|
11
|
+
def default_time_param
|
12
|
+
t_now = Time.now
|
13
|
+
t_now.change :min => (t_now.min/15) * 15
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_schedule_query_params(p = params)
|
17
|
+
@t1 = p[:t1] || default_time_param
|
18
|
+
@t2 = p[:t2] || @t1 + ScheduledResource.visible_time
|
19
|
+
@inc= p[:inc]
|
20
|
+
end
|
21
|
+
|
22
|
+
# Set up instance variables for render templates or returned json
|
23
|
+
# params: @t1: time-inverval start
|
24
|
+
# @t2: time-inverval end
|
25
|
+
# @inc: incremental update? One of: nil, 'lo', 'hi'
|
26
|
+
#
|
27
|
+
# creates: @rsrcs ordered resource list
|
28
|
+
# @blockss: lists of use-blocks, keyed by resource
|
29
|
+
def get_data_for_time_span()
|
30
|
+
set_schedule_query_params
|
31
|
+
|
32
|
+
@t1 = Time.at(@t1.to_i)
|
33
|
+
@t2 = Time.at(@t2.to_i)
|
34
|
+
|
35
|
+
@rsrcs = ScheduledResource.resource_list
|
36
|
+
|
37
|
+
@blockss = ScheduledResource.get_all_blocks(@t1, @t2, @inc)
|
38
|
+
|
39
|
+
json_adjustments
|
40
|
+
end
|
41
|
+
|
42
|
+
def min_time; ScheduledResource.config[:time_range_min].to_i end
|
43
|
+
def max_time; ScheduledResource.config[:time_range_max].to_i end
|
44
|
+
|
45
|
+
# Always send starttime/endtime attributes as Integer values (UTC) -- they are
|
46
|
+
# used to size and place the blocks. Timezone is configured separately in the
|
47
|
+
# ZTime* classes (config/resource_schedule.yml).
|
48
|
+
def json_adjustments
|
49
|
+
@blockss.each do |rsrc, blocks|
|
50
|
+
blocks.each do |block|
|
51
|
+
block.starttime = block.starttime.to_i
|
52
|
+
block.endtime = block.endtime.to_i
|
53
|
+
end
|
54
|
+
end
|
55
|
+
@blockss['meta'] = {
|
56
|
+
rsrcs: @rsrcs, min_time: min_time, max_time: max_time,
|
57
|
+
t1: @t1.to_i, t2: @t2.to_i, inc: @inc,
|
58
|
+
}
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# Using ScheduledResource as a module here for namespacing (in transition).
|
2
|
+
class ScheduledResource
|
3
|
+
|
4
|
+
# ResourceUseBlock
|
5
|
+
#
|
6
|
+
# Represents the USE of a resource for an interval of time.
|
7
|
+
#
|
8
|
+
# Resource X UseModel X [startime..endtime];
|
9
|
+
# | | Example -- tv:
|
10
|
+
# | | Program [ belongs_to :channel ]
|
11
|
+
# | | Timelabel [ belongs_to :timeheader ]
|
12
|
+
# |
|
13
|
+
# | Example -- tv: Channel, TimeHeader
|
14
|
+
#
|
15
|
+
class ResourceUseBlock
|
16
|
+
|
17
|
+
delegate :kind, :to => :@rsrc
|
18
|
+
|
19
|
+
delegate :starttime=, :endtime=,
|
20
|
+
:starttime, :endtime,
|
21
|
+
# No longer used by view templates...
|
22
|
+
# :title, :subtitle, :description, :stars,
|
23
|
+
# :airdate, :category, :previouslyshown,
|
24
|
+
:to => :@blk
|
25
|
+
|
26
|
+
def initialize(rsrc, blk)
|
27
|
+
@rsrc = rsrc
|
28
|
+
@blk = blk
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This is a base for ScheduledResource classes (see below) for timezone-aware time
|
2
|
+
# headers. The timezone is specified by the last component of the resource id
|
3
|
+
# (rid). Eg, for 'Day_-8' the timezone is ActiveSupport::TimeZone.new(-8)
|
4
|
+
|
5
|
+
|
6
|
+
class ZTimeHeader
|
7
|
+
|
8
|
+
# (For ScheduledResource protocol) This method lets us set display attributes
|
9
|
+
# on the instance in a way specific to the resource-class and rid.
|
10
|
+
#
|
11
|
+
# ==== Parameters
|
12
|
+
# * <tt>rsrc</tt> - A ScheduledResource instance.
|
13
|
+
def self.decorate_resource( rsrc )
|
14
|
+
rid = rsrc.sub_id
|
15
|
+
|
16
|
+
rsrc.label = 'Time' # Overridden, presumably
|
17
|
+
rsrc.title = rid
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
class ZTimeHeaderDay < ZTimeHeader
|
3
|
+
|
4
|
+
# (For ScheduledResource protocol) This method lets us set display attributes
|
5
|
+
# on the instance in a way specific to the resource-class and rid.
|
6
|
+
#
|
7
|
+
# ==== Parameters
|
8
|
+
# * <tt>rsrc</tt> - A ScheduledResource instance.
|
9
|
+
def self.decorate_resource( rsrc )
|
10
|
+
rid = rsrc.sub_id
|
11
|
+
|
12
|
+
rsrc.label = "Day"
|
13
|
+
rsrc.title = rid
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class ZTimeHeaderHour < ZTimeHeader
|
2
|
+
|
3
|
+
# (For ScheduledResource protocol) This method lets us set display attributes
|
4
|
+
# on the instance in a way specific to the resource-class and rid.
|
5
|
+
#
|
6
|
+
# ==== Parameters
|
7
|
+
# * <tt>rsrc</tt> - A ScheduledResource instance.
|
8
|
+
def self.decorate_resource( rsrc )
|
9
|
+
rid = rsrc.sub_id
|
10
|
+
|
11
|
+
rsrc.label = "Hour"
|
12
|
+
rsrc.title = rid
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/z_time_label.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
# For ScheduledResource protocol. This is a base UseBlock class for ZTimeHeader
|
2
|
+
# use-block subclasses. These are timezone-aware time headers (rows) and labels
|
3
|
+
# (use-blocks). The timezone is specified by the last component of the resource
|
4
|
+
# id (rid). Eg, for '-8' the timezone is ActiveSupport::TimeZone.new(-8)
|
5
|
+
|
6
|
+
class ZTimeLabel
|
7
|
+
attr_accessor :starttime, :endtime, :css_classes, :title
|
8
|
+
|
9
|
+
class_attribute :label, :format, :t_block # t_block (if used) set by subclass
|
10
|
+
|
11
|
+
# Parameters are TimeWithZone or similar
|
12
|
+
def initialize( starttime, endtime )
|
13
|
+
@starttime, @endtime = starttime, endtime
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# (ScheduledResource protocol) Returns a hash where each key is an
|
18
|
+
# <tt>rid</tt> and the value is an array of ZTimeLabels (use
|
19
|
+
# blocks) in the interval <tt>t1...t2</tt>, ordered by
|
20
|
+
# <tt>starttime</tt>.
|
21
|
+
#
|
22
|
+
# What <em>in</em> means depends on *inc*. If inc(remental) is
|
23
|
+
# nil/false, client is building the interval from scratch. If "hi", it is
|
24
|
+
# an addition to an existing interval on the high side. Similarly
|
25
|
+
# for "lo". This is to avoid re-transmitting blocks that span the
|
26
|
+
# current time boundaries on the client.
|
27
|
+
#
|
28
|
+
# Here the resource is a ZTimeHeader and the use-blocks are ZTimeLabels.
|
29
|
+
#
|
30
|
+
# ==== Parameters
|
31
|
+
# * <tt>rids</tt> - A list of schedules resource ids (strings).
|
32
|
+
# * <tt>t1</tt> - Start time.
|
33
|
+
# * <tt>t2</tt> - End time.
|
34
|
+
# * <tt>inc</tt> - One of nil, "lo", "hi" (See above).
|
35
|
+
#
|
36
|
+
# ==== Returns
|
37
|
+
# * <tt>Hash</tt> - Each key is a <tt>rid</tt> such as Hour0
|
38
|
+
# and the value is an array of Timelabels in the interval, ordered by
|
39
|
+
# <tt>starttime</tt>.
|
40
|
+
def self.get_all_blocks(ids, t1, t2, inc)
|
41
|
+
h = {}
|
42
|
+
ids.each{|id| h[id] = get_timeblocks(id, t1, t2, inc)}
|
43
|
+
h
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def self.get_timeblocks(id, t1, t2, inc)
|
48
|
+
tz = tz_from_rid( id )
|
49
|
+
|
50
|
+
t1 = floor( tz.at(t1) )
|
51
|
+
t1 = end_for_start(t1) if inc == 'hi'
|
52
|
+
|
53
|
+
t2 = tz.at(t2)
|
54
|
+
t2 = floor( t2 ) - 1 if inc == 'lo'
|
55
|
+
|
56
|
+
enum_for( :time_blocks_starting_through, t1, t2 ).to_a
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def self.time_blocks_starting_through( starttime, limit )
|
61
|
+
while starttime <= limit do # Hmm... I would have guessed '<' over '<='...
|
62
|
+
endtime = end_for_start starttime
|
63
|
+
yield new( starttime, endtime )
|
64
|
+
starttime = endtime
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
TZ_INT_MAP = {
|
70
|
+
-8 => ActiveSupport::TimeZone.new('Pacific Time (US & Canada)' ), # P
|
71
|
+
-7 => ActiveSupport::TimeZone.new('Mountain Time (US & Canada)'), # M
|
72
|
+
-6 => ActiveSupport::TimeZone.new('Central Time (US & Canada)' ), # C
|
73
|
+
-5 => ActiveSupport::TimeZone.new('Eastern Time (US & Canada)' ), # E
|
74
|
+
}
|
75
|
+
|
76
|
+
def self.tz_from_rid( rid )
|
77
|
+
# ActiveSupport::TimeZone.new offset_from_rid(rid)
|
78
|
+
TZ_INT_MAP[ offset_from_rid(rid) ] || TZ_INT_MAP[-8]
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.offset_from_rid( rid )
|
82
|
+
(rid.split('_').last || '').to_i
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.end_for_start(t) t + 1 end # Overridden.
|
86
|
+
def self.floor(t) t end # Overridden.
|
87
|
+
|
88
|
+
end
|