mybustracker 0.1.0 → 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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/mybustracker.rb +209 -12
- metadata +62 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 54a03b29fb608175ede8ece1d2edd85a90fdf3df
|
4
|
+
data.tar.gz: b9fee2a737759b20a6c0b830db3f0e5e40329f08
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 416ab8ca11c80f68f38d38ac40a8b8a03d6149988d4737612ff892405db1df1220d4fc7000f86e4c7892d7bb5ec8b0189cfa2f588f003507cc52873aaed7397b
|
7
|
+
data.tar.gz: df8b09df88105badb3f94c01593b0b9a058997ffc819181ada379935ef8791b422fcbf2dab481bdc3630739dca2395b39500378b64e4b5dfdcf4f0f779dd5c13
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/mybustracker.rb
CHANGED
@@ -4,11 +4,194 @@
|
|
4
4
|
|
5
5
|
require 'savon'
|
6
6
|
require 'digest'
|
7
|
+
require 'subunit'
|
8
|
+
require 'geocoder'
|
9
|
+
require 'geodesic'
|
10
|
+
|
7
11
|
|
8
12
|
class MyBusTrackerException < Exception
|
13
|
+
|
14
|
+
class Service < Exception
|
15
|
+
end
|
16
|
+
|
9
17
|
end
|
10
18
|
|
19
|
+
|
11
20
|
class MyBusTracker
|
21
|
+
|
22
|
+
class Service
|
23
|
+
|
24
|
+
attr_reader :ref, :operator, :number, :name, :bus_stops
|
25
|
+
|
26
|
+
def initialize(client, appkey, service, all_dests,
|
27
|
+
all_bus_stops, number='')
|
28
|
+
|
29
|
+
if number.empty? then
|
30
|
+
raise MyBusTrackerException::Service, 'provide a bus service number'
|
31
|
+
end
|
32
|
+
|
33
|
+
@client, @appkey = client, appkey
|
34
|
+
|
35
|
+
# find out the reference number from the service hash object
|
36
|
+
|
37
|
+
#e.g. => {:ref=>"7", :operator_id=>"LB", :mnemo=>"4", :name=>"The Jewel
|
38
|
+
#-- Hillend", :type=>nil, :dests=>{:list=>["458752", ...]}
|
39
|
+
|
40
|
+
@number, @name, @ref, relative_dests, operator = \
|
41
|
+
%i(mnemo name ref dests operator).map {|field| service[field]}
|
42
|
+
|
43
|
+
@all_bus_stops = all_bus_stops
|
44
|
+
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# accepts a bus service number and returns the relative bus times
|
49
|
+
#
|
50
|
+
def query(times: 'next hour', from: nil, to: nil)
|
51
|
+
|
52
|
+
#from ||=
|
53
|
+
|
54
|
+
start_bus_stop1, start_bus_stop2 = find_bus_stop(from)
|
55
|
+
end_bus_stop1, end_bus_stop2 = find_bus_stop(to)
|
56
|
+
|
57
|
+
# get the bus times
|
58
|
+
|
59
|
+
@bus_stops, journey_times = get_stop_journeys(start_bus_stop1)
|
60
|
+
|
61
|
+
# select the bus stop end
|
62
|
+
|
63
|
+
end_stop = journey_times.find do |x|
|
64
|
+
x[:stop_id] == end_bus_stop1[:stop_id] or x[:stop_id] == end_bus_stop2[:stop_id]
|
65
|
+
end
|
66
|
+
|
67
|
+
if end_stop then
|
68
|
+
start_bus_stop = start_bus_stop1
|
69
|
+
else
|
70
|
+
start_bus_stop = start_bus_stop2
|
71
|
+
@bus_stops, journey_times = get_stop_journeys(start_bus_stop2) unless end_stop
|
72
|
+
return unless @bus_stops
|
73
|
+
# select the bus stop end
|
74
|
+
|
75
|
+
end_stop = journey_times.find do |x|
|
76
|
+
(x[:stop_id] == end_bus_stop1[:stop_id]) or (x[:stop_id] == end_bus_stop2[:stop_id])
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
tstart = Time.strptime(journey_times[0][:time],"%H:%M")
|
82
|
+
tend = Time.strptime(end_stop[:time],"%H:%M")
|
83
|
+
travel_time = '~' + Subunit.new(units={minutes:60, hours:60}, \
|
84
|
+
seconds: tend - tstart).to_s(omit: [:seconds])
|
85
|
+
|
86
|
+
{
|
87
|
+
from: {bus_stop: start_bus_stop[:name], bus_stop_id: start_bus_stop[:stop_id]},
|
88
|
+
to: {bus_stop: end_stop[:stop_name], bus_stop_id: end_stop[:stop_id]},
|
89
|
+
start: journey_times[0][:time],
|
90
|
+
end: end_stop[:time],
|
91
|
+
travel_time: travel_time
|
92
|
+
}
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def find_bus_stop(address)
|
99
|
+
|
100
|
+
results = Geocoder.search(address.sub(/,? *edinburgh$/i,'') \
|
101
|
+
+ ", Edinburgh")
|
102
|
+
|
103
|
+
p1 = Geodesic::Position.new(*results[0].coordinates)
|
104
|
+
|
105
|
+
a = @all_bus_stops.sort_by do |h|
|
106
|
+
|
107
|
+
x, y = %i(x y).map {|fields| h[fields].to_f.round(4)}
|
108
|
+
|
109
|
+
p2 = Geodesic::Position.new(x, y)
|
110
|
+
d = Geodesic::dist_haversine(p1.lat, p1.lon, p2.lat, p2.lon).round(4)
|
111
|
+
end
|
112
|
+
a.take 2
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_stop_journeys(start_bus_stop)
|
117
|
+
|
118
|
+
response = @client.call(:get_bus_times, message: { key: @appkey, time_requests: {list: [{stop_id: start_bus_stop[:stop_id] }]} })
|
119
|
+
|
120
|
+
bus_times = response.body[:bus_times_response][:bus_times][:list].find do |bus_time|
|
121
|
+
bus_time[:ref_service] == @ref
|
122
|
+
end
|
123
|
+
|
124
|
+
#e.g.r.keys => [:operator_id, :stop_id, :stop_name, :ref_service, :mnemo_service, :name_service,
|
125
|
+
# :time_datas, :global_disruption, :service_disruption, :bus_stop_disruption, :service_diversion]
|
126
|
+
|
127
|
+
return unless bus_times
|
128
|
+
|
129
|
+
# get the 1st journey id
|
130
|
+
list = bus_times[:time_datas][:list]
|
131
|
+
journey_id = list.is_a?(Array) ? list[0][:journey_id] : list[:journey_id]
|
132
|
+
|
133
|
+
response = @client.call(:get_journey_times, message: { key: @appkey, journey_id: journey_id, stop_id: start_bus_stop[:stop_id] })
|
134
|
+
journey = response.body[:journey_times_response][:journey_times][:list]
|
135
|
+
#=> [:journey_id, :bus_id, :operator_id, :ref_service, :mnemo_service, :name_service, :ref_dest, :name_dest, :terminus, :journey_time_datas, :global_disruption, :service_disruption, :service_diversion]
|
136
|
+
|
137
|
+
journey_times = journey[:journey_time_datas][:list]
|
138
|
+
# get the bus stops
|
139
|
+
[journey_times.inject({}) {|r,x| r.merge(x[:stop_name] => {id: x[:stop_id]}) }, journey_times]
|
140
|
+
end
|
141
|
+
|
142
|
+
# method no longer used
|
143
|
+
#
|
144
|
+
def fetch_bus_stops2()
|
145
|
+
# find the outbound destination
|
146
|
+
dest = relative_dests[:list].find do |ref|
|
147
|
+
all_dests.find {|x| x[:ref] == ref and x[:direction] == 'R' }
|
148
|
+
end
|
149
|
+
|
150
|
+
# go through each bus stop to find the dests
|
151
|
+
|
152
|
+
raw_bus_stops = all_bus_stops.select do |bus_stop|
|
153
|
+
bus_stop[:dests][:list].include? dest
|
154
|
+
end
|
155
|
+
|
156
|
+
c = ->(coord){ coord.to_f.round(4)}
|
157
|
+
|
158
|
+
response = client.call(:get_service_points, message: \
|
159
|
+
{ key: appkey, ref: ref })
|
160
|
+
all_service_points = response.body[:service_points_response]\
|
161
|
+
[:service_points][:list]
|
162
|
+
|
163
|
+
# select only the 1st chain
|
164
|
+
#service_points = all_service_points#.group_by {|x| x[:chainage]}.first[-1]
|
165
|
+
#puts 'service_points: ' + service_points.inspect
|
166
|
+
|
167
|
+
unsorted_bus_stops = []
|
168
|
+
raw_bus_stops.each do |bus_stop|
|
169
|
+
|
170
|
+
x, y = %i(x y).map {|field| bus_stop[field]}.map(&c)
|
171
|
+
|
172
|
+
r = all_service_points.select do |point|
|
173
|
+
[point[:x], point[:y]].map(&c) == [x, y]
|
174
|
+
end
|
175
|
+
|
176
|
+
r.each do |x|
|
177
|
+
unsorted_bus_stops << [bus_stop[:name], bus_stop[:stop_id], x, x[:order].to_i ]
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
|
183
|
+
#@bus_stops = unsorted_bus_stops.compact.sort_by(&:last)
|
184
|
+
#=begin
|
185
|
+
# find the correct chainage by the most records
|
186
|
+
h = unsorted_bus_stops.group_by {|x| x[2][:chainage]}
|
187
|
+
a = h.map {|k,v| v.count {|x| x[2][:chainage] == k}}
|
188
|
+
|
189
|
+
@bus_stops = h.to_a[a.index(a.max)].last\
|
190
|
+
.sort_by(&:last).inject({}){|r, x| r.merge(x[0] => {id: x[1]}) }
|
191
|
+
#=end
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
12
195
|
|
13
196
|
|
14
197
|
def initialize(api_key: '')
|
@@ -16,7 +199,7 @@ class MyBusTracker
|
|
16
199
|
|
17
200
|
raise MyBusTrackerException, 'api_key missing' if api_key.empty?
|
18
201
|
|
19
|
-
@client = Savon.client(wsdl: 'http://ws.mybustracker.co.uk/?wsdl')
|
202
|
+
@client = client = Savon.client(wsdl: 'http://ws.mybustracker.co.uk/?wsdl')
|
20
203
|
|
21
204
|
#@client.operations
|
22
205
|
|
@@ -24,23 +207,37 @@ class MyBusTracker
|
|
24
207
|
# :get_bus_stops, :get_bus_times, :get_journey_times, :get_disruptions,
|
25
208
|
# :get_diversions, :get_diversion_points]
|
26
209
|
|
27
|
-
@appkey = Digest::MD5.hexdigest( api_key +
|
210
|
+
@appkey = appkey = Digest::MD5.hexdigest( api_key +
|
211
|
+
Time.now.strftime("%Y%m%d%H"))
|
212
|
+
|
213
|
+
response = client.call(:get_services, message: { key: appkey })
|
214
|
+
@all_services= response.body[:services_response][:services][:list]
|
215
|
+
|
216
|
+
response = client.call(:get_dests, message: { key: appkey })
|
217
|
+
@all_dests = response.body[:dests_response][:dests][:list]
|
218
|
+
|
219
|
+
response = client.call(:get_bus_stops, message: { key: appkey })
|
220
|
+
@all_bus_stops = response.body[:bus_stops_response][:bus_stops][:list]
|
28
221
|
|
29
222
|
|
30
223
|
end
|
31
224
|
|
225
|
+
# returns the number and name of all bus services
|
226
|
+
#
|
32
227
|
def services()
|
33
228
|
|
34
|
-
|
35
|
-
response = @client.call(:get_services, message: { key: @appkey })
|
36
|
-
r = response.body
|
37
|
-
|
38
|
-
a = r[:services_response][:services][:list].map do |x|
|
39
|
-
[x[:mnemo], x[:name]]
|
40
|
-
end
|
41
|
-
|
42
|
-
a.to_h
|
229
|
+
@all_services.map {|x| [x[:mnemo], x[:name]] }.to_h
|
43
230
|
|
44
231
|
end
|
232
|
+
|
233
|
+
# accepts a bus service number and returns the relative bus times
|
234
|
+
#
|
235
|
+
def service(number='')
|
236
|
+
|
237
|
+
service = @all_services.find {|x| x[:mnemo] == number }
|
238
|
+
Service.new @client, @appkey, service, @all_dests, @all_bus_stops, number
|
239
|
+
|
240
|
+
end
|
241
|
+
|
242
|
+
|
45
243
|
end
|
46
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mybustracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Robertson
|
@@ -53,6 +53,66 @@ dependencies:
|
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: 2.11.2
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: subunit
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - "~>"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0.2'
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 0.2.7
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - "~>"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0.2'
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 0.2.7
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: geocoder
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.4'
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.4.4
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - "~>"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '1.4'
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: 1.4.4
|
96
|
+
- !ruby/object:Gem::Dependency
|
97
|
+
name: geodesic
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '1.0'
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: 1.0.1
|
106
|
+
type: :runtime
|
107
|
+
prerelease: false
|
108
|
+
version_requirements: !ruby/object:Gem::Requirement
|
109
|
+
requirements:
|
110
|
+
- - "~>"
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
version: '1.0'
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 1.0.1
|
56
116
|
description:
|
57
117
|
email: james@jamesrobertson.eu
|
58
118
|
executables: []
|
@@ -83,6 +143,6 @@ rubyforge_project:
|
|
83
143
|
rubygems_version: 2.6.8
|
84
144
|
signing_key:
|
85
145
|
specification_version: 4
|
86
|
-
summary: "*Currently under development*. An
|
146
|
+
summary: "*Currently under development*. An unofficial gem to query the mybustracker.co.uk
|
87
147
|
web service for bus times etc. #edinburgh"
|
88
148
|
test_files: []
|
metadata.gz.sig
CHANGED
Binary file
|