policymap_wrap 0.1.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/LICENSE +20 -0
- data/README.rdoc +154 -0
- data/VERSION +1 -0
- data/lib/policymap.rb +2 -0
- data/lib/policymap_wrap.rb +22 -0
- data/lib/policymap_wrap/client.rb +126 -0
- data/lib/policymap_wrap/connection.rb +136 -0
- data/lib/policymap_wrap/endpoint.rb +15 -0
- data/lib/policymap_wrap/hash_utils.rb +33 -0
- data/spec/policymap_wrap_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- metadata +127 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Gemini SBS, LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
= PolicyMap Wrap
|
2
|
+
|
3
|
+
Ruby wrapper around the PolicyMap API.
|
4
|
+
|
5
|
+
== Notes
|
6
|
+
|
7
|
+
PolicyMap APIs are custom designed, so your mileage may vary depending on your API.
|
8
|
+
|
9
|
+
== Usage
|
10
|
+
|
11
|
+
Before you can perform searches, you must first setup your PolicyMap credentials:
|
12
|
+
|
13
|
+
PolicyMap::Client.set_credentials(<account_id>)
|
14
|
+
|
15
|
+
There are three types of searches: query, boundary and indicator.
|
16
|
+
Each search is performed as follows, respectively:
|
17
|
+
|
18
|
+
PolicyMap::Client.query_search(<search_options>)
|
19
|
+
PolicyMap::Client.boundary_search(<search_options>)
|
20
|
+
PolicyMap::Client.indicator_search(<search_options>)
|
21
|
+
|
22
|
+
The search options (required and optional) will vary based on the type of search you are performing.
|
23
|
+
|
24
|
+
=== PolicyMap::Client.query_search(<search_options>)
|
25
|
+
|
26
|
+
A +:search+ type of search is a free form query that *returns an array of hashes (with symbolized keys)* each containing the
|
27
|
+
boundary id of each match.
|
28
|
+
|
29
|
+
Required search options:
|
30
|
+
|
31
|
+
:query => "some sort of search string (eg, a city name: 'miami')"
|
32
|
+
:boundary_types => [:city, :zip] # Array or single boundary type
|
33
|
+
|
34
|
+
Required search options for *some* boundary types:
|
35
|
+
|
36
|
+
:state => "CA" # state abbreviation
|
37
|
+
:county => "Miami Dade"
|
38
|
+
:census_tract => 35525 # Numeric representing a census tract
|
39
|
+
|
40
|
+
Optional search options:
|
41
|
+
|
42
|
+
:max => 25 # Max number of results in the resultset
|
43
|
+
|
44
|
+
=== PolicyMap::Client.boundary_search(<search_options>)
|
45
|
+
|
46
|
+
A +:boundary+ search *returns a hash (with symbolized keys)* containing a MultiPolygon.
|
47
|
+
|
48
|
+
Required search options:
|
49
|
+
|
50
|
+
:boundary_types => [:city, :zip, :state] # Can only specify 0 or 1 boundary type
|
51
|
+
# if boundary IDs (below) are also specified
|
52
|
+
|
53
|
+
Other search options:
|
54
|
+
|
55
|
+
:boundary_ids => [1024944, 1024989] # Array of boundary IDs
|
56
|
+
:lat => 33.805094 # Only to be used if boundary_ids (above) is not specified
|
57
|
+
:lng => -118.353717
|
58
|
+
|
59
|
+
=== PolicyMap::Client.indicator_search(<search_options>)
|
60
|
+
|
61
|
+
An +:indicator+ type of search *returns a hash (with symbolized keys)* containing indicator data for the specified boundaries.
|
62
|
+
|
63
|
+
Required search options:
|
64
|
+
|
65
|
+
:boundary_types => [:city, :zip, :state] # Can only specify 0 or 1 boundary type
|
66
|
+
# if boundary IDs (below) are also specified
|
67
|
+
:indicators => [:total_population, :percent_asian]
|
68
|
+
|
69
|
+
Other search options:
|
70
|
+
|
71
|
+
:boundary_ids => [1024944, 1024989] # Array of boundary IDs
|
72
|
+
:lat => 33.805094 # Only to be used if boundary_ids (above) is not specified
|
73
|
+
:lng => -118.353717
|
74
|
+
|
75
|
+
=== Available Boundary Types
|
76
|
+
|
77
|
+
:state
|
78
|
+
:county
|
79
|
+
:city
|
80
|
+
:zip
|
81
|
+
:census_tract
|
82
|
+
:block_group
|
83
|
+
:congressional_district
|
84
|
+
:assembly_district
|
85
|
+
:senate_district
|
86
|
+
:all # includes all boundary types
|
87
|
+
|
88
|
+
=== Available Indicators
|
89
|
+
|
90
|
+
Population
|
91
|
+
|
92
|
+
:total_population
|
93
|
+
:percent_african_american
|
94
|
+
:percent_asian
|
95
|
+
:percent_pacific_islander
|
96
|
+
:percent_hispanic
|
97
|
+
:percent_native_american
|
98
|
+
:percent_mixed_race
|
99
|
+
:percent_under_18
|
100
|
+
:percent_65_or_older
|
101
|
+
:percent_foreign_born
|
102
|
+
:percent_disabled
|
103
|
+
|
104
|
+
Education
|
105
|
+
|
106
|
+
:percent_high_school_or_less
|
107
|
+
:percent_college_degree
|
108
|
+
:percent_graduate_degree
|
109
|
+
|
110
|
+
Housing
|
111
|
+
|
112
|
+
:median_home_value
|
113
|
+
:median_rent
|
114
|
+
:percent_moved_in_since_1990
|
115
|
+
:percent_homeowners
|
116
|
+
:vacancy_rate
|
117
|
+
|
118
|
+
Income
|
119
|
+
|
120
|
+
:median_household_income
|
121
|
+
:poverty_rate
|
122
|
+
:percent_households_wo_car
|
123
|
+
:average_vehicles_per_household
|
124
|
+
:percent_who_commute_to_work_using_public_transit
|
125
|
+
:unemployment_rate
|
126
|
+
|
127
|
+
Industry Concentrations
|
128
|
+
|
129
|
+
:independent_artists
|
130
|
+
:performing_arts_and_spectator_sports
|
131
|
+
:movie_and_sound_industries
|
132
|
+
:mueseums_and_historical_sites
|
133
|
+
:publishing_industries
|
134
|
+
:broadcasting
|
135
|
+
:other_info_services
|
136
|
+
|
137
|
+
Other
|
138
|
+
|
139
|
+
:all # includes all indicators
|
140
|
+
|
141
|
+
== Dependencies
|
142
|
+
|
143
|
+
PolicyMap Wrap stands on the shoulders of giants:
|
144
|
+
|
145
|
+
* {yajl-ruby}[http://github.com/brianmario/yajl-ruby] (Ruby wrapper around the great {yajl}[http://lloyd.github.com/yajl])
|
146
|
+
* {curb}[http://github.com/taf2/curb] (Ruby wrapper around the great {libcurl}[http://curl.haxx.se/])
|
147
|
+
|
148
|
+
== Copyright
|
149
|
+
|
150
|
+
Copyright (c) 2010 Gemini SBS. See LICENSE for details.
|
151
|
+
|
152
|
+
== Authors
|
153
|
+
|
154
|
+
* {Mauricio Gomes}[http://github.com/mgomes]
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/policymap.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'yajl/json_gem'
|
3
|
+
require 'curb'
|
4
|
+
|
5
|
+
require 'policymap_wrap/connection'
|
6
|
+
require 'policymap_wrap/endpoint'
|
7
|
+
require 'policymap_wrap/hash_utils'
|
8
|
+
require 'policymap_wrap/client'
|
9
|
+
|
10
|
+
module PolicyMap
|
11
|
+
REALM = "http://staging.www.policymap.com"
|
12
|
+
VERSION = File.read(File.join(File.dirname(__FILE__), '..', 'VERSION'))
|
13
|
+
|
14
|
+
class PolicyMapError < StandardError; end
|
15
|
+
class InsufficientArgsForSearch < PolicyMapError; end
|
16
|
+
class Unauthorized < PolicyMapError; end
|
17
|
+
class NotFound < PolicyMapError; end
|
18
|
+
class ServerError < PolicyMapError; end
|
19
|
+
class Unavailable < PolicyMapError; end
|
20
|
+
class DecodeError < PolicyMapError; end
|
21
|
+
class NoConnectionEstablished < PolicyMapError; end
|
22
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module PolicyMap
|
2
|
+
|
3
|
+
class Client
|
4
|
+
|
5
|
+
BOUNDARY_TYPES = { :state => 2, :county => 4, :city => 16, :zip => 8, :census_tract => 6,
|
6
|
+
:block_group => 15, :congressional_district => 23, :assembly_district => 48,
|
7
|
+
:senate_district => 49, :all => 'all' }
|
8
|
+
|
9
|
+
INDICATORS = { :total_population => 9840661, :percent_african_american => 9840139, :percent_asian => 9840102,
|
10
|
+
:percent_pacific_islander => 9840497, :percent_hispanic => 9840238, :percent_native_american => 9840708,
|
11
|
+
:percent_mixed_race => 9840447, :percent_under_18 => 9840423, :percent_65_or_older => 9840365,
|
12
|
+
:percent_foreign_born => 9840645, :percent_disabled => 9840630, :percent_high_school_or_less => 9840299,
|
13
|
+
:percent_college_degree => 9840342, :percent_graduate_degree => 9840503, :median_home_value => 9840587,
|
14
|
+
:median_rent => 9840655, :percent_moved_in_since_1990 => 9840118, :percent_homeowners => 9840172,
|
15
|
+
:vacancy_rate => 9840676, :median_household_income => 9840169, :poverty_rate => 9840120,
|
16
|
+
:percent_households_wo_car => 0, :average_vehicles_per_household => 9845668,
|
17
|
+
:percent_who_commute_to_work_using_public_transit => 9845660, :unemployment_rate => 9841103,
|
18
|
+
:independent_artists => 9618303, :performing_arts_and_spectator_sports => 9584608,
|
19
|
+
:movie_and_sound_industries => 9584731, :mueseums_and_historical_sites => 9584676,
|
20
|
+
:publishing_industries => 9584638, :broadcasting => 9584691, :other_info_services => 9584624, :all => 'all' }
|
21
|
+
|
22
|
+
@@connection = nil
|
23
|
+
@@debug = false
|
24
|
+
@@default_options = nil
|
25
|
+
|
26
|
+
class << self
|
27
|
+
|
28
|
+
def set_credentials(client_id)
|
29
|
+
@@default_options = { :id => client_id, :ty => 'data', :f => 'j' }
|
30
|
+
@@connection = Connection.new(client_id)
|
31
|
+
@@connection.debug = @@debug
|
32
|
+
true
|
33
|
+
end
|
34
|
+
|
35
|
+
def debug=(debug_flag)
|
36
|
+
@@debug = debug_flag
|
37
|
+
@@connection.debug = @@debug if @@connection
|
38
|
+
end
|
39
|
+
|
40
|
+
def debug
|
41
|
+
@@debug
|
42
|
+
end
|
43
|
+
|
44
|
+
def query_search(*args)
|
45
|
+
default_options = @@default_options
|
46
|
+
default_options[:t] = "sch"
|
47
|
+
|
48
|
+
options = extract_options!(args)
|
49
|
+
|
50
|
+
raise InsufficientArgsForSearch unless options.has_key?(:boundary_types) && options.has_key?(:query)
|
51
|
+
|
52
|
+
options[:boundary_types] = Array(options[:boundary_types]).collect {|bt| BOUNDARY_TYPES[bt] }.join(',')
|
53
|
+
HashUtils.rename_key!(options, :boundary_types, :bt)
|
54
|
+
HashUtils.rename_key!(options, :query, :s)
|
55
|
+
HashUtils.rename_key!(options, :state, :st) if options.has_key?(:state)
|
56
|
+
HashUtils.rename_key!(options, :county, :co) if options.has_key?(:county)
|
57
|
+
HashUtils.rename_key!(options, :census_tract, :ct) if options.has_key?(:census_tract)
|
58
|
+
|
59
|
+
options = default_options.merge(options)
|
60
|
+
|
61
|
+
result = get(Endpoint.endpoint_url, options)
|
62
|
+
result['sch'].collect {|hsh| HashUtils.symbolize_keys(hsh) }
|
63
|
+
end
|
64
|
+
|
65
|
+
def boundary_search(*args)
|
66
|
+
default_options = @@default_options
|
67
|
+
default_options[:t] = "bnd"
|
68
|
+
|
69
|
+
options = extract_options!(args)
|
70
|
+
|
71
|
+
raise InsufficientArgsForSearch unless options.has_key?(:boundary_types) || options.has_key?(:boundary_ids)
|
72
|
+
|
73
|
+
options[:boundary_types] = Array(options[:boundary_types]).collect {|bt| BOUNDARY_TYPES[bt] }.join(',') if options.has_key?(:boundary_types)
|
74
|
+
options[:boundary_ids] = Array(options[:boundary_ids]).join(',') if options.has_key?(:boundary_ids)
|
75
|
+
HashUtils.rename_key!(options, :boundary_types, :bt) if options.has_key?(:boundary_types)
|
76
|
+
HashUtils.rename_key!(options, :boundary_ids, :bi) if options.has_key?(:boundary_ids)
|
77
|
+
HashUtils.rename_key!(options, :lng, :lon) if options.has_key?(:lng)
|
78
|
+
|
79
|
+
options = default_options.merge(options)
|
80
|
+
|
81
|
+
result = get(Endpoint.endpoint_url, options)
|
82
|
+
HashUtils.recursively_symbolize_keys(result["bnd"])
|
83
|
+
end
|
84
|
+
|
85
|
+
def indicator_search(*args)
|
86
|
+
default_options = @@default_options
|
87
|
+
default_options[:t] = "ind"
|
88
|
+
|
89
|
+
options = extract_options!(args)
|
90
|
+
|
91
|
+
raise InsufficientArgsForSearch unless options.has_key?(:indicators) && (options.has_key?(:boundary_types) || options.has_key?(:boundary_ids))
|
92
|
+
|
93
|
+
options[:indicators] = Array(options[:indicators]).collect {|i| INDICATORS[i] }.join(',')
|
94
|
+
options[:boundary_types] = Array(options[:boundary_types]).collect {|bt| BOUNDARY_TYPES[bt] }.join(',') if options.has_key?(:boundary_types)
|
95
|
+
options[:boundary_ids] = Array(options[:boundary_ids]).join(',') if options.has_key?(:boundary_ids)
|
96
|
+
HashUtils.rename_key!(options, :indicators, :ii)
|
97
|
+
HashUtils.rename_key!(options, :boundary_types, :bt) if options.has_key?(:boundary_types)
|
98
|
+
HashUtils.rename_key!(options, :boundary_ids, :bi) if options.has_key?(:boundary_ids)
|
99
|
+
HashUtils.rename_key!(options, :lng, :lon) if options.has_key?(:lng)
|
100
|
+
|
101
|
+
options = default_options.merge(options)
|
102
|
+
|
103
|
+
result = get(Endpoint.endpoint_url, options)
|
104
|
+
HashUtils.recursively_symbolize_keys(result["ind"])
|
105
|
+
end
|
106
|
+
|
107
|
+
def get(endpoint, data=nil)
|
108
|
+
raise NoConnectionEstablished if @@connection.nil?
|
109
|
+
@@connection.get endpoint, data
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def extract_options!(args)
|
115
|
+
if args.last.is_a?(Hash)
|
116
|
+
return args.pop
|
117
|
+
else
|
118
|
+
return {}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
module PolicyMap
|
2
|
+
|
3
|
+
class Connection
|
4
|
+
|
5
|
+
attr_accessor :debug
|
6
|
+
attr_reader :client_id
|
7
|
+
|
8
|
+
def initialize(client_id)
|
9
|
+
@client_id = client_id
|
10
|
+
@debug = false
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(endpoint, data=nil)
|
14
|
+
request :get, endpoint, data
|
15
|
+
end
|
16
|
+
|
17
|
+
class Response
|
18
|
+
|
19
|
+
attr_reader :code, :header, :body, :message
|
20
|
+
|
21
|
+
HTTP_RESPONSES = { '100' => 'Continue', '101' => 'SwitchProtocol', '200' => 'OK', '201' => 'Created', '202' => 'Accepted', '203' => 'NonAuthoritativeInformation',
|
22
|
+
'204' => 'NoContent', '205' => 'ResetContent', '206' => 'PartialContent', '300' => 'MultipleChoice', '301' => 'MovedPermanently',
|
23
|
+
'302' => 'Found', '303' => 'SeeOther', '304' => 'NotModified', '305' => 'UseProxy', '307' => 'TemporaryRedirect', '400' => 'BadRequest',
|
24
|
+
'401' => 'Unauthorized', '402' => 'PaymentRequired', '403' => 'Forbidden', '404' => 'NotFound', '405' => 'MethodNotAllowed',
|
25
|
+
'406' => 'NotAcceptable', '407' => 'ProxyAuthenticationRequired', '408' => 'RequestTimeOut', '409' => 'Conflict', '410' => 'Gone',
|
26
|
+
'411' => 'LengthRequired', '412' => 'PreconditionFailed', '413' => 'RequestEntityTooLarge', '414' => 'RequestURITooLong',
|
27
|
+
'415' => 'UnsupportedMediaType', '416' => 'RequestedRangeNotSatisfiable', '417' => 'ExpectationFailed', '500' => 'InternalServerError',
|
28
|
+
'501' => 'NotImplemented', '502' => 'BadGateway', '503' => 'ServiceUnavailable', '504' => 'GatewayTimeOut', '505' => 'VersionNotSupported' }
|
29
|
+
|
30
|
+
def initialize(http_client)
|
31
|
+
@code = http_client.response_code
|
32
|
+
@header = http_client.header_str.is_a?(String) ? parse_headers(http_client.header_str) : http_client.header_str
|
33
|
+
@body = http_client.body_str
|
34
|
+
@message = HTTP_RESPONSES[@code.to_s]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def parse_headers(header_string)
|
40
|
+
header_lines = header_string.split($/)
|
41
|
+
header_lines.shift
|
42
|
+
header_lines.inject({}) do |hsh, line|
|
43
|
+
whole_enchillada, key, value = /^(.*?):\s*(.*)$/.match(line.chomp).to_a
|
44
|
+
hsh[key] = value unless whole_enchillada.nil?
|
45
|
+
hsh
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def request(method, endpoint, data)
|
54
|
+
headers = { 'User-Agent' => "PolicyMap Ruby Client v#{VERSION}" }
|
55
|
+
|
56
|
+
if [:get].include?(method) && !data.nil?
|
57
|
+
endpoint = endpoint + '?' + build_query(data)
|
58
|
+
end
|
59
|
+
|
60
|
+
if debug
|
61
|
+
puts "request: #{method.to_s.upcase} #{endpoint}"
|
62
|
+
puts "headers:"
|
63
|
+
headers.each do |key, value|
|
64
|
+
puts "#{key}=#{value}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
response = send_request(method, endpoint, headers)
|
69
|
+
|
70
|
+
if debug
|
71
|
+
puts "\nresponse: #{response.code}"
|
72
|
+
puts "headers:"
|
73
|
+
response.header.each do |key, value|
|
74
|
+
puts "#{key}=#{value}"
|
75
|
+
end
|
76
|
+
puts "body:"
|
77
|
+
puts response.body
|
78
|
+
end
|
79
|
+
|
80
|
+
raise_errors(response)
|
81
|
+
|
82
|
+
if response.body.empty?
|
83
|
+
content = nil
|
84
|
+
else
|
85
|
+
begin
|
86
|
+
content = JSON.parse(response.body)
|
87
|
+
rescue JSON::ParserError
|
88
|
+
raise DecodeError, "content: <#{response.body}>"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
content
|
93
|
+
end
|
94
|
+
|
95
|
+
def build_query(data)
|
96
|
+
data = data.to_a if data.is_a?(Hash)
|
97
|
+
data.map do |key, value|
|
98
|
+
[key.to_s, URI.escape(value.to_s)].join('=')
|
99
|
+
end.join('&')
|
100
|
+
end
|
101
|
+
|
102
|
+
def send_request(method, endpoint, headers)
|
103
|
+
if method == :get
|
104
|
+
@http_client = Curl::Easy.new(endpoint) do |c|
|
105
|
+
c.headers = headers
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
@http_client.perform
|
110
|
+
|
111
|
+
Response.new(@http_client)
|
112
|
+
end
|
113
|
+
|
114
|
+
def raise_errors(response)
|
115
|
+
response_description = "(#{response.code}): #{response.message}"
|
116
|
+
response_description += " - #{response.body}" unless response.body.empty?
|
117
|
+
|
118
|
+
case response.code.to_i
|
119
|
+
when 401
|
120
|
+
raise Unauthorized
|
121
|
+
when 404
|
122
|
+
raise NotFound
|
123
|
+
when 500
|
124
|
+
raise ServerError, "PolicyMap had an internal error. Please let them know. #{response_description}"
|
125
|
+
when 502..503
|
126
|
+
raise Unavailable, response_description
|
127
|
+
else
|
128
|
+
unless response.code.to_i == 200
|
129
|
+
raise PolicyMapError, response_description
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module PolicyMap
|
2
|
+
|
3
|
+
class HashUtils
|
4
|
+
|
5
|
+
def self.rename_key!(hash, old_key, new_key)
|
6
|
+
hash[new_key] = hash.delete(old_key)
|
7
|
+
hash
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.symbolize_keys(hash)
|
11
|
+
hash.inject({}) do |options, (key, value)|
|
12
|
+
options[(key.to_sym rescue key) || key] = value
|
13
|
+
options
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.recursively_symbolize_keys(object)
|
18
|
+
if object.is_a? Hash
|
19
|
+
symbolized_hash = symbolize_keys(object)
|
20
|
+
symbolized_hash.each do |key, value|
|
21
|
+
symbolized_hash[key] = recursively_symbolize_keys(value)
|
22
|
+
end
|
23
|
+
symbolized_hash
|
24
|
+
elsif object.is_a? Array
|
25
|
+
object.map {|value| recursively_symbolize_keys(value) }
|
26
|
+
else
|
27
|
+
object
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: policymap_wrap
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Mauricio Gomes
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-27 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: yajl-ruby
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 7
|
33
|
+
- 7
|
34
|
+
version: 0.7.7
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: curb
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 105
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 7
|
49
|
+
- 7
|
50
|
+
- 1
|
51
|
+
version: 0.7.7.1
|
52
|
+
type: :runtime
|
53
|
+
version_requirements: *id002
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: rspec
|
56
|
+
prerelease: false
|
57
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
hash: 13
|
63
|
+
segments:
|
64
|
+
- 1
|
65
|
+
- 2
|
66
|
+
- 9
|
67
|
+
version: 1.2.9
|
68
|
+
type: :development
|
69
|
+
version_requirements: *id003
|
70
|
+
description: Ruby wrapper around the PolicyMap API. Your API may vary.
|
71
|
+
email: mauricio@geminisbs.com
|
72
|
+
executables: []
|
73
|
+
|
74
|
+
extensions: []
|
75
|
+
|
76
|
+
extra_rdoc_files:
|
77
|
+
- LICENSE
|
78
|
+
- README.rdoc
|
79
|
+
files:
|
80
|
+
- LICENSE
|
81
|
+
- README.rdoc
|
82
|
+
- VERSION
|
83
|
+
- lib/policymap.rb
|
84
|
+
- lib/policymap_wrap.rb
|
85
|
+
- lib/policymap_wrap/client.rb
|
86
|
+
- lib/policymap_wrap/connection.rb
|
87
|
+
- lib/policymap_wrap/endpoint.rb
|
88
|
+
- lib/policymap_wrap/hash_utils.rb
|
89
|
+
- spec/policymap_wrap_spec.rb
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
has_rdoc: true
|
92
|
+
homepage: http://github.com/geminisbs/policymap_wrap
|
93
|
+
licenses: []
|
94
|
+
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options:
|
97
|
+
- --charset=UTF-8
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 3
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
version: "0"
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ">="
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
hash: 3
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
requirements: []
|
119
|
+
|
120
|
+
rubyforge_project:
|
121
|
+
rubygems_version: 1.3.7
|
122
|
+
signing_key:
|
123
|
+
specification_version: 3
|
124
|
+
summary: Ruby wrapper around the PolicyMap API
|
125
|
+
test_files:
|
126
|
+
- spec/policymap_wrap_spec.rb
|
127
|
+
- spec/spec_helper.rb
|