tube 0.2.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/README.txt +36 -0
- data/lib/tube/line.rb +24 -0
- data/lib/tube/station.rb +20 -0
- data/lib/tube/status.rb +84 -0
- data/lib/tube/status_parser.rb +135 -0
- data/test/dummy.html +71 -0
- data/test/status_parser_test.rb +140 -0
- metadata +71 -0
data/README.txt
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
= Tube/Status
|
2
|
+
|
3
|
+
A simple MIT licensed Ruby library to access the status of the London Underground network as displayed on the Transport for London {Live travel news}[http://www.tfl.gov.uk/tfl/livetravelnews/realtime/tube/default.html] page.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
$ gem install tube --source http://gemcutter.org
|
8
|
+
|
9
|
+
== Examples
|
10
|
+
require 'tube/status'
|
11
|
+
|
12
|
+
status = Tube::Status.new
|
13
|
+
|
14
|
+
broken_lines = status.lines.select {|line| line.problem?}
|
15
|
+
broken_lines.collect {|line| line.name}
|
16
|
+
#=> ["Circle", "District", "Jubilee", "Metropolitan", "Northern"]
|
17
|
+
|
18
|
+
status.lines.detect {|line| line.id == :circle}.message
|
19
|
+
#=> "Saturday 7 and Sunday 8 March, suspended."
|
20
|
+
|
21
|
+
closed_stations = status.station_groups["Closed stations"]
|
22
|
+
closed_stations.collect {|station| station.name}
|
23
|
+
#=> ["Blackfriars", "Hatton Cross"]
|
24
|
+
|
25
|
+
stations = status.station_groups.values.flatten
|
26
|
+
stations.detect {|station| station.name =~ "hatton"}.message
|
27
|
+
#=> "Saturday 7 and Sunday 8 March, closed."
|
28
|
+
|
29
|
+
status.updated.strftime("%I:%M%p")
|
30
|
+
#=> "04:56PM"
|
31
|
+
|
32
|
+
status.reload
|
33
|
+
status.updated.strftime("%I:%M%p")
|
34
|
+
#=> "05:00PM"
|
35
|
+
|
36
|
+
See the {documentation}[http://sourcetagsandcodes.com/codes/tube_status/doc/] for more details.
|
data/lib/tube/line.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Tube # :nodoc:
|
2
|
+
|
3
|
+
# Models the data gathered on a tube line from the tfl.gov.uk "Live travel
|
4
|
+
# news" page.
|
5
|
+
#
|
6
|
+
class Line
|
7
|
+
attr_reader :id
|
8
|
+
attr_accessor :name, :status, :problem, :message
|
9
|
+
alias problem? problem
|
10
|
+
|
11
|
+
# :call-seq: Line.new(id, name, status, problem, message=nil)
|
12
|
+
#
|
13
|
+
# Create a new Line.
|
14
|
+
#
|
15
|
+
def initialize( id, name, status, problem, message=nil )
|
16
|
+
@id = id
|
17
|
+
@name = name
|
18
|
+
@status = status
|
19
|
+
@problem = problem
|
20
|
+
@message = message
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
data/lib/tube/station.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Tube # :nodoc:
|
2
|
+
|
3
|
+
# Models the data gathered on a tube station from the tfl.gov.uk "Live travel
|
4
|
+
# news" page.
|
5
|
+
#
|
6
|
+
class Station
|
7
|
+
attr_reader :name
|
8
|
+
attr_accessor :message
|
9
|
+
|
10
|
+
# :call-seq: Station.new(name, message)
|
11
|
+
#
|
12
|
+
# Create a new Station.
|
13
|
+
#
|
14
|
+
def initialize( name, message )
|
15
|
+
@name = name
|
16
|
+
@message = message
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/tube/status.rb
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
require "#{File.dirname( __FILE__ )}/status_parser"
|
4
|
+
require "#{File.dirname( __FILE__ )}/line"
|
5
|
+
require "#{File.dirname( __FILE__ )}/station"
|
6
|
+
|
7
|
+
module Tube # :nodoc:
|
8
|
+
|
9
|
+
# Models the status of the London Underground network as displayed on
|
10
|
+
# http://www.tfl.gov.uk/tfl/livetravelnews/realtime/tube/default.html.
|
11
|
+
#
|
12
|
+
# It is a very thin abstraction over the tfl website, as a result the access
|
13
|
+
# to data on stations is somewhat different to lines due to the differing
|
14
|
+
# presentation.
|
15
|
+
# However it is very dynamic, for example should the East London line return
|
16
|
+
# it will show up in the lines array automatically.
|
17
|
+
#
|
18
|
+
# ==Example Usage
|
19
|
+
# require 'tube/status'
|
20
|
+
#
|
21
|
+
# status = Tube::Status.new
|
22
|
+
#
|
23
|
+
# broken_lines = status.lines.select {|line| line.problem?}
|
24
|
+
# broken_lines.collect {|line| line.name}
|
25
|
+
# #=> ["Circle", "District", "Jubilee", "Metropolitan", "Northern"]
|
26
|
+
#
|
27
|
+
# status.lines.detect {|line| line.id == :circle}.message
|
28
|
+
# #=> "Saturday 7 and Sunday 8 March, suspended."
|
29
|
+
#
|
30
|
+
# closed_stations = status.station_groups["Closed stations"]
|
31
|
+
# closed_stations.collect {|station| station.name}
|
32
|
+
# #=> ["Blackfriars", "Hatton Cross"]
|
33
|
+
#
|
34
|
+
# stations = status.station_groups.values.flatten
|
35
|
+
# stations.detect {|station| station.name =~ "hatton"}.message
|
36
|
+
# #=> "Saturday 7 and Sunday 8 March, closed."
|
37
|
+
#
|
38
|
+
# status.updated.strftime("%I:%M%p")
|
39
|
+
# #=> "04:56PM"
|
40
|
+
#
|
41
|
+
# status.reload
|
42
|
+
# status.updated.strftime("%I:%M%p")
|
43
|
+
# #=> "05:00PM"
|
44
|
+
#
|
45
|
+
class Status
|
46
|
+
attr_reader :updated, :lines, :station_groups
|
47
|
+
|
48
|
+
# :call-seq: Status.new -> status
|
49
|
+
#
|
50
|
+
# Request and parse the status of the London Underground network from the
|
51
|
+
# tfl.gov.uk "Live travel news" page.
|
52
|
+
#
|
53
|
+
def initialize( url=
|
54
|
+
"http://www.tfl.gov.uk/tfl/livetravelnews/realtime/tube/default.html" )
|
55
|
+
results = Tube::StatusParser.parse( open( url ) )
|
56
|
+
@updated = results[:updated]
|
57
|
+
|
58
|
+
@lines = results[:lines].map do |line|
|
59
|
+
id = line[:html_class].to_sym
|
60
|
+
name = line[:name]
|
61
|
+
status = line[:status][:headline]
|
62
|
+
problem = line[:status][:problem]
|
63
|
+
message = line[:status][:message]
|
64
|
+
|
65
|
+
Line.new( id, name, status, problem, message )
|
66
|
+
end
|
67
|
+
|
68
|
+
@station_groups = results[:station_groups].inject( {} ) do |memo, group|
|
69
|
+
stations = group[:stations].map do |station|
|
70
|
+
Station.new( station[:name], station[:message] )
|
71
|
+
end
|
72
|
+
|
73
|
+
memo[group[:name]] = stations
|
74
|
+
memo
|
75
|
+
end
|
76
|
+
|
77
|
+
self
|
78
|
+
end
|
79
|
+
|
80
|
+
alias reload initialize
|
81
|
+
public :reload
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'time'
|
2
|
+
require 'date'
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hpricot'
|
5
|
+
|
6
|
+
module Tube # :nodoc:
|
7
|
+
module StatusParser # :nodoc:
|
8
|
+
extend self
|
9
|
+
|
10
|
+
def parse( html_doc )
|
11
|
+
service_board = Hpricot( html_doc ).at( "#service-board" )
|
12
|
+
|
13
|
+
updated_element = service_board.previous_sibling.children.first
|
14
|
+
updated = parse_updated( updated_element )
|
15
|
+
|
16
|
+
lines = service_board.search( "dl#lines dt" ).map do |line_element|
|
17
|
+
parse_line( line_element )
|
18
|
+
end
|
19
|
+
|
20
|
+
station_group_elements = service_board.search( "dl#stations dt" )
|
21
|
+
station_groups = station_group_elements.map do |station_group_element|
|
22
|
+
parse_station_group( station_group_element )
|
23
|
+
end
|
24
|
+
|
25
|
+
{:updated => updated, :lines => lines, :station_groups => station_groups}
|
26
|
+
end
|
27
|
+
|
28
|
+
def parse_updated( updated_element )
|
29
|
+
time_text = updated_element.inner_text.match( /(\d?\d:\d\d(a|p)m)/ )[0]
|
30
|
+
time_zone = if is_bst? then "+0100" else "+0000" end
|
31
|
+
|
32
|
+
Time.parse( "#{time_text} #{time_zone}" )
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse_line( line_element )
|
36
|
+
name = line_element.inner_text.strip
|
37
|
+
html_class = line_element.attributes["class"]
|
38
|
+
status = parse_status( line_element.next_sibling )
|
39
|
+
|
40
|
+
{:name => name, :html_class => html_class, :status => status}
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_status( status_element )
|
44
|
+
header = status_element.at( "h3" )
|
45
|
+
|
46
|
+
if header
|
47
|
+
headline = header.inner_text.strip
|
48
|
+
message = parse_status_message( status_element.search( "div.message p" ) )
|
49
|
+
else
|
50
|
+
headline = status_element.inner_text.strip
|
51
|
+
end
|
52
|
+
problem = status_element.attributes["class"] == "problem"
|
53
|
+
|
54
|
+
{:headline => headline, :problem => problem, :message => message}
|
55
|
+
end
|
56
|
+
|
57
|
+
def parse_station_group( station_group_element )
|
58
|
+
name = station_group_element.inner_text.strip
|
59
|
+
stations = []
|
60
|
+
|
61
|
+
station_element = station_group_element
|
62
|
+
while station_element = station_element.next_sibling
|
63
|
+
if station_element.to_html =~ /^<dd/
|
64
|
+
stations.push( parse_station( station_element ) )
|
65
|
+
elsif station_element.to_html =~ /^<dt/
|
66
|
+
break
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
{:name => name, :stations => stations}
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_station( station_element )
|
74
|
+
name = station_element.at( "h3" ).inner_text.strip
|
75
|
+
message = parse_status_message( station_element.search("div.message p") )
|
76
|
+
|
77
|
+
{:name => name, :message => message}
|
78
|
+
end
|
79
|
+
|
80
|
+
def parse_status_message( messages )
|
81
|
+
text_messages = messages.map do |message|
|
82
|
+
if message.children
|
83
|
+
message.children.select {|child| child.text?}.join( " " )
|
84
|
+
end
|
85
|
+
end.compact
|
86
|
+
text_messages.reject! {|m| m.empty?}
|
87
|
+
|
88
|
+
text_messages.map {|m| m.gsub( /\s+/, " " ).strip}.join( "\n" )
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
# :call-seq: is_bst? -> bool
|
94
|
+
#
|
95
|
+
# Is British Summer Time currently in effect.
|
96
|
+
#
|
97
|
+
def is_bst?
|
98
|
+
bst_start = last_sunday_of_month( "march" )
|
99
|
+
bst_end = last_sunday_of_month( "october" )
|
100
|
+
|
101
|
+
one_hour = 3600
|
102
|
+
bst_start = Time.gm( bst_start.year, bst_start.month ) + one_hour
|
103
|
+
bst_end = Time.gm( bst_end.year, bst_end.month ) + one_hour
|
104
|
+
|
105
|
+
(bst_start..bst_end).include?( Time.now.getgm )
|
106
|
+
end
|
107
|
+
|
108
|
+
# :call-seq: last_sunday_of_month(month_name) -> date
|
109
|
+
#
|
110
|
+
def last_sunday_of_month( month )
|
111
|
+
start_of_next_month = Date.parse( next_month_name( month ) )
|
112
|
+
|
113
|
+
week_day = start_of_next_month.wday
|
114
|
+
|
115
|
+
distance_from_sunday = if week_day == 0 then 7 else week_day end
|
116
|
+
start_of_next_month - distance_from_sunday
|
117
|
+
end
|
118
|
+
|
119
|
+
# :call-seq: next_month_name(month_name) -> string
|
120
|
+
#
|
121
|
+
def next_month_name( month )
|
122
|
+
index = Date::MONTHNAMES.index( month.capitalize )
|
123
|
+
index ||= ABBR_MONTHNAMES.index( month.capitalize )
|
124
|
+
|
125
|
+
index += 1
|
126
|
+
|
127
|
+
if index >= 12
|
128
|
+
index = 1
|
129
|
+
end
|
130
|
+
|
131
|
+
Date::MONTHNAMES[index]
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
data/test/dummy.html
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<title>Service update now | Transport for London</title>
|
6
|
+
<!-- Transport for London website template version 1.7 -->
|
7
|
+
|
8
|
+
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
|
9
|
+
</head>
|
10
|
+
<body class="template-6">
|
11
|
+
<!-- <lm>Sun, 15 Nov 2009 12:12:20 GMT</lm> -->
|
12
|
+
|
13
|
+
<div id="container" class="live-travel-news">
|
14
|
+
<div id="main-content">
|
15
|
+
<h1>Live travel news</h1>
|
16
|
+
|
17
|
+
<h2>Service update at 12:12pm <a href="later.html" id="works_later" class="alert" name="works_later">View engineering works planned for <strong>later today</strong></a></h2>
|
18
|
+
<div id="service-board">
|
19
|
+
<dl id="lines">
|
20
|
+
<dt class="central">Central</dt>
|
21
|
+
<dd>Good service</dd>
|
22
|
+
<dt class="district">District</dt>
|
23
|
+
<dd class="problem">
|
24
|
+
<h3>Part closure</h3>
|
25
|
+
<div class="message">
|
26
|
+
<p>Rail replacement bus</p>
|
27
|
+
<p>Service A: details...</p>
|
28
|
+
<p><a href="/transform">See how we are transforming the Tube</a></p>
|
29
|
+
</div>
|
30
|
+
</dd>
|
31
|
+
<dt class="waterlooandcity">Waterloo & City</dt>
|
32
|
+
<dd class="problem">
|
33
|
+
<h3>Planned closure</h3>
|
34
|
+
<div class="message">
|
35
|
+
<p>Closed Sunday.</p>
|
36
|
+
<p><a href="/transform">See how we are transforming the Tube</a></p>
|
37
|
+
</div>
|
38
|
+
</dd>
|
39
|
+
</dl>
|
40
|
+
<dl id="stations">
|
41
|
+
<dt>Closed stations</dt>
|
42
|
+
<dd>
|
43
|
+
<h3>Bank</h3>
|
44
|
+
<div class="message">
|
45
|
+
<p>Closed due to excessive noise.</p>
|
46
|
+
<p><a href="/transform">See how we are transforming the Tube</a></p>
|
47
|
+
</div>
|
48
|
+
</dd>
|
49
|
+
<dd>
|
50
|
+
<h3>Holborn</h3>
|
51
|
+
<div class="message">
|
52
|
+
<p>Closed due to fire investigation.</p>
|
53
|
+
<p>Go to Chancery Lane or Tottenham Court Road instead.</p>
|
54
|
+
<p><a href="/transform">See how we are transforming the Tube</a></p>
|
55
|
+
</div>
|
56
|
+
</dd>
|
57
|
+
|
58
|
+
<dt>Station maintenance</dt>
|
59
|
+
<dd>
|
60
|
+
<h3>Elephant & Castle</h3>
|
61
|
+
<div class="message">
|
62
|
+
<p>Reduced lift service.</p>
|
63
|
+
<p><a href="/transform">See how we are transforming the Tube</a></p>
|
64
|
+
</div>
|
65
|
+
</dd>
|
66
|
+
</dl>
|
67
|
+
</div>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
</body>
|
71
|
+
</html>
|
@@ -0,0 +1,140 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
|
3
|
+
require "#{File.dirname( __FILE__ )}/../lib/tube/status"
|
4
|
+
|
5
|
+
class TestStatusParser < Test::Unit::TestCase
|
6
|
+
def test_parse_updated
|
7
|
+
document = Hpricot("<h2>Service update at 6:26pm</h2>")
|
8
|
+
element = document.at("h2")
|
9
|
+
result = Tube::StatusParser.parse_updated(element)
|
10
|
+
|
11
|
+
assert_equal(Time.parse("6:26pm"), result)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_parse_updated_with_anchor_in_element
|
15
|
+
document = Hpricot(%Q{<h2>Service update at 12:12pm <a href="/later.html">View engineering works planned for later today</a></h2>})
|
16
|
+
element = document.at("h2")
|
17
|
+
result = Tube::StatusParser.parse_updated(element)
|
18
|
+
|
19
|
+
assert_equal(Time.parse("12:12pm"), result)
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_parse_line
|
23
|
+
document = Hpricot(%Q{<dt class="central">Central</dt> <dd>Good service</dd>})
|
24
|
+
element = document.at("dt")
|
25
|
+
result = Tube::StatusParser.parse_line(element)
|
26
|
+
|
27
|
+
assert_equal("Central", result[:name])
|
28
|
+
assert_equal("central", result[:html_class])
|
29
|
+
assert_equal("Good service", result[:status][:headline])
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_parse_line_with_complex_name
|
33
|
+
document = Hpricot(%Q{<dt class="waterlooandcity">Waterloo & City</dt> <dd></dd>})
|
34
|
+
element = document.at("dt")
|
35
|
+
result = Tube::StatusParser.parse_line(element)
|
36
|
+
|
37
|
+
assert_equal("Waterloo & City", result[:name])
|
38
|
+
assert_equal("waterlooandcity", result[:html_class])
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_parse_status
|
42
|
+
document = Hpricot("<dd>Good service</dd>")
|
43
|
+
element = document.at("dd")
|
44
|
+
result = Tube::StatusParser.parse_status(element)
|
45
|
+
|
46
|
+
assert_equal("Good service", result[:headline])
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_parse_status_with_problem
|
50
|
+
document = Hpricot(%Q{<dd class="problem">Part suspended</dd>})
|
51
|
+
element = document.at("dd")
|
52
|
+
result = Tube::StatusParser.parse_status(element)
|
53
|
+
|
54
|
+
assert_equal(true, result[:problem])
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_parse_status_with_header
|
58
|
+
document = Hpricot(%Q{<dd><h3>Part suspended</h3></dd>})
|
59
|
+
element = document.at("dd")
|
60
|
+
result = Tube::StatusParser.parse_status(element)
|
61
|
+
|
62
|
+
assert_equal("Part suspended", result[:headline])
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_parse_status_with_message
|
66
|
+
document = Hpricot(%Q{<dd class="problem"><h3>Part closure</h3><div class="message"><p>engineering works, etc...</p></div></dd>})
|
67
|
+
element = document.at("dd")
|
68
|
+
result = Tube::StatusParser.parse_status(element)
|
69
|
+
|
70
|
+
assert_equal("Part closure", result[:headline])
|
71
|
+
assert_equal(true, result[:problem])
|
72
|
+
assert_equal("engineering works, etc...", result[:message])
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_parse_status_message
|
76
|
+
document = Hpricot(%Q{<div><p>engineering works, etc...</p></div>})
|
77
|
+
elements = document.search("div p")
|
78
|
+
result = Tube::StatusParser.parse_status_message(elements)
|
79
|
+
|
80
|
+
assert_equal("engineering works, etc...", result)
|
81
|
+
end
|
82
|
+
|
83
|
+
def test_parse_status_message_with_multi_paragraph_message
|
84
|
+
document = Hpricot(%Q{<div><p>Rail replacement bus</p><p>Service A: details...</p></div>})
|
85
|
+
elements = document.search("div p")
|
86
|
+
result = Tube::StatusParser.parse_status_message(elements)
|
87
|
+
|
88
|
+
assert_equal("Rail replacement bus\nService A: details...", result)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_parse_status_message_removes_anchor_from_message
|
92
|
+
document = Hpricot(%Q{<div><p>Closed Sunday.</p><p><a href="/transform">See how we are transforming the Tube</a></p></div>})
|
93
|
+
elements = document.search("div p")
|
94
|
+
result = Tube::StatusParser.parse_status_message(elements)
|
95
|
+
|
96
|
+
assert_equal("Closed Sunday.", result)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_parse_station_group
|
100
|
+
document = Hpricot(%Q{<dt>Closed stations</dt>
|
101
|
+
<dd><h3>Bank</h3><div class="message"><p>Closed due to excessive noise.</p></div></dd>
|
102
|
+
<dd><h3>Holborn</h3><div class="message"><p>Closed due to fire investigation.</p></div></dd>})
|
103
|
+
element = document.at("dt")
|
104
|
+
result = Tube::StatusParser.parse_station_group(element)
|
105
|
+
|
106
|
+
assert_equal("Closed stations", result[:name])
|
107
|
+
assert_equal("Bank", result[:stations].first[:name])
|
108
|
+
assert_equal("Holborn", result[:stations].last[:name])
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_parse_station
|
112
|
+
document = Hpricot(%Q{<dd><h3>Bank</h3><div class="message"><p>Closed due to excessive noise.</p></div></dd>})
|
113
|
+
element = document.at("dd")
|
114
|
+
result = Tube::StatusParser.parse_station(element)
|
115
|
+
|
116
|
+
assert_equal("Bank", result[:name])
|
117
|
+
# This seriously happend once.
|
118
|
+
assert_equal("Closed due to excessive noise.", result[:message])
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_parse
|
122
|
+
# the file used here is an approximation of the most important bits of the
|
123
|
+
# Live travel news at http://www.tfl.gov.uk/tfl/livetravelnews/realtime/tube/default.html
|
124
|
+
document = open("#{File.dirname( __FILE__ )}/dummy.html")
|
125
|
+
result = Tube::StatusParser.parse(document)
|
126
|
+
|
127
|
+
assert(result)
|
128
|
+
assert_equal(Time.parse("12:12pm"), result[:updated])
|
129
|
+
assert_equal(3, result[:lines].length)
|
130
|
+
assert_equal("Central", result[:lines].first[:name])
|
131
|
+
assert_equal("Closed Sunday.", result[:lines].last[:status][:message])
|
132
|
+
assert_equal(2, result[:station_groups].length)
|
133
|
+
assert_equal(2, result[:station_groups].first[:stations].length)
|
134
|
+
assert_equal(1, result[:station_groups].last[:stations].length)
|
135
|
+
assert_equal("Closed stations", result[:station_groups].first[:name])
|
136
|
+
assert_equal("Elephant & Castle", result[:station_groups].last[:stations].first[:name])
|
137
|
+
|
138
|
+
assert_equal({:updated=>Time.parse("12:12pm"), :station_groups=>[{:stations=>[{:message=>"Closed due to excessive noise.", :name=>"Bank"}, {:message=>"Closed due to fire investigation.\nGo to Chancery Lane or Tottenham Court Road instead.", :name=>"Holborn"}], :name=>"Closed stations"}, {:stations=>[{:message=>"Reduced lift service.", :name=>"Elephant & Castle"}], :name=>"Station maintenance"}], :lines=>[{:status=>{:problem=>false, :message=>nil, :headline=>"Good service"}, :html_class=>"central", :name=>"Central"}, {:status=>{:problem=>true, :message=>"Rail replacement bus\nService A: details...", :headline=>"Part closure"}, :html_class=>"district", :name=>"District"}, {:status=>{:problem=>true, :message=>"Closed Sunday.", :headline=>"Planned closure"}, :html_class=>"waterlooandcity", :name=>"Waterloo & City"}]}, result)
|
139
|
+
end
|
140
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tube
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Sadler
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-15 00:00:00 +00:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hpricot
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.8.1
|
24
|
+
version:
|
25
|
+
description: A simple Ruby library to access the status of the London Underground network.
|
26
|
+
email: mat@sourcetagsandcodes.com
|
27
|
+
executables: []
|
28
|
+
|
29
|
+
extensions: []
|
30
|
+
|
31
|
+
extra_rdoc_files:
|
32
|
+
- README.txt
|
33
|
+
files:
|
34
|
+
- lib/tube/line.rb
|
35
|
+
- lib/tube/station.rb
|
36
|
+
- lib/tube/status.rb
|
37
|
+
- lib/tube/status_parser.rb
|
38
|
+
- test/dummy.html
|
39
|
+
- test/status_parser_test.rb
|
40
|
+
- README.txt
|
41
|
+
has_rdoc: true
|
42
|
+
homepage: http://github.com/matsadler/tube
|
43
|
+
licenses: []
|
44
|
+
|
45
|
+
post_install_message:
|
46
|
+
rdoc_options:
|
47
|
+
- --main
|
48
|
+
- README.txt
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.3.5
|
67
|
+
signing_key:
|
68
|
+
specification_version: 3
|
69
|
+
summary: Access the status of the London Underground network.
|
70
|
+
test_files:
|
71
|
+
- test/status_parser_test.rb
|