bort 0.0.1

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.
@@ -0,0 +1,160 @@
1
+ require 'net/http'
2
+ require 'time'
3
+ require 'date'
4
+ require 'hpricot'
5
+ require 'bort/realtime'
6
+ require 'bort/route'
7
+ require 'bort/schedule'
8
+ require 'bort/station'
9
+
10
+ module Bort
11
+ def self.Bort(key)
12
+ Util.set_key(key)
13
+ end
14
+ def Bort(key); Bort::Bort(key); end
15
+
16
+ # shortcuts
17
+ def self.trains_near(orig, filters={})
18
+ Realtime::Estimates.new(orig).select(filters)
19
+ end
20
+
21
+ def self.routes(options={})
22
+ Route.routes(options)
23
+ end
24
+
25
+ def self.route(route_number, options={})
26
+ Route::Info.new(route_number, options)
27
+ end
28
+
29
+ def self.trips(orig, dest, options={})
30
+ command = options.delete(:by) { 'arrive' }
31
+ Schedule::Trips.new(command, orig, dest, options).trips
32
+ end
33
+
34
+ def self.fare(orig, dest, options={})
35
+ Schedule::fare(orig, dest, options)
36
+ end
37
+
38
+ def self.schedules
39
+ Schedule.schedules
40
+ end
41
+
42
+ def self.schedule_at(abbreviation, options={})
43
+ Schedule::StationSchedule.new(abbreviation, options).schedules
44
+ end
45
+
46
+ def self.stations
47
+ Station.stations
48
+ end
49
+
50
+ def self.station_info(abbreviation)
51
+ Station.info(abbreviation)
52
+ end
53
+
54
+ class Util
55
+ def self.set_key(key)
56
+ @@api_key = key
57
+ end
58
+
59
+ def self.download(params)
60
+ params[:key] = @@api_key
61
+ action = params.delete(:action)
62
+
63
+ queries = params.delete_if{|k, v|v.nil?}.map{|k, v| "#{k}=#{v}" }.join('&')
64
+ request = Net::HTTP::Get.new("/api/#{action}.aspx?#{queries}")
65
+ response = Net::HTTP.start('api.bart.gov') do |http|
66
+ http.request(request)
67
+ end
68
+
69
+ response.body
70
+ end
71
+
72
+ # param validation
73
+ VALID_AM_PM = ['am', 'pm', nil]
74
+ VALID_DATE_STRING = ['today', 'now', nil]
75
+
76
+ def self.validate_time(time)
77
+ return unless time
78
+
79
+ hm, ap = time.split('+')
80
+ hh, mm = hm.split(':').map(&:to_i)
81
+
82
+ unless /^\d{1,2}:\d{1,2}\+\w\w$/ === time &&
83
+ VALID_AM_PM.include?(ap.downcase) &&
84
+ (1..12) === hh &&
85
+ (0..59) === mm
86
+
87
+ raise InvalidTime.new(time)
88
+ end
89
+ end
90
+
91
+ def self.validate_date(date)
92
+ return if VALID_DATE_STRING.include?(date)
93
+
94
+ mm, dd, yyyy = date.split('/').map(&:to_i)
95
+ year = Time.now.year
96
+
97
+ unless /^\d{1,2}\/\d{1,2}\/\d{4}$/ === date &&
98
+ (1..12) === mm &&
99
+ (1..31) === dd &&
100
+ (year-1..year+1) === yyyy
101
+
102
+ raise InvalidDate.new(date)
103
+ end
104
+ end
105
+
106
+ def self.validate_station(station)
107
+ raise InvalidStation.new(station) unless STATIONS.keys.map(&:to_s).include?(station.to_s.downcase)
108
+ end
109
+ end
110
+
111
+ STATIONS = {
112
+ :"12th" => "12th St. Oakland City Center",
113
+ :"16th" => "16th St. Mission (SF)",
114
+ :"19th" => "19th St. Oakland",
115
+ :"24th" => "24th St. Mission (SF)",
116
+ :ashb => "Ashby (Berkeley)",
117
+ :balb => "Balboa Park (SF)",
118
+ :bayf => "Bay Fair (San Leandro)",
119
+ :cast => "Castro Valley",
120
+ :civc => "Civic Center (SF)",
121
+ :cols => "Coliseum/Oakland Airport",
122
+ :colm => "Colma",
123
+ :conc => "Concord",
124
+ :daly => "Daly City",
125
+ :dbrk => "Downtown Berkeley",
126
+ :dubl => "Dublin/Pleasanton",
127
+ :deln => "El Cerrito del Norte",
128
+ :plza => "El Cerrito Plaza",
129
+ :embr => "Embarcadero (SF)",
130
+ :frmt => "Fremont",
131
+ :ftvl => "Fruitvale (Oakland)",
132
+ :glen => "Glen Park (SF)",
133
+ :hayw => "Hayward",
134
+ :lafy => "Lafayette",
135
+ :lake => "Lake Merritt (Oakland)",
136
+ :mcar => "MacArthur (Oakland)",
137
+ :mlbr => "Millbrae",
138
+ :mont => "Montgomery St. (SF)",
139
+ :nbrk => "North Berkeley",
140
+ :ncon => "North Concord/Martinez",
141
+ :orin => "Orinda",
142
+ :pitt => "Pittsburg/Bay Point",
143
+ :phil => "Pleasant Hill",
144
+ :powl => "Powell St. (SF)",
145
+ :rich => "Richmond",
146
+ :rock => "Rockridge (Oakland)",
147
+ :sbrn => "San Bruno",
148
+ :sfia => "San Francisco Int'l Airport",
149
+ :sanl => "San Leandro",
150
+ :shay => "South Hayward",
151
+ :ssan => "South San Francisco",
152
+ :ucty => "Union City",
153
+ :wcrk => "Walnut Creek",
154
+ :woak => "West Oakland",
155
+ }
156
+
157
+ class InvalidDate < RuntimeError; end
158
+ class InvalidTime < RuntimeError; end
159
+ class InvalidStation < RuntimeError; end
160
+ end
@@ -0,0 +1,83 @@
1
+ module Bort
2
+ module Realtime
3
+ class Estimates
4
+ attr_accessor :origin, :platform, :direction, :fetched_at, :destinations, :trains
5
+
6
+ VALID_PLATFORMS = %w(1 2 3 4)
7
+ VALID_DIRECTIONS = %w(n s)
8
+ def initialize(orig, options={})
9
+ self.origin = orig
10
+ load_options(options)
11
+
12
+ download_options = {
13
+ :action => 'etd',
14
+ :cmd => 'etd',
15
+ :orig => origin,
16
+ :plat => platform,
17
+ :dir => direction,
18
+ }
19
+
20
+ xml = Util.download(download_options)
21
+ data = Hpricot(xml)
22
+
23
+ self.origin = (data/:abbr).inner_text
24
+ self.fetched_at = Time.parse((data/:time).inner_text)
25
+ self.trains = []
26
+ self.destinations = []
27
+
28
+ (data/:etd).map do |estimate|
29
+ destination = (estimate/:abbreviation).inner_text
30
+ self.destinations << destination
31
+ (estimate/:estimate).map do |train|
32
+ self.trains << Train.new(train, origin, destination)
33
+ end
34
+ end
35
+ end
36
+
37
+ def select(type, value=nil)
38
+ filters =
39
+ if type.class == Hash
40
+ type
41
+ else
42
+ { type => value }
43
+ end
44
+ trains.select do |train|
45
+ filters.all? do |type, value|
46
+ train.send(type) == value
47
+ end
48
+ end
49
+ end
50
+ alias :filter :select
51
+
52
+ private
53
+ def load_options(options)
54
+ self.platform = options.delete(:platform)
55
+ self.direction = options.delete(:direction)
56
+
57
+ Util.validate_station(origin)
58
+ raise InvalidPlatform.new(platform) unless platform.nil? || VALID_PLATFORMS.include?(platform.to_s)
59
+ raise InvalidDirection.new(direction) unless direction.nil? || VALID_DIRECTIONS.include?(direction.to_s)
60
+ end
61
+ end
62
+
63
+ class Train
64
+ attr_accessor :station, :destination, :minutes, :platform, :direction, :length, :color, :hexcolor, :bike_flag
65
+
66
+ def initialize(doc, orig, dest)
67
+ self.station = orig
68
+ self.destination = dest
69
+ self.minutes = (doc/:minutes).inner_text.to_i
70
+ self.platform = (doc/:platform).inner_text.to_i
71
+ self.direction = (doc/:direction).inner_text[0,1].downcase
72
+ self.length = (doc/:length).inner_text.to_i
73
+ self.color = (doc/:color).inner_text.downcase
74
+ self.hexcolor = (doc/:hexcolor).inner_text.downcase
75
+ self.bike_flag = (doc/:bikeflag).inner_text == '1'
76
+ end
77
+ end
78
+
79
+ class InvalidPlatform < RuntimeError; end
80
+ class InvalidDirection < RuntimeError; end
81
+
82
+ end
83
+ end
@@ -0,0 +1,105 @@
1
+ module Bort
2
+ module Route
3
+ class Route
4
+ attr_accessor :name, :abbreviation, :route_id, :number, :color
5
+ def self.parse(doc)
6
+ route = Route.new
7
+ route.name = (doc/:name).inner_text
8
+ route.abbreviation = (doc/:abbr).inner_text
9
+ route.route_id = (doc/:routeid).inner_text
10
+ route.number = (doc/:number).inner_text.to_i
11
+ route.color = (doc/:color).inner_text
12
+
13
+ route
14
+ end
15
+
16
+ def info(options={})
17
+ Info.new(number, options)
18
+ end
19
+
20
+ def schedule(options={})
21
+ Schedule::RouteSchedule.new(number, options)
22
+ end
23
+
24
+ def <=> other
25
+ self.number <=> other.number
26
+ end
27
+ end
28
+
29
+ def self.routes(options={})
30
+ Routes.new(options).routes
31
+ end
32
+
33
+ class Routes
34
+ attr_accessor :schedule, :date, :schedule_number, :routes
35
+
36
+ def initialize(options={})
37
+ load_options(options)
38
+
39
+ download_options = {
40
+ :action => 'route',
41
+ :cmd => 'routes',
42
+ }
43
+ download_options[:sched] = schedule
44
+ download_options[:date] = date
45
+
46
+ xml = Util.download(download_options)
47
+ data = Hpricot(xml)
48
+
49
+ self.schedule_number = (data/:sched_num).inner_text
50
+ self.routes = (data/:route).map do |route|
51
+ Route.parse(route)
52
+ end.sort
53
+ end
54
+
55
+ private
56
+ def load_options(options)
57
+ self.schedule = options.delete(:schedule)
58
+ # date does not appear to be supported by the current API
59
+ self.date = options.delete(:date)
60
+
61
+ Util.validate_date(date)
62
+ end
63
+ end
64
+
65
+ class Info
66
+ attr_accessor :route_number, :schedule_number, :date, :name, :abbreviation,
67
+ :route_id, :origin, :destination, :color, :holidays, :stations
68
+
69
+ def initialize(number, options={})
70
+ self.route_number = number
71
+ load_options(options)
72
+
73
+ download_options = {
74
+ :action => 'route',
75
+ :cmd => 'routeinfo',
76
+ :route => route_number,
77
+ }
78
+ download_options[:sched] = schedule_number
79
+ download_options[:date] = date
80
+
81
+ xml = Util.download(download_options)
82
+ data = Hpricot(xml)
83
+
84
+ self.schedule_number = (data/:sched_num).inner_text
85
+ self.name = (data/:route/:name).inner_text
86
+ self.abbreviation = (data/:route/:abbr).inner_text
87
+ self.route_number = (data/:route/:number).inner_text
88
+ self.origin = (data/:route/:origin).inner_text
89
+ self.destination = (data/:route/:destination).inner_text
90
+ self.color = (data/:route/:color).inner_text
91
+ self.holidays = (data/:route/:holidays).inner_text
92
+ self.stations = (data/:route/:config/:station).map(&:inner_text)
93
+ end
94
+
95
+ private
96
+ def load_options(options)
97
+ self.schedule_number = options.delete(:schedule_number)
98
+ self.date = options.delete(:date)
99
+
100
+ Util.validate_date(date)
101
+ end
102
+ end
103
+
104
+ end
105
+ end
@@ -0,0 +1,342 @@
1
+ module Bort
2
+ module Schedule
3
+ def self.trips_by_arrival(orig, dest, options={})
4
+ Trips.new('arrive', orig, dest, options).trips
5
+ end
6
+
7
+ def self.trips_by_departure(orig, dest, options={})
8
+ Trips.new('depart', orig, dest, options).trips
9
+ end
10
+
11
+ class Trips
12
+ attr_accessor :origin, :destination, :time, :date, :before, :after,
13
+ :legend, :schedule_number, :trips
14
+
15
+ def initialize(command, orig, dest, options={})
16
+ self.origin = orig
17
+ self.destination = dest
18
+ load_options(options)
19
+
20
+ download_options = {
21
+ :action => 'sched',
22
+ :cmd => command,
23
+ :orig => origin,
24
+ :dest => destination,
25
+ :time => time,
26
+ :date => date,
27
+ :b => before,
28
+ :a => after,
29
+ :l => legend,
30
+ }
31
+
32
+ xml = Util.download(download_options)
33
+ data = Hpricot(xml)
34
+
35
+ self.date = Date.parse((data/:date).inner_text)
36
+ self.time = Time.parse("#{(data/:date).inner_text} #{(data/:time).inner_text}")
37
+ self.before = (data/:before).inner_text.to_i
38
+ self.after = (data/:after).inner_text.to_i
39
+ self.legend = (data/:legend).inner_text
40
+ self.schedule_number = (data/:sched_num).inner_text
41
+ self.trips = (data/:trip).map{|trip| Trip.parse(trip)}
42
+ end
43
+
44
+ private
45
+ def load_options(options)
46
+ self.time = options.delete(:time)
47
+ self.date = options.delete(:date)
48
+ self.legend = options.delete(:legend)
49
+ self.before = options.delete(:before)
50
+ self.after = options.delete(:after)
51
+
52
+ Util.validate_time(time)
53
+ Util.validate_date(date)
54
+
55
+ self.legend = [[0, legend.to_i].max, 1].min unless legend.nil?
56
+ self.before = [[0, before.to_i].max, 4].min unless before.nil?
57
+ self.after = [[0, after.to_i].max, 4].min unless after.nil?
58
+ end
59
+ end
60
+
61
+ class Trip
62
+ attr_accessor :origin, :destination, :fare, :origin_time, :origin_date,
63
+ :destination_time, :destination_date, :legs
64
+
65
+ def self.parse(doc)
66
+ trip = Trip.new
67
+ trip.origin = doc.attributes['origin']
68
+ trip.destination = doc.attributes['destination']
69
+ trip.fare = doc.attributes['fare'].to_f
70
+ trip.origin_date = Date.parse(doc.attributes['origtimedate'])
71
+ trip.destination_date = Date.parse(doc.attributes['desttimedate'])
72
+ trip.origin_time = Time.parse("#{doc.attributes['origtimedate']} #{doc.attributes['origtimemin']}")
73
+ trip.destination_time = Time.parse("#{doc.attributes['desttimedate']} #{doc.attributes['desttimemin']}")
74
+ trip.legs = (doc/:leg).map{|leg| Leg.parse(leg)}
75
+
76
+ trip
77
+ end
78
+ end
79
+
80
+ class Leg
81
+ attr_accessor :order, :transfer_code, :origin, :destination,
82
+ :origin_time, :origin_date, :destination_time, :destination_date,
83
+ :line, :bike_flag, :train_head_station
84
+
85
+ def self.parse(doc)
86
+ leg = Leg.new
87
+ leg.order = doc.attributes['order'].to_i
88
+ leg.transfer_code = doc.attributes['transfercode']
89
+ leg.origin = doc.attributes['origin']
90
+ leg.destination = doc.attributes['destination']
91
+ leg.origin_date = Date.parse(doc.attributes['origtimedate'])
92
+ leg.destination_date = Date.parse(doc.attributes['desttimedate'])
93
+ leg.origin_time = Time.parse("#{doc.attributes['origtimedate']} #{doc.attributes['origtimemin']}")
94
+ leg.destination_time = Time.parse("#{doc.attributes['desttimedate']} #{doc.attributes['desttimemin']}")
95
+ leg.line = doc.attributes['line']
96
+ leg.bike_flag = doc.attributes['bikeflag'] == '1'
97
+ leg.train_head_station = doc.attributes['trainheadstation']
98
+
99
+ leg
100
+ end
101
+ end
102
+
103
+ def self.fare(orig, dest, options={})
104
+ Fare.new(orig, dest, options).fare
105
+ end
106
+
107
+ class Fare
108
+ attr_accessor :origin, :destination, :date, :schedule_number, :fare
109
+
110
+ def initialize(orig, dest, options={})
111
+ self.origin = orig
112
+ self.destination = dest
113
+ load_options(options)
114
+
115
+ download_options = {
116
+ :action => 'sched',
117
+ :cmd => 'fare',
118
+ :orig => origin,
119
+ :dest => destination,
120
+ :date => date,
121
+ :sched => schedule_number,
122
+ }
123
+
124
+ xml = Util.download(download_options)
125
+ data = Hpricot(xml)
126
+
127
+ self.schedule_number = (data/:sched_num).inner_text.to_i
128
+ self.fare = (data/:fare).inner_text.to_f
129
+ end
130
+
131
+ private
132
+ def load_options(options)
133
+ self.date = options.delete(:date)
134
+ self.schedule_number = options.delete(:schedule_number)
135
+
136
+ Util.validate_date(date)
137
+ end
138
+ end
139
+
140
+ def self.holidays
141
+ download_options = {
142
+ :action => 'sched',
143
+ :cmd => 'holiday',
144
+ }
145
+
146
+ xml = Util.download(download_options)
147
+ data = Hpricot(xml)
148
+
149
+ (data/:holiday).map{|holiday|HolidayData.parse(holiday)}
150
+ end
151
+
152
+ class HolidayData
153
+ attr_accessor :name, :date, :schedule_type
154
+
155
+ def self.parse(doc)
156
+ data = HolidayData.new
157
+ data.name = (doc/:name).inner_text
158
+ data.date = Date.parse((doc/:date).inner_text)
159
+ data.schedule_type = (doc/:schedule_type).inner_text
160
+
161
+ data
162
+ end
163
+ end
164
+
165
+ class RouteSchedule
166
+ attr_accessor :route_number, :schedule_number, :date, :legend, :trains
167
+
168
+ def initialize(route_num, options={})
169
+ self.route_number = route_num
170
+ load_options(options)
171
+
172
+ download_options = {
173
+ :action => 'sched',
174
+ :cmd => 'routesched',
175
+ :route => route_number,
176
+ :sched => schedule_number,
177
+ :date => date,
178
+ :l => legend,
179
+ }
180
+
181
+ xml = Util.download(download_options)
182
+ data = Hpricot(xml)
183
+
184
+ self.date = Date.parse((data/:date).inner_text)
185
+ self.schedule_number = (data/:sched_num).inner_text.to_i
186
+ self.trains = (data/:train).map{|train| TrainSchedule.parse(train, date)}
187
+ self.legend = (data/:legend).inner_text
188
+ end
189
+
190
+ private
191
+ def load_options(options)
192
+ self.date = options.delete(:date)
193
+ self.schedule_number = options.delete(:schedule_number)
194
+ self.legend = options.delete(:legend)
195
+ self.date = options.delete(:date)
196
+
197
+ Util.validate_date(date)
198
+ end
199
+ end
200
+
201
+ class TrainSchedule
202
+ attr_accessor :stops, :index
203
+
204
+ def self.parse(doc, date)
205
+ schedule = TrainSchedule.new
206
+ schedule.index = doc.attributes['index'].to_i
207
+ schedule.stops = (doc/:stop).map{|stop| Stop.parse(stop, date)}
208
+
209
+ schedule
210
+ end
211
+ end
212
+
213
+ class Stop
214
+ attr_accessor :station, :origin_time, :bike_flag
215
+
216
+ def self.parse(doc, date)
217
+ stop = Stop.new
218
+ stop.station = doc.attributes['station']
219
+ stop.origin_time = Time.parse("#{date.to_s} #{doc.attributes['origtime']}")
220
+ stop.bike_flag = doc.attributes['bikeflag'] == '1'
221
+
222
+ stop
223
+ end
224
+ end
225
+
226
+ def self.schedules
227
+ download_options = {
228
+ :action => 'sched',
229
+ :cmd => 'scheds',
230
+ }
231
+
232
+ xml = Util.download(download_options)
233
+ data = Hpricot(xml)
234
+
235
+ (data/:schedule).map{|schedule| Schedule.parse(schedule)}.sort
236
+ end
237
+
238
+ class Schedule
239
+ attr_accessor :schedule_id, :effective_date
240
+
241
+ def self.parse(doc)
242
+ schedule = Schedule.new
243
+ schedule.schedule_id = doc.attributes['id'].to_i
244
+ schedule.effective_date = Time.parse(doc.attributes['effectivedate'])
245
+
246
+ schedule
247
+ end
248
+
249
+ def <=> other
250
+ self.schedule_id <=> other.schedule_id
251
+ end
252
+ end
253
+
254
+ def self.special_schedules(print_legend=false)
255
+ download_options = {
256
+ :action => 'sched',
257
+ :cmd => 'special',
258
+ :l => print_legend ? '1' : '0',
259
+ }
260
+
261
+ xml = Util.download(download_options)
262
+ data = Hpricot(xml)
263
+
264
+ puts (data/:legend).inner_text if print_legend
265
+
266
+ (data/:special_schedule).map{|special| SpecialSchedule.parse(special)}
267
+ end
268
+
269
+ class SpecialSchedule
270
+ attr_accessor :start_date, :end_date, :start_time, :end_time,
271
+ :text, :link, :origin, :destination, :day_of_week, :routes_affected
272
+
273
+ def self.parse(doc)
274
+ schedule = SpecialSchedule.new
275
+ schedule.start_date = Date.parse((doc/:start_date).inner_text)
276
+ schedule.end_date = Date.parse((doc/:end_date).inner_text)
277
+ schedule.start_time = Time.parse("#{schedule.start_date.to_s} #{(doc/:start_time).inner_text}")
278
+ schedule.end_time = Time.parse("#{schedule.end_date.to_s} #{(doc/:end_time).inner_text}")
279
+ schedule.text = (doc/:text).inner_text
280
+ schedule.link = (doc/:link).inner_text
281
+ schedule.origin = (doc/:orig).inner_text
282
+ schedule.destination = (doc/:dest).inner_text
283
+ schedule.day_of_week = (doc/:day_of_week).inner_text.split(',').map(&:to_i)
284
+ schedule.routes_affected = (doc/:routes_affected).inner_text.split(',')
285
+
286
+ schedule
287
+ end
288
+ end
289
+
290
+ class StationSchedule
291
+ attr_accessor :origin, :date, :schedule_number, :name, :abbreviation, :schedules, :legend
292
+
293
+ def initialize(origin, options={})
294
+ load_options(options)
295
+
296
+ download_options = {
297
+ :action => 'sched',
298
+ :cmd => 'stnsched',
299
+ :orig => origin,
300
+ :date => date,
301
+ :l => legend,
302
+ }
303
+
304
+ xml = Util.download(download_options)
305
+ data = Hpricot(xml)
306
+
307
+ self.date = Date.parse((data/:date).inner_text)
308
+ self.schedule_number = (data/:sched_num).inner_text.to_i
309
+ self.name = (data/:name).inner_text
310
+ self.abbreviation = (data/:abbr).inner_text
311
+ self.legend = (data/:legend).inner_text
312
+ self.schedules = (data/:station/:item).map{|line| StationLine.parse(line, date)}
313
+ end
314
+
315
+ private
316
+ def load_options(options)
317
+ self.date = options.delete(:date)
318
+ self.legend = options.delete(:legend)
319
+
320
+ Util.validate_date(date)
321
+ end
322
+ end
323
+
324
+ # TODO: DRY with Leg?
325
+ class StationLine
326
+
327
+ attr_accessor :name, :train_head_station, :origin_time, :destination_time, :index, :bike_flag
328
+ def self.parse(doc, date)
329
+ line = StationLine.new
330
+ line.name = doc.attributes['line']
331
+ line.train_head_station = doc.attributes['trainheadstation']
332
+ line.origin_time = Time.parse("#{date} #{doc.attributes['origtime']}")
333
+ line.destination_time = Time.parse("#{date} #{doc.attributes['desttime']}")
334
+ line.index = doc.attributes['trainidx'].to_i
335
+ line.bike_flag = doc.attributes['bikeflag'] == '1'
336
+
337
+ line
338
+ end
339
+ end
340
+
341
+ end
342
+ end
@@ -0,0 +1,106 @@
1
+ module Bort
2
+ module Station
3
+ class Station
4
+ attr_accessor :abbreviation, :destinations,
5
+ :north_platforms, :north_routes, :south_platforms, :south_routes, :platform_info,
6
+ :geo, :address, :city, :county, :state, :zip, :cross_street,
7
+ :bike_flag, :bike_station_flag, :bike_station_text,
8
+ :parking, :parking_flag, :transit_info, :car_share, :entering, :exiting,
9
+ :attraction, :shopping, :food, :intro, :locker_flag, :lockers, :fill_time, :link
10
+
11
+ def self.parse(doc)
12
+ station = Station.new
13
+ station.abbreviation = (doc/:abbr).inner_text
14
+ station.destinations = (doc/:destinations).inner_text
15
+
16
+ station.north_routes = (doc/:north_routes/:route).map(&:inner_text)
17
+ station.south_routes = (doc/:south_routes/:route).map(&:inner_text)
18
+ station.north_platforms = (doc/:north_platforms/:platform).map(&:inner_text).map(&:to_i)
19
+ station.south_platforms = (doc/:south_platforms/:platform).map(&:inner_text).map(&:to_i)
20
+ station.platform_info = (doc/:platform_info).inner_text
21
+
22
+ latitude = (doc/:gtfs_latitude).inner_text
23
+ longitude = (doc/:gtfs_longitude).inner_text
24
+ station.geo = [latitude, longitude] if latitude and longitude
25
+ station.address = (doc/:address).inner_text
26
+ station.city = (doc/:city).inner_text
27
+ station.county = (doc/:county).inner_text
28
+ station.state = (doc/:state).inner_text
29
+ station.zip = (doc/:zipcode).inner_text
30
+ station.cross_street = (doc/:cross_street).inner_text
31
+
32
+ station.bike_flag = parse_flag(doc.attributes['bike_flag'])
33
+ station.bike_station_flag = parse_flag(doc.attributes['bike_station_flag'])
34
+ station.bike_station_text = (doc/:bike_station_text).inner_text
35
+ station.parking = (doc/:parking).inner_text
36
+ station.parking_flag = parse_flag(doc.attributes['parking_flag'])
37
+ station.transit_info = (doc/:transit_info).inner_text
38
+ station.car_share = (doc/:car_share).inner_text
39
+ station.entering = (doc/:entering).inner_text
40
+ station.exiting = (doc/:exiting).inner_text
41
+
42
+ station.attraction = (doc/:attraction).inner_text
43
+ station.shopping = (doc/:shopping).inner_text
44
+ station.food = (doc/:food).inner_text
45
+ station.intro = (doc/:intro).inner_text
46
+ station.locker_flag = parse_flag(doc.attributes['locker_flag'])
47
+ station.lockers = (doc/:lockers).inner_text
48
+ station.fill_time = (doc/:fill_time).inner_text
49
+ station.link = (doc/:link).inner_text
50
+
51
+ station
52
+ end
53
+
54
+ def self.parse_flag(flag)
55
+ case flag
56
+ when '1' then true
57
+ when '0' then false
58
+ else nil
59
+ end
60
+ end
61
+ end
62
+
63
+ def self.access_info(station, print_legend=false)
64
+
65
+ download_options = {
66
+ :action => 'stn',
67
+ :cmd => 'stnaccess',
68
+ :orig => station,
69
+ :l => print_legend ? '1' : '0',
70
+ }
71
+
72
+ xml = Util.download(download_options)
73
+ data = Hpricot(xml)
74
+
75
+ puts (data/:legend).inner_text if print_legend
76
+ Station.parse((data/:station).first)
77
+ end
78
+
79
+ def self.info(abbreviation)
80
+ download_options = {
81
+ :action => 'stn',
82
+ :cmd => 'stninfo',
83
+ :orig => abbreviation,
84
+ }
85
+
86
+ xml = Util.download(download_options)
87
+ data = Hpricot(xml)
88
+
89
+ Station.parse((data/:station).first)
90
+ end
91
+
92
+ def self.stations
93
+
94
+ download_options = {
95
+ :action => 'stn',
96
+ :cmd => 'stns',
97
+ }
98
+
99
+ xml = Util.download(download_options)
100
+ data = Hpricot(xml)
101
+
102
+ (data/:station).map{|station| Station.parse(station)}
103
+ end
104
+
105
+ end
106
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bort
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - hc5duke
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-05-27 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: hpricot
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: Bort makes BART API available in ruby.
36
+ email: hc5duke@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - lib/bort/realtime.rb
45
+ - lib/bort/route.rb
46
+ - lib/bort/schedule.rb
47
+ - lib/bort/station.rb
48
+ - lib/bort.rb
49
+ has_rdoc: true
50
+ homepage: https://github.com/hc5duke/bort
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ hash: 3
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.3.7
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: BART API ruby wrapper.
83
+ test_files: []
84
+