bort 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+