api_object 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,19 +7,6 @@
7
7
  <station>
8
8
  <name>16th St. Mission</name>
9
9
  <abbr>16TH</abbr>
10
- <etd>
11
- <destination>24th Street</destination>
12
- <abbreviation>24TH</abbreviation>
13
- <estimate>
14
- <minutes>2</minutes>
15
- <platform>1</platform>
16
- <direction>South</direction>
17
- <length>9</length>
18
- <color>YELLOW</color>
19
- <hexcolor>#ffff33</hexcolor>
20
- <bikeflag>0</bikeflag>
21
- </estimate>
22
- </etd>
23
10
  <etd>
24
11
  <destination>Daly City</destination>
25
12
  <abbreviation>DALY</abbreviation>
@@ -82,59 +69,6 @@
82
69
  <bikeflag>1</bikeflag>
83
70
  </estimate>
84
71
  </etd>
85
- <etd>
86
- <destination>Fremont</destination>
87
- <abbreviation>FRMT</abbreviation>
88
- <estimate>
89
- <minutes>3</minutes>
90
- <platform>2</platform>
91
- <direction>North</direction>
92
- <length>8</length>
93
- <color>GREEN</color>
94
- <hexcolor>#339933</hexcolor>
95
- <bikeflag>1</bikeflag>
96
- </estimate>
97
- <estimate>
98
- <minutes>16</minutes>
99
- <platform>2</platform>
100
- <direction>North</direction>
101
- <length>9</length>
102
- <color>GREEN</color>
103
- <hexcolor>#339933</hexcolor>
104
- <bikeflag>1</bikeflag>
105
- </estimate>
106
- <estimate>
107
- <minutes>31</minutes>
108
- <platform>2</platform>
109
- <direction>North</direction>
110
- <length>9</length>
111
- <color>GREEN</color>
112
- <hexcolor>#339933</hexcolor>
113
- <bikeflag>1</bikeflag>
114
- </estimate>
115
- </etd>
116
- <etd>
117
- <destination>Millbrae</destination>
118
- <abbreviation>MLBR</abbreviation>
119
- <estimate>
120
- <minutes>4</minutes>
121
- <platform>1</platform>
122
- <direction>South</direction>
123
- <length>8</length>
124
- <color>RED</color>
125
- <hexcolor>#ff0000</hexcolor>
126
- <bikeflag>0</bikeflag>
127
- </estimate>
128
- <estimate>
129
- <minutes>18</minutes>
130
- <platform>1</platform>
131
- <direction>South</direction>
132
- <length>10</length>
133
- <color>RED</color>
134
- <hexcolor>#ff0000</hexcolor>
135
- <bikeflag>1</bikeflag>
136
- </estimate>
137
- </etd>
138
72
  <etd>
139
73
  <destination>Pittsburg/Bay Point</destination>
140
74
  <abbreviation>PITT</abbreviation>
@@ -166,81 +100,6 @@
166
100
  <bikeflag>1</bikeflag>
167
101
  </estimate>
168
102
  </etd>
169
- <etd>
170
- <destination>Richmond</destination>
171
- <abbreviation>RICH</abbreviation>
172
- <estimate>
173
- <minutes>11</minutes>
174
- <platform>2</platform>
175
- <direction>North</direction>
176
- <length>10</length>
177
- <color>RED</color>
178
- <hexcolor>#ff0000</hexcolor>
179
- <bikeflag>1</bikeflag>
180
- </estimate>
181
- <estimate>
182
- <minutes>20</minutes>
183
- <platform>2</platform>
184
- <direction>North</direction>
185
- <length>10</length>
186
- <color>RED</color>
187
- <hexcolor>#ff0000</hexcolor>
188
- <bikeflag>1</bikeflag>
189
- </estimate>
190
- <estimate>
191
- <minutes>35</minutes>
192
- <platform>2</platform>
193
- <direction>North</direction>
194
- <length>10</length>
195
- <color>RED</color>
196
- <hexcolor>#ff0000</hexcolor>
197
- <bikeflag>1</bikeflag>
198
- </estimate>
199
- </etd>
200
- <etd>
201
- <destination>SF Airport</destination>
202
- <abbreviation>SFIA</abbreviation>
203
- <estimate>
204
- <minutes>9</minutes>
205
- <platform>1</platform>
206
- <direction>South</direction>
207
- <length>10</length>
208
- <color>YELLOW</color>
209
- <hexcolor>#ffff33</hexcolor>
210
- <bikeflag>0</bikeflag>
211
- </estimate>
212
- </etd>
213
- <etd>
214
- <destination>SFO/Millbrae</destination>
215
- <abbreviation>MLBR</abbreviation>
216
- <estimate>
217
- <minutes>24</minutes>
218
- <platform>1</platform>
219
- <direction>South</direction>
220
- <length>10</length>
221
- <color>YELLOW</color>
222
- <hexcolor>#ffff33</hexcolor>
223
- <bikeflag>1</bikeflag>
224
- </estimate>
225
- <estimate>
226
- <minutes>39</minutes>
227
- <platform>1</platform>
228
- <direction>South</direction>
229
- <length>9</length>
230
- <color>YELLOW</color>
231
- <hexcolor>#ffff33</hexcolor>
232
- <bikeflag>1</bikeflag>
233
- </estimate>
234
- <estimate>
235
- <minutes>54</minutes>
236
- <platform>1</platform>
237
- <direction>South</direction>
238
- <length>9</length>
239
- <color>YELLOW</color>
240
- <hexcolor>#ffff33</hexcolor>
241
- <bikeflag>1</bikeflag>
242
- </estimate>
243
- </etd>
244
103
  </station>
245
104
  <message/>
246
105
  </root>
@@ -69,59 +69,6 @@
69
69
  <bikeflag>1</bikeflag>
70
70
  </estimate>
71
71
  </etd>
72
- <etd>
73
- <destination>Fremont</destination>
74
- <abbreviation>FRMT</abbreviation>
75
- <estimate>
76
- <minutes>14</minutes>
77
- <platform>2</platform>
78
- <direction>North</direction>
79
- <length>9</length>
80
- <color>GREEN</color>
81
- <hexcolor>#339933</hexcolor>
82
- <bikeflag>1</bikeflag>
83
- </estimate>
84
- <estimate>
85
- <minutes>29</minutes>
86
- <platform>2</platform>
87
- <direction>North</direction>
88
- <length>9</length>
89
- <color>GREEN</color>
90
- <hexcolor>#339933</hexcolor>
91
- <bikeflag>1</bikeflag>
92
- </estimate>
93
- <estimate>
94
- <minutes>44</minutes>
95
- <platform>2</platform>
96
- <direction>North</direction>
97
- <length>8</length>
98
- <color>GREEN</color>
99
- <hexcolor>#339933</hexcolor>
100
- <bikeflag>1</bikeflag>
101
- </estimate>
102
- </etd>
103
- <etd>
104
- <destination>Millbrae</destination>
105
- <abbreviation>MLBR</abbreviation>
106
- <estimate>
107
- <minutes>5</minutes>
108
- <platform>1</platform>
109
- <direction>South</direction>
110
- <length>8</length>
111
- <color>RED</color>
112
- <hexcolor>#ff0000</hexcolor>
113
- <bikeflag>1</bikeflag>
114
- </estimate>
115
- <estimate>
116
- <minutes>19</minutes>
117
- <platform>1</platform>
118
- <direction>South</direction>
119
- <length>10</length>
120
- <color>RED</color>
121
- <hexcolor>#ff0000</hexcolor>
122
- <bikeflag>1</bikeflag>
123
- </estimate>
124
- </etd>
125
72
  <etd>
126
73
  <destination>Pittsburg/Bay Point</destination>
127
74
  <abbreviation>PITT</abbreviation>
@@ -153,81 +100,6 @@
153
100
  <bikeflag>1</bikeflag>
154
101
  </estimate>
155
102
  </etd>
156
- <etd>
157
- <destination>Richmond</destination>
158
- <abbreviation>RICH</abbreviation>
159
- <estimate>
160
- <minutes>8</minutes>
161
- <platform>2</platform>
162
- <direction>North</direction>
163
- <length>10</length>
164
- <color>RED</color>
165
- <hexcolor>#ff0000</hexcolor>
166
- <bikeflag>1</bikeflag>
167
- </estimate>
168
- <estimate>
169
- <minutes>18</minutes>
170
- <platform>2</platform>
171
- <direction>North</direction>
172
- <length>10</length>
173
- <color>RED</color>
174
- <hexcolor>#ff0000</hexcolor>
175
- <bikeflag>1</bikeflag>
176
- </estimate>
177
- <estimate>
178
- <minutes>33</minutes>
179
- <platform>2</platform>
180
- <direction>North</direction>
181
- <length>10</length>
182
- <color>RED</color>
183
- <hexcolor>#ff0000</hexcolor>
184
- <bikeflag>1</bikeflag>
185
- </estimate>
186
- </etd>
187
- <etd>
188
- <destination>SF Airport</destination>
189
- <abbreviation>SFIA</abbreviation>
190
- <estimate>
191
- <minutes>11</minutes>
192
- <platform>1</platform>
193
- <direction>South</direction>
194
- <length>10</length>
195
- <color>YELLOW</color>
196
- <hexcolor>#ffff33</hexcolor>
197
- <bikeflag>1</bikeflag>
198
- </estimate>
199
- </etd>
200
- <etd>
201
- <destination>SFO/Millbrae</destination>
202
- <abbreviation>MLBR</abbreviation>
203
- <estimate>
204
- <minutes>25</minutes>
205
- <platform>1</platform>
206
- <direction>South</direction>
207
- <length>10</length>
208
- <color>YELLOW</color>
209
- <hexcolor>#ffff33</hexcolor>
210
- <bikeflag>1</bikeflag>
211
- </estimate>
212
- <estimate>
213
- <minutes>40</minutes>
214
- <platform>1</platform>
215
- <direction>South</direction>
216
- <length>9</length>
217
- <color>YELLOW</color>
218
- <hexcolor>#ffff33</hexcolor>
219
- <bikeflag>1</bikeflag>
220
- </estimate>
221
- <estimate>
222
- <minutes>55</minutes>
223
- <platform>1</platform>
224
- <direction>South</direction>
225
- <length>9</length>
226
- <color>YELLOW</color>
227
- <hexcolor>#ffff33</hexcolor>
228
- <bikeflag>1</bikeflag>
229
- </estimate>
230
- </etd>
231
103
  </station>
232
104
  <message/>
233
105
  </root>
@@ -0,0 +1,49 @@
1
+ <xml_api_reply version="1">
2
+ <weather module_id="0" tab_id="0" mobile_row="0" mobile_zipped="1" row="0" section="0">
3
+ <forecast_information>
4
+ <city data="Mountain View, CA"/>
5
+ <postal_code data="Mountain View"/>
6
+ <latitude_e6 data=""/>
7
+ <longitude_e6 data=""/>
8
+ <forecast_date data="2012-06-01"/>
9
+ <current_date_time data="2012-06-01 20:56:00 +0000"/>
10
+ <unit_system data="US"/>
11
+ </forecast_information>
12
+ <current_conditions>
13
+ <condition data="Clear"/>
14
+ <temp_f data="75"/>
15
+ <temp_c data="24"/>
16
+ <humidity data="Humidity: 51%"/>
17
+ <icon data="/ig/images/weather/sunny.gif"/>
18
+ <wind_condition data="Wind: NW at 9 mph"/>
19
+ </current_conditions>
20
+ <forecast_conditions>
21
+ <day_of_week data="Fri"/>
22
+ <low data="57"/>
23
+ <high data="78"/>
24
+ <icon data="/ig/images/weather/mostly_sunny.gif"/>
25
+ <condition data="Mostly Sunny"/>
26
+ </forecast_conditions>
27
+ <forecast_conditions>
28
+ <day_of_week data="Sat"/>
29
+ <low data="55"/>
30
+ <high data="77"/>
31
+ <icon data="/ig/images/weather/mostly_sunny.gif"/>
32
+ <condition data="Mostly Sunny"/>
33
+ </forecast_conditions>
34
+ <forecast_conditions>
35
+ <day_of_week data="Sun"/>
36
+ <low data="54"/>
37
+ <high data="72"/>
38
+ <icon data="/ig/images/weather/mostly_sunny.gif"/>
39
+ <condition data="Mostly Sunny"/>
40
+ </forecast_conditions>
41
+ <forecast_conditions>
42
+ <day_of_week data="Mon"/>
43
+ <low data="48"/>
44
+ <high data="68"/>
45
+ <icon data="/ig/images/weather/chance_of_rain.gif"/>
46
+ <condition data="Chance of Rain"/>
47
+ </forecast_conditions>
48
+ </weather>
49
+ </xml_api_reply>
@@ -1,32 +1,94 @@
1
1
  require 'minitest/autorun'
2
2
  require_relative 'station'
3
+ require_relative 'weather'
4
+ require_relative 'route'
3
5
 
4
6
  class ApiObjectTest < MiniTest::Unit::TestCase
5
7
 
6
8
  include ActiveApi
7
9
  include TestObjects
8
-
10
+
9
11
  @@data_directory = File.expand_path('../../data', __FILE__)
10
12
  @@estimate_directory = @@data_directory + "/estimate"
11
-
13
+ @@weather_directory = @@data_directory + "/weather"
14
+ @@bus_directory = @@data_directory + "/bus"
15
+
12
16
  @@glen_estimate = Station.load_from_xml(File.read(@@estimate_directory + '/glen.xml'))
13
17
  @@sixteenth_estimate = Station.load_from_xml(File.read(@@estimate_directory + '/sixteenth.xml'))
14
18
  @@twenty_fourth_estimate = Station.load_from_xml(File.read(@@estimate_directory + '/twenty_fourth.xml'))
15
-
16
- def test_should_get_correct_estimates
19
+
20
+
21
+
22
+ @@weather = Weather.load_from_xml(File.read(@@weather_directory + '/mountain_view.xml'))
23
+
24
+ @@muni_routes = Route.load_from_xml(File.read(@@bus_directory + "/muni_routes.xml"))
25
+ @@muni_F = Route.load_from_xml(File.read(@@bus_directory + "/muni_F.xml"))
26
+
27
+ def test_should_get_correct_BART_estimates
17
28
  glen_estimate = Station.new(Station.get_results(:orig => 'GLEN'))
18
29
  now = DateTime.strptime(glen_estimate.date + " " + glen_estimate.time, "%m/%d/%Y %I:%M:%S %p %Z")
19
30
  if business_time? now
20
31
  sixteenth_estimate = Station.new(Station.get_results(:orig => '16TH'))
21
32
  twenty_fourth_estimate = Station.new(Station.get_results(:orig => '24TH'))
22
- assert_equal(glen_estimate, @@glen_estimate)
23
- assert_equal(sixteenth_estimate, @@sixteenth_estimate)
24
- assert_equal(twenty_fourth_estimate, @@twenty_fourth_estimate)
33
+ assert_equal_station(glen_estimate, @@glen_estimate)
34
+ assert_equal_station(sixteenth_estimate, @@sixteenth_estimate)
35
+ assert_equal_station(twenty_fourth_estimate, @@twenty_fourth_estimate)
36
+ end
37
+ end
38
+
39
+ def test_should_not_get_correct_BART_estimates
40
+ glen_estimate = Station.new(Station.get_results(:orig => 'GLEN'))
41
+ now = DateTime.strptime(glen_estimate.date + " " + glen_estimate.time, "%m/%d/%Y %I:%M:%S %p %Z")
42
+ if business_time? now
43
+ sixteenth_estimate = Station.new(Station.get_results(:orig => '16TH'))
44
+ twenty_fourth_estimate = Station.new(Station.get_results(:orig => '24TH'))
45
+ refute_equal_station(glen_estimate, @@sixteenth_estimate)
46
+ refute_equal_station(sixteenth_estimate, @@twenty_fourth_estimate)
47
+ refute_equal_station(twenty_fourth_estimate, @@glen_estimate)
48
+ end
49
+ end
50
+
51
+
52
+ def test_should_get_correct_weather
53
+ weather = Weather.new(Weather.get_results(:weather => 'Mountain+View'))
54
+ assert_equal(weather, @@weather)
55
+ end
56
+
57
+ def test_should_get_correct_bus_routes
58
+ routes = Route.get_results(:a => 'sf-muni', :command => 'routeList').map {|r| Route.new(r)}
59
+ assert_equal(routes, @@muni_routes)
60
+ end
61
+
62
+ def test_should_get_correct_route_information
63
+ route_F = Route.new(Route.get_results(:a => 'sf-muni', :command => 'routeConfig', :r => 'F', :mode => 'terse'))
64
+ assert_equal(route_F, @@muni_F)
65
+ end
66
+
67
+ def test_should_handle_invalid_url
68
+ estimate = Station.new(Station.get_results(:orig => 'YES'))
69
+ weather = Weather.new(Weather.get_results(:weather => "Here"))
70
+ routes = Route.get_results(:a => 'sffg').map {|r| Route.new(r)}
71
+ end
72
+
73
+
74
+ private
75
+
76
+ #ensure that the estimates of the first station include the sample
77
+ def assert_equal_station station, sample_station
78
+ if station.instance_of?(Station) && sample_station.instance_of?(Station)
79
+ return assert(station.abbreviation == sample_station.abbreviation && station.est.include_all?(sample_station.est), "Estimates should be equal")
80
+ end
81
+ false
82
+ end
83
+
84
+ def refute_equal_station station, sample_station
85
+ if station.instance_of?(Station) && sample_station.instance_of?(Station)
86
+ return assert(station.abbreviation != sample_station.abbreviation || station.est.exclude_any?(sample_station.est), "Estimates should be different")
25
87
  end
88
+ false
26
89
  end
27
90
 
28
91
 
29
- private
30
92
  def business_time? now
31
93
  unless now.to_date.sunday?
32
94
  #t = now.to_time.localtime(now.zone)
@@ -39,4 +101,16 @@ private
39
101
  return false
40
102
  end
41
103
 
104
+
105
+ end
106
+
107
+ class Array
108
+ def include_all? elems
109
+ return elems.all? {|e| self.include?(e)} if elems.instance_of?(Array)
110
+ false
111
+ end
112
+
113
+ def exclude_any? elems
114
+ return elems.any? {|e| not self.include?(e) if elems.instance_of?(Array)}
115
+ end
42
116
  end
@@ -1,10 +1,25 @@
1
1
  module LoadFromXML
2
- def load_from_xml xml
3
- hash = Nori.parse(xml)
4
- hash = hash["root"] if hash.keys.include?("root")
5
- timestamp = hash["date"].nil? ? {} : {"date" => hash["date"], "time" => hash["time"]}
6
- hash = hash["stations"] if hash.keys.include?("stations")
7
- hash = hash["station"] if hash.keys.include?("station")
8
- new(timestamp.merge(hash))
2
+ def load_from_xml xml, root = nil, object_names = []
3
+ result = Nori.parse(xml)
4
+ result = result[root] if root && result.key?(root)
5
+ result.instance_of?(Array) ? result.map {|res| get_object(res, object_names)} : get_object(result, object_names)
9
6
  end
7
+
8
+ def get_object obj, object_names = []
9
+ timestamp = obj["date"].nil? ? {} : {"date" => obj["date"], "time" => obj["time"]}
10
+ [*object_names].each do |o|
11
+ obj = get_next_level(obj, o)
12
+ end
13
+ obj.instance_of?(Array) ? obj.map{|o| new(timestamp.merge(o))} : new(timestamp.merge(obj))
14
+ end
15
+
16
+ def get_next_level obj, object_name
17
+ if obj.instance_of?(Array)
18
+ return obj.map {|o| o[object_name]} if obj[0].key?(object_name)
19
+ else
20
+ return obj[object_name] if obj.key?(object_name)
21
+ end
22
+ obj
23
+ end
24
+
10
25
  end
@@ -0,0 +1,76 @@
1
+ require 'api_object'
2
+ require_relative 'load_from_xml'
3
+ module TestObjects
4
+
5
+ module BusMethods
6
+ def to_s
7
+ inspect
8
+ end
9
+ end
10
+
11
+ class Stop < ActiveApi::ApiObject
12
+ include BusMethods
13
+
14
+ attr_reader :tag, :description
15
+
16
+ api_column :description, :title
17
+
18
+ def inspect
19
+ "Stop #{@tag}" + (@description.nil? ? '': "- #{@description}")
20
+ end
21
+
22
+ def ==(other_stop)
23
+ return false if other_stop.nil?
24
+ self.tag == other_stop.tag && self.description == other_stop.description
25
+ end
26
+
27
+ end
28
+
29
+ class Direction < ActiveApi::ApiObject
30
+ include BusMethods
31
+
32
+ attr_reader :tag, :description, :name, :stops
33
+
34
+ api_column :description, :title
35
+ api_association :stops, :stop, :as => TestObjects::Stop
36
+
37
+ def inspect
38
+ "Direction #{@tag} - #{@description} \n\t#{@stops.inject('') {|str, s| (str + s.inspect + "\n\t")}}"
39
+ end
40
+
41
+ end
42
+
43
+ class Route < ActiveApi::ApiObject
44
+ extend LoadFromXML
45
+ include BusMethods
46
+
47
+ attr_reader :tag, :description, :stops, :directions
48
+
49
+ initialize_from_api :url => 'http://webservices.nextbus.com/service', :action => 'publicXMLFeed'
50
+
51
+ api_column :description, :title
52
+ api_association :stops, :stop, :as => TestObjects::Stop
53
+ api_association :directions, :direction, :as => TestObjects::Direction
54
+
55
+ def inspect
56
+ "Route #{@tag} - #{@description}" + (@stops.nil? ? '':"\n\t#{@stops.inject('') {|str, s| (str + s.inspect + "\n\t")}}") + (@directions.nil? ? '':"\n\t#{@directions.inject('') {|str, d| (str + d.inspect + "\n\t")}}")
57
+ end
58
+
59
+ def ==(other_route)
60
+ return false if other_route.nil?
61
+ self.tag == other_route.tag && self.description == other_route.description && self.stops == other_route.stops
62
+ end
63
+
64
+ class << self
65
+ alias_method :general_load_from_xml, :load_from_xml
66
+
67
+ def load_from_xml xml
68
+ general_load_from_xml(xml, 'body', 'route')
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+
76
+ end
data/test/unit/station.rb CHANGED
@@ -36,7 +36,7 @@ module TestObjects
36
36
  end
37
37
 
38
38
  def ==(other_est)
39
- return false if other_est.nil?
39
+ return false if other_est.nil?
40
40
  self.abbreviation == other_est.abbreviation && self.destination == other_est.destination
41
41
  end
42
42
 
@@ -48,7 +48,7 @@ module TestObjects
48
48
 
49
49
  attr_reader :name, :abbreviation, :date, :time, :est
50
50
 
51
- initialize_from_api :url => "http://api.bart.gov/api/", :command => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
51
+ initialize_from_api :url => "http://api.bart.gov/api/", :action => 'etd.aspx', :key => 'MW9S-E7SL-26DU-VV8V', :url_options => {:cmd => 'etd'}
52
52
 
53
53
  api_column :abbreviation, :abbr
54
54
  api_association :est, :etd, :as => TestObjects::Estimate
@@ -61,6 +61,15 @@ module TestObjects
61
61
  return false if other_station.nil?
62
62
  self.abbreviation == other_station.abbreviation && self.est == other_station.est
63
63
  end
64
+
65
+ class << self
66
+ alias_method :general_load_from_xml, :load_from_xml
67
+
68
+ def load_from_xml xml
69
+ general_load_from_xml(xml, 'root', ['stations', 'station'])
70
+ end
71
+
72
+ end
64
73
 
65
74
  end
66
75