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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e485184e0c61f0acea90948b5a905cfac6985f00
4
- data.tar.gz: '06593b9b4fa21e9d7d2f1f5c49b71aa413f6168f'
3
+ metadata.gz: 54a03b29fb608175ede8ece1d2edd85a90fdf3df
4
+ data.tar.gz: b9fee2a737759b20a6c0b830db3f0e5e40329f08
5
5
  SHA512:
6
- metadata.gz: 3d4f85c5063bc643bd1c27c8f7b0f8a1af0fcd8a3fe2699ae334a6b9cb2ca67af17505d3a95600b6205066a73924cc6eae13242d3ebdf9358c487fd8ef9c783b
7
- data.tar.gz: 2092051f1aa751d9b945e70512ae248e81a1787ad7b5f400be5c207987558e0848c2616d5653e957f773e53119886851b1037009a6024917ee7feb1e5b66fef7
6
+ metadata.gz: 416ab8ca11c80f68f38d38ac40a8b8a03d6149988d4737612ff892405db1df1220d4fc7000f86e4c7892d7bb5ec8b0189cfa2f588f003507cc52873aaed7397b
7
+ data.tar.gz: df8b09df88105badb3f94c01593b0b9a058997ffc819181ada379935ef8791b422fcbf2dab481bdc3630739dca2395b39500378b64e4b5dfdcf4f0f779dd5c13
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -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 + Time.now.strftime("%Y%m%d%H"))
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
- # call the get_services operation
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.1.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 unoficial gem to query the mybustracker.co.uk
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