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 CHANGED
@@ -1 +1 @@
1
- 0.2.2
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
- Time.local(Time.now.year, Time.now.month, Time.now.day, self.hour, self.min, self.sec)
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.in_time?(@start, @time)
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
- if (stop_time.hour == time.hour)
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
 
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{metra_schedule}
8
- s.version = "0.2.2"
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-01-05}
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
+