lothianbusestimetable 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- checksums.yaml.gz.sig +0 -0
- data/lib/lothianbusestimetable.rb +223 -0
- data.tar.gz.sig +0 -0
- metadata +67 -0
- metadata.gz.sig +2 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 89109e7c243f925900258b5abfaf15ccc4171fef
|
4
|
+
data.tar.gz: 8036b687f860a180f3cd8a238f5c4c1e7e64b2bb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2551f7e1894eb925bc324935298c91e89849e95a64e7b83570d3e5aca527190a06d7267070f98fad437b4d0908e2386dfe90afcd57bbc0fa4c06ccf435fd6dc8
|
7
|
+
data.tar.gz: ecabce83a5273642bba82590710e8b3b21c0a091676e0a42f935a5c7979fe60ba167a318d3698f4256900a00e94468fde0373e474f0206acb479c501fdaa45df
|
checksums.yaml.gz.sig
ADDED
Binary file
|
@@ -0,0 +1,223 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# file: lothianbusestimetable.rb
|
4
|
+
|
5
|
+
require 'time'
|
6
|
+
require 'nokorexi'
|
7
|
+
|
8
|
+
=begin
|
9
|
+
|
10
|
+
# Example usage:
|
11
|
+
|
12
|
+
lbt = LothianBusesTimetable.new
|
13
|
+
lbt.fetch_timetable '44'
|
14
|
+
lbt.timetable.keys #=> [:service, :weekday, :saturday, :sunday]
|
15
|
+
lbt.timetable[:weekday][:inbound]
|
16
|
+
|
17
|
+
# return the bus times for Juniper Green heading towards Balerno
|
18
|
+
lbt.timetable[:weekday][:outbound]["Juniper Green Post Office"]
|
19
|
+
|
20
|
+
=end
|
21
|
+
|
22
|
+
|
23
|
+
class LothianBusesTimetable
|
24
|
+
|
25
|
+
attr_reader :timetable
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
super()
|
29
|
+
@base_url = 'https://lothianbuses.co.uk/timetables-and-maps/timetables/'
|
30
|
+
end
|
31
|
+
|
32
|
+
def fetch_timetable(service_number)
|
33
|
+
|
34
|
+
url = @base_url + service_number
|
35
|
+
|
36
|
+
doc = Nokorexi.new(url).to_doc
|
37
|
+
|
38
|
+
table = doc.root.element('//table')
|
39
|
+
|
40
|
+
prev_col = ''
|
41
|
+
a0 = []
|
42
|
+
|
43
|
+
# get the destinations
|
44
|
+
# inbound and outbound
|
45
|
+
table.xpath('tr').each do |tr|
|
46
|
+
|
47
|
+
# get the name
|
48
|
+
a = tr.xpath('td//text()').map(&:to_s)
|
49
|
+
|
50
|
+
col1 = a.shift.strip
|
51
|
+
|
52
|
+
if col1 =~ /Service (\w?\d+)/ then
|
53
|
+
|
54
|
+
a0 << {service: $1}
|
55
|
+
|
56
|
+
elsif col1.empty? or col1.length <= 1
|
57
|
+
|
58
|
+
if prev_col.empty? or prev_col.length <= 1 and a0.last.any? then
|
59
|
+
|
60
|
+
a0 << {}
|
61
|
+
|
62
|
+
else
|
63
|
+
|
64
|
+
prev_col = ''
|
65
|
+
end
|
66
|
+
|
67
|
+
elsif prev_col =~ /Service \w?\d+/
|
68
|
+
|
69
|
+
a0.last.merge!(timetable: col1)
|
70
|
+
|
71
|
+
else
|
72
|
+
|
73
|
+
if a.any? then
|
74
|
+
|
75
|
+
h = a0.last
|
76
|
+
|
77
|
+
if h.has_key? col1 then
|
78
|
+
h[col1].concat a
|
79
|
+
else
|
80
|
+
h[col1] = a
|
81
|
+
end
|
82
|
+
|
83
|
+
else
|
84
|
+
a0.pop if a0.last.empty?
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
prev_col = col1
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
master = {
|
94
|
+
service: '',
|
95
|
+
weekday: {desc: '', inbound: {}, outbound: {}},
|
96
|
+
saturday: {desc: '', inbound: {}, outbound: {}},
|
97
|
+
sunday: {desc: '', inbound: {}, outbound: {}}
|
98
|
+
}
|
99
|
+
|
100
|
+
h = a0.shift
|
101
|
+
master[:service] = h[:service]
|
102
|
+
master[:weekday][:desc] = h[:timetable]
|
103
|
+
|
104
|
+
h = a0.shift
|
105
|
+
master[:weekday][:inbound] = h
|
106
|
+
h = a0.shift
|
107
|
+
master[:weekday][:outbound] = h
|
108
|
+
|
109
|
+
h = a0.shift
|
110
|
+
h = a0.shift until h.any?
|
111
|
+
master[:saturday][:desc] = h[:timetable]
|
112
|
+
h = a0.shift
|
113
|
+
master[:saturday][:inbound] = h
|
114
|
+
h = a0.shift
|
115
|
+
master[:saturday][:outbound] = h
|
116
|
+
|
117
|
+
h = a0.shift
|
118
|
+
h = a0.shift until h.any?
|
119
|
+
master[:sunday][:desc] = h[:timetable]
|
120
|
+
h = a0.shift
|
121
|
+
master[:sunday][:inbound] = h
|
122
|
+
h = a0.shift
|
123
|
+
master[:sunday][:outbound] = h
|
124
|
+
|
125
|
+
# note: the special character looks like a space
|
126
|
+
# but is in fact " ".ord #=> 160
|
127
|
+
|
128
|
+
master.to_a[1..-1].each do |key, timetable|
|
129
|
+
|
130
|
+
timetable.to_a[1..-1].each do |direction, printed_rows|
|
131
|
+
|
132
|
+
# find the interval gaps
|
133
|
+
|
134
|
+
a = printed_rows.to_a
|
135
|
+
index = a.index a.detect {|x| x.last.grep(/^ $/).any? }
|
136
|
+
a2 = a[index].last
|
137
|
+
|
138
|
+
gaps = a2.map.with_index.select {|x,i| x == " "}.map(&:last)
|
139
|
+
|
140
|
+
gaps.delete_at -1 if gaps.last >= a2.length - 1
|
141
|
+
|
142
|
+
# sanitise the times (where short hand times are
|
143
|
+
# given i.e. minutes only)
|
144
|
+
|
145
|
+
printed_rows.each do |name, row|
|
146
|
+
|
147
|
+
prev_time = nil
|
148
|
+
printed_rows[name] = row.map.with_index do |col,i|
|
149
|
+
|
150
|
+
if gaps.include? i then
|
151
|
+
col
|
152
|
+
else
|
153
|
+
case col
|
154
|
+
when /^\d{4}$/
|
155
|
+
# record the time
|
156
|
+
prev_time = Time.strptime(col, "%H%M")
|
157
|
+
col
|
158
|
+
when /^\d{2}$/
|
159
|
+
|
160
|
+
# substitute with a time
|
161
|
+
val = "%02d%02d" % [prev_time.hour, col.to_i]
|
162
|
+
|
163
|
+
#if col is less than minutes, increment the hour
|
164
|
+
t = Time.strptime(val, "%H%M")
|
165
|
+
t = t + (60 * 60) if prev_time.min > t.min
|
166
|
+
prev_time = t
|
167
|
+
t.strftime("%H%M")
|
168
|
+
else
|
169
|
+
col
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
# fill in the gaps
|
177
|
+
|
178
|
+
periods = gaps.map {|i| a.map {|k,v| v[i].to_s.gsub(/\W/,'')}
|
179
|
+
.compact.join(' ').strip }
|
180
|
+
|
181
|
+
gap_times = gaps.zip(periods)
|
182
|
+
|
183
|
+
|
184
|
+
intervaltimes = gap_times.map do |i, desc|
|
185
|
+
|
186
|
+
interval = desc[/then every (\d+) mins until/,1].to_i
|
187
|
+
|
188
|
+
new_rows = printed_rows.map do |k,v|
|
189
|
+
|
190
|
+
times = []
|
191
|
+
next unless v[i-1] && v[i-1] =~ /^\d{4}$/
|
192
|
+
|
193
|
+
t = Time.strptime(v[i-1], "%H%M") #if v[i-1] =~ /^\d{4}$/
|
194
|
+
|
195
|
+
while t + (60 * interval) < Time.strptime(v[i+1], "%H%M") do
|
196
|
+
t = t + (60 * interval)
|
197
|
+
times << t.strftime("%H%M")
|
198
|
+
end
|
199
|
+
|
200
|
+
[k,times]
|
201
|
+
end.compact
|
202
|
+
|
203
|
+
[i, new_rows]
|
204
|
+
end
|
205
|
+
|
206
|
+
intervaltimes.reverse.each do |i, rows|
|
207
|
+
|
208
|
+
rows.each do |name, xtimes|
|
209
|
+
|
210
|
+
printed_rows[name].delete_at i
|
211
|
+
printed_rows[name].insert i, *xtimes
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
@timetable = master
|
220
|
+
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lothianbusestimetable
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- James Robertson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain:
|
11
|
+
- |
|
12
|
+
-----BEGIN CERTIFICATE-----
|
13
|
+
MIIDljCCAn6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBIMRIwEAYDVQQDDAlnZW1t
|
14
|
+
YXN0ZXIxHjAcBgoJkiaJk/IsZAEZFg5qYW1lc3JvYmVydHNvbjESMBAGCgmSJomT
|
15
|
+
8ixkARkWAmV1MB4XDTE3MDgyMjEyMzg1OFoXDTE4MDgyMjEyMzg1OFowSDESMBAG
|
16
|
+
A1UEAwwJZ2VtbWFzdGVyMR4wHAYKCZImiZPyLGQBGRYOamFtZXNyb2JlcnRzb24x
|
17
|
+
EjAQBgoJkiaJk/IsZAEZFgJldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
18
|
+
ggEBANn4wnsqPgnkuEmMe25DFlvzQD22UYMiPEFTfNC6WWoD/XGT/YV9hgPQ0Vxe
|
19
|
+
JdP67UjkqAT7dGceN7dBie6cjDx0koddtOOdioYQQ4i/ugCeyQPuqHbsSbDr2Dpu
|
20
|
+
wEQFUWAY3QXSuQojLwNIF9N1jwa6eTZji77VyA/+t5HO485EB4AQjBAgS1j09XRQ
|
21
|
+
8mInZcpsDFXy+SRmKy/k5UgoO+UPl1l7frGfF7ngad6Y66hFhv/qBg4bSbyHytfL
|
22
|
+
G1BSTbsXYFw+TemSHNOZ6omP5Gi6PIMZHbc8nOgPSVJ3miMTI3HSIvArrnmsF3Dg
|
23
|
+
FtLWSyZhm09xfPQp6O+eRkRugHUCAwEAAaOBijCBhzAJBgNVHRMEAjAAMAsGA1Ud
|
24
|
+
DwQEAwIEsDAdBgNVHQ4EFgQUWWYnDtPOZj84D4zYKoL5ka1Xg/gwJgYDVR0RBB8w
|
25
|
+
HYEbZ2VtbWFzdGVyQGphbWVzcm9iZXJ0c29uLmV1MCYGA1UdEgQfMB2BG2dlbW1h
|
26
|
+
c3RlckBqYW1lc3JvYmVydHNvbi5ldTANBgkqhkiG9w0BAQUFAAOCAQEAb8XQ6GME
|
27
|
+
ZhiRy44IrSVoTn9x+0/vXlSiR0A5pp/6l/tIhnCLRj033XA6WEYLGhhh8pYP8rbW
|
28
|
+
YPThZ/7jz2yzazCzfcvHi8dTd5RHtHZC2P5doj0yqjG+zBtq4nlmfZFSDD+m5+wJ
|
29
|
+
FNnNN1AZxxllHLxtBFvBhHMpccjU1BP/Rnmw9x9+l25eCn+GbvqvV1jurtKGWcml
|
30
|
+
DF7dZobpSzQTyh2BO/HWiJSdKHB6sB5oKWvpCDW4eltRAg/QLku5bkCK25zPVg5f
|
31
|
+
K7yWGJq+eGl34xrLaucvTbO8Ua3rHayCkBzgfx5LVcch22Axj8quw+YGsPnhuosr
|
32
|
+
BHdCmx9eUF/TKg==
|
33
|
+
-----END CERTIFICATE-----
|
34
|
+
date: 2017-08-22 00:00:00.000000000 Z
|
35
|
+
dependencies: []
|
36
|
+
description:
|
37
|
+
email: james@jamesrobertson.eu
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- lib/lothianbusestimetable.rb
|
43
|
+
homepage: https://github.com/jrobertson/lothianbusestimetable
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata: {}
|
47
|
+
post_install_message:
|
48
|
+
rdoc_options: []
|
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
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0'
|
61
|
+
requirements: []
|
62
|
+
rubyforge_project:
|
63
|
+
rubygems_version: 2.6.8
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: lothianbusestimetable
|
67
|
+
test_files: []
|
metadata.gz.sig
ADDED