geo_pack 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/.document +5 -0
- data/.gitignore +21 -0
- data/README.md +79 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/lib/geo_pack.rb +73 -0
- data/lib/geo_pack/geo_names.rb +116 -0
- data/lib/geo_pack/rillow.rb +261 -0
- data/lib/geo_pack/rillow_helper.rb +34 -0
- data/lib/geo_pack/urban_mapping.rb +88 -0
- data/lib/geo_pack/zillower.rb +111 -0
- data/test/helper.rb +10 -0
- data/test/test_config.yml +5 -0
- data/test/test_geo_pack.rb +59 -0
- metadata +115 -0
data/.document
ADDED
data/.gitignore
ADDED
data/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
#geo_pack#
|
2
|
+
|
3
|
+
Geo related services.
|
4
|
+
|
5
|
+
##Usage##
|
6
|
+
|
7
|
+
First create an instance passing the configuration file path to the constructor:
|
8
|
+
|
9
|
+
geo_pack = GeoPack.new("config.yml")
|
10
|
+
|
11
|
+
The configuration file contains this structure:
|
12
|
+
|
13
|
+
urbanmapping:
|
14
|
+
neighborhoods_apikey: jwncnt4vgs8xarc7pvap2ra7
|
15
|
+
secret: RRGxwfEn
|
16
|
+
zillow:
|
17
|
+
zwsid: X1-ZW3mlz1cqh8sej_1y8f9
|
18
|
+
|
19
|
+
Now you can transform an address into a normalized address with its coordinates, neighborhood with its coordinates/bounding box, city and state like this:
|
20
|
+
|
21
|
+
geo_pack.get_location("2114 bigelow Avenue , seattle")
|
22
|
+
=>
|
23
|
+
{
|
24
|
+
:state => { :name => "WA"},
|
25
|
+
:city => { :name => "Seattle"},
|
26
|
+
:neighborhood => { :name=>"Queen Anne", :geom=>[[47.617989, -122.378464], [47.656792, -122.34182]]},
|
27
|
+
:address => { :name => "2114 Bigelow Ave N, Seattle, WA 98109, USA", :geom => [47.637936, -122.34813]}
|
28
|
+
}
|
29
|
+
|
30
|
+
The address passed to get_location is strong enough to support weakly specified addresses. For example we can search just by zip code:
|
31
|
+
|
32
|
+
geo_pack.get_location("90210")
|
33
|
+
=>
|
34
|
+
{
|
35
|
+
:state=>{:name=>"CA"},
|
36
|
+
:city=>{:name=>"Beverly Hills"},
|
37
|
+
:neighborhood=>{:geom=>[[34.088879, -118.43866], [34.129559, -118.373741]], :name=>"Beverly Crest"},
|
38
|
+
:address=>{:geom=>[34.1030032, -118.4104684], :name=>"Beverly Hills, CA 90210, USA"}
|
39
|
+
}
|
40
|
+
|
41
|
+
If the address could not be found an empty hash will be returned:
|
42
|
+
|
43
|
+
geo_pack.get_location("supercalifragilisticexpialidocious address")
|
44
|
+
=>
|
45
|
+
{}
|
46
|
+
|
47
|
+
The neighborhood search, which uses an extra stack of api services, can be excluded if you don't need it and want faster results:
|
48
|
+
|
49
|
+
geo_pack.get_location("90210", :exclude => :neighborhood)
|
50
|
+
=>
|
51
|
+
{
|
52
|
+
:state=>{:name=>"CA"},
|
53
|
+
:city=>{:name=>"Beverly Hills"},
|
54
|
+
:address=>{:geom=>[34.1030032, -118.4104684], :name=>"Beverly Hills, CA 90210, USA"}
|
55
|
+
}
|
56
|
+
|
57
|
+
Zillow lookups are also supported:
|
58
|
+
|
59
|
+
geo_pack.get_property_details("2114 Bigelow, seattle")
|
60
|
+
=>
|
61
|
+
{
|
62
|
+
:error=>false,
|
63
|
+
:data=> {
|
64
|
+
:year_built=>1920,
|
65
|
+
:housing_type=>"house",
|
66
|
+
:square_footage=>"3470"
|
67
|
+
},
|
68
|
+
:message=>"Request successfully processed"
|
69
|
+
}
|
70
|
+
|
71
|
+
In case of error you'll get:
|
72
|
+
|
73
|
+
geo_pack.get_property_details("Somewhere")
|
74
|
+
=>
|
75
|
+
{
|
76
|
+
:error=>true,
|
77
|
+
:data=>{},
|
78
|
+
:message=>"Error: no exact match found for input address"
|
79
|
+
}
|
data/Rakefile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "geo_pack"
|
8
|
+
gem.summary = %Q{Geo related services"}
|
9
|
+
gem.description = %Q{Geo related services"}
|
10
|
+
gem.homepage = "http://github.com/efficiency20/geo_pack"
|
11
|
+
gem.authors = ["Efficiency 2.0"]
|
12
|
+
gem.add_dependency "geokit", "= 1.5.0"
|
13
|
+
gem.add_dependency "geoplanet", "= 0.2.3"
|
14
|
+
gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'rake/testtask'
|
23
|
+
Rake::TestTask.new(:test) do |test|
|
24
|
+
test.libs << 'lib' << 'test'
|
25
|
+
test.pattern = 'test/**/test_*.rb'
|
26
|
+
test.verbose = true
|
27
|
+
end
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'rcov/rcovtask'
|
31
|
+
Rcov::RcovTask.new do |test|
|
32
|
+
test.libs << 'test'
|
33
|
+
test.pattern = 'test/**/test_*.rb'
|
34
|
+
test.verbose = true
|
35
|
+
end
|
36
|
+
rescue LoadError
|
37
|
+
task :rcov do
|
38
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
task :test => :check_dependencies
|
43
|
+
|
44
|
+
task :default => :test
|
45
|
+
|
46
|
+
require 'rake/rdoctask'
|
47
|
+
Rake::RDocTask.new do |rdoc|
|
48
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
49
|
+
|
50
|
+
rdoc.rdoc_dir = 'rdoc'
|
51
|
+
rdoc.title = "geo_pack #{version}"
|
52
|
+
rdoc.rdoc_files.include('README*')
|
53
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
54
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/geo_pack.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'geokit'
|
2
|
+
require 'geoplanet'
|
3
|
+
require 'geo_pack/urban_mapping'
|
4
|
+
require 'geo_pack/geo_names'
|
5
|
+
require 'geo_pack/zillower'
|
6
|
+
|
7
|
+
class GeoPack
|
8
|
+
Geokit::Geocoders::provider_order = [:google, :us, :yahoo, :geonames]
|
9
|
+
GeoPlanet.appid = 'aaaaaaaaaaaaaaaaaaaanobodyatyahoochecksthisaaaaaaaaaaaaaaaaaaaaa'
|
10
|
+
|
11
|
+
def initialize(config_file_path)
|
12
|
+
config = YAML.load_file(config_file_path)
|
13
|
+
@urban_mapping = UrbanMapping.new(config["urbanmapping"]["neighborhoods_apikey"], config["urbanmapping"]["secret"])
|
14
|
+
@geo_names = GeoNames.new
|
15
|
+
@zillower = Zillower.new(config["zillow"]["zwsid"])
|
16
|
+
end
|
17
|
+
|
18
|
+
def get_location(address, options = {})
|
19
|
+
location = {}
|
20
|
+
location.merge!(get_address_city_and_state(address, options))
|
21
|
+
return location if options[:exclude] == :neighborhood || location.empty?
|
22
|
+
location.merge!(get_neighborhood(location[:address][:geom]))
|
23
|
+
location
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_property_details(address)
|
27
|
+
geokit_result = GeoKit::Geocoders::MultiGeocoder.geocode(address)
|
28
|
+
@zillower.lookup_address(:address => geokit_result.street_address, :citystatezip => "#{geokit_result.city}, #{geokit_result.state}, #{geokit_result.zip}")
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
def get_address_city_and_state(address, options)
|
33
|
+
location = {}
|
34
|
+
geokit_result = GeoKit::Geocoders::MultiGeocoder.geocode(address)
|
35
|
+
if geokit_result.success?
|
36
|
+
location[:address] = { :name => geokit_result.full_address, :geom => [geokit_result.lat, geokit_result.lng]}
|
37
|
+
location[:city] = { :name => geokit_result.city}
|
38
|
+
location[:state] = { :name => geokit_result.state}
|
39
|
+
end
|
40
|
+
location
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_neighborhood(geom)
|
44
|
+
location = {}
|
45
|
+
lat, lng = geom
|
46
|
+
urban_mapping_result = @urban_mapping.query(:method => "getNeighborhoodsByLatLng", :lat => lat, :lng => lng)
|
47
|
+
|
48
|
+
unless urban_mapping_result.empty?
|
49
|
+
geom_or_bounding_box = get_bounding_box(urban_mapping_result) || geom
|
50
|
+
location[:neighborhood] = {:name => urban_mapping_result.first["name"], :geom => geom_or_bounding_box}
|
51
|
+
else
|
52
|
+
geo_names_result = @geo_names.query(:method => 'findNearbyPlaceName', :lat => lat, :lng => lng)
|
53
|
+
unless geo_names_result.empty?
|
54
|
+
geom_or_bounding_box = get_bounding_box(geo_names_result) || geom
|
55
|
+
location[:neighborhood] = {:name => geo_names_result.first["name"], :geom => geom_or_bounding_box}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
location
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_bounding_box(api_result)
|
63
|
+
name = api_result.first["name"]
|
64
|
+
city = api_result.first["city"]
|
65
|
+
state = api_result.first["state"]
|
66
|
+
|
67
|
+
if geo_planet_response = GeoPlanet::Place.search("#{name}, #{city}, #{state}, US")
|
68
|
+
geo_planet_response.first.bounding_box
|
69
|
+
else
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
#geonames rest api
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'httparty'
|
5
|
+
require 'digest/md5'
|
6
|
+
|
7
|
+
|
8
|
+
#$ curl 'http://ws.geonames.org/findNearbyPlaceNameJSON?lat=40.871992&lng=-124.087883&style=full'
|
9
|
+
#{"geonames":[{"adminCode2":"023","countryName":"United States","adminCode1":"CA","fclName":"city, village,...","elevation":7,"countryCode":"US","lng":-124.0828396,"adminName2":"Humboldt County","adminName3":"","fcodeName":"populated place","distance":"0.7419","adminName4":"","timezone":{"dstOffset":-7,"gmtOffset":-8,"timeZoneId":"America/Los_Angeles"},"fcl":"P","name":"Arcata","fcode":"PPL","geonameId":5558953,"lat":40.8665166,"population":17199,"adminName1":"California"}]}
|
10
|
+
#geoname = um.query_geonames(:method => 'findNearbyPlaceName',:lat => 40.871992, :lng => -124.087883, :style => 'full' )
|
11
|
+
|
12
|
+
|
13
|
+
class GeoPack
|
14
|
+
class GeoNames
|
15
|
+
include HTTParty
|
16
|
+
format :json
|
17
|
+
|
18
|
+
GEONAMES_API = {
|
19
|
+
'findNearbyPlaceName' => [:lat, :lng],
|
20
|
+
'postalCodeSearch' => [:postalcode]
|
21
|
+
}
|
22
|
+
|
23
|
+
def method_missing(method, *args)
|
24
|
+
if GEONAMES_API.has_key?( method )
|
25
|
+
query(method, *args)
|
26
|
+
else
|
27
|
+
super
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.query(options= {})
|
32
|
+
geonames = self.new(options[:apikey])
|
33
|
+
return geonames.query(options)
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def query(options={})
|
38
|
+
check_requirements(options)
|
39
|
+
options.merge!({:style => 'full'}) unless options.has_key? :style
|
40
|
+
options = munge_key_names(options)
|
41
|
+
method = options.delete(:method)
|
42
|
+
results = munge_results( GeoNames.get("http://ws.geonames.org/" + method + "JSON", :query => options) )
|
43
|
+
|
44
|
+
if results.kind_of?(Hash) && results.has_key?('status')
|
45
|
+
#throw exception here because there was an error
|
46
|
+
return[]
|
47
|
+
else
|
48
|
+
return results
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
#so we can use prettier options than geonames provides
|
53
|
+
def munge_key_names(options={})
|
54
|
+
options_mapping = {
|
55
|
+
'latitude' => 'lat',
|
56
|
+
'longitude' => 'lng',
|
57
|
+
'long' => 'lng',
|
58
|
+
'zip' => 'postalcode',
|
59
|
+
'zipcode' => 'postalcode',
|
60
|
+
'zip_code' => 'postalcode',
|
61
|
+
'postalCode' => 'postalcode'}
|
62
|
+
|
63
|
+
|
64
|
+
options.map do |key,value|
|
65
|
+
if options_mapping.has_key? key.to_s
|
66
|
+
options[options_mapping[key.to_s]] = options.delete key
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
options[:countryBias] = 'US' if options[:method] == 'postalCodeSearch'
|
71
|
+
|
72
|
+
return options
|
73
|
+
end
|
74
|
+
|
75
|
+
def munge_results(results)
|
76
|
+
results = results["geonames"] if results.kind_of?(Hash) && results.has_key?("geonames")
|
77
|
+
results = results["postalCodes"] if results.kind_of?(Hash) && results.has_key?("postalCodes")
|
78
|
+
return [] if results.nil?
|
79
|
+
|
80
|
+
return munge_single_result(results) if results.kind_of?(Hash)
|
81
|
+
|
82
|
+
results_array = []
|
83
|
+
results.each {|result| results_array<<munge_single_result(result)}
|
84
|
+
|
85
|
+
return results_array
|
86
|
+
end
|
87
|
+
|
88
|
+
def munge_single_result(results)
|
89
|
+
mapping = {
|
90
|
+
'latitude' => 'lat',
|
91
|
+
'longitude' => 'lng',
|
92
|
+
'long' => 'lng',
|
93
|
+
'zip' => 'postalcode',
|
94
|
+
'zipcode' => 'postalcode',
|
95
|
+
'neighborhoodId' => 'neighborhood_id',
|
96
|
+
'adminCode1' => 'state',
|
97
|
+
'name' => 'city',
|
98
|
+
'geonameId' => 'id',
|
99
|
+
'placeName' => 'name'}
|
100
|
+
|
101
|
+
results.map do |key,value|
|
102
|
+
if mapping.has_key? key.to_s
|
103
|
+
results[mapping[key]] = results[ key ]
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
return results
|
108
|
+
end
|
109
|
+
|
110
|
+
def check_requirements(options)
|
111
|
+
#raise( 'apikey required for geonames' ) if @apikey.nil?
|
112
|
+
raise( 'method required for geonames' ) if options[:method].nil?
|
113
|
+
raise( "method #{options[:method]} geonames" ) unless GEONAMES_API.has_key?( options[:method] )
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,261 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'net/http'
|
3
|
+
require 'uri'
|
4
|
+
require 'xmlsimple'
|
5
|
+
require 'cgi'
|
6
|
+
require 'geo_pack/rillow_helper'
|
7
|
+
|
8
|
+
# This api is created by Leo Chan on 10/29/2007.
|
9
|
+
# There is no license requirement. Use it or copy any part of the code that you want to use.
|
10
|
+
# Use it at your own risk. I am not liable for anything. Just want to share what I wrote. Hopefully you will find it useful.
|
11
|
+
# Rillow is a simple ruby wrapper to zillow webservice api: http://www.zillow.com/howto/api/APIOverview.htm
|
12
|
+
# It does the web service call and gets the result back for you. You don't have to know about the url request, url encoding or
|
13
|
+
# parsing the result. The result object is in hash/array format. So no need to parsse xml.
|
14
|
+
# You will need to register with zillow to get the Zillow Web Service Identifier first.
|
15
|
+
# You will need to pass the Zillow Web Service Identifier to the constructor.
|
16
|
+
# This wrapper depends on xmlsimple.
|
17
|
+
#
|
18
|
+
# Example:
|
19
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
20
|
+
# result = rillow.get_search_results(:address => '2114 Bigelow Ave', :citystatezip => 'Seattle WA')
|
21
|
+
# result.to_hash
|
22
|
+
# result.find_attribute 'valudationRange'
|
23
|
+
class GeoPack
|
24
|
+
class Rillow
|
25
|
+
attr_accessor :webservice_url, :zwsid
|
26
|
+
|
27
|
+
VALID_METHODS = {
|
28
|
+
:get_search_results => 'GetSearchResults',
|
29
|
+
:get_zestimate => 'GetZestimate',
|
30
|
+
:get_chart => 'GetChart',
|
31
|
+
:get_region_chart => 'GetRegionChart',
|
32
|
+
:get_demographics => 'GetDemographics',
|
33
|
+
:get_comps => "GetComps",
|
34
|
+
:get_region_children => 'GetRegionChildren',
|
35
|
+
:get_ratesummary => 'GetRateSummary',
|
36
|
+
:get_monthly_payments => 'GetMonthlyPayments',
|
37
|
+
:get_deep_search_results => 'GetDeepSearchResults',
|
38
|
+
:get_property_details => 'GetDeepSearchResults',
|
39
|
+
:get_deep_comps => 'GetDeepComps',
|
40
|
+
:get_region_postings => 'GetRegionPostings',
|
41
|
+
:get_updated_property_details => 'GetUpdatedPropertyDetails'
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
46
|
+
def initialize(my_zwsid, my_webservice_url= 'http://www.zillow.com/webservice/')
|
47
|
+
@zwsid= my_zwsid
|
48
|
+
|
49
|
+
@webservice_url = my_webservice_url
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(method, *args)
|
53
|
+
super(method, args) unless VALID_METHODS.has_key? method
|
54
|
+
fetch_from_zillow(VALID_METHODS[method], args)
|
55
|
+
end
|
56
|
+
|
57
|
+
#The get_search_results finds a property for a specified address.
|
58
|
+
#The content returned contains the address for the property or properties as well as the Zillow Property ID (ZPID) and current Zestimate.
|
59
|
+
#It also includes the date the Zestimate was computed, a valuation range and the Zestimate ranking for the property within its ZIP code.
|
60
|
+
#If no exact address match for a property is found, a list of closely matching properties is returned.
|
61
|
+
#See: http://www.zillow.com/howto/api/GetSearchResults.htm
|
62
|
+
# parameter:
|
63
|
+
# address street address
|
64
|
+
# citystatezip city&state or zip code
|
65
|
+
#Example:
|
66
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
67
|
+
# result = rillow.get_search_results(:address => '2114 Bigelow Ave', :citystatezip => 'Seattle, WA')
|
68
|
+
# result.to_hash
|
69
|
+
|
70
|
+
#For a specified Zillow property identifier (zpid), the get_zestimate returns:
|
71
|
+
#1. The most recent property Zestimate
|
72
|
+
#2. The date the Zestimate was computed
|
73
|
+
#3. The valuation range
|
74
|
+
#4. The Zestimate ranking within the property's ZIP code.
|
75
|
+
#5. The full property address and geographic location (latitude/longitude) and a set of identifiers that uniquely represent the region (ZIP code, city, county & state) in which the property exists.
|
76
|
+
#The GetZestimate API will only surface properties for which a Zestimate exists.
|
77
|
+
#If a request is made for a property that has no Zestimate, an error code is returned.
|
78
|
+
#See: http://www.zillow.com/howto/api/GetZestimate.htm
|
79
|
+
#parameter:
|
80
|
+
# zpid zillow property id
|
81
|
+
#Example:
|
82
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
83
|
+
# result = rillow.get_zestimate(:zpid => '48749425')
|
84
|
+
# result.to_hash
|
85
|
+
|
86
|
+
|
87
|
+
#The get_chart api generates a URL for an image file that displays historical Zestimates for a specific property.
|
88
|
+
#The API accepts as input the Zillow Property ID as well as a chart type: either percentage or dollar value change.
|
89
|
+
#Optionally, the API accepts width and height parameters that constrain the size of the image.
|
90
|
+
#The historical data can be for the past 1 year, 5 years or 10 years.
|
91
|
+
#See: http://www.zillow.com/howto/api/GetChart.htm
|
92
|
+
#parameters:
|
93
|
+
#require:
|
94
|
+
# zpid: The Zillow Property ID for the property; the parameter type is an integer
|
95
|
+
# unit_type: A string value that specifies whether to show the percent change, parameter value of "percent,"
|
96
|
+
# or dollar change, parameter value of "dollar"
|
97
|
+
#options:
|
98
|
+
# :width => width of the generated graph. The value must be between 200 and 600, inclusive
|
99
|
+
# :height=> height of the generated graph. The value must be between 100 and 300, inclusive.
|
100
|
+
# :chart_duration => The duration of past data that needs to be shown in the chart. Valid values are "1year",
|
101
|
+
# "5years" and "10years". If unspecified, the value defaults to "1year"
|
102
|
+
#Example:
|
103
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
104
|
+
# result = rillow.get_chart(:zpid => '48749425',:unit_type => 'percent',:width=>300, :height=>150, :chart_duration=>'5years')
|
105
|
+
# result.to_hash
|
106
|
+
|
107
|
+
#The get_region_chart generates a URL for an image file that displays the historical Zestimates for a specific geographic region.
|
108
|
+
#The API accepts as input the name of the region as well as a chart type: either percentage or dollar value change. #
|
109
|
+
#Optionally, the API accepts width and height parameters that constrain the size of the image.
|
110
|
+
#The historical data can be for the past 1 year, 5 years or 10 years.
|
111
|
+
#see: http://www.zillow.com/howto/api/GetRegionChart.htm
|
112
|
+
#parameters:
|
113
|
+
#require:
|
114
|
+
# unit_type: A string value that specifies whether to show the percent change, parameter value of "percent,"
|
115
|
+
# or dollar change, parameter value of "dollar"
|
116
|
+
#options:
|
117
|
+
# :city=> name of the city
|
118
|
+
# :state=> The two-letter abbreviation for a state
|
119
|
+
# :zip=> The 5-digit ZIP code
|
120
|
+
# :width=> width of the generated graph. The value must be between 200 and 600, inclusive
|
121
|
+
# :height=> height of the generated graph. The value must be between 100 and 300, inclusive.
|
122
|
+
# :chart_duration => The duration of past data that needs to be shown in the chart. Valid values are "1year",
|
123
|
+
# "5years" and "10years". If unspecified, the value defaults to "1year"
|
124
|
+
#Example:
|
125
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
126
|
+
# result = rillow.get_region_chart(:unit_type =>'percent',:city=>'seattle',:state=>'WA',:width=>300, :height=>150, :chart_duration=>'5years')
|
127
|
+
# result.to_hash
|
128
|
+
|
129
|
+
#For a specified region, the GetDemographics API returns a set of demographic data which includes:
|
130
|
+
# * A URL linking to the corresponding demographics page at Zillow.com
|
131
|
+
# * Census Information (i.e. total population, median household income, recent homeowners, etc)
|
132
|
+
# * Age Distributions
|
133
|
+
# * Who Lives Here (if available for the region)
|
134
|
+
# * What's Unique About the People (if available for the region)
|
135
|
+
# A region can be specified either through its respective Region ID or by providing one to three parameters:
|
136
|
+
# state, city, neighborhood. The neighborhood parameter can be omitted if demographic data on a city is desired.
|
137
|
+
# The state and city parameter are always required.
|
138
|
+
# see: http://www.zillow.com/howto/api/GetDemographics.htm
|
139
|
+
# parameters:
|
140
|
+
# :rid => region id
|
141
|
+
# :city=> name of the city
|
142
|
+
# :state=> The two-letter abbreviation for a state
|
143
|
+
# :neighborhood=> The neighborhood of the region to retrieve data
|
144
|
+
#Example:
|
145
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
146
|
+
# result = rillow.get_demographics(:city=>'seattle',:state=>'WA',:neighborhood=>'Ballard')
|
147
|
+
# result.to_hash
|
148
|
+
|
149
|
+
# For a specified region, the get_region_children API returns a list of subregions with the following information:
|
150
|
+
# * Subregion Type
|
151
|
+
# * Region IDs
|
152
|
+
# * Region Names
|
153
|
+
# * Latitudes and Longitudes
|
154
|
+
#A region can be specified at various levels of the region hierarchy.
|
155
|
+
#An optional childtype parameter can also be specified to return subregions of a specific type.
|
156
|
+
#Allowable region types include:
|
157
|
+
#country, state, county, and city. Country and county are optional parameters unless they are the region to be specified.
|
158
|
+
#Possible childtype parameters include: state, county, city, zipcode, and neighborhood.
|
159
|
+
#Any childtype parameter can be specified as long as the childtype parameter is a subregion type
|
160
|
+
#(i.e.. you cannot retrieve the subregion counties of a city).
|
161
|
+
#The only exception is that only subregion state can be specified for a country (otherwise it returns too many results).
|
162
|
+
#
|
163
|
+
#Childtype parameter is optional and defaults to types dependent on the specified region type:
|
164
|
+
#country defaults to return subregions of type state, state -> county, county -> city, city -> zipcode.
|
165
|
+
#see: http://www.zillow.com/howto/api/GetRegionChildren.htm
|
166
|
+
#parameters:
|
167
|
+
# :city=> name of the city. The city of the region to retrieve subregions from.
|
168
|
+
# :state=> The two-letter abbreviation for a state. The state of the region to retrieve subregions from.
|
169
|
+
# :country=> The country of the region to retrieve subregions from.
|
170
|
+
# :rid=> The regionId of the region to retrieve subregions from.
|
171
|
+
# :childtype=> The type of subregions to retrieve (available types: state, county, city, zipcode, and neighborhood)
|
172
|
+
# Example:
|
173
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
174
|
+
# result = rillow.get_region_children(:city=>'seattle',:state=>'WA',:country=>'united states',:childtype=>'neighborhood')
|
175
|
+
# result.to_hash
|
176
|
+
|
177
|
+
#The get_comps returns a list of comparable recent sales for a specified property.
|
178
|
+
#The result set returned contains the address, Zillow property identifier, and Zestimate for the comparable properties and
|
179
|
+
#the principal property for which the comparables are being retrieved.
|
180
|
+
#see: http://www.zillow.com/howto/api/GetComps.htm
|
181
|
+
#parameters:
|
182
|
+
#zpid The Zillow Property ID for the property for which to obtain information; the parameter type is an integer
|
183
|
+
#count The number of comparable recent sales to obtain
|
184
|
+
# Examples:
|
185
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
186
|
+
# result = rillow.get_comps('48749425',5)
|
187
|
+
# result.to_hash
|
188
|
+
|
189
|
+
#The get_deep_search_results finds a property for a specified address
|
190
|
+
#(or, if no exact match for a property is found, a list of closely matching properties is returned).
|
191
|
+
#The result set returned contains the full address(s), zpid and Zestimate data that is provided by the get_search_results API.
|
192
|
+
#Moreover, this API call also gives rich property data like lot size, year built, bath/beds, last sale details etc.
|
193
|
+
#see: http://www.zillow.com/howto/api/GetDeepSearchResults.htm
|
194
|
+
# parameter:
|
195
|
+
# address street address
|
196
|
+
# citystatezip city&state or zip code
|
197
|
+
#Example:
|
198
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
199
|
+
# result = rillow.get_deep_search_results('2114 Bigelow Ave','Seattle, WA')
|
200
|
+
# result.to_hash
|
201
|
+
|
202
|
+
#The get_deep_comps api returns a list of comparable recent sales for a specified property.
|
203
|
+
#The result set returned contains the address, Zillow property identifier,
|
204
|
+
#and Zestimate for the comparable properties and the principal property for which the comparables are being retrieved.
|
205
|
+
#This API call also returns rich property data for the comparables.
|
206
|
+
#see: http://www.zillow.com/howto/api/GetDeepComps.htm
|
207
|
+
#parameters:
|
208
|
+
#zpid The Zillow Property ID for the property for which to obtain information; the parameter type is an integer
|
209
|
+
#count The number of comparable recent sales to obtain
|
210
|
+
# Examples:
|
211
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
212
|
+
# result = rillow.get_deep_comps('48749425',5)
|
213
|
+
# result.to_hash
|
214
|
+
|
215
|
+
# Get monthly mortgage payments.
|
216
|
+
# price is required.
|
217
|
+
# optional parameters:
|
218
|
+
# :down => down payment, as an integer, representing the percent. If ommitted, 20% is assumed.
|
219
|
+
# :dollarsdown => down payment in dollars
|
220
|
+
# :zip => location of property, used to calculate tax and insurance estimate, if known.
|
221
|
+
# see: http://www.zillow.com/howto/api/GetMonthlyPayments.htm
|
222
|
+
# Example:
|
223
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
224
|
+
# result = rillow.get_monthlypayments(350000, {:down => 15, :zip => '33432'})
|
225
|
+
# result.to_hash
|
226
|
+
|
227
|
+
# Get current mortgage rates.
|
228
|
+
# No params.
|
229
|
+
# see: http://www.zillow.com/howto/api/GetRateSummary.htm
|
230
|
+
# Example:
|
231
|
+
# rillow = Rillow.new('your-zillow-service identifier')
|
232
|
+
# result = rillow.get_ratesummary
|
233
|
+
# result.to_hash
|
234
|
+
|
235
|
+
private
|
236
|
+
def fetch_from_zillow(method,options)
|
237
|
+
options = options[0] if options.kind_of? Array
|
238
|
+
options.merge!({'zws-id', zwsid})
|
239
|
+
fetch_result [webservice_url, method, '.htm?', to_arguments(options)].join
|
240
|
+
end
|
241
|
+
|
242
|
+
def to_arguments(options)
|
243
|
+
options.map {|k,v| "#{clean_param_key(k)}=#{CGI.escape(v.to_s)}" }.join("&")
|
244
|
+
end
|
245
|
+
|
246
|
+
def clean_param_key(param_key)
|
247
|
+
return 'chartDuration' if param_key == :chart_duration
|
248
|
+
param_key.to_s.gsub('_','-')
|
249
|
+
end
|
250
|
+
|
251
|
+
def fetch_result(url_s)
|
252
|
+
url = URI.parse(url_s)
|
253
|
+
res = Net::HTTP.get_response(url)
|
254
|
+
doc = XmlSimple.xml_in res.body
|
255
|
+
class<<doc
|
256
|
+
include RillowHelper
|
257
|
+
end
|
258
|
+
return doc
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
class GeoPack
|
2
|
+
module RillowHelper
|
3
|
+
# The find_attribute helper method is to provide a easy eay to find a attribute within the hash and array
|
4
|
+
# Examples:
|
5
|
+
# rillow = Rillow.new ('your-zillow-service identifier')
|
6
|
+
# result = rillow.get_search_results('2114 Bigelow Ave','Seattle, WA')
|
7
|
+
# valuationRange = result.find_attribute 'valuationRange'
|
8
|
+
def find_attribute(key,obj=nil)
|
9
|
+
if obj==nil then
|
10
|
+
obj=self
|
11
|
+
end
|
12
|
+
if obj.is_a? Hash then
|
13
|
+
obj.each { |k,v|
|
14
|
+
if k==key then
|
15
|
+
return v
|
16
|
+
else
|
17
|
+
result = find_attribute(key,v)
|
18
|
+
if result != nil then
|
19
|
+
return result
|
20
|
+
end
|
21
|
+
end
|
22
|
+
}
|
23
|
+
elsif obj.is_a? Array then
|
24
|
+
obj.each {|o|
|
25
|
+
result = find_attribute(key,o)
|
26
|
+
if result != nil then
|
27
|
+
return result
|
28
|
+
end
|
29
|
+
}
|
30
|
+
end
|
31
|
+
return nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
#urbanmapping rest api
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'httparty'
|
5
|
+
require 'digest/md5'
|
6
|
+
|
7
|
+
class GeoPack
|
8
|
+
class UrbanMapping
|
9
|
+
include HTTParty
|
10
|
+
format :json
|
11
|
+
|
12
|
+
URBAN_MAPPING_API = {
|
13
|
+
'getNeighborhoodsByLatLng' => [:lat, :lng],
|
14
|
+
'getNearestNeighborhood' => [:lat, :lng],
|
15
|
+
'getNeighborhoodsByExtent' => [:swlat, :swlng, :nelat, :nelng],
|
16
|
+
'getNeighborhoodsByAddress'=> [:street, :city, :state, :country],
|
17
|
+
'getNeighborhoodsByCityStateCountry' => [:city, :state, :country],
|
18
|
+
'getNeighborhoodsByPostalCode' => [:postalcode],
|
19
|
+
'getNeighborhoodsByName' => [:name],
|
20
|
+
'getNeighborhoodDetail' => [:neighborhoodId],
|
21
|
+
'getNeighborhoodRelationships' => [:neighborhoodId]
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(apikey, secret)
|
25
|
+
@apikey = apikey
|
26
|
+
@secret = secret
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(method, *args)
|
30
|
+
if URBAN_MAPPING_API.has_key?( method )
|
31
|
+
query(method, *args)
|
32
|
+
else
|
33
|
+
super
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.query(options= {})
|
38
|
+
um = self.new(options[:apikey])
|
39
|
+
return um.query(options)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def query(options={})
|
44
|
+
check_requirements(options)
|
45
|
+
|
46
|
+
method = options.delete(:method)
|
47
|
+
options.merge!({:apikey => @apikey})
|
48
|
+
options.merge!({:sig => generate_sig})
|
49
|
+
|
50
|
+
UrbanMapping.get("http://api1.urbanmapping.com/neighborhoods/rest/" + method, :query => options)
|
51
|
+
end
|
52
|
+
|
53
|
+
#so we can use prettier options than urbanmapping provides
|
54
|
+
def munge_key_names(options={})
|
55
|
+
options_mapping = {
|
56
|
+
:latitude => :lat,
|
57
|
+
:longitude => :lng,
|
58
|
+
:long => :lng,
|
59
|
+
:zip => :postalcode,
|
60
|
+
:zipcode => :postalcode,
|
61
|
+
:neighborhood_id => :neighborhoodId}
|
62
|
+
|
63
|
+
options.map do |key,value|
|
64
|
+
if options_mapping.has_key? key
|
65
|
+
options[options_mapping[key]] = options.delete key
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
return options
|
70
|
+
end
|
71
|
+
|
72
|
+
def check_requirements(options)
|
73
|
+
raise( 'apikey required for urbanmapping' ) if @apikey.nil?
|
74
|
+
raise( 'method required for urbanmapping' ) if options[:method].nil?
|
75
|
+
raise( "method #{options[:method]} urbanmapping" ) unless URBAN_MAPPING_API.has_key?( options[:method] )
|
76
|
+
#missing_params = []
|
77
|
+
#URBAN_MAPPING_API[options[:method]].each {|param| missing_params<<param unless options.has_key?(param) }
|
78
|
+
#raise( "#{options[:method]} requires #{missing_params.join(", ")} parameters" ) unless missing_params.empty?
|
79
|
+
end
|
80
|
+
|
81
|
+
def generate_sig
|
82
|
+
md5_input_string = @apikey + @secret + Time.now.to_i.to_s
|
83
|
+
d = Digest::MD5.new
|
84
|
+
|
85
|
+
return d.hexdigest(md5_input_string)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'geo_pack/rillow'
|
2
|
+
|
3
|
+
class GeoPack
|
4
|
+
class Zillower
|
5
|
+
def initialize(zwsid)
|
6
|
+
@zwsid = zwsid
|
7
|
+
end
|
8
|
+
|
9
|
+
def lookup_address(options)
|
10
|
+
rillow = Rillow.new(@zwsid)
|
11
|
+
@base_result = rillow.get_property_details options
|
12
|
+
@message = @base_result['message'].first['text'].first
|
13
|
+
zpid = @base_result.find_attribute('zpid')
|
14
|
+
@updated_result = rillow.get_updated_property_details({:zpid => zpid}) if zpid
|
15
|
+
result = {
|
16
|
+
:message => @message,
|
17
|
+
:error => failure?,
|
18
|
+
:data => {}
|
19
|
+
}
|
20
|
+
|
21
|
+
unless result[:error]
|
22
|
+
{
|
23
|
+
:rooms => get_zillow_rooms,
|
24
|
+
:year_built => get_zillow_year,
|
25
|
+
:housing_type => get_zillow_housing_type,
|
26
|
+
:square_footage => get_zillow_square_footage
|
27
|
+
}.inject(result[:data]){|h, (k,v)| h[k] = v if v; h }
|
28
|
+
end
|
29
|
+
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
def failure?
|
35
|
+
!!(@message =~ /error/i)
|
36
|
+
end
|
37
|
+
|
38
|
+
def get_zillow_rooms
|
39
|
+
rooms = @updated_result.find_attribute('numRooms') || @base_result.find_attribute('numRooms')
|
40
|
+
rooms.first if rooms.kind_of? Array
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_zillow_square_footage
|
44
|
+
finishedSqFt = @updated_result.find_attribute('finishedSqFt') || @base_result.find_attribute('finishedSqFt')
|
45
|
+
finishedSqFt.first if finishedSqFt.kind_of? Array
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_zillow_year
|
49
|
+
year_built = @updated_result.find_attribute('yearBuilt') || @base_result.find_attribute('yearBuilt')
|
50
|
+
year_built = year_built.first if year_built.kind_of? Array
|
51
|
+
|
52
|
+
#remember to remove this once the methods from the block comment below is moved to the client
|
53
|
+
map_year_to_range(year_built)
|
54
|
+
end
|
55
|
+
|
56
|
+
####################
|
57
|
+
# This should be moved to the geo_pack client
|
58
|
+
def home_year_built
|
59
|
+
[
|
60
|
+
['before 1940', 1920],
|
61
|
+
['1940 to 1949', 1945],
|
62
|
+
['1950 to 1959', 1955],
|
63
|
+
['1960 to 1969', 1965],
|
64
|
+
['1970 to 1979', 1975],
|
65
|
+
['1980 to 1984', 1982],
|
66
|
+
['1985 to 1989', 1987],
|
67
|
+
['1990 to 1994', 1992],
|
68
|
+
['1995 to 1999', 1997],
|
69
|
+
['2000 or newer', 2002]
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
def map_year_to_range(year_built)
|
74
|
+
option_year_built = nil
|
75
|
+
if year_built
|
76
|
+
home_year_built.each do |option, value|
|
77
|
+
option.match(/^(\d{4}) (to|or) (\d*)/)
|
78
|
+
end_date = $3.to_i == 0 ? 2100 : $3.to_i
|
79
|
+
if ($1.to_i..end_date).include? year_built.to_i
|
80
|
+
option_year_built = value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
if option_year_built.nil?
|
84
|
+
option_year_built = year_built
|
85
|
+
end
|
86
|
+
end
|
87
|
+
option_year_built
|
88
|
+
end
|
89
|
+
##################################
|
90
|
+
|
91
|
+
def get_zillow_housing_type
|
92
|
+
unit_type = @updated_result.find_attribute('useCode') || @base_result.find_attribute('useCode')
|
93
|
+
case unit_type.first
|
94
|
+
when 'Single family' : 'house'
|
95
|
+
when 'SingleFamily' : 'house'
|
96
|
+
when 'Unknown' : nil
|
97
|
+
when 'Duplex' : 'small_apartment'
|
98
|
+
when 'Triplex' : 'small_apartment'
|
99
|
+
when 'Quadruplex' : 'small_apartment'
|
100
|
+
when 'Condominium' : nil
|
101
|
+
when 'Cooperative' : nil
|
102
|
+
when 'Mobile' : 'mobile'
|
103
|
+
when 'MultiFamily2To4' : 'small_apartment'
|
104
|
+
when 'MultiFamily5Plus' : 'large_apartment'
|
105
|
+
when 'Timeshare' : nil
|
106
|
+
when 'Miscellaneous' : nil
|
107
|
+
when 'VacantResidentialLand' : nil
|
108
|
+
end if unit_type.kind_of? Array
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
#This is not stubbed on purpose, this are integration tests. We want it to break when any api is updated
|
4
|
+
class TestGeoPack < Test::Unit::TestCase
|
5
|
+
context "GeoPack" do
|
6
|
+
setup do
|
7
|
+
@geo_pack = GeoPack.new("#{File.dirname(__FILE__)}/test_config.yml")
|
8
|
+
end
|
9
|
+
|
10
|
+
should "get a complete location from a user provided address" do
|
11
|
+
location = @geo_pack.get_location("2114 bigelow Avenue , seattle")
|
12
|
+
assert_equal({
|
13
|
+
:state => { :name => "WA"},
|
14
|
+
:city => { :name => "Seattle"},
|
15
|
+
:neighborhood => { :name=>"Queen Anne", :geom=>[[47.617989, -122.378464], [47.656792, -122.34182]]},
|
16
|
+
:address => { :name => "2114 Bigelow Ave N, Seattle, WA 98109, USA", :geom => [47.637936, -122.34813]}
|
17
|
+
}, location)
|
18
|
+
end
|
19
|
+
|
20
|
+
should "get an empty location from an invalid address" do
|
21
|
+
location = @geo_pack.get_location("Foruncotolundo")
|
22
|
+
assert_equal({}, location)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "be possible to exclude neighborhood search" do
|
26
|
+
location = @geo_pack.get_location("2114 bigelow Avenue , seattle", :exclude => :neighborhood)
|
27
|
+
assert_equal({
|
28
|
+
:state => { :name => "WA"},
|
29
|
+
:city => { :name => "Seattle"},
|
30
|
+
:address => { :name => "2114 Bigelow Ave N, Seattle, WA 98109, USA", :geom => [47.637936, -122.34813]}
|
31
|
+
}, location)
|
32
|
+
end
|
33
|
+
|
34
|
+
should "fallback to geo_names when urbanmapping fails finding a neighborhood" do
|
35
|
+
location = @geo_pack.get_location("Aetna Road and Cottage Creek Road")
|
36
|
+
assert_equal({
|
37
|
+
:state=>{:name=>"KS"},
|
38
|
+
:city=>{:name=>"Lake City"},
|
39
|
+
:neighborhood=> {:name=>"Aetna", :geom=>[[37.064449, -98.975754], [37.08263, -98.952972]]},
|
40
|
+
:address=> {:name=>"Aetna Rd & Cottage Creek Rd, Lake City, KS 67071, USA", :geom=>[37.0858864, -98.964822]}
|
41
|
+
}, location)
|
42
|
+
end
|
43
|
+
|
44
|
+
should "return zillow data from existent address" do
|
45
|
+
zillow_response = @geo_pack.get_property_details("2114 Bigelow, seattle, wA")
|
46
|
+
assert_equal({
|
47
|
+
:housing_type => "house",
|
48
|
+
:square_footage => "3470",
|
49
|
+
:year_built => 1920
|
50
|
+
}, zillow_response[:data])
|
51
|
+
assert !zillow_response[:error]
|
52
|
+
end
|
53
|
+
|
54
|
+
should "return zillow error from a non existent address" do
|
55
|
+
zillow_response = @geo_pack.get_property_details("asfsafdadsf ")
|
56
|
+
assert zillow_response[:error]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
metadata
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geo_pack
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Efficiency 2.0
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-02-28 00:00:00 -02:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: geokit
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 1
|
29
|
+
- 5
|
30
|
+
- 0
|
31
|
+
version: 1.5.0
|
32
|
+
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: geoplanet
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - "="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
segments:
|
42
|
+
- 0
|
43
|
+
- 2
|
44
|
+
- 3
|
45
|
+
version: 0.2.3
|
46
|
+
type: :runtime
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: thoughtbot-shoulda
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
segments:
|
56
|
+
- 0
|
57
|
+
version: "0"
|
58
|
+
type: :development
|
59
|
+
version_requirements: *id003
|
60
|
+
description: Geo related services"
|
61
|
+
email:
|
62
|
+
executables: []
|
63
|
+
|
64
|
+
extensions: []
|
65
|
+
|
66
|
+
extra_rdoc_files:
|
67
|
+
- README.md
|
68
|
+
files:
|
69
|
+
- .document
|
70
|
+
- .gitignore
|
71
|
+
- README.md
|
72
|
+
- Rakefile
|
73
|
+
- VERSION
|
74
|
+
- lib/geo_pack.rb
|
75
|
+
- lib/geo_pack/geo_names.rb
|
76
|
+
- lib/geo_pack/rillow.rb
|
77
|
+
- lib/geo_pack/rillow_helper.rb
|
78
|
+
- lib/geo_pack/urban_mapping.rb
|
79
|
+
- lib/geo_pack/zillower.rb
|
80
|
+
- test/helper.rb
|
81
|
+
- test/test_config.yml
|
82
|
+
- test/test_geo_pack.rb
|
83
|
+
has_rdoc: true
|
84
|
+
homepage: http://github.com/efficiency20/geo_pack
|
85
|
+
licenses: []
|
86
|
+
|
87
|
+
post_install_message:
|
88
|
+
rdoc_options:
|
89
|
+
- --charset=UTF-8
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
segments:
|
104
|
+
- 0
|
105
|
+
version: "0"
|
106
|
+
requirements: []
|
107
|
+
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 1.3.6
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Geo related services"
|
113
|
+
test_files:
|
114
|
+
- test/helper.rb
|
115
|
+
- test/test_geo_pack.rb
|