sniff 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. data/README.markdown +5 -1
  2. data/lib/sniff.rb +4 -14
  3. data/lib/sniff/database.rb +20 -57
  4. data/lib/sniff/emitter.rb +12 -5
  5. data/spec/lib/sniff/database_spec.rb +8 -9
  6. metadata +56 -119
  7. data/lib/sniff/active_record_ext.rb +0 -12
  8. data/lib/sniff/conversions_ext.rb +0 -45
  9. data/lib/test_support/data_models/census_division.rb +0 -9
  10. data/lib/test_support/data_models/census_region.rb +0 -9
  11. data/lib/test_support/data_models/climate_division.rb +0 -8
  12. data/lib/test_support/data_models/country.rb +0 -9
  13. data/lib/test_support/data_models/egrid_region.rb +0 -7
  14. data/lib/test_support/data_models/egrid_subregion.rb +0 -8
  15. data/lib/test_support/data_models/gender.rb +0 -6
  16. data/lib/test_support/data_models/petroleum_administration_for_defense_district.rb +0 -9
  17. data/lib/test_support/data_models/state.rb +0 -13
  18. data/lib/test_support/data_models/urbanity.rb +0 -6
  19. data/lib/test_support/data_models/zip_code.rb +0 -14
  20. data/lib/test_support/db/fixtures/yearly_anonymous_emissions.csv +0 -0
  21. data/lib/test_support/db/fixtures/yearly_typical_emissions.csv +0 -0
  22. data/lib/test_support/db/schema.rb +0 -117
  23. data/spec/spec.opts +0 -2
  24. data/vendor/geokit-rails/CHANGELOG.rdoc +0 -46
  25. data/vendor/geokit-rails/MIT-LICENSE +0 -20
  26. data/vendor/geokit-rails/README.markdown +0 -561
  27. data/vendor/geokit-rails/Rakefile +0 -18
  28. data/vendor/geokit-rails/about.yml +0 -9
  29. data/vendor/geokit-rails/assets/api_keys_template +0 -61
  30. data/vendor/geokit-rails/init.rb +0 -1
  31. data/vendor/geokit-rails/install.rb +0 -14
  32. data/vendor/geokit-rails/lib/geokit-rails.rb +0 -24
  33. data/vendor/geokit-rails/lib/geokit-rails/acts_as_mappable.rb +0 -456
  34. data/vendor/geokit-rails/lib/geokit-rails/adapters/abstract.rb +0 -31
  35. data/vendor/geokit-rails/lib/geokit-rails/adapters/mysql.rb +0 -22
  36. data/vendor/geokit-rails/lib/geokit-rails/adapters/postgresql.rb +0 -22
  37. data/vendor/geokit-rails/lib/geokit-rails/adapters/sqlserver.rb +0 -43
  38. data/vendor/geokit-rails/lib/geokit-rails/defaults.rb +0 -22
  39. data/vendor/geokit-rails/lib/geokit-rails/geocoder_control.rb +0 -16
  40. data/vendor/geokit-rails/lib/geokit-rails/ip_geocode_lookup.rb +0 -46
  41. data/vendor/geokit-rails/test/acts_as_mappable_test.rb +0 -474
  42. data/vendor/geokit-rails/test/boot.rb +0 -25
  43. data/vendor/geokit-rails/test/database.yml +0 -20
  44. data/vendor/geokit-rails/test/fixtures/companies.yml +0 -7
  45. data/vendor/geokit-rails/test/fixtures/custom_locations.yml +0 -54
  46. data/vendor/geokit-rails/test/fixtures/locations.yml +0 -54
  47. data/vendor/geokit-rails/test/fixtures/mock_addresses.yml +0 -17
  48. data/vendor/geokit-rails/test/fixtures/mock_families.yml +0 -2
  49. data/vendor/geokit-rails/test/fixtures/mock_houses.yml +0 -9
  50. data/vendor/geokit-rails/test/fixtures/mock_organizations.yml +0 -5
  51. data/vendor/geokit-rails/test/fixtures/mock_people.yml +0 -5
  52. data/vendor/geokit-rails/test/fixtures/stores.yml +0 -0
  53. data/vendor/geokit-rails/test/ip_geocode_lookup_test.rb +0 -77
  54. data/vendor/geokit-rails/test/models/company.rb +0 -3
  55. data/vendor/geokit-rails/test/models/custom_location.rb +0 -12
  56. data/vendor/geokit-rails/test/models/location.rb +0 -4
  57. data/vendor/geokit-rails/test/models/mock_address.rb +0 -4
  58. data/vendor/geokit-rails/test/models/mock_family.rb +0 -3
  59. data/vendor/geokit-rails/test/models/mock_house.rb +0 -3
  60. data/vendor/geokit-rails/test/models/mock_organization.rb +0 -4
  61. data/vendor/geokit-rails/test/models/mock_person.rb +0 -4
  62. data/vendor/geokit-rails/test/models/store.rb +0 -3
  63. data/vendor/geokit-rails/test/schema.rb +0 -60
  64. data/vendor/geokit-rails/test/tasks.rake +0 -31
  65. data/vendor/geokit-rails/test/test_helper.rb +0 -23
@@ -1,12 +0,0 @@
1
- require 'active_record'
2
- require 'common_name'
3
- require 'falls_back_on'
4
-
5
- ActiveRecord::Base.class_eval do
6
- extend FallsBackOn
7
-
8
- def self._common_name
9
- name.underscore
10
- end
11
- include CommonName
12
- end
@@ -1,45 +0,0 @@
1
- require 'conversions'
2
- Conversions.register(:miles, :nautical_miles, 0.868976242)
3
- Conversions.register(:kilometres, :nautical_miles, 0.539956803)
4
- Conversions.register(:pounds_per_gallon, :kilograms_per_litre, 0.119826427)
5
- Conversions.register(:inches, :meters, 0.0254)
6
- Conversions.register(:kilowatt_hours, :watt_hours, 1_000.0)
7
- Conversions.register(:kilowatt_hours, :btus, 3_412.14163) # obsolete?
8
- Conversions.register(:watt_hours, :btus, 3.4121414799) # obsolete?
9
- Conversions.register(:watt_hours, :joules, 3_600.0)
10
- Conversions.register(:kilowatt_hours, :joules, 3_600_000.0)
11
-
12
- # Conversions.register(:btus, :gallons_of_kerosene, 0.000007419521097)
13
- Conversions.register(:joules, :litres_of_kerosene, 1.0 / (135_000.0 * 3.78541178 * 1_055.05585)) # should only be used for RECS 2005
14
-
15
- # Conversions.register(:btus, :gallons_of_propane, 0.000010471204188)
16
- Conversions.register(:joules, :litres_of_propane, 1.0 / (91_333.0 * 3.78541178 * 1_055.05585)) # should only be used for RECS 2005
17
-
18
- # Conversions.register(:btus, :therms, 0.000010002388121)
19
- Conversions.register(:therms, :joules, 105_505_585.0) # should only be used for RECS 2005
20
-
21
- # Conversions.register(:btus, :gallons_of_fuel_oil, 0.0000072007637183)
22
- Conversions.register(:joules, :litres_of_fuel_oil, 1.0 / (138_690.0 * 3.78541178 * 1_055.05585)) # should only be used for RECS 2005
23
-
24
- # Conversions.register(:tons_of_coal, :btus, 20_169_000.0)
25
- Conversions.register(:joules, :kilograms_of_coal, 1.0 / (22_342_000.0 * 0.00110231131 * 1_055.05585)) # should only be used for RECS 2005
26
-
27
- Conversions.register(:kilograms, :lbs, 2.20462262)
28
- Conversions.register(:kbtus, :btus, 1_000.0)
29
- Conversions.register(:square_feet, :square_metres, 0.09290304)
30
- Conversions.register(:pounds_per_square_foot, :kilograms_per_square_metre, 4.88242764)
31
- Conversions.register(:kilograms_per_kilowatt_hour, :kilograms_per_megawatt_hour, 1_000.0)
32
- Conversions.register(:btus, :joules, 1_055.05585)
33
- Conversions.register(:kbtus, :joules, 1_000.0 * 1_055.05585)
34
- Conversions.register(:cords, :joules, 2.11011171e10)
35
-
36
- Conversions.register(:gallons_per_mile, :litres_per_kilometre, 2.35214583)
37
- Conversions.register(:pounds_per_mile, :kilograms_per_kilometre, 0.281849232)
38
- Conversions.register(:dollars, :cents, 100)
39
- Conversions.register(:cubic_feet, :cubic_metres, 0.0283168466)
40
- # 1 (kilocalories per pound) = 9 224.14105 joules per kilogram
41
- Conversions.register :kilocalories_per_pound, :joules_per_kilogram, 9_224.14105
42
- # 1 (grams per kilocalories) = 2.39005736 × 10-7 kilograms per joules
43
- Conversions.register :grams_per_kilocalorie, :kilograms_per_joule, 2.39005736e-7
44
- # 1 joule = 0.000239005736 kilocalories
45
- Conversions.register :joules, :kilocalories, 0.000239005736
@@ -1,9 +0,0 @@
1
- class CensusDivision < ActiveRecord::Base
2
- set_primary_key :number
3
-
4
- belongs_to :census_region, :foreign_key => 'census_region_number'
5
- has_many :states, :foreign_key => 'census_division_number'
6
- has_many :zip_codes, :through => :states
7
- has_many :climate_divisions, :through => :states
8
- has_many :residential_energy_consumption_survey_responses, :foreign_key => 'census_division_number'
9
- end
@@ -1,9 +0,0 @@
1
- class CensusRegion < ActiveRecord::Base
2
- set_primary_key :number
3
-
4
- has_many :census_divisions, :foreign_key => 'census_region_number'
5
- has_many :states, :through => :census_divisions
6
- # has_many :climate_divisions, :through => :census_divisions
7
- # has_many :zip_codes, :through => :census_divisions
8
- has_many :residential_energy_consumption_survey_responses, :foreign_key => 'census_region_number'
9
- end
@@ -1,8 +0,0 @@
1
- class ClimateDivision < ActiveRecord::Base
2
- set_primary_key :name
3
-
4
- has_many :zip_codes, :foreign_key => 'climate_division_name'
5
- belongs_to :state, :foreign_key => 'state_postal_abbreviation'
6
-
7
- RADIUS = 750
8
- end
@@ -1,9 +0,0 @@
1
- class Country < ActiveRecord::Base
2
- set_primary_key :iso_3166_code
3
-
4
- class << self
5
- def united_states
6
- find_by_iso_3166_code('US')
7
- end
8
- end
9
- end
@@ -1,7 +0,0 @@
1
- class EgridRegion < ActiveRecord::Base
2
- set_primary_key :name
3
-
4
- has_many :egrid_subregions, :foreign_key => 'egrid_region_name'
5
-
6
- falls_back_on :loss_factor => 0.061311 # Ian
7
- end
@@ -1,8 +0,0 @@
1
- class EgridSubregion < ActiveRecord::Base
2
- set_primary_key :abbreviation
3
-
4
- has_many :zip_codes, :foreign_key => 'egrid_subregion_abbreviation'
5
- belongs_to :egrid_region, :foreign_key => 'egrid_region_name'
6
-
7
- falls_back_on :electricity_emission_factor => 1.404.pounds.to(:kilograms) # kg CO2 / kWh https://brighterplanet.sifterapp.com/projects/30/issues/437?return_uri=%2Fprojects%2F30%2Fissues%3Fa%3D79%26s%3D1-2
8
- end
@@ -1,6 +0,0 @@
1
- class Gender < ActiveRecord::Base
2
- set_primary_key :name
3
-
4
- has_many :pets
5
- has_many :breed_genders, :foreign_key => 'gender_name'
6
- end
@@ -1,9 +0,0 @@
1
- class PetroleumAdministrationForDefenseDistrict < ActiveRecord::Base
2
- set_primary_key :code
3
-
4
- def name
5
- str = "PAD District #{district_code} (#{district_name})"
6
- str << " Subdistrict #{district_code}#{subdistrict_code} (#{subdistrict_name})" if subdistrict_code
7
- str
8
- end
9
- end
@@ -1,13 +0,0 @@
1
- class State < ActiveRecord::Base
2
- set_primary_key :postal_abbreviation
3
-
4
- has_many :climate_divisions, :foreign_key => 'state_postal_abbreviation'
5
- has_many :zip_codes, :foreign_key => 'state_postal_abbreviation'
6
- belongs_to :census_division, :foreign_key => 'census_division_number'
7
- belongs_to :petroleum_administration_for_defense_district, :foreign_key => 'petroleum_administration_for_defense_district_code'
8
- has_one :census_region, :through => :census_division
9
-
10
- def country
11
- Country.united_states
12
- end
13
- end
@@ -1,6 +0,0 @@
1
- class Urbanity < ActiveRecord::Base
2
- set_primary_key :name
3
-
4
- has_many :residences
5
- has_many :residential_energy_consumption_survey_responses
6
- end
@@ -1,14 +0,0 @@
1
- class ZipCode < ActiveRecord::Base
2
- set_primary_key :name
3
-
4
- belongs_to :egrid_subregion, :foreign_key => 'egrid_subregion_abbreviation'
5
- belongs_to :climate_division, :foreign_key => 'climate_division_name'
6
- belongs_to :state, :foreign_key => 'state_postal_abbreviation'
7
- # has_one :census_division, :through => :state
8
- # has_one :census_region, :through => :state
9
- has_many :residences
10
-
11
- acts_as_mappable :default_units => :miles, # FIXME imperial
12
- :lat_column_name => :latitude,
13
- :lng_column_name => :longitude
14
- end
@@ -1,117 +0,0 @@
1
- require 'sniff/database'
2
-
3
- Sniff::Database.define_schema do
4
- create_table "census_divisions", :primary_key => "number", :id => false, :force => true do |t|
5
- t.string "number"
6
- t.string "name"
7
- t.string "census_region_name"
8
- t.integer "census_region_number"
9
- t.datetime "created_at"
10
- t.datetime "updated_at"
11
- end
12
-
13
- create_table "census_regions", :primary_key => "number", :id => false, :force => true do |t|
14
- t.string "number"
15
- t.string "name"
16
- t.datetime "created_at"
17
- t.datetime "updated_at"
18
- end
19
-
20
- create_table "climate_divisions", :primary_key => "name", :id => false, :force => true do |t|
21
- t.string "name"
22
- t.float "heating_degree_days"
23
- t.float "cooling_degree_days"
24
- t.string "state_postal_abbreviation"
25
- t.datetime "created_at"
26
- t.datetime "updated_at"
27
- end
28
-
29
- create_table "countries", :primary_key => "iso_3166_code", :id => false, :force => true do |t|
30
- t.string "iso_3166_code"
31
- t.string "name"
32
- t.datetime "created_at"
33
- t.datetime "updated_at"
34
- end
35
-
36
- create_table "egrid_regions", :primary_key => "name", :id => false, :force => true do |t|
37
- t.string "name"
38
- t.float "loss_factor"
39
- t.string "loss_factor_units"
40
- t.datetime "updated_at"
41
- t.datetime "created_at"
42
- end
43
-
44
- create_table "egrid_subregions", :primary_key => "abbreviation", :id => false, :force => true do |t|
45
- t.string "abbreviation"
46
- t.string "name"
47
- t.float "electricity_emission_factor"
48
- t.string "electricity_emission_factor_units"
49
- t.string "nerc_abbreviation"
50
- t.string "egrid_region_name"
51
- t.datetime "updated_at"
52
- t.datetime "created_at"
53
- end
54
-
55
- create_table "fallbacks", :force => true do |t|
56
- t.string "name"
57
- t.text "values"
58
- t.datetime "created_at"
59
- t.datetime "updated_at"
60
- end
61
-
62
- create_table "genders", :primary_key => "name", :id => false, :force => true do |t|
63
- t.string "name"
64
- t.datetime "created_at"
65
- t.datetime "updated_at"
66
- end
67
-
68
- create_table "petroleum_administration_for_defense_districts", :primary_key => "code", :id => false, :force => true do |t|
69
- t.string "code"
70
- t.string "district_code"
71
- t.string "district_name"
72
- t.string "subdistrict_code"
73
- t.string "subdistrict_name"
74
- t.datetime "updated_at"
75
- t.datetime "created_at"
76
- end
77
-
78
- create_table "states", :primary_key => "postal_abbreviation", :id => false, :force => true do |t|
79
- t.string "postal_abbreviation"
80
- t.integer "fips_code"
81
- t.string "name"
82
- t.string "census_division_number"
83
- t.string "petroleum_administration_for_defense_district_code"
84
- t.datetime "updated_at"
85
- t.datetime "created_at"
86
- end
87
-
88
- create_table "urbanities", :primary_key => "name", :id => false, :force => true do |t|
89
- t.string "name"
90
- t.datetime "created_at"
91
- t.datetime "updated_at"
92
- end
93
-
94
- create_table "yearly_anonymous_emissions", :force => true do |t|
95
- t.string "component"
96
- t.integer "year"
97
- t.float "emission"
98
- end
99
-
100
- create_table "yearly_typical_emissions", :force => true do |t|
101
- t.string "component"
102
- t.integer "year"
103
- t.float "emission"
104
- end
105
-
106
- create_table "zip_codes", :primary_key => "name", :id => false, :force => true do |t|
107
- t.string "name"
108
- t.string "state_postal_abbreviation"
109
- t.string "description"
110
- t.string "latitude"
111
- t.string "longitude"
112
- t.string "egrid_subregion_abbreviation"
113
- t.string "climate_division_name"
114
- t.datetime "created_at"
115
- t.datetime "updated_at"
116
- end
117
- end
data/spec/spec.opts DELETED
@@ -1,2 +0,0 @@
1
- --colour
2
- --format progress
@@ -1,46 +0,0 @@
1
- == 2009-10-02 / Version 1.2.0
2
- * Overhaul the test suite to be independent of a Rails project
3
- * Added concept of database adapter. Ported mysql/postgresql conditional code to their own adapter.
4
- * Added SQL Server support. THANKS http://github.com/brennandunn for all the improvements in this release
5
-
6
- == 2009-09-26 / Version 1.1.3
7
- * documentation updates and updated to work with Geokit gem v1.5.0
8
- * IMPORTANT: in the Geokit gem, Geokit::Geocoders::timeout became Geokit::Geocoders::request_timeout for jruby compatibility.
9
- The plugin sets this in config/initializers/geokit_config.rb. So if you've upgraded the gem to 1.5.0, you need to
10
- make the change manually from Geokit::Geocoders::timeout to Geokit::Geocoders::request_timeout in config/initializers/geokit_config.rb
11
-
12
- == 2009-06-08 / Version 1.1.2
13
- * Added support for hashes in :through. So you can do: acts_as_mappable :through => { :state => :country } (Thanks José Valim).
14
-
15
- == 2009-05-22 / Version 1.1.1
16
- * Support for multiple ip geocoders (Thanks dreamcat4)
17
- * Now checks if either :origin OR :bounds is passed, and proceeds with geokit query if this is true (Thanks Glenn Powell)
18
- * Raises a helpful error if someone uses through but the association does not exists or was not defined yet (Thanks José Valim)
19
-
20
- == 2009-04-11 / Version 1.1.0
21
- * Fixed :through usages so that the through model is only included in the query if there
22
- is an :origin passed in (Only if it is a geokit search) (Thanks Glenn Powell)
23
- * Move library initialisation into lib/geokit-rails. init.rb uses lib/geokit-rails now (thanks Alban Peignier)
24
- * Handle the case where a user passes a hash to the :conditions Finder option (thanks Adam Greene)
25
- * Added ability to specify domain-specific API keys (Thanks Glenn Powell)
26
-
27
- == 2009-02-20
28
- * More powerful assosciations in the Rails Plugin:You can now specify a model as mappable "through" an associated model.
29
- In other words, that associated model is the actual mappable model with "lat" and "lng" attributes, but this "through" model
30
- can still utilize all Geokit's "find by distance" finders. Also Rails 2.3 compatibility (thanks github/glennpow)
31
-
32
- == 2008-12-18
33
- * Split Rails plugin from geocoder gem
34
- * updated for Rails 2.2.2
35
-
36
- == 2008-08-20
37
- * Further fix of distance calculation, this time in SQL. Now uses least() function, which is available in MySQL version 3.22.5+ and postgres versions 8.1+
38
-
39
- == 2008-01-16
40
- * fixed the "zero-distance" bug (calculating between two points that are the same)
41
-
42
- == 2007-11-12
43
- * fixed a small but with queries crossing meridian, and also fixed find(:closest)
44
-
45
- == 2007-10-11
46
- * Fixed Rails2/Edge compatability
@@ -1,20 +0,0 @@
1
- Copyright (c) 2007 Bill Eisenhauer & Andre Lewis
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,561 +0,0 @@
1
- ## INSTALLATION
2
-
3
- Geokit consists of a Gem ([geokit-gem](http://github.com/andre/geokit-gem/tree/master)) and a Rails plugin ([geokit-rails](http://github.com/andre/geokit-rails/tree/master)).
4
-
5
- #### 1. Install the Rails plugin:
6
-
7
- cd [YOUR_RAILS_APP_ROOT]
8
- script/plugin install git://github.com/andre/geokit-rails.git
9
-
10
- #### 2. Add this line to your environment.rb
11
- (inside the Rails::Initializer.run do |config| block)
12
-
13
- config.gem "geokit"
14
-
15
- This informs Rails of the gem dependency.
16
-
17
- #### 3. Tell Rails to install the gem:
18
-
19
- rake gems:install
20
-
21
- And you're good to go! If you're running an older verion of Rails, just install the gem manually: `sudo gem install rails`
22
-
23
- ## FEATURE SUMMARY
24
-
25
- Geokit provides key functionality for location-oriented Rails applications:
26
-
27
- - Distance calculations, for both flat and spherical environments. For example,
28
- given the location of two points on the earth, you can calculate the miles/KM
29
- between them.
30
- - ActiveRecord distance-based finders. For example, you can find all the points
31
- in your database within a 50-mile radius.
32
- - IP-based location lookup utilizing hostip.info. Provide an IP address, and get
33
- city name and latitude/longitude in return
34
- - A before_filter helper to geocoder the user's location based on IP address,
35
- and retain the location in a cookie.
36
- - Geocoding from multiple providers. It provides a fail-over mechanism, in case
37
- your input fails to geocode in one service. Geocoding is provided buy the Geokit
38
- gem, which you must have installed
39
-
40
- The goal of this plugin is to provide the common functionality for location-oriented
41
- applications (geocoding, location lookup, distance calculation) in an easy-to-use
42
- package.
43
-
44
- ## A NOTE ON TERMINOLOGY
45
-
46
- Throughout the code and API, latitude and longitude are referred to as lat
47
- and lng. We've found over the long term the abbreviation saves lots of typing time.
48
-
49
- ## LOCATION QUERIES
50
-
51
- To get started, just specify an ActiveRecord class as `acts_as_mappale`:
52
-
53
- class Location < ActiveRecord::Base
54
- acts_as_mappable
55
- end
56
-
57
- There are some defaults you can override:
58
-
59
- class Location < ActiveRecord::Base
60
- acts_as_mappable :default_units => :miles,
61
- :default_formula => :sphere,
62
- :distance_field_name => :distance,
63
- :lat_column_name => :lat,
64
- :lng_column_name => :lng
65
- end
66
-
67
-
68
- The optional parameters are :units, :formula, and distance_field_name.
69
- Values for :units can be :miles, :kms (kilometers), or :nms (nautical miles),
70
- with :miles as the default. Values for :formula can be :sphere or :flat with
71
- :sphere as the default. :sphere gives you Haversine calculations, while :flat
72
- gives the Pythagoreum Theory. These defaults persist through out the plug-in.
73
-
74
- The plug-in creates a calculated `distance` field on AR instances that have
75
- been retrieved throw a Geokit location query. By default, these fields are
76
- known as "distance" but this can be changed through the `:distance_field_name` key.
77
-
78
- You can also define alternative column names for latitude and longitude using
79
- the `:lat_column_name` and `:lng_column_name` keys. The defaults are 'lat' and
80
- 'lng' respectively.
81
-
82
- Once you've specified acts_as_mappable, a set of distance-based
83
- finder methods are available:
84
-
85
- Origin as a two-element array of latititude/longitude:
86
-
87
- find(:all, :origin => [37.792,-122.393])
88
-
89
- Origin as a geocodeable string:
90
-
91
- find(:all, :origin => '100 Spear st, San Francisco, CA')
92
-
93
- Origin as an object which responds to lat and lng methods,
94
- or latitude and longitude methods, or whatever methods you have
95
- specified for `lng_column_name` and `lat_column_name`:
96
-
97
- find(:all, :origin=>my_store) # my_store.lat and my_store.lng methods exist
98
-
99
- Often you will need to find within a certain distance. The prefered syntax is:
100
-
101
- find(:all, :origin => @somewhere, :within => 5)
102
-
103
- . . . however these syntaxes will also work:
104
-
105
- find_within(5, :origin => @somewhere)
106
- find(:all, :origin => @somewhere, :conditions => "distance < 5")
107
-
108
- Note however that the third form should be avoided. With either of the first two,
109
- Geokit automatically adds a bounding box to speed up the radial query in the database.
110
- With the third form, it does not.
111
-
112
- If you need to combine distance conditions with other conditions, you should do
113
- so like this:
114
-
115
- find(:all, :origin => @somewhere, :within => 5, :conditions=>['state=?',state])
116
-
117
- If :origin is not provided in the finder call, the find method
118
- works as normal. Further, the key is removed
119
- from the :options hash prior to invoking the superclass behavior.
120
-
121
- Other convenience methods work intuitively and are as follows:
122
-
123
- find_within(distance, :origin => @somewhere)
124
- find_beyond(distance, :origin => @somewhere)
125
- find_closest(:origin => @somewhere)
126
- find_farthest(:origin => @somewhere)
127
-
128
- where the options respect the defaults, but can be overridden if
129
- desired.
130
-
131
- Lastly, if all that is desired is the raw SQL for distance
132
- calculations, you can use the following:
133
-
134
- distance_sql(origin, units=default_units, formula=default_formula)
135
-
136
- Thereafter, you are free to use it in find_by_sql as you wish.
137
-
138
- There are methods available to enable you to get the count based upon
139
- the find condition that you have provided. These all work similarly to
140
- the finders. So for instance:
141
-
142
- count(:origin, :conditions => "distance < 5")
143
- count_within(distance, :origin => @somewhere)
144
- count_beyond(distance, :origin => @somewhere)
145
-
146
- ## FINDING WITHIN A BOUNDING BOX
147
-
148
- If you are displaying points on a map, you probably need to query for whatever falls within the rectangular bounds of the map:
149
-
150
- Store.find :all, :bounds=>[sw_point,ne_point]
151
-
152
- The input to :bounds can be array with the two points or a Bounds object. However you provide them, the order should always be the southwest corner, northeast corner of the rectangle. Typically, you will be getting the sw_point and ne_point from a map that is displayed on a web page.
153
-
154
- If you need to calculate the bounding box from a point and radius, you can do that:
155
-
156
- bounds=Bounds.from_point_and_radius(home,5)
157
- Store.find :all, :bounds=>bounds
158
-
159
- ## USING INCLUDES
160
-
161
- You can use includes along with your distance finders:
162
-
163
- stores=Store.find :all, :origin=>home, :include=>[:reviews,:cities] :within=>5, :order=>'distance'
164
-
165
- *However*, ActiveRecord drops the calculated distance column when you use include. So, if you need to
166
- use the distance column, you'll have to re-calculate it post-query in Ruby:
167
-
168
- stores.sort_by_distance_from(home)
169
-
170
- In this case, you may want to just use the bounding box
171
- condition alone in your SQL (there's no use calculating the distance twice):
172
-
173
- bounds=Bounds.from_point_and_radius(home,5)
174
- stores=Store.find :all, :include=>[:reviews,:cities] :bounds=>bounds
175
- stores.sort_by_distance_from(home)
176
-
177
- ## USING :through
178
-
179
- You can also specify a model as mappable "through" another associated model.
180
- In other words, that associated model is the actual mappable model with
181
- "lat" and "lng" attributes, but this "through" model can still utilize
182
- all of the above find methods to search for records.
183
-
184
- class Location < ActiveRecord::Base
185
- belongs_to :locatable, :polymorphic => true
186
- acts_as_mappable
187
- end
188
-
189
- class Company < ActiveRecord::Base
190
- has_one :location, :as => :locatable # also works for belongs_to associations
191
- acts_as_mappable :through => :location
192
- end
193
-
194
- Then you can still call:
195
-
196
- Company.find_within(distance, :origin => @somewhere)
197
-
198
- You can also give :through a hash if you location is nested deep. For example, given:
199
-
200
- class House
201
- acts_as_mappable
202
- end
203
-
204
- class Family
205
- belongs_to :house
206
- end
207
-
208
- class Person
209
- belongs_to :family
210
- acts_as_mappable :through => { :family => :house }
211
- end
212
-
213
- Remember that the notes above about USING INCLUDES apply to the results from
214
- this find, since an include is automatically used.
215
-
216
- ## IP GEOCODING
217
-
218
- You can obtain the location for an IP at any time using the geocoder
219
- as in the following example:
220
-
221
- location = IpGeocoder.geocode('12.215.42.19')
222
-
223
- where Location is a GeoLoc instance containing the latitude,
224
- longitude, city, state, and country code. Also, the success
225
- value is true.
226
-
227
- If the IP cannot be geocoded, a GeoLoc instance is returned with a
228
- success value of false.
229
-
230
- It should be noted that the IP address needs to be visible to the
231
- Rails application. In other words, you need to ensure that the
232
- requesting IP address is forwarded by any front-end servers that
233
- are out in front of the Rails app. Otherwise, the IP will always
234
- be that of the front-end server.
235
-
236
- The Multi-Geocoder will also geocode IP addresses and provide
237
- failover among multiple IP geocoders. Just pass in an IP address for the
238
- parameter instead of a street address. Eg:
239
-
240
- location = Geocoders::MultiGeocoder.geocode('12.215.42.19')
241
-
242
- The MultiGeocoder class requires 2 configuration setting for the provider order.
243
- Ordering is done through `Geokit::Geocoders::provider_order` and
244
- `Geokit::Geocoders::ip_provider_order`, found in
245
- `config/initializers/geokit_config.rb`. If you don't already have a
246
- `geokit_config.rb` file, the plugin creates one when it is first installed.
247
-
248
-
249
- ## IP GEOCODING HELPER
250
-
251
- A class method called geocode_ip_address has been mixed into the
252
- ActionController::Base. This enables before_filter style lookup of
253
- the IP address. Since it is a filter, it can accept any of the
254
- available filter options.
255
-
256
- Usage is as below:
257
-
258
- class LocationAwareController < ActionController::Base
259
- geocode_ip_address
260
- end
261
-
262
- A first-time lookup will result in the GeoLoc class being stored
263
- in the session as `:geo_location` as well as in a cookie called
264
- `:geo_session`. Subsequent lookups will use the session value if it
265
- exists or the cookie value if it doesn't exist. The last resort is
266
- to make a call to the web service. Clients are free to manage the
267
- cookie as they wish.
268
-
269
- The intent of this feature is to be able to provide a good guess as
270
- to a new visitor's location.
271
-
272
- ## INTEGRATED FIND AND GEOCODING
273
-
274
- Geocoding has been integrated with the finders enabling you to pass
275
- a physical address or an IP address. This would look the following:
276
-
277
- Location.find_farthest(:origin => '217.15.10.9')
278
- Location.find_farthest(:origin => 'Irving, TX')
279
-
280
- where the IP or physical address would be geocoded to a location and
281
- then the resulting latitude and longitude coordinates would be used
282
- in the find. This is not expected to be common usage, but it can be
283
- done nevertheless.
284
-
285
- ## ADDRESS GEOCODING
286
-
287
- Geocoding is provided by the Geokit gem, which is required for this plugin.
288
- See the top of this file for instructions on installing the Geokit gem.
289
-
290
- Geokit can geocode addresses using multiple geocodeing web services.
291
- Geokit supports services like Google, Yahoo, and Geocoder.us, and more --
292
- see the Geokit gem API for a complete list.
293
-
294
- These geocoder services are made available through the following classes:
295
- GoogleGeocoder, YahooGeocoder, UsGeocoder, CaGeocoder, and GeonamesGeocoder.
296
- Further, an additional geocoder class called MultiGeocoder incorporates an ordered failover
297
- sequence to increase the probability of successful geocoding.
298
-
299
- All classes are called using the following signature:
300
-
301
- include Geokit::Geocoders
302
- location = XxxGeocoder.geocode(address)
303
-
304
- where you replace Xxx Geocoder with the appropriate class. A GeoLoc
305
- instance is the result of the call. This class has a "success"
306
- attribute which will be true if a successful geocoding occurred.
307
- If successful, the lat and lng properties will be populated.
308
-
309
- Geocoders are named with the convention NameGeocoder. This
310
- naming convention enables Geocoder to auto-detect its sub-classes
311
- in order to create methods called `name_geocoder(address)` so that
312
- all geocoders can be called through the base class. This is done
313
- purely for convenience; the individual geocoder classes are expected
314
- to be used independently.
315
-
316
- The MultiGeocoder class requires the configuration of a provider
317
- order which dictates what order to use the various geocoders. Ordering
318
- is done through `Geokit::Geocoders::provider_order`, found in
319
- `config/initializers/geokit_config.rb`.
320
-
321
- If you don't already have a `geokit_config.rb` file, the plugin creates one
322
- when it is first installed.
323
-
324
- Make sure your failover configuration matches the usage characteristics
325
- of your application -- for example, if you routinely get bogus input to
326
- geocode, your code will be much slower if you have to failover among
327
- multiple geocoders before determining that the input was in fact bogus.
328
-
329
- The Geocoder.geocode method returns a GeoLoc object. Basic usage:
330
-
331
- loc=Geocoder.geocode('100 Spear St, San Francisco, CA')
332
- if loc.success
333
- puts loc.lat
334
- puts loc.lng
335
- puts loc.full_address
336
- end
337
-
338
- ## REVERSE GEOCODING
339
-
340
- Currently, only the Google Geocoder supports reverse geocoding.
341
- Pass the lat/lng as a string, array or LatLng instance:
342
-
343
- res=Geokit::Geocoders::GoogleGeocoder.reverse_geocode "37.791821,-122.394679"
344
- => #<Geokit::GeoLoc:0x558ed0 ...
345
- res.full_address
346
- "101-115 Main St, San Francisco, CA 94105, USA"
347
-
348
- The address will usually appear as a range, as it does in the above example.
349
-
350
-
351
- ## INTEGRATED FIND WITH ADDRESS GEOCODING
352
-
353
- Just has you can pass an IP address directly into an ActiveRecord finder
354
- as the origin, you can also pass a physical address as the origin:
355
-
356
- Location.find_closest(:origin => '100 Spear st, San Francisco, CA')
357
-
358
- where the physical address would be geocoded to a location and then the
359
- resulting latitude and longitude coordinates would be used in the
360
- find.
361
-
362
- Note that if the address fails to geocode, the find method will raise an
363
- ActiveRecord::GeocodeError you must be prepared to catch. Alternatively,
364
- You can geocoder the address beforehand, and pass the resulting lat/lng
365
- into the finder if successful.
366
-
367
- ## Auto Geocoding
368
-
369
- If your geocoding needs are simple, you can tell your model to automatically
370
- geocode itself on create:
371
-
372
- class Store < ActiveRecord::Base
373
- acts_as_mappable :auto_geocode=>true
374
- end
375
-
376
- It takes two optional params:
377
-
378
- class Store < ActiveRecord::Base
379
- acts_as_mappable :auto_geocode=>{:field=>:address, :error_message=>'Could not geocode address'}
380
- end
381
-
382
- . . . which is equivilent to:
383
-
384
- class Store << ActiveRecord::Base
385
- acts_as_mappable
386
- before_validation_on_create :geocode_address
387
-
388
- private
389
- def geocode_address
390
- geo=Geokit::Geocoders::MultiGeocoder.geocode (address)
391
- errors.add(:address, "Could not Geocode address") if !geo.success
392
- self.lat, self.lng = geo.lat,geo.lng if geo.success
393
- end
394
- end
395
-
396
- If you need any more complicated geocoding behavior for your model, you should roll your own
397
- `before_validate` callback.
398
-
399
-
400
- ## Distances, headings, endpoints, and midpoints
401
-
402
- distance=home.distance_from(work, :units=>:miles)
403
- heading=home.heading_to(work) # result is in degrees, 0 is north
404
- endpoint=home.endpoint(90,2) # two miles due east
405
- midpoing=home.midpoint_to(work)
406
-
407
- ## Cool stuff you can do with bounds
408
-
409
- bounds=Bounds.new(sw_point,ne_point)
410
- bounds.contains?(home)
411
- puts bounds.center
412
-
413
-
414
- HOW TO . . .
415
- =================================================================================
416
-
417
- A few quick examples to get you started ....
418
-
419
- ## How to install the Geokit Rails plugin
420
- (See the very top of this file)
421
-
422
- ## How to find all stores within a 10-mile radius of a given lat/lng
423
- 1. ensure your stores table has lat and lng columns with numeric or float
424
- datatypes to store your latitude/longitude
425
-
426
- 3. use `acts_as_mappable` on your store model:
427
-
428
- class Store < ActiveRecord::Base
429
- acts_as_mappable
430
- ...
431
- end
432
-
433
- 3. finders now have extra capabilities:
434
-
435
- Store.find(:all, :origin =>[32.951613,-96.958444], :within=>10)
436
-
437
- ## How to geocode an address
438
-
439
- 1. configure your geocoder key(s) in `config/initializers/geokit_config.rb`
440
-
441
- 2. also in `geokit_config.rb`, make sure that `Geokit::Geocoders::provider_order` reflects the
442
- geocoder(s). If you only want to use one geocoder, there should
443
- be only one symbol in the array. For example:
444
-
445
- Geokit::Geocoders::provider_order=[:google]
446
-
447
- 3. Test it out in script/console
448
-
449
- include Geokit::Geocoders
450
- res = MultiGeocoder.geocode('100 Spear St, San Francisco, CA')
451
- puts res.lat
452
- puts res.lng
453
- puts res.full_address
454
- ... etc. The return type is GeoLoc, see the API for
455
- all the methods you can call on it.
456
-
457
- ## How to find all stores within 10 miles of a given address
458
-
459
- 1. as above, ensure your table has the lat/lng columns, and you've
460
- applied `acts_as_mappable` to the Store model.
461
-
462
- 2. configure and test out your geocoder, as above
463
-
464
- 3. pass the address in under the :origin key
465
-
466
- Store.find(:all, :origin=>'100 Spear st, San Francisco, CA',
467
- :within=>10)
468
-
469
- 4. you can also use a zipcode, or anything else that's geocodable:
470
-
471
- Store.find(:all, :origin=>'94117',
472
- :conditions=>'distance<10')
473
-
474
- ## How to sort a query by distance from an origin
475
-
476
- You now have access to a 'distance' column, and you can use it
477
- as you would any other column. For example:
478
- Store.find(:all, :origin=>'94117', :order=>'distance')
479
-
480
- ## How to elements of an array according to distance from a common point
481
-
482
- Usually, you can do your sorting in the database as part of your find call.
483
- If you need to sort things post-query, you can do so:
484
-
485
- stores=Store.find :all
486
- stores.sort_by_distance_from(home)
487
- puts stores.first.distance
488
-
489
- Obviously, each of the items in the array must have a latitude/longitude so
490
- they can be sorted by distance.
491
-
492
- ## Database indexes
493
-
494
- MySQL can't create indexes on a calculated field such as those Geokit uses to
495
- calculate distance based on latitude/longitude values for a record. However,
496
- indexing the lat and lng columns does improve Geokit distance calculation
497
- performance since the lat and lng columns are used in a straight comparison
498
- for distance calculation. Assuming a Page model that is incorporating the
499
- Geokit plugin the migration would be as follows.
500
-
501
- class AddIndexOPageLatAndLng < ActiveRecord::Migration
502
-
503
- def self.up
504
- add_index :pages, [:lat, :lng]
505
- end
506
-
507
- def self.down
508
- remove_index :pages, [:lat, :lng]
509
- end
510
- end
511
-
512
- ## Database Compatability
513
-
514
- * Geokit works with MySQL (tested with version 5.0.41), PostgreSQL (tested with version 8.2.6) and Microsoft SQL Server (tested with 2000).
515
- * Geokit does *not* work with SQLite, as it lacks the necessary geometry functions.
516
- * Geokit is known to *not* work with Postgres versions under 8.1 -- it uses the least() funciton.
517
-
518
-
519
- ## HIGH-LEVEL NOTES ON WHAT'S WHERE
520
-
521
- `acts_as_mappable.rb`, as you'd expect, contains the ActsAsMappable
522
- module which gets mixed into your models to provide the
523
- location-based finder goodness.
524
-
525
- `ip_geocode_lookup.rb` contains the before_filter helper method which
526
- enables auto lookup of the requesting IP address.
527
-
528
- ### The Geokit gem provides the building blocks of distance-based operations:
529
-
530
- The Mappable module, which provides basic
531
- distance calculation methods, i.e., calculating the distance
532
- between two points.
533
-
534
- The LatLng class is a simple container for latitude and longitude, but
535
- it's made more powerful by mixing in the above-mentioned Mappable
536
- module -- therefore, you can calculate easily the distance between two
537
- LatLng ojbects with `distance = first.distance_to(other)`
538
-
539
- GeoLoc represents an address or location which
540
- has been geocoded. You can get the city, zipcode, street address, etc.
541
- from a GeoLoc object. GeoLoc extends LatLng, so you also get lat/lng
542
- AND the Mappable modeule goodness for free.
543
-
544
- ## GOOGLE GROUP
545
-
546
- Follow the Google Group for updates and discussion on Geokit: http://groups.google.com/group/geokit
547
-
548
- ## IMPORTANT POST-INSTALLATION NOTES:
549
-
550
- *1. The configuration file*: Geokit for Rails uses a configuration file in config/initializers.
551
- You *must* add your own keys for the various geocoding services if you want to use geocoding.
552
- If you need to refer to the original template again, see the `assets/api_keys_template` file.
553
-
554
- *2. The gem dependency*: Geokit for Rails depends on the Geokit gem. Tell Rails about this
555
- dependency in `config/environment.rb`, within the initializer block:
556
- config.gem "geokit"
557
-
558
- *If you're having trouble with dependencies ....*
559
-
560
- Try installing the gem manually (sudo gem install geokit), then adding a `require 'geokit'` to the top of
561
- `vendor/plugins/geokit-rails/init.rb` and/or `config/geokit_config.rb`.