soda-ruby 0.2.13 → 0.2.15
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.
- checksums.yaml +4 -4
- data/README.mkd +22 -2
- data/lib/soda.rb +1 -1
- data/lib/soda/client.rb +103 -86
- data/lib/soda/version.rb +1 -1
- metadata +145 -5
- data/CHANGELOG.mkd +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e08ae803c8dea78e00b08a07bc2be1cc4b87cd95
|
4
|
+
data.tar.gz: a9e5a9781c7fcfd40f599698128ed84063bee1d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70975c06355fbcb43a20571dc20d2c0e75ff3f197b59977bd6adaf804f8069e75dd465b311addd7691017074e41aec6474d0f07b6ad19f227bbd286719cc7498
|
7
|
+
data.tar.gz: ea997e8681e790a13e0b59f34e196d62367240a7c15929389e07f2536343f719d7098dcb3a535f85555b37b1e403038f729a4c1ba230f28bae0a8ec3f9bbceec
|
data/README.mkd
CHANGED
@@ -18,10 +18,30 @@ Create a new client. Register for an application token at <http://dev.socrata.co
|
|
18
18
|
client = SODA::Client.new({:domain => "explore.data.gov", :app_token => "CGxadgoQlgQSev4zyUh5aR5J3"})
|
19
19
|
```
|
20
20
|
|
21
|
-
Issue a
|
21
|
+
Issue a filter query. `644b-gaut` is the identifier for the dataset we want to access. The return object is an array of [Hashie::Mash](https://github.com/intridea/hashie) objects:
|
22
22
|
|
23
23
|
```ruby
|
24
24
|
response = client.get("644b-gaut", {"$limit" => 1, :namelast => "WINFREY", :namefirst => "OPRAH"})
|
25
25
|
|
26
|
-
|
26
|
+
#=> [#<Hashie::Mash appt_end_date="12/3/09 23:59" appt_made_date="12/2/09 18:05" appt_start_date="12/3/09 9:30" caller_name_first="SALLY" caller_name_last="ARMBRUSTER" last_updatedby="J7" lastentrydate="12/2/09 18:05" meeting_loc="WH" meeting_room="DIP ROOM" namefirst="OPRAH" namelast="WINFREY" post="WIN" release_date=1269586800 terminal_suffix="J7" total_people="10" type_of_access="VA" uin="U60816" visitee_namefirst="SEMONTI" visitee_namelast="STEPHENS">]
|
27
27
|
```
|
28
|
+
|
29
|
+
You can use other simple query SoQL methods found here: <http://dev.socrata.com/docs/queries.html>
|
30
|
+
|
31
|
+
```ruby
|
32
|
+
client = SODA::Client.new({:domain => "soda.demo.socrata.com"})
|
33
|
+
magnitude_response = client.get("4tka-6guv", {"$where" => "magnitude > '3.0'"})
|
34
|
+
|
35
|
+
#=> [#<Hashie::Mash datetime="2012-09-14T09:28:55" depth="20" earthquake_id="12258012" location=#<Hashie::Mash latitude="19.7859" longitude="-64.0849" needs_recoding=false> magnitude="3.1" number_of_stations="6" region="north of the Virgin Islands" source="pr" version="0">, #<Hashie::Mash datetime="2012-09-14T07:58:39" depth="74" earthquake_id="12258011" location=#<Hashie::Mash latitude="19.5907" longitude="-64.1723" needs_recoding=false> magnitude="3.3" number_of_stations="4" region="Virgin Islands region" source="pr" version="0">, ... ]
|
36
|
+
|
37
|
+
datetime_response = client.get("4tka-6guv", {"$where" => "datetime > '2012-09-14T09:28:55' AND datetime < '2012-12-25T09:00:00'"})
|
38
|
+
|
39
|
+
#=> [#<Hashie::Mash datetime="2012-09-14T10:10:19" depth="8.2" earthquake_id="00388609" location=#<Hashie::Mash latitude="36.9447" longitude="-117.6778" needs_recoding=false> magnitude="1.7" number_of_stations="29" region="Northern California" source="nn" version="9">, #<Hashie::Mash datetime="2012-09-14T10:06:11" depth="6.4" earthquake_id="00388607" location=#<Hashie::Mash latitude="36.9417" longitude="-117.6903" needs_recoding=false> magnitude="1.7" number_of_stations="29" region="Central California" source="nn" version="9">, ... ]
|
40
|
+
```
|
41
|
+
|
42
|
+
All the field names have built in getter methods since the objects are Hashie::Mashes.
|
43
|
+
|
44
|
+
```ruby
|
45
|
+
magnitude_response.first.number_of_stations #=> "6"
|
46
|
+
```
|
47
|
+
*Note that the return value is a string object.*
|
data/lib/soda.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'soda/client'
|
data/lib/soda/client.rb
CHANGED
@@ -10,9 +10,18 @@ require 'uri'
|
|
10
10
|
require 'json'
|
11
11
|
require 'cgi'
|
12
12
|
require 'hashie'
|
13
|
+
require 'sys/uname'
|
14
|
+
require 'soda/version'
|
15
|
+
include Sys
|
13
16
|
|
14
17
|
module SODA
|
15
18
|
class Client
|
19
|
+
class << self
|
20
|
+
def generate_user_agent
|
21
|
+
"soda-ruby/#{SODA::VERSION} (#{Uname.uname.sysname}/#{Uname.uname.release}; Ruby/#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
16
25
|
##
|
17
26
|
#
|
18
27
|
# Creates a new SODA client.
|
@@ -34,7 +43,8 @@ module SODA
|
|
34
43
|
# client = SODA::Client.new({ :domain => "data.agency.gov", :app_token => "CGxarwoQlgQSev4zyUh5aR5J3" })
|
35
44
|
#
|
36
45
|
def initialize(config = {})
|
37
|
-
@config =
|
46
|
+
@config = Hashie.symbolize_keys! config
|
47
|
+
@user_agent = SODA::Client.generate_user_agent
|
38
48
|
end
|
39
49
|
|
40
50
|
##
|
@@ -114,120 +124,127 @@ module SODA
|
|
114
124
|
connection(:delete, resource, body, params)
|
115
125
|
end
|
116
126
|
|
117
|
-
def post_form(
|
127
|
+
def post_form(resource, body = {}, params = {})
|
118
128
|
query = query_string(params)
|
119
|
-
|
120
|
-
|
121
|
-
# Create our request
|
122
|
-
uri = URI.parse("https://#{@config[:domain]}#{resource}.json?#{query}")
|
123
|
-
http = build_http_client(uri.host, uri.port)
|
129
|
+
path = resource_path(resource)
|
130
|
+
uri = URI.parse("https://#{@config[:domain]}#{path}?#{query}")
|
124
131
|
|
125
132
|
request = Net::HTTP::Post.new(uri.request_uri)
|
126
|
-
request
|
127
|
-
request.set_form_data(
|
133
|
+
add_default_headers_to_request(request)
|
134
|
+
request.set_form_data(body)
|
128
135
|
|
129
136
|
# Authenticate if we're supposed to
|
130
|
-
|
131
|
-
request.basic_auth @config[:username], @config[:password]
|
132
|
-
end
|
137
|
+
authenticate(request)
|
133
138
|
|
134
139
|
# BAM!
|
135
|
-
|
140
|
+
http = build_http_client(uri.host, uri.port)
|
141
|
+
handle_response(http.request(request))
|
136
142
|
end
|
137
143
|
|
138
144
|
private
|
139
|
-
def query_string(params)
|
140
|
-
# Create query string of escaped key, value pairs
|
141
|
-
return params.collect{ |key, val| "#{key}=#{CGI::escape(val.to_s)}" }.join("&")
|
142
|
-
end
|
143
145
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
end
|
146
|
+
def query_string(params)
|
147
|
+
# Create query string of escaped key, value pairs
|
148
|
+
params.map { |key, val| "#{key}=#{CGI.escape(val.to_s)}" }.join('&')
|
149
|
+
end
|
149
150
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
resource = matches.captures[0]
|
154
|
-
extension = matches.captures[1]
|
155
|
-
end
|
151
|
+
def resource_path(resource)
|
152
|
+
# If we didn't get a full path, assume "/resource/"
|
153
|
+
resource = '/resource/' + resource unless resource.start_with?('/')
|
156
154
|
|
157
|
-
|
155
|
+
# Check to see if we were given an output type
|
156
|
+
extension = '.json'
|
157
|
+
if matches = resource.match(/^(.+)(\.\w+)$/)
|
158
|
+
resource = matches.captures[0]
|
159
|
+
extension = matches.captures[1]
|
158
160
|
end
|
159
161
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
162
|
+
resource + extension
|
163
|
+
end
|
164
|
+
|
165
|
+
def handle_response(response)
|
166
|
+
# Check our response code
|
167
|
+
check_response_fail(response)
|
168
|
+
if response.body.nil? || response.body.empty?
|
169
|
+
return nil
|
170
|
+
elsif response['Content-Type'].include?('application/json')
|
171
|
+
# Return a bunch of mashes if we're JSON
|
172
|
+
response = JSON.parse(response.body, :max_nesting => false)
|
173
|
+
if response.is_a? Array
|
174
|
+
return response.map { |r| Hashie::Mash.new(r) }
|
164
175
|
else
|
165
|
-
|
166
|
-
return nil
|
167
|
-
elsif response["Content-Type"].include?("application/json")
|
168
|
-
# Return a bunch of mashes if we're JSON
|
169
|
-
response = JSON::parse(response.body, :max_nesting => false)
|
170
|
-
if response.is_a? Array
|
171
|
-
return response.collect { |r| Hashie::Mash.new(r) }
|
172
|
-
else
|
173
|
-
return Hashie::Mash.new(response)
|
174
|
-
end
|
175
|
-
else
|
176
|
-
# We don't partically care, just return the raw body
|
177
|
-
return response.body
|
178
|
-
end
|
176
|
+
return Hashie::Mash.new(response)
|
179
177
|
end
|
178
|
+
else
|
179
|
+
# We don't partically care, just return the raw body
|
180
|
+
return response.body
|
180
181
|
end
|
182
|
+
end
|
181
183
|
|
182
|
-
|
183
|
-
|
184
|
+
def check_response_fail(response)
|
185
|
+
return if %w(200 202).include? response.code
|
186
|
+
fail "Error in request: #{response.body}"
|
187
|
+
end
|
184
188
|
|
185
|
-
|
189
|
+
def connection(method = 'Get', resource = nil, body = nil, params = {})
|
190
|
+
method = method.to_sym.capitalize
|
186
191
|
|
187
|
-
|
192
|
+
query = query_string(params)
|
193
|
+
path = resource_path(resource)
|
194
|
+
uri = URI.parse("https://#{@config[:domain]}#{path}?#{query}")
|
188
195
|
|
189
|
-
|
196
|
+
request = eval("Net::HTTP::#{method}").new(uri.request_uri)
|
197
|
+
add_default_headers_to_request(request)
|
190
198
|
|
191
|
-
|
192
|
-
|
193
|
-
request.add_field("X-App-Token", @config[:app_token])
|
199
|
+
# Authenticate if we're supposed to
|
200
|
+
authenticate(request)
|
194
201
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
end
|
202
|
+
http = request_by_method(method, body, request, uri)
|
203
|
+
send_request(method, http, request)
|
204
|
+
end
|
199
205
|
|
200
|
-
|
206
|
+
def send_request(method, http, request)
|
207
|
+
return delete_method_response(method, http, request) if method === :Delete
|
208
|
+
handle_response(http.request(request))
|
209
|
+
end
|
201
210
|
|
202
|
-
|
203
|
-
|
204
|
-
|
211
|
+
def delete_method_response(http, request)
|
212
|
+
response = http.request(request)
|
213
|
+
return response if response.code == '200'
|
214
|
+
fail "Error querying \"#{uri}\": #{response.body}"
|
215
|
+
end
|
205
216
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
if response.code != "200"
|
210
|
-
raise "Error querying \"#{uri.to_s}\": #{response.body}"
|
211
|
-
else
|
212
|
-
# Return a bunch of mashes
|
213
|
-
return response
|
214
|
-
end
|
215
|
-
else
|
216
|
-
return handle_response(http.request(request))
|
217
|
-
end
|
218
|
-
end
|
217
|
+
def net_http_class(method)
|
218
|
+
Object.const_get("Net::HTTP::#{method}")
|
219
|
+
end
|
219
220
|
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
225
|
-
end
|
226
|
-
if @config[:timeout]
|
227
|
-
http.read_timeout = @config[:timeout]
|
228
|
-
end
|
229
|
-
http
|
221
|
+
def request_by_method(method, body, request, uri)
|
222
|
+
if method === :Post || :Put || :Delete
|
223
|
+
request.content_type = 'application/json'
|
224
|
+
request.body = body.to_json(:max_nesting => false)
|
230
225
|
end
|
231
226
|
|
227
|
+
build_http_client(uri.host, uri.port)
|
228
|
+
end
|
229
|
+
|
230
|
+
def build_http_client(host, port)
|
231
|
+
http = Net::HTTP.new(host, port)
|
232
|
+
http.use_ssl = true
|
233
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if @config[:ignore_ssl]
|
234
|
+
http.read_timeout = @config[:timeout] if @config[:timeout]
|
235
|
+
http
|
236
|
+
end
|
237
|
+
|
238
|
+
def authenticate(request)
|
239
|
+
return unless @config[:username]
|
240
|
+
# Authenticate if we're supposed to
|
241
|
+
request.basic_auth @config[:username], @config[:password]
|
242
|
+
end
|
243
|
+
|
244
|
+
def add_default_headers_to_request(request)
|
245
|
+
request.delete('User-Agent')
|
246
|
+
request.add_field('X-App-Token', @config[:app_token])
|
247
|
+
request.add_field('User-Agent', @user_agent)
|
248
|
+
end
|
232
249
|
end
|
233
250
|
end
|
data/lib/soda/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: soda-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Metcalf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-10-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hashie
|
@@ -24,13 +24,153 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
-
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: multipart-post
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sys-uname
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.7'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.7'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rake
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: shoulda
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: webmock
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: minitest
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: test-unit
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: rubocop
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: mocha
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: A simple wrapper for SODA 2.0. Includes an OmniAuth provider for OAuth
|
168
|
+
2.0
|
28
169
|
email: chris.metcalf@socrata.com
|
29
170
|
executables: []
|
30
171
|
extensions: []
|
31
172
|
extra_rdoc_files: []
|
32
173
|
files:
|
33
|
-
- CHANGELOG.mkd
|
34
174
|
- LICENSE
|
35
175
|
- README.mkd
|
36
176
|
- lib/omniauth-socrata.rb
|
@@ -57,7 +197,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
197
|
version: 1.3.6
|
58
198
|
requirements: []
|
59
199
|
rubyforge_project: soda-ruby
|
60
|
-
rubygems_version: 2.
|
200
|
+
rubygems_version: 2.4.5
|
61
201
|
signing_key:
|
62
202
|
specification_version: 4
|
63
203
|
summary: Ruby for SODA 2.0
|
data/CHANGELOG.mkd
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
0.2.0 - Initial Public Release
|
2
|
-
0.2.1 - Point release to update gemspec dependencies
|
3
|
-
...
|
4
|
-
0.2.4 - Point release including tests that are now mocked properly
|
5
|
-
0.2.6 - Code cleanup from @raykao
|
6
|
-
0.2.7 - Removing dead code and an un-needed dependency
|
7
|
-
0.2.8 - Removing the nesting limit on the JSON parser
|
8
|
-
0.2.10 - Removing a nesting limit that we missed
|
9
|
-
0.2.11 - We weren't properly handling an empty payload response
|
10
|
-
0.2.12 - Added a global option to disable SSL checking from https://github.com/socrata/soda-ruby/pull/7
|
11
|
-
0.2.13 - Added a global :timeout option to override the default Net:HTTP timeout, and accepting 202 as an "OK" response code, which should only occur during import.
|