metra_schedule 0.2.2 → 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.
- data/VERSION +1 -1
- data/lib/metra/cacher.rb +30 -1
- data/lib/metra/delay_parser.rb +60 -0
- data/lib/metra/extensions/time_extension.rb +5 -1
- data/lib/metra/line.rb +29 -2
- data/lib/metra/train.rb +10 -15
- data/lib/metra.rb +1 -0
- data/metra_schedule.gemspec +9 -2
- data/test/fixture/service_updates_alerts.html +26 -0
- data/test/fixture/service_updates_alerts_multiple_with_non_delay.html +39 -0
- data/test/fixture/service_updates_alerts_no_advisories.html +792 -0
- data/test/fixture/service_updates_alerts_no_range.html +25 -0
- data/test/functional/test_all_filters.rb +8 -8
- data/test/integration/test_line_integration.rb +16 -0
- data/test/test_helper.rb +1 -0
- data/test/unit/test_cacher.rb +29 -0
- data/test/unit/test_delay_parser.rb +76 -0
- data/test/unit/test_line.rb +26 -0
- data/test/unit/test_parser.rb +5 -24
- data/test/unit/test_time_extension.rb +7 -0
- data/test/unit/test_train.rb +17 -0
- metadata +9 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/metra/cacher.rb
CHANGED
@@ -3,10 +3,11 @@ require 'fileutils'
|
|
3
3
|
module MetraSchedule
|
4
4
|
class Cacher
|
5
5
|
|
6
|
-
attr_accessor :cache_dir
|
6
|
+
attr_accessor :cache_dir, :delays
|
7
7
|
|
8
8
|
def initialize
|
9
9
|
@cache_dir = "#{ENV['HOME']}/.metra_schedule"
|
10
|
+
@delay_file = 'delays'
|
10
11
|
end
|
11
12
|
|
12
13
|
def self.load_from_cache(line)
|
@@ -43,6 +44,20 @@ module MetraSchedule
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
47
|
+
def delays_exist?
|
48
|
+
return true if File.exists?(File.join(@cache_dir, @delay_file))
|
49
|
+
false
|
50
|
+
end
|
51
|
+
|
52
|
+
def clear_delays
|
53
|
+
begin
|
54
|
+
FileUtils.rm(File.join(@cache_dir, @delay_file))
|
55
|
+
true
|
56
|
+
rescue
|
57
|
+
false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
46
61
|
def persist_line(line)
|
47
62
|
create_cache_dir_if_not_exists
|
48
63
|
return false unless line.engines
|
@@ -56,6 +71,20 @@ module MetraSchedule
|
|
56
71
|
nil
|
57
72
|
end
|
58
73
|
end
|
74
|
+
|
75
|
+
def persist_delays(delays)
|
76
|
+
create_cache_dir_if_not_exists
|
77
|
+
return false unless delays
|
78
|
+
true if File.open(File.join(@cache_dir, @delay_file), 'w') {|f| Marshal.dump(delays, f)}
|
79
|
+
end
|
80
|
+
|
81
|
+
def retrieve_delays
|
82
|
+
if delays_exist?
|
83
|
+
File.open(File.join(@cache_dir, @delay_file), 'r') {|f| Marshal.load(f)}
|
84
|
+
else
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
end
|
59
88
|
|
60
89
|
end
|
61
90
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
|
4
|
+
module MetraSchedule
|
5
|
+
class DelayParser
|
6
|
+
attr_reader :html_doc, :url
|
7
|
+
attr_accessor :line
|
8
|
+
|
9
|
+
def initialize(html_doc=nil)
|
10
|
+
time = Time.now.to_i
|
11
|
+
@url = "http://metrarail.com/content/metra/en/home/service_updates/service_updates_alerts/jcr:content/serviceAdvisory.display.html?t=#{time}"
|
12
|
+
@html_doc = @url unless html_doc
|
13
|
+
@html_doc = html_doc if html_doc
|
14
|
+
end
|
15
|
+
|
16
|
+
def scrape
|
17
|
+
parse_nokogiri
|
18
|
+
make_train_delays
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_nokogiri
|
22
|
+
html_doc = open(@html_doc) if @html_doc.is_a?(String)
|
23
|
+
html_doc = @html_doc if @html_doc.is_a?(File)
|
24
|
+
@html_doc = Nokogiri::HTML(html_doc)
|
25
|
+
end
|
26
|
+
|
27
|
+
def make_train_delays
|
28
|
+
return unless has_delays?
|
29
|
+
all_advisories.inject([]) do |total, node|
|
30
|
+
total << {:train_num => find_train_num(node), :delay => find_delay(node)}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_train_num(node)
|
35
|
+
node.text.scan(/#([0-9]+)/).first.first.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
def find_delay(node)
|
39
|
+
text_array = node.text.delete("\r\n").split("\s")[3..-1]
|
40
|
+
text_array.delete_at(0) if text_array[0] == "-"
|
41
|
+
text_array.join("\s").strip
|
42
|
+
end
|
43
|
+
|
44
|
+
def has_delays?
|
45
|
+
@html_doc.css('#serviceAdvisory').count > 0
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def all_advisories
|
51
|
+
nodes = @html_doc.css('#serviceAdvisory dl dd')
|
52
|
+
advisories = nodes.inject([]) do |total, node|
|
53
|
+
id = node.attributes.has_key?("id")
|
54
|
+
total << node unless id
|
55
|
+
total
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
@@ -2,7 +2,11 @@ module MetraSchedule
|
|
2
2
|
module Extensions
|
3
3
|
module TimeExtension
|
4
4
|
def to_today
|
5
|
-
|
5
|
+
if self.hour >= 0 and self.hour <= 2 # Midnight to 2AM counts as the same day
|
6
|
+
Time.local(Time.now.year, Time.now.month, Time.now.day+1, self.hour, self.min, self.sec)
|
7
|
+
else
|
8
|
+
Time.local(Time.now.year, Time.now.month, Time.now.day, self.hour, self.min, self.sec)
|
9
|
+
end
|
6
10
|
end
|
7
11
|
end
|
8
12
|
end
|
data/lib/metra/line.rb
CHANGED
@@ -5,7 +5,7 @@ module MetraSchedule
|
|
5
5
|
include MetraSchedule::TrainData
|
6
6
|
|
7
7
|
attr_reader :cacher, :cache_dir
|
8
|
-
attr_reader :line_key, :name, :url, :dir, :sched, :start, :destination, :time
|
8
|
+
attr_reader :line_key, :name, :url, :dir, :sched, :start, :destination, :time, :del_threshold
|
9
9
|
attr_accessor :engines
|
10
10
|
|
11
11
|
def initialize(line_name)
|
@@ -30,6 +30,7 @@ module MetraSchedule
|
|
30
30
|
else
|
31
31
|
@engines = cached_engines
|
32
32
|
end
|
33
|
+
self
|
33
34
|
end
|
34
35
|
|
35
36
|
def update_schedule
|
@@ -155,8 +156,16 @@ module MetraSchedule
|
|
155
156
|
@engines.find {|e| e.train_num == train_num}
|
156
157
|
end
|
157
158
|
|
159
|
+
def delay_threshold(minutes)
|
160
|
+
@del_threshold = minutes if minutes
|
161
|
+
self
|
162
|
+
end
|
163
|
+
|
158
164
|
def trains
|
159
165
|
return [] unless engines
|
166
|
+
if MetraSchedule::Cacher.new.delays_exist?
|
167
|
+
@filters.insert(0, inject_delays)
|
168
|
+
end
|
160
169
|
@filters.inject(engines) { |e, fun| fun.call(e) }.sort
|
161
170
|
end
|
162
171
|
|
@@ -172,6 +181,20 @@ module MetraSchedule
|
|
172
181
|
end
|
173
182
|
end
|
174
183
|
|
184
|
+
def inject_delays
|
185
|
+
lambda do |engines|
|
186
|
+
delays = MetraSchedule::Cacher.new.retrieve_delays
|
187
|
+
delays.each do |d|
|
188
|
+
if engines.any? {|e| e.train_num == d[:train_num] }
|
189
|
+
train = find_train_by_train_num(d[:train_num])
|
190
|
+
train.delay = d[:delay]
|
191
|
+
train.del_threshold = @del_threshold if @del_threshold
|
192
|
+
end
|
193
|
+
end
|
194
|
+
engines
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
175
198
|
def filter_by_stop
|
176
199
|
lambda do |engines|
|
177
200
|
if @start and not @destination
|
@@ -190,7 +213,11 @@ module MetraSchedule
|
|
190
213
|
lambda do |engines|
|
191
214
|
return engines unless @time and @start
|
192
215
|
engines.find_all do |engine|
|
193
|
-
engine.
|
216
|
+
if @del_threshold and engine.delay
|
217
|
+
engine.in_time?(@start, @time - (60 * @del_threshold))
|
218
|
+
else
|
219
|
+
engine.in_time?(@start, @time)
|
220
|
+
end
|
194
221
|
end
|
195
222
|
end
|
196
223
|
end
|
data/lib/metra/train.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module MetraSchedule
|
2
2
|
class Train
|
3
3
|
attr_reader :train_num, :schedule, :bike_limit, :direction, :stops
|
4
|
-
attr_accessor :my_departure, :my_arrival # Injected when the line is filtered
|
4
|
+
attr_accessor :my_departure, :my_arrival, :delay, :del_threshold # Injected when the line is filtered
|
5
5
|
|
6
6
|
def initialize(options={})
|
7
7
|
unless options.empty?
|
@@ -20,17 +20,7 @@ module MetraSchedule
|
|
20
20
|
|
21
21
|
def in_time?(station, time)
|
22
22
|
stop_time = stops.find {|s| s.station == station}.time
|
23
|
-
|
24
|
-
if (stop_time.min > time.min)
|
25
|
-
return true
|
26
|
-
else
|
27
|
-
return false
|
28
|
-
end
|
29
|
-
elsif (stop_time.hour > time.hour)
|
30
|
-
return true
|
31
|
-
else
|
32
|
-
return false
|
33
|
-
end
|
23
|
+
stop_time.to_today > time.to_today
|
34
24
|
end
|
35
25
|
|
36
26
|
def departure_and_arrival(start, destination)
|
@@ -39,11 +29,16 @@ module MetraSchedule
|
|
39
29
|
{:departure => departure.to_today, :arrival => arrival.to_today}
|
40
30
|
end
|
41
31
|
|
32
|
+
def departure_with_delay
|
33
|
+
return @my_departure unless @del_threshold
|
34
|
+
if @my_departure
|
35
|
+
@my_departure + (60 * @del_threshold)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
42
39
|
def my_travel_time
|
43
40
|
return nil unless @my_departure and @my_arrival
|
44
|
-
minutes = (@my_arrival.to_i - @my_departure.to_i) / 60
|
45
|
-
return minutes if minutes > 0
|
46
|
-
return minutes + 1440 if minutes < 0
|
41
|
+
minutes = (@my_arrival.to_today.to_i - @my_departure.to_today.to_i) / 60
|
47
42
|
end
|
48
43
|
|
49
44
|
def print_my_travel_time
|
data/lib/metra.rb
CHANGED
@@ -3,6 +3,7 @@ require File.join(File.dirname(__FILE__), 'metra', 'line')
|
|
3
3
|
require File.join(File.dirname(__FILE__), 'metra', 'train')
|
4
4
|
require File.join(File.dirname(__FILE__), 'metra', 'stop')
|
5
5
|
require File.join(File.dirname(__FILE__), 'metra', 'parser')
|
6
|
+
require File.join(File.dirname(__FILE__), 'metra', 'delay_parser')
|
6
7
|
require File.join(File.dirname(__FILE__), 'metra', 'cacher')
|
7
8
|
require File.join(File.dirname(__FILE__), 'metra', 'extensions', 'time_extension')
|
8
9
|
|
data/metra_schedule.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{metra_schedule}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Blake Smith"]
|
12
|
-
s.date = %q{2010-
|
12
|
+
s.date = %q{2010-02-03}
|
13
13
|
s.description = %q{metra_schedule provides a ruby object interface to the Chicago metra train schedule}
|
14
14
|
s.email = %q{blakesmith0@gmail.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
"lib/metra.rb",
|
26
26
|
"lib/metra/cacher.rb",
|
27
27
|
"lib/metra/classmethods.rb",
|
28
|
+
"lib/metra/delay_parser.rb",
|
28
29
|
"lib/metra/extensions/time_extension.rb",
|
29
30
|
"lib/metra/line.rb",
|
30
31
|
"lib/metra/parser.rb",
|
@@ -33,6 +34,10 @@ Gem::Specification.new do |s|
|
|
33
34
|
"lib/metra/train_data.rb",
|
34
35
|
"metra_schedule.gemspec",
|
35
36
|
"test/fixture/UP_NW.html",
|
37
|
+
"test/fixture/service_updates_alerts.html",
|
38
|
+
"test/fixture/service_updates_alerts_multiple_with_non_delay.html",
|
39
|
+
"test/fixture/service_updates_alerts_no_advisories.html",
|
40
|
+
"test/fixture/service_updates_alerts_no_range.html",
|
36
41
|
"test/functional/test_all_filters.rb",
|
37
42
|
"test/integration/test_line_integration.rb",
|
38
43
|
"test/test_helper.rb",
|
@@ -46,6 +51,7 @@ Gem::Specification.new do |s|
|
|
46
51
|
"test/timecop/lib/timecop/time_stack_item.rb",
|
47
52
|
"test/timecop/lib/timecop/timecop.rb",
|
48
53
|
"test/unit/test_cacher.rb",
|
54
|
+
"test/unit/test_delay_parser.rb",
|
49
55
|
"test/unit/test_line.rb",
|
50
56
|
"test/unit/test_metra.rb",
|
51
57
|
"test/unit/test_parser.rb",
|
@@ -71,6 +77,7 @@ Gem::Specification.new do |s|
|
|
71
77
|
"test/unit/test_metra.rb",
|
72
78
|
"test/unit/test_stop.rb",
|
73
79
|
"test/unit/test_parser.rb",
|
80
|
+
"test/unit/test_delay_parser.rb",
|
74
81
|
"test/unit/test_cacher.rb",
|
75
82
|
"test/test_helper.rb"
|
76
83
|
]
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<div id="serviceAdvisory">
|
2
|
+
|
3
|
+
|
4
|
+
|
5
|
+
<h2><span class="hidden">Service Advisories</span></h2>
|
6
|
+
|
7
|
+
|
8
|
+
<dl>
|
9
|
+
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
<dt class="line md-n first">Milwaukee District / North Line</dt>
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
<dd class="first"><a href="#serviceAdvisory1">Inbound Train #2156 18 - 20 minutes delayed</a></dd>
|
20
|
+
<dd id="serviceAdvisory1" class="details">Inbound Train #2156 scheduled to arrive Chicago at 8:59 p.m., is operating approximately 20 minutes behind schedule due to freight train interference.</dd>
|
21
|
+
|
22
|
+
|
23
|
+
</dl>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
<div id="serviceAdvisory">
|
3
|
+
|
4
|
+
|
5
|
+
|
6
|
+
<h2><span class="hidden">Service Advisories</span></h2>
|
7
|
+
|
8
|
+
|
9
|
+
<dl>
|
10
|
+
|
11
|
+
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
<dt class="line sws first">SouthWest Service</dt>
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
<dd class="first"><a href="#serviceAdvisory1">Outbound Train #807 - Stopped North of Ashburn</a></dd>
|
21
|
+
<dd id="serviceAdvisory1" class="details">Train #807, scheduled to arrive Orland Park 179th at 9:39 a.m., is stopped north of Ashburn due to switch problems. The duration of this delay is unknown. Metra will update this site as information becomes available.</dd>
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
<dt class="line up-w ">Union Pacific / West Line</dt>
|
29
|
+
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
<dd ><a href="#serviceAdvisory2">Outbound Train #25 - 15 Minute Delay</a></dd>
|
34
|
+
<dd id="serviceAdvisory2" class="details">Train #25, scheduled to arrive Elburn at 10:08 a.m., is operating 15 minutes behind schedule due to switch problems.</dd>
|
35
|
+
|
36
|
+
|
37
|
+
</dl>
|
38
|
+
</div>
|
39
|
+
|