api_object 0.0.1 → 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.
@@ -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