From 9a524bca16a8a90ae8fd25fd13a869c5ed9eed1c Mon Sep 17 00:00:00 2001 From: Alex Reisner <alex@alexreisner.com> Date: Mon, 7 Mar 2011 00:13:41 -0500 Subject: [PATCH] Deprecate auto-saving feature of fetch_x methods. Add geocode and reverse_geocode methods along with bang versions which can be used to skip auto-assignment of address or coordinates (specify a block that handles the Geocoder::Result instead). --- lib/geocoder/orms/active_record.rb | 40 ++++++--------- lib/geocoder/orms/active_record_legacy.rb | 58 +++++++++++++++++++++ lib/geocoder/orms/base.rb | 61 +++++++++++++++++++---- lib/geocoder/railtie.rb | 16 +++--- test/geocoder_test.rb | 37 +++++++++----- 5 files changed, 158 insertions(+), 54 deletions(-) create mode 100644 lib/geocoder/orms/active_record_legacy.rb diff --git a/lib/geocoder/orms/active_record.rb b/lib/geocoder/orms/active_record.rb index 90e54067..8eda3c25 100644 --- a/lib/geocoder/orms/active_record.rb +++ b/lib/geocoder/orms/active_record.rb @@ -1,4 +1,5 @@ require 'geocoder/orms/base' +require 'geocoder/orms/active_record_legacy' ## # Add geocoding functionality to any ActiveRecord object. @@ -6,6 +7,7 @@ require 'geocoder/orms/base' module Geocoder::Orm module ActiveRecord include Base + include ActiveRecord::Legacy ## # Implementation of 'included' hook method. @@ -145,46 +147,34 @@ module Geocoder::Orm end ## - # Fetch coordinates and assign +latitude+ and +longitude+. Also returns - # coordinates as an array: <tt>[lat, lon]</tt>. + # Look up coordinates and assign to +latitude+ and +longitude+ attributes + # (or other as specified in +geocoded_by+). Returns coordinates (array). # - def fetch_coordinates(save = false) - geocode do |o,r| + def geocode + geocode! do |o,r| unless r.latitude.nil? or r.longitude.nil? - method = (save ? "update" : "write") + "_attribute" - o.send method, self.class.geocoder_options[:latitude], r.latitude - o.send method, self.class.geocoder_options[:longitude], r.longitude + o.send :write_attribute, self.class.geocoder_options[:latitude], r.latitude + o.send :write_attribute, self.class.geocoder_options[:longitude], r.longitude end r.coordinates end end - ## - # Fetch coordinates and update (save) +latitude+ and +longitude+ data. - # - def fetch_coordinates! - fetch_coordinates(true) - end + #alias_method :fetch_coordinates, :geocode ## - # Fetch address and assign +address+ attribute. Also returns - # address as a string. + # Look up address and assign to +address+ attribute (or other as specified + # in +reverse_geocoded_by+). Returns address (string). # - def fetch_address(save = false) - geocode do |o,r| + def reverse_geocode + reverse_geocode! do |o,r| unless r.address.nil? - method = (save ? "update" : "write") + "_attribute" - o.send method, self.class.geocoder_options[:fetched_address], r.address + o.send :write_attribute, self.class.geocoder_options[:fetched_address], r.address end r.address end end - ## - # Fetch address and update (save) +address+ data. - # - def fetch_address! - fetch_address(true) - end + #alias_method :fetch_address, :reverse_geocode end end diff --git a/lib/geocoder/orms/active_record_legacy.rb b/lib/geocoder/orms/active_record_legacy.rb new file mode 100644 index 00000000..225e2c44 --- /dev/null +++ b/lib/geocoder/orms/active_record_legacy.rb @@ -0,0 +1,58 @@ +module Geocoder::Orm::ActiveRecord + module Legacy + + ## + # Fetch coordinates and update (save) +latitude+ and +longitude+ data. + # + def fetch_coordinates! + warn "DEPRECATION WARNING: The 'fetch_coordinates!' method is deprecated and will be removed in geocoder v1.0. " + + "Please use 'geocode' instead and then save your objects manually." + geocode! do |o,r| + unless r.latitude.nil? or r.longitude.nil? + o.send :update_attribute, self.class.geocoder_options[:latitude], r.latitude + o.send :update_attribute, self.class.geocoder_options[:longitude], r.longitude + end + r.coordinates + end + end + + def fetch_coordinates(*args) + warn "DEPRECATION WARNING: The 'fetch_coordinates' method will cease taking " + + "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0 + geocode! do |o,r| + unless r.latitude.nil? or r.longitude.nil? + method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute" + o.send method, self.class.geocoder_options[:latitude], r.latitude + o.send method, self.class.geocoder_options[:longitude], r.longitude + end + r.coordinates + end + end + + ## + # Fetch address and update (save) +address+ data. + # + def fetch_address! + warn "DEPRECATION WARNING: The 'fetch_address!' method is deprecated and will be removed in geocoder v1.0. " + + "Please use 'reverse_geocode' instead and then save your objects manually." + reverse_geocode! do |o,r| + unless r.address.nil? + o.send :update_attribute, self.class.geocoder_options[:fetched_address], r.address + end + r.address + end + end + + def fetch_address(*args) + warn "DEPRECATION WARNING: The 'fetch_address' method will cease taking " + + "an argument in geocoder v1.0. Please save your objects manually." if args.size > 0 + reverse_geocode! do |o,r| + unless r.latitude.nil? or r.longitude.nil? + method = ((args.size > 0 && args.first) ? "update" : "write" ) + "_attribute" + o.send method, self.class.geocoder_options[:fetched_address], r.address + end + r.coordinates + end + end + end +end diff --git a/lib/geocoder/orms/base.rb b/lib/geocoder/orms/base.rb index b2db781d..bb321eff 100644 --- a/lib/geocoder/orms/base.rb +++ b/lib/geocoder/orms/base.rb @@ -32,6 +32,41 @@ module Geocoder self.class.near(read_coordinates, radius, options) end + ## + # Look up coordinates and assign to +latitude+ and +longitude+ attributes + # (or other as specified in +geocoded_by+). Returns coordinates (array). + # + def geocode + fail + end + + ## + # Look up address and assign to +address+ attribute (or other as specified + # in +reverse_geocoded_by+). Returns address (string). + # + def reverse_geocode + fail + end + + ## + # Look up coordinates and execute block, if given. Block should take two + # arguments: the object and a Geocoder::Result object. + # + def geocode!(&block) + do_lookup(false, &block) + end + + ## + # Look up address and execute block, if given. Block should take two + # arguments: the object and a Geocoder::Result object. + # + def reverse_geocode!(&block) + do_lookup(true, &block) + end + + + private # -------------------------------------------------------------- + ## # Look up geographic data based on object attributes (configured in # geocoded_by or reverse_geocoded_by) and handle the result with the @@ -39,25 +74,31 @@ module Geocoder # given two-arguments: the object being geocoded and a # Geocoder::Result object with the geocoding results). # - def geocode + def do_lookup(reverse = false) options = self.class.geocoder_options - args = options[:user_address] ? - [:user_address] : [:latitude, :longitude] + if reverse and options[:reverse_geocode] + args = [:latitude, :longitude] + elsif !reverse and options[:geocode] + args = [:user_address] + else + return + end args.map!{ |a| send(options[a]) } - # passing a block to this method overrides the one given in the model if result = Geocoder.search(*args) + # first execute block passed directly to this method if block_given? - yield(self, result) - else - self.class.geocoder_options[:block].call(self, result) + value = yield(self, result) + end + # then execute block specified in configuration + block_key = reverse ? :reverse_block : :geocode_block + if custom_block = options[block_key] + value = custom_block.call(self, result) end + value end end - - private # -------------------------------------------------------------- - ## # Read the coordinates [lat,lon] of the object. # Looks at user config to determine attributes. diff --git a/lib/geocoder/railtie.rb b/lib/geocoder/railtie.rb index 1e2eeef2..4745c245 100644 --- a/lib/geocoder/railtie.rb +++ b/lib/geocoder/railtie.rb @@ -32,10 +32,11 @@ module Geocoder # def geocoded_by(address_attr, options = {}, &block) geocoder_init( - :user_address => address_attr, - :latitude => options[:latitude] || :latitude, - :longitude => options[:longitude] || :longitude, - :block => block + :geocode => true, + :user_address => address_attr, + :latitude => options[:latitude] || :latitude, + :longitude => options[:longitude] || :longitude, + :geocode_block => block ) end @@ -44,10 +45,11 @@ module Geocoder # def reverse_geocoded_by(latitude_attr, longitude_attr, options = {}, &block) geocoder_init( + :reverse_geocode => true, :fetched_address => options[:address] || :address, - :latitude => latitude_attr, - :longitude => longitude_attr, - :block => block + :latitude => latitude_attr, + :longitude => longitude_attr, + :reverse_block => block ) end diff --git a/test/geocoder_test.rb b/test/geocoder_test.rb index 01cbf011..b951ac8a 100644 --- a/test/geocoder_test.rb +++ b/test/geocoder_test.rb @@ -23,7 +23,7 @@ class GeocoderTest < Test::Unit::TestCase def test_does_not_choke_on_nil_address v = Venue.new("Venue", nil) assert_nothing_raised do - v.fetch_coordinates + v.geocode end end @@ -42,42 +42,55 @@ class GeocoderTest < Test::Unit::TestCase # --- general --- - def test_fetch_coordinates_assigns_and_returns_coordinates + def test_geocode_assigns_and_returns_coordinates v = Venue.new(*venue_params(:msg)) coords = [40.750354, -73.993371] - assert_equal coords, v.fetch_coordinates + assert_equal coords, v.geocode assert_equal coords, [v.latitude, v.longitude] end - def test_fetch_address_assigns_and_returns_address + def test_reverse_geocode_assigns_and_returns_address v = Landmark.new(*landmark_params(:msg)) address = "4 Penn Plaza, New York, NY 10001, USA" - assert_equal address, v.fetch_address + assert_equal address, v.reverse_geocode assert_equal address, v.address end - def test_geocode_fetches_and_assigns_custom_coordinates + def test_geocode_bang_fetches_and_assigns_custom_coordinates e = Event.new(*venue_params(:msg)) coords = [40.750354, -73.993371] - e.geocode + e.geocode! assert_equal coords.map{ |c| c.to_s }.join(','), e.coordinates end - def test_geocode_fetches_and_assigns_custom_address_components + def test_geocode_bang_doesnt_auto_assign_coordinates + e = Event.new(*venue_params(:msg)) + e.geocode! + assert_nil e.latitude + assert_nil e.longitude + end + + def test_reverse_geocode_bang_fetches_and_assigns_custom_address_components e = Party.new(*landmark_params(:msg)) - e.geocode + e.reverse_geocode! assert_equal "US", e.country end - def test_fetch_forward_and_reverse_geocoding_on_same_model + def test_reverse_geocode_bang_doesnt_auto_assign_address + e = Party.new(*landmark_params(:msg)) + e.reverse_geocode! + assert_nil e.address + end + + def test_forward_and_reverse_geocoding_on_same_model g = GasStation.new("Exxon") g.address = "404 New St, Middletown, CT" - g.fetch_coordinates + g.geocode assert_not_nil g.lat assert_not_nil g.lon assert_nil g.location - g.fetch_address + g.reverse_geocode assert_not_nil g.location end -- GitLab