diff --git a/lib/twitter.rb b/lib/twitter.rb index 819077158..218f602ce 100644 --- a/lib/twitter.rb +++ b/lib/twitter.rb @@ -165,3 +165,4 @@ def rubyify_keys! require File.join(directory, "twitter", "base") require File.join(directory, "twitter", "search") require File.join(directory, "twitter", "trends") +require File.join(directory, "twitter", "geo") diff --git a/lib/twitter/geo.rb b/lib/twitter/geo.rb new file mode 100644 index 000000000..b8aab99d7 --- /dev/null +++ b/lib/twitter/geo.rb @@ -0,0 +1,25 @@ +module Twitter + class Geo + include HTTParty + base_uri "api.twitter.com/#{API_VERSION}/geo" + format :json + + def self.place(place_id, query={}) + Twitter.mash(get("/id/#{place_id}.json", :query => query)) + end + + def self.search(query={}) + mashup(get("/search.json", :query => query)) + end + + def self.reverse_geocode(query={}) + mashup(get("/reverse_geocode.json", :query => query)) + end + + private + + def self.mashup(response) + response["result"].values.flatten.map{|t| Twitter.mash(t)} + end + end +end diff --git a/test/fixtures/geo_place.json b/test/fixtures/geo_place.json new file mode 100644 index 000000000..989e0d70e --- /dev/null +++ b/test/fixtures/geo_place.json @@ -0,0 +1 @@ +{"country":"The United States of America","place_type":"neighborhood","country_code":"US","attributes":{"162834:id":"53228"},"contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Charlotte, NC","url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","name":"Charlotte","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]},"id":"512a8a4a4c4b4be0"}],"full_name":"Ballantyne West, Charlotte","url":"http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json","name":"Ballantyne West","geometry":{"type":"Polygon","coordinates":[[[-80.87219316,35.06571702],[-80.86735404,35.065773],[-80.86841388,35.06246001],[-80.86431816,35.06202],[-80.86356792,35.06029803],[-80.860968,35.061246],[-80.85807792,35.06548203],[-80.84569284,35.06514696],[-80.85025296,35.05508298],[-80.84654712,35.04180096],[-80.83437984,35.03659599],[-80.83440684,35.033346],[-80.83791216,35.03078298],[-80.83847808,35.02645101],[-80.846181,35.02217097],[-80.849034,35.02199196],[-80.85131496,35.01486999],[-80.87055516,35.03680002],[-80.86154508,35.04053502],[-80.87618808,35.05916097],[-80.875818,35.060526],[-80.87025816,35.060931],[-80.869662,35.06253102],[-80.87219316,35.06571702]]]},"polylines":["ww_uEdjrlNIg]tSrEvAqXvIuC}DgOmYaQ`AmlA|}@n[~qAcVn_@akAhSD`OzT`ZpBvYbo@b@xPnk@fMahChwBkViw@ksBnzAqGiAoAwa@_IwB}RxN"],"bounding_box":{"type":"Polygon","coordinates":[[[-80.87618808,35.01486999],[-80.83437984,35.01486999],[-80.83437984,35.065773],[-80.87618808,35.065773]]]},"id":"ea76a36c5bc2bdff"} \ No newline at end of file diff --git a/test/fixtures/geo_reverse_geocode.json b/test/fixtures/geo_reverse_geocode.json new file mode 100644 index 000000000..7e08b814e --- /dev/null +++ b/test/fixtures/geo_reverse_geocode.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"neighborhood","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Charlotte, NC","url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","name":"Charlotte","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]},"id":"512a8a4a4c4b4be0"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json","full_name":"Ballantyne West, Charlotte","name":"Ballantyne West","id":"ea76a36c5bc2bdff","bounding_box":{"type":"Polygon","coordinates":[[[-80.87618808,35.01486999],[-80.83437984,35.01486999],[-80.83437984,35.065773],[-80.87618808,35.065773]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"North Carolina, US","url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","name":"North Carolina","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]},"id":"3b98b02fba3f9753"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","full_name":"Charlotte, NC","name":"Charlotte","id":"512a8a4a4c4b4be0","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]}},{"country":"The United States of America","place_type":"admin","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"country","country_code":"US","attributes":{},"full_name":"The United States of America","url":"http://api.twitter.com/1/geo/id/96683cc9126741d1.json","name":"The United States of America","bounding_box":null,"id":"96683cc9126741d1"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","full_name":"North Carolina, US","name":"North Carolina","id":"3b98b02fba3f9753","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]}},{"country":"The United States of America","place_type":"country","country_code":"US","contained_within":[],"attributes":{},"url":"http://api.twitter.com/1/geo/id/96683cc9126741d1.json","full_name":"The United States of America","name":"The United States of America","id":"96683cc9126741d1","bounding_box":null}]},"query":{"type":"reverse_geocode","url":"http://api.twitter.com/1/geo/reverse_geocode.json?granularity=neighborhood&accuracy=0&long=-80.854568&lat=35.061161","params":{"granularity":"neighborhood","accuracy":0,"coordinates":{"type":"Point","coordinates":[-80.854568,35.061161]}}}} \ No newline at end of file diff --git a/test/fixtures/geo_reverse_geocode_granularity.json b/test/fixtures/geo_reverse_geocode_granularity.json new file mode 100644 index 000000000..639c8d374 --- /dev/null +++ b/test/fixtures/geo_reverse_geocode_granularity.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"North Carolina, US","url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","name":"North Carolina","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]},"id":"3b98b02fba3f9753"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","full_name":"Charlotte, NC","name":"Charlotte","id":"512a8a4a4c4b4be0","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]}},{"country":"The United States of America","place_type":"admin","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"country","country_code":"US","attributes":{},"full_name":"The United States of America","url":"http://api.twitter.com/1/geo/id/96683cc9126741d1.json","name":"The United States of America","bounding_box":null,"id":"96683cc9126741d1"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","full_name":"North Carolina, US","name":"North Carolina","id":"3b98b02fba3f9753","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]}},{"country":"The United States of America","place_type":"country","country_code":"US","contained_within":[],"attributes":{},"url":"http://api.twitter.com/1/geo/id/96683cc9126741d1.json","full_name":"The United States of America","name":"The United States of America","id":"96683cc9126741d1","bounding_box":null}]},"query":{"type":"reverse_geocode","url":"http://api.twitter.com/1/geo/reverse_geocode.json?granularity=city&accuracy=0&long=-80.854568&lat=35.061161","params":{"granularity":"city","accuracy":0,"coordinates":{"type":"Point","coordinates":[-80.854568,35.061161]}}}} \ No newline at end of file diff --git a/test/fixtures/geo_reverse_geocode_limit.json b/test/fixtures/geo_reverse_geocode_limit.json new file mode 100644 index 000000000..6da0f4ced --- /dev/null +++ b/test/fixtures/geo_reverse_geocode_limit.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"neighborhood","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Charlotte, NC","url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","name":"Charlotte","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]},"id":"512a8a4a4c4b4be0"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json","full_name":"Ballantyne West, Charlotte","name":"Ballantyne West","id":"ea76a36c5bc2bdff","bounding_box":{"type":"Polygon","coordinates":[[[-80.87618808,35.01486999],[-80.83437984,35.01486999],[-80.83437984,35.065773],[-80.87618808,35.065773]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"North Carolina, US","url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","name":"North Carolina","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]},"id":"3b98b02fba3f9753"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","full_name":"Charlotte, NC","name":"Charlotte","id":"512a8a4a4c4b4be0","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]}}]},"query":{"type":"reverse_geocode","url":"http://api.twitter.com/1/geo/reverse_geocode.json?granularity=neighborhood&accuracy=0&long=-80.854568&lat=35.061161","params":{"granularity":"neighborhood","accuracy":0,"coordinates":{"type":"Point","coordinates":[-80.854568,35.061161]}}}} \ No newline at end of file diff --git a/test/fixtures/geo_search.json b/test/fixtures/geo_search.json new file mode 100644 index 000000000..c3cc0c2ba --- /dev/null +++ b/test/fixtures/geo_search.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"neighborhood","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Charlotte, NC","url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","name":"Charlotte","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]},"id":"512a8a4a4c4b4be0"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json","full_name":"Ballantyne West, Charlotte","name":"Ballantyne West","id":"ea76a36c5bc2bdff","bounding_box":{"type":"Polygon","coordinates":[[[-80.87618808,35.01486999],[-80.83437984,35.01486999],[-80.83437984,35.065773],[-80.87618808,35.065773]]]}},{"country":"The United States of America","place_type":"neighborhood","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Charlotte, NC","url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","name":"Charlotte","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]},"id":"512a8a4a4c4b4be0"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/0f2ebc6cdab74561.json","full_name":"Whiteoak, Charlotte","name":"Whiteoak","id":"0f2ebc6cdab74561","bounding_box":{"type":"Polygon","coordinates":[[[-80.85807792,35.06373603],[-80.82110592,35.06373603],[-80.82110592,35.07697602],[-80.85807792,35.07697602]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"North Carolina, US","url":"http://api.twitter.com/1/geo/id/3b98b02fba3f9753.json","name":"North Carolina","bounding_box":{"type":"Polygon","coordinates":[[[-84.321869,33.752878],[-75.400119,33.752878],[-75.400119,36.588157],[-84.321869,36.588157]]]},"id":"3b98b02fba3f9753"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/512a8a4a4c4b4be0.json","full_name":"Charlotte, NC","name":"Charlotte","id":"512a8a4a4c4b4be0","bounding_box":{"type":"Polygon","coordinates":[[[-81.001923,35.021524],[-80.670104,35.021524],[-80.670104,35.385542],[-81.001923,35.385542]]]}}]},"query":{"type":"search","url":"http://api.twitter.com/1/geo/search.json?granularity=neighborhood&accuracy=0&query=&long=-80.854568&autocomplete=false&lat=35.061161","params":{"granularity":"neighborhood","query":"","accuracy":0,"coordinates":{"type":"Point","coordinates":[-80.854568,35.061161]},"autocomplete":false}}} \ No newline at end of file diff --git a/test/fixtures/geo_search_ip_address.json b/test/fixtures/geo_search_ip_address.json new file mode 100644 index 000000000..fac54c4c2 --- /dev/null +++ b/test/fixtures/geo_search_ip_address.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"California, US","url":"http://api.twitter.com/1/geo/id/fbd6d2f5a4e4a15e.json","name":"California","bounding_box":{"type":"Polygon","coordinates":[[[-124.482003,32.528832],[-114.131211,32.528832],[-114.131211,42.009517],[-124.482003,42.009517]]]},"id":"fbd6d2f5a4e4a15e"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/b19a2cc5134b7e0a.json","full_name":"Mountain View, CA","name":"Mountain View","id":"b19a2cc5134b7e0a","bounding_box":{"type":"Polygon","coordinates":[[[-122.117852,37.35676],[-122.044473,37.35676],[-122.044473,37.469887],[-122.117852,37.469887]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"California, US","url":"http://api.twitter.com/1/geo/id/fbd6d2f5a4e4a15e.json","name":"California","bounding_box":{"type":"Polygon","coordinates":[[[-124.482003,32.528832],[-114.131211,32.528832],[-114.131211,42.009517],[-124.482003,42.009517]]]},"id":"fbd6d2f5a4e4a15e"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/45cadd6ef118ec9f.json","full_name":"Sunnyvale, CA","name":"Sunnyvale","id":"45cadd6ef118ec9f","bounding_box":{"type":"Polygon","coordinates":[[[-122.065265,37.329895],[-121.98242,37.329895],[-121.98242,37.464087],[-122.065265,37.464087]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"California, US","url":"http://api.twitter.com/1/geo/id/fbd6d2f5a4e4a15e.json","name":"California","bounding_box":{"type":"Polygon","coordinates":[[[-124.482003,32.528832],[-114.131211,32.528832],[-114.131211,42.009517],[-124.482003,42.009517]]]},"id":"fbd6d2f5a4e4a15e"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/7d62cffe6f98f349.json","full_name":"San Jose, CA","name":"San Jose","id":"7d62cffe6f98f349","bounding_box":{"type":"Polygon","coordinates":[[[-122.045572,37.124503],[-121.589153,37.124503],[-121.589153,37.469163],[-122.045572,37.469163]]]}},{"country":"The United States of America","place_type":"city","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"admin","country_code":"US","attributes":{},"full_name":"California, US","url":"http://api.twitter.com/1/geo/id/fbd6d2f5a4e4a15e.json","name":"California","bounding_box":{"type":"Polygon","coordinates":[[[-124.482003,32.528832],[-114.131211,32.528832],[-114.131211,42.009517],[-124.482003,42.009517]]]},"id":"fbd6d2f5a4e4a15e"}],"attributes":{},"url":"http://api.twitter.com/1/geo/id/30344aecffe6a491.json","full_name":"Fremont, CA","name":"Fremont","id":"30344aecffe6a491","bounding_box":{"type":"Polygon","coordinates":[[[-122.149175,37.454389],[-121.867979,37.454389],[-121.867979,37.604624],[-122.149175,37.604624]]]}}]},"query":{"type":"search","url":"http://api.twitter.com/1/geo/search.json?granularity=neighborhood&accuracy=0&query=&ip=74.125.19.104&autocomplete=false","params":{"granularity":"neighborhood","query":"","accuracy":0,"ip":"74.125.19.104","autocomplete":false}}} \ No newline at end of file diff --git a/test/fixtures/geo_search_query.json b/test/fixtures/geo_search_query.json new file mode 100644 index 000000000..ec3aa4c44 --- /dev/null +++ b/test/fixtures/geo_search_query.json @@ -0,0 +1 @@ +{"result":{"places":[{"country":"The United States of America","place_type":"poi","country_code":"US","contained_within":[{"country":"The United States of America","place_type":"city","country_code":"US","attributes":{},"full_name":"Princeton, NJ","url":"http://api.twitter.com/1/geo/id/c833fbabba6fe48e.json","name":"Princeton","bounding_box":{"type":"Polygon","coordinates":[[[-74.681254,40.337932],[-74.63659,40.337932],[-74.63659,40.361323],[-74.681254,40.361323]]]},"id":"c833fbabba6fe48e"}],"attributes":{"street_address":"20 S Tulane St"},"url":"http://api.twitter.com/1/geo/id/64b54dbe6b9fb828.json","full_name":"Princeton Record Exchange, Princeton","name":"Princeton Record Exchange","id":"64b54dbe6b9fb828","bounding_box":{"type":"Polygon","coordinates":[[[-74.658733,40.351105],[-74.658733,40.351105],[-74.658733,40.351105],[-74.658733,40.351105]]]}}]},"query":{"type":"search","url":"http://api.twitter.com/1/geo/search.json?granularity=neighborhood&accuracy=0&query=princeton+record+exchange&autocomplete=false","params":{"granularity":"neighborhood","query":"princeton record exchange","accuracy":0,"autocomplete":false}}} \ No newline at end of file diff --git a/test/twitter/geo_test.rb b/test/twitter/geo_test.rb new file mode 100644 index 000000000..53426234a --- /dev/null +++ b/test/twitter/geo_test.rb @@ -0,0 +1,79 @@ +require 'test_helper' + +class GeoTest < Test::Unit::TestCase + include Twitter + + context "Geographic place lookup" do + + should "work" do + stub_get 'http://api.twitter.com/1/geo/id/ea76a36c5bc2bdff.json', 'geo_place.json' + place = Geo.place('ea76a36c5bc2bdff') + place.country.should == 'The United States of America' + place.full_name.should == 'Ballantyne West, Charlotte' + place.geometry.coordinates.should be_kind_of(Array) + end + + end + + context "Geographic search" do + + should "work" do + stub_get 'http://api.twitter.com:80/1/geo/search.json?lat=35.061161&long=-80.854568', 'geo_search.json' + places = Geo.search(:lat => 35.061161, :long => -80.854568) + places.size.should == 3 + places[0].full_name.should eql('Ballantyne West, Charlotte') + places[0].name.should eql('Ballantyne West') + end + + should "be able to search with free form text" do + stub_get 'http://api.twitter.com/1/geo/search.json?query=princeton%20record%20exchange', 'geo_search_query.json' + places = Geo.search(:query => 'princeton record exchange') + places.size.should == 1 + places[0].name.should eql('Princeton Record Exchange') + places[0].place_type.should eql('poi') + places[0].attributes.street_address.should eql('20 S Tulane St') + end + + should "be able to search by ip address" do + stub_get 'http://api.twitter.com/1/geo/search.json?ip=74.125.19.104', 'geo_search_ip_address.json' + places = Geo.search(:ip => '74.125.19.104') + places.size.should == 4 + places[0].full_name.should eql("Mountain View, CA") + places[0].name.should eql("Mountain View") + places[1].full_name.should eql("Sunnyvale, CA") + places[1].name.should eql('Sunnyvale') + end + + end + + context "Geographic reverse_geocode" do + + should "work" do + stub_get 'http://api.twitter.com:80/1/geo/reverse_geocode.json?lat=35.061161&long=-80.854568', 'geo_reverse_geocode.json' + places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568) + places.size.should == 4 + places[0].full_name.should eql('Ballantyne West, Charlotte') + places[0].name.should eql('Ballantyne West') + end + + should "be able to limit the number of results returned" do + stub_get 'http://api.twitter.com/1/geo/reverse_geocode.json?lat=35.061161&max_results=2&long=-80.854568', 'geo_reverse_geocode_limit.json' + places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568, :max_results => 2) + places.size.should == 2 + places[0].full_name.should eql('Ballantyne West, Charlotte') + places[0].name.should eql('Ballantyne West') + end + + should "be able to lookup with granularity" do + stub_get 'http://api.twitter.com/1/geo/reverse_geocode.json?lat=35.061161&long=-80.854568&granularity=city', 'geo_reverse_geocode_granularity.json' + places = Geo.reverse_geocode(:lat => 35.061161, :long => -80.854568, :granularity => 'city') + places.size.should == 3 + places[0].full_name.should eql('Charlotte, NC') + places[0].name.should eql('Charlotte') + places[1].full_name.should eql('North Carolina, US') + places[1].name.should eql('North Carolina') + end + + end + +end