geo_pack 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|