api_object 0.5.1 → 0.6.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.
- data/README.md +12 -2
- data/lib/api_object/version.rb +1 -1
- data/lib/api_object.rb +68 -13
- data/test/unit/api_object_test.rb +29 -7
- metadata +16 -16
data/README.md
CHANGED
@@ -129,7 +129,16 @@ The function takes parameters to define what fields from the location object are
|
|
129
129
|
data = Weather.get_results(:weather => '99.156.82.20')
|
130
130
|
```
|
131
131
|
|
132
|
-
7)
|
132
|
+
7) Error handling
|
133
|
+
|
134
|
+
In case data cannot be retrived (possible causes might be a wrong url or service downtime), the object returned is empty. Error messages could be checked using functions errors and has_errors?
|
135
|
+
|
136
|
+
```
|
137
|
+
station.has_errors?
|
138
|
+
errors = station.errors
|
139
|
+
```
|
140
|
+
|
141
|
+
8) Testing
|
133
142
|
|
134
143
|
The gem has been tested on BART, Google Weather and NextBus APIs.
|
135
144
|
|
@@ -143,9 +152,10 @@ API_KEY='<your key>' rake test
|
|
143
152
|
|
144
153
|
There is no existing api key provided with this gem as per the Terms and Conditions of the ipinfodb service.
|
145
154
|
|
146
|
-
|
155
|
+
9) Limitations
|
147
156
|
|
148
157
|
* Api data must be presented either in XML or in JSON format. The distinction between XML and JSON is determinted automatically.
|
158
|
+
* Location by ip service uses a free database which is not always reliable.
|
149
159
|
* When using this gem with external APIs, check Terms and Conditions of the API usage.
|
150
160
|
* If something is not working, feel free to submit bugs and or/contribute.
|
151
161
|
|
data/lib/api_object/version.rb
CHANGED
data/lib/api_object.rb
CHANGED
@@ -4,17 +4,19 @@ require "active_support/all"
|
|
4
4
|
require "geo_ip"
|
5
5
|
|
6
6
|
module ActiveApi
|
7
|
-
|
7
|
+
|
8
8
|
module ClassMethods
|
9
|
-
|
9
|
+
|
10
10
|
def self.extended(base)
|
11
11
|
base.send(:extend, Query)
|
12
12
|
end
|
13
13
|
|
14
14
|
def initialize_from_api options = {}
|
15
|
+
|
15
16
|
class_attribute :url, :action, :key, :mode, :url_options, :data_tags, :object_name
|
16
17
|
self.url, self.action, self.key, self.mode, self.url_options, self.data_tags, self.object_name = [options[:url], options[:action], options[:key], options[:mode], (options[:url_options] || {}), ([*options[:data_tags]] || []), (options[:object_name] || self.to_s.downcase.gsub(/^(.+::)(.+)$/, '\2'))]
|
17
18
|
instance_eval do
|
19
|
+
|
18
20
|
|
19
21
|
def get_results_by_ip ip, arguments = {}
|
20
22
|
self.api_key = arguments.delete(:key) if arguments[:key]
|
@@ -22,8 +24,8 @@ module ActiveApi
|
|
22
24
|
raise unless location[:status_code] == "OK"
|
23
25
|
get_results [*arguments.keys].inject({}) { |opts, a| opts.merge(a.to_sym => location[arguments[a.to_sym]]) }
|
24
26
|
rescue
|
25
|
-
puts "
|
26
|
-
return
|
27
|
+
puts "ERROR: Cannot get results or location by ip. Verify that you have a valid key for the ipinfodb.com service"
|
28
|
+
return ApiObjectError.new(:class => self, :errors => invalid_loc_msg)
|
27
29
|
end
|
28
30
|
|
29
31
|
def get_results options = {}
|
@@ -32,8 +34,8 @@ module ActiveApi
|
|
32
34
|
result = query_api(self.url, self.action, self.mode, self.url_options.merge(options))
|
33
35
|
process_result result
|
34
36
|
rescue
|
35
|
-
puts "
|
36
|
-
return
|
37
|
+
puts "ERROR: The request returned no valid data. #{error_invalid_url result[:url]}"
|
38
|
+
return ApiObjectError.new(:class => self, :errors => invalid_url_msg)
|
37
39
|
end
|
38
40
|
|
39
41
|
def api_key=(key)
|
@@ -44,9 +46,21 @@ module ActiveApi
|
|
44
46
|
GeoIp.api_key
|
45
47
|
end
|
46
48
|
|
47
|
-
def
|
49
|
+
def error_invalid_url url
|
48
50
|
"The request url is #{url}, please, check if it's invalid of there is no connectivity." unless url.nil?
|
49
51
|
end
|
52
|
+
|
53
|
+
def invalid_url_msg
|
54
|
+
"Cannot get results from the url"
|
55
|
+
end
|
56
|
+
|
57
|
+
def invalid_loc_msg
|
58
|
+
"Cannot obtain results by ip, check the location"
|
59
|
+
end
|
60
|
+
|
61
|
+
def invalid_data_msg
|
62
|
+
"Cannot initialize the object"
|
63
|
+
end
|
50
64
|
|
51
65
|
private
|
52
66
|
def process_result result
|
@@ -74,9 +88,10 @@ module ActiveApi
|
|
74
88
|
end
|
75
89
|
|
76
90
|
module InstanceMethods
|
77
|
-
|
91
|
+
|
78
92
|
def initialize(*args)
|
79
93
|
url = args.first.delete(:url)
|
94
|
+
errors = args.first.delete(:errors)
|
80
95
|
tags = respond_to?('data_tags') ? self.data_tags : args.last[:tags]
|
81
96
|
args.first.each do |k, v|
|
82
97
|
k = k.gsub(/@/, '')
|
@@ -87,11 +102,18 @@ module ActiveApi
|
|
87
102
|
instance_variable_set("@#{k.to_s}", result)
|
88
103
|
end
|
89
104
|
end if args.first.is_a?(Hash)
|
90
|
-
|
105
|
+
if self.empty?
|
106
|
+
puts "ERROR: data passed for #{self.class} initialization was invalid. #{self.class.error_invalid_url url}"
|
107
|
+
@errors = errors || self.class.invalid_data_msg
|
108
|
+
end
|
91
109
|
end
|
92
110
|
|
93
111
|
def empty?
|
94
|
-
self.instance_variables.empty?
|
112
|
+
(self.instance_variables - [:@errors]).empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
def has_errors?
|
116
|
+
self.instance_variables.include?(:@errors)
|
95
117
|
end
|
96
118
|
|
97
119
|
|
@@ -142,8 +164,41 @@ module ActiveApi
|
|
142
164
|
class_attribute :columns, :assoc
|
143
165
|
self.columns, self.assoc = [{}, {}]
|
144
166
|
|
145
|
-
|
167
|
+
attr_reader :errors
|
168
|
+
|
169
|
+
end
|
146
170
|
|
147
|
-
|
171
|
+
class ApiObjectError < Hash
|
172
|
+
attr_reader :errors, :klass
|
173
|
+
|
174
|
+
def initialize *args
|
175
|
+
options = args.extract_options!
|
176
|
+
@errors = options.delete(:errors)
|
177
|
+
@klass = options.delete(:class)
|
178
|
+
end
|
179
|
+
|
180
|
+
def keys
|
181
|
+
[:errors]
|
182
|
+
end
|
183
|
+
|
184
|
+
def [](key)
|
185
|
+
eval("self.#{key.to_s}") if keys.include?(key)
|
186
|
+
end
|
187
|
+
|
188
|
+
def map &block
|
189
|
+
klass.new({:errors => @errors})
|
190
|
+
end
|
191
|
+
|
192
|
+
alias_method :collect, :map
|
193
|
+
|
194
|
+
def inspect
|
195
|
+
"ApiObjectError: #{@errors}"
|
196
|
+
end
|
197
|
+
|
198
|
+
def to_s
|
199
|
+
inspect
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
148
203
|
end
|
149
|
-
|
204
|
+
|
@@ -8,11 +8,15 @@ class ApiObjectTest < MiniTest::Unit::TestCase
|
|
8
8
|
include ActiveApi
|
9
9
|
include TestObjects
|
10
10
|
|
11
|
+
IP = '99.156.82.20'
|
12
|
+
GeoIp.api_key = nil
|
13
|
+
|
11
14
|
@@data_directory = File.expand_path('../../data', __FILE__)
|
12
15
|
@@estimate_directory = @@data_directory + "/estimate"
|
13
16
|
@@weather_directory = @@data_directory + "/weather"
|
14
17
|
@@bus_directory = @@data_directory + "/bus"
|
15
18
|
@@key_directory = @@data_directory +"/keys"
|
19
|
+
|
16
20
|
|
17
21
|
@@glen_estimate = Station.load_from_xml(File.read(@@estimate_directory + '/glen.xml'))
|
18
22
|
@@sixteenth_estimate = Station.load_from_xml(File.read(@@estimate_directory + '/sixteenth.xml'))
|
@@ -21,8 +25,6 @@ class ApiObjectTest < MiniTest::Unit::TestCase
|
|
21
25
|
@@weather_mv = Weather.load_from_xml(File.read(@@weather_directory + '/mountain_view.xml'))
|
22
26
|
@@weather_au = Weather.load_from_xml(File.read(@@weather_directory + '/austin.xml'))
|
23
27
|
@@ip_key = File.read(@@key_directory + "/ipinfodb_key.txt") rescue ENV['API_KEY']
|
24
|
-
IP = '99.156.82.20'
|
25
|
-
GeoIp.api_key = nil
|
26
28
|
|
27
29
|
@@muni_routes = Route.load_from_xml(File.read(@@bus_directory + "/muni_routes.xml"))
|
28
30
|
@@muni_F = Route.load_from_xml(File.read(@@bus_directory + "/muni_F.xml"))
|
@@ -64,6 +66,7 @@ class ApiObjectTest < MiniTest::Unit::TestCase
|
|
64
66
|
unless @@ip_key.nil?
|
65
67
|
weather_au = Weather.new(Weather.get_results_by_ip(IP, :key => @@ip_key, :weather => :zip_code))
|
66
68
|
assert_equal(weather_au, @@weather_au)
|
69
|
+
refute_has_errors(weather_au)
|
67
70
|
end
|
68
71
|
end
|
69
72
|
|
@@ -71,33 +74,44 @@ class ApiObjectTest < MiniTest::Unit::TestCase
|
|
71
74
|
GeoIp.api_key = @@ip_key
|
72
75
|
weather_au = Weather.new(Weather.get_results_by_ip(IP, :weather => :zip_code))
|
73
76
|
assert_equal(weather_au, @@weather_au)
|
77
|
+
refute_has_errors(weather_au)
|
74
78
|
end
|
75
|
-
|
79
|
+
|
76
80
|
def test_should_not_get_correct_weather_with_no_key
|
77
81
|
GeoIp.api_key = nil
|
78
82
|
weather_au = Weather.new(Weather.get_results_by_ip(IP, :weather => :zip_code))
|
79
83
|
assert_empty(weather_au)
|
84
|
+
assert_has_errors(weather_au)
|
80
85
|
end
|
81
86
|
|
82
87
|
def test_should_get_correct_bus_routes
|
83
88
|
routes = Route.get_results(:a => 'sf-muni', :command => 'routeList').map {|r| Route.new(r)}
|
84
89
|
assert_equal_route_list(routes, @@muni_routes)
|
90
|
+
routes.map {|r| refute_has_errors(r)}
|
85
91
|
end
|
86
|
-
|
92
|
+
|
87
93
|
def test_should_get_correct_route_information
|
88
94
|
route_F = Route.new(Route.get_results(:a => 'sf-muni', :command => 'routeConfig', :r => 'F', :mode => 'terse'))
|
89
95
|
assert_equal(route_F, @@muni_F)
|
96
|
+
refute_has_errors(route_F)
|
90
97
|
end
|
91
|
-
|
98
|
+
|
92
99
|
def test_should_handle_invalid_url
|
93
|
-
estimate = Station.new(Station.get_results(:orig => 'YES'))
|
100
|
+
estimate = Station.new(Station.get_results(:orig => 'YES'))
|
94
101
|
assert(estimate.empty?, "Estimate should be an empty object")
|
102
|
+
assert_has_errors(estimate)
|
103
|
+
assert(estimate.errors, Station.invalid_url_msg)
|
95
104
|
weather = Weather.new(Weather.get_results(:weather => "Here"))
|
96
105
|
assert(weather.empty?, "Weather should be an empty object")
|
97
|
-
|
106
|
+
assert_has_errors(weather)
|
107
|
+
assert(weather.errors, Weather.invalid_data_msg)
|
108
|
+
routes = Route.get_results(:a => 'sffg').collect {|r| Route.new(r)}
|
98
109
|
assert(routes.empty?, "Routes should be an empty object")
|
110
|
+
assert_has_errors(routes)
|
111
|
+
assert(routes.errors, Route.invalid_url_msg)
|
99
112
|
end
|
100
113
|
|
114
|
+
|
101
115
|
private
|
102
116
|
|
103
117
|
#ensure that the estimates of the first station include the sample
|
@@ -119,6 +133,14 @@ private
|
|
119
133
|
return assert(route_list.include_all?(sample_route_list), "Route list should include all the sample routes")
|
120
134
|
end
|
121
135
|
|
136
|
+
def assert_has_errors obj
|
137
|
+
return assert(obj.has_errors?, "Object should have errors")
|
138
|
+
end
|
139
|
+
|
140
|
+
def refute_has_errors obj
|
141
|
+
return refute(obj.has_errors?, "Object shouldn't have errors")
|
142
|
+
end
|
143
|
+
|
122
144
|
|
123
145
|
def business_time? now
|
124
146
|
unless now.to_date.sunday?
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: api_object
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activemodel
|
16
|
-
requirement: &
|
16
|
+
requirement: &76922910 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *76922910
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &76922660 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *76922660
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: minitest
|
38
|
-
requirement: &
|
38
|
+
requirement: &77001800 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *77001800
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: activesupport
|
49
|
-
requirement: &
|
49
|
+
requirement: &77001550 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *77001550
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: nori
|
60
|
-
requirement: &
|
60
|
+
requirement: &77001240 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '1.1'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *77001240
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rest-client
|
71
|
-
requirement: &
|
71
|
+
requirement: &77000930 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '1.6'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *77000930
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: geo_ip
|
82
|
-
requirement: &
|
82
|
+
requirement: &77000700 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,7 +87,7 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *77000700
|
91
91
|
description: An interface to load objects from external APIs provided in XML and JSON
|
92
92
|
formats
|
93
93
|
email:
|