metra_schedule 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|