policymap_wrap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,2 @@
1
+ # So you can require "policymap" instead of "policymap_wrap"
2
+ require "policymap_wrap"
@@ -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,15 @@
1
+ module PolicyMap
2
+
3
+ class Endpoint
4
+
5
+ class << self
6
+
7
+ def endpoint_url
8
+ [REALM, 's/'].join('/')
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+
15
+ 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
@@ -0,0 +1,7 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "PolicymapWrap" do
4
+ it "fails" do
5
+ fail "hey buddy, you should probably rename this file and start specing for real"
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'policymap_wrap'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
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