has_distance 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "http://rubygems.org"
2
+ gem 'rails', '>= 3.0.0'
3
+
4
+ group :development do
5
+ gem "rspec", "~> 2.3.0"
6
+ gem "bundler", "~> 1.0.0"
7
+ gem "jeweler", "~> 1.6.4"
8
+ gem "rcov", ">= 0"
9
+ gem 'sqlite3'
10
+ gem 'csv-mapper'
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,99 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ abstract (1.0.0)
5
+ actionmailer (3.0.9)
6
+ actionpack (= 3.0.9)
7
+ mail (~> 2.2.19)
8
+ actionpack (3.0.9)
9
+ activemodel (= 3.0.9)
10
+ activesupport (= 3.0.9)
11
+ builder (~> 2.1.2)
12
+ erubis (~> 2.6.6)
13
+ i18n (~> 0.5.0)
14
+ rack (~> 1.2.1)
15
+ rack-mount (~> 0.6.14)
16
+ rack-test (~> 0.5.7)
17
+ tzinfo (~> 0.3.23)
18
+ activemodel (3.0.9)
19
+ activesupport (= 3.0.9)
20
+ builder (~> 2.1.2)
21
+ i18n (~> 0.5.0)
22
+ activerecord (3.0.9)
23
+ activemodel (= 3.0.9)
24
+ activesupport (= 3.0.9)
25
+ arel (~> 2.0.10)
26
+ tzinfo (~> 0.3.23)
27
+ activeresource (3.0.9)
28
+ activemodel (= 3.0.9)
29
+ activesupport (= 3.0.9)
30
+ activesupport (3.0.9)
31
+ arel (2.0.10)
32
+ builder (2.1.2)
33
+ csv-mapper (0.5.1)
34
+ fastercsv
35
+ diff-lcs (1.1.2)
36
+ erubis (2.6.6)
37
+ abstract (>= 1.0.0)
38
+ fastercsv (1.5.4)
39
+ git (1.2.5)
40
+ i18n (0.5.0)
41
+ jeweler (1.6.4)
42
+ bundler (~> 1.0)
43
+ git (>= 1.2.5)
44
+ rake
45
+ mail (2.2.19)
46
+ activesupport (>= 2.3.6)
47
+ i18n (>= 0.4.0)
48
+ mime-types (~> 1.16)
49
+ treetop (~> 1.4.8)
50
+ mime-types (1.16)
51
+ polyglot (0.3.2)
52
+ rack (1.2.3)
53
+ rack-mount (0.6.14)
54
+ rack (>= 1.0.0)
55
+ rack-test (0.5.7)
56
+ rack (>= 1.0)
57
+ rails (3.0.9)
58
+ actionmailer (= 3.0.9)
59
+ actionpack (= 3.0.9)
60
+ activerecord (= 3.0.9)
61
+ activeresource (= 3.0.9)
62
+ activesupport (= 3.0.9)
63
+ bundler (~> 1.0)
64
+ railties (= 3.0.9)
65
+ railties (3.0.9)
66
+ actionpack (= 3.0.9)
67
+ activesupport (= 3.0.9)
68
+ rake (>= 0.8.7)
69
+ rdoc (~> 3.4)
70
+ thor (~> 0.14.4)
71
+ rake (0.9.2)
72
+ rcov (0.9.9)
73
+ rdoc (3.9.1)
74
+ rspec (2.3.0)
75
+ rspec-core (~> 2.3.0)
76
+ rspec-expectations (~> 2.3.0)
77
+ rspec-mocks (~> 2.3.0)
78
+ rspec-core (2.3.1)
79
+ rspec-expectations (2.3.0)
80
+ diff-lcs (~> 1.1.2)
81
+ rspec-mocks (2.3.0)
82
+ sqlite3 (1.3.4)
83
+ thor (0.14.6)
84
+ treetop (1.4.10)
85
+ polyglot
86
+ polyglot (>= 0.3.1)
87
+ tzinfo (0.3.29)
88
+
89
+ PLATFORMS
90
+ ruby
91
+
92
+ DEPENDENCIES
93
+ bundler (~> 1.0.0)
94
+ csv-mapper
95
+ jeweler (~> 1.6.4)
96
+ rails (>= 3.0.0)
97
+ rcov
98
+ rspec (~> 2.3.0)
99
+ sqlite3
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Fernando Barajas
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.
data/README.rdoc ADDED
@@ -0,0 +1,24 @@
1
+ = has_distance
2
+
3
+ A Ruby gem to add has_distance to your ActiveRecord Model.
4
+ has_distance is used for latitude/longitude distance lookup.
5
+ It also works with SQLite
6
+
7
+ == Usage
8
+
9
+
10
+ == Contributing to has_distance
11
+
12
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
13
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
14
+ * Fork the project
15
+ * Start a feature/bugfix branch
16
+ * Commit and push until you are happy with your contribution
17
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
18
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
19
+
20
+ == Copyright
21
+
22
+ Copyright (c) 2011 Fernando Barajas. See LICENSE.txt for
23
+ further details.
24
+
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "has_distance"
18
+ gem.homepage = "http://github.com/fernyb/has_distance"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Adds has_distance to ActiveRecord}
21
+ gem.description = %Q{Used to find nearby records via latitude/longitude}
22
+ gem.email = "fernyb@fernyb.net"
23
+ gem.authors = ["Fernando Barajas"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+ require 'rspec/core'
29
+ require 'rspec/core/rake_task'
30
+ RSpec::Core::RakeTask.new(:spec) do |spec|
31
+ spec.pattern = FileList['spec/**/*_spec.rb']
32
+ end
33
+
34
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
35
+ spec.pattern = 'spec/**/*_spec.rb'
36
+ spec.rcov = true
37
+ end
38
+
39
+ task :default => :spec
40
+
41
+ require 'rdoc/task'
42
+ RDoc::Task.new do |rdoc|
43
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
44
+
45
+ rdoc.rdoc_dir = 'rdoc'
46
+ rdoc.title = "has_distance #{version}"
47
+ rdoc.rdoc_files.include('README*')
48
+ rdoc.rdoc_files.include('lib/**/*.rb')
49
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,75 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{has_distance}
8
+ s.version = "1.0.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Fernando Barajas"]
12
+ s.date = %q{2011-08-09}
13
+ s.description = %q{Used to find nearby records via latitude/longitude}
14
+ s.email = %q{fernyb@fernyb.net}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE.txt",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".document",
21
+ ".rspec",
22
+ "Gemfile",
23
+ "Gemfile.lock",
24
+ "LICENSE.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION",
28
+ "has_distance.gemspec",
29
+ "lib/has_distance.rb",
30
+ "lib/has_distance/distance.rb",
31
+ "lib/has_distance/railtie.rb",
32
+ "spec/has_distance_spec.rb",
33
+ "spec/spec_helper.rb",
34
+ "spec/support/store.rb",
35
+ "spec/support/stores.csv",
36
+ "spec/support/test.db"
37
+ ]
38
+ s.homepage = %q{http://github.com/fernyb/has_distance}
39
+ s.licenses = ["MIT"]
40
+ s.require_paths = ["lib"]
41
+ s.rubygems_version = %q{1.3.7}
42
+ s.summary = %q{Adds has_distance to ActiveRecord}
43
+
44
+ if s.respond_to? :specification_version then
45
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
46
+ s.specification_version = 3
47
+
48
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
49
+ s.add_runtime_dependency(%q<rails>, [">= 3.0.0"])
50
+ s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
51
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
52
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
53
+ s.add_development_dependency(%q<rcov>, [">= 0"])
54
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
55
+ s.add_development_dependency(%q<csv-mapper>, [">= 0"])
56
+ else
57
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
58
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
59
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
60
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
61
+ s.add_dependency(%q<rcov>, [">= 0"])
62
+ s.add_dependency(%q<sqlite3>, [">= 0"])
63
+ s.add_dependency(%q<csv-mapper>, [">= 0"])
64
+ end
65
+ else
66
+ s.add_dependency(%q<rails>, [">= 3.0.0"])
67
+ s.add_dependency(%q<rspec>, ["~> 2.3.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ s.add_dependency(%q<sqlite3>, [">= 0"])
72
+ s.add_dependency(%q<csv-mapper>, [">= 0"])
73
+ end
74
+ end
75
+
@@ -0,0 +1,126 @@
1
+ require 'active_record'
2
+ require 'active_support/concern'
3
+
4
+ module HasDistance
5
+ module Distance
6
+ module Glue
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def has_distance(field_name=:distance, options={}, &block)
11
+ cattr_accessor :distance_config
12
+ self.distance_config = Struct.new(:column_name,
13
+ :lat_name,
14
+ :lng_name,
15
+ :units,
16
+ :distance,
17
+ :limit
18
+ ).new(
19
+ field_name,
20
+ options[:latitude] || 'latitude',
21
+ options[:longitude] || 'longitude',
22
+ options[:units] || :miles,
23
+ options[:distance] || 20,
24
+ options[:limit] || 12
25
+ )
26
+
27
+ if block_given?
28
+ block.call(self.distance_config)
29
+ end
30
+ end
31
+ end # ClassMethods
32
+
33
+ module InstanceMethods
34
+ KMS_PER_MILE = 1.609
35
+ NMS_PER_MILE = 0.868976242
36
+ EARTH_RADIUS_IN_MILES = 3963.19
37
+ EARTH_RADIUS_IN_KMS = EARTH_RADIUS_IN_MILES * KMS_PER_MILE
38
+ EARTH_RADIUS_IN_NMS = EARTH_RADIUS_IN_MILES * NMS_PER_MILE
39
+
40
+ def nearby(options={})
41
+ _config = self.distance_config
42
+
43
+ _local_latitude = self.send(_config.lat_name)
44
+ _local_longitude = self.send(_config.lng_name)
45
+ _distance_name = _config.column_name
46
+
47
+ _distance = options.delete(:distance)
48
+ _distance = _distance ? _distance : _config.distance
49
+ _limit = options.delete(:limit) || _config.limit
50
+
51
+ _lat = _deg2rad(_local_latitude)
52
+ _lng = _deg2rad(_local_longitude)
53
+
54
+ _sql = _sphere_distance_sql(_lat, _lng, _units_sphere_multiplier(_config.units))
55
+ _sql << " AS #{_config.column_name}"
56
+
57
+ _klass = self.class
58
+ _arreflector = _klass.select("*, #{_sql}").group('id').
59
+ having("#{_distance_name} <= #{_distance}")
60
+
61
+ if !_limit.nil?
62
+ _arreflector.limit(_limit)
63
+ else
64
+ _arreflector
65
+ end
66
+ end
67
+
68
+ private
69
+ def _qualified_lat_column_name
70
+ self.distance_config.lat_name
71
+ end
72
+
73
+ def _qualified_lng_column_name
74
+ self.distance_config.lng_name
75
+ end
76
+
77
+ def _create_db_functions(db)
78
+ db.create_function("COS", 1) do |func, value|
79
+ func.result = Math.cos(value)
80
+ end
81
+
82
+ db.create_function("SIN", 1) do |func, value|
83
+ func.result = Math.sin(value)
84
+ end
85
+
86
+ db.create_function('ACOS', 1) do |func, value|
87
+ func.result = Math.acos(value)
88
+ end
89
+
90
+ db.create_function('RADIANS', 1) do |func, value|
91
+ func.result = _deg2rad(value)
92
+ end
93
+
94
+ db.create_function('least', 2) do |func, v1, v2|
95
+ func.result = [v1, v2].min
96
+ end
97
+ end
98
+
99
+ def _sphere_distance_sql(lat, lng, multiplier)
100
+ db = self.class.connection.instance_variable_get(:@connection)
101
+ _create_db_functions(db) if db.class.to_s =~ /SQLite3/i
102
+
103
+ # Took this part from Geokit
104
+ %|
105
+ (ACOS(least(1,COS(#{lat})*COS(#{lng})*COS(RADIANS(#{_qualified_lat_column_name}))*COS(RADIANS(#{_qualified_lng_column_name}))+
106
+ COS(#{lat})*SIN(#{lng})*COS(RADIANS(#{_qualified_lat_column_name}))*SIN(RADIANS(#{_qualified_lng_column_name}))+
107
+ SIN(#{lat})*SIN(RADIANS(#{_qualified_lat_column_name}))))*#{multiplier})
108
+ |
109
+ end
110
+
111
+ def _units_sphere_multiplier(units)
112
+ case units
113
+ when :kms; EARTH_RADIUS_IN_KMS
114
+ when :nms; EARTH_RADIUS_IN_NMS
115
+ else EARTH_RADIUS_IN_MILES
116
+ end
117
+ end
118
+
119
+ def _deg2rad(degrees)
120
+ degrees.to_f / 180.0 * Math::PI
121
+ end
122
+ end # InstanceMethods
123
+
124
+ end # Glue
125
+ end # Distance
126
+ end
@@ -0,0 +1,14 @@
1
+ require 'has_distance'
2
+ require 'rails'
3
+
4
+ module HasDistance
5
+ class Railtie < ::Rails::Railtie
6
+
7
+ initializer 'has_distance.insert_into_active_record' do
8
+ ActiveSupport.on_load :active_record do
9
+ ActiveRecord::Base.send(:include, HasDistance::Distance::Glue)
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,2 @@
1
+ require 'has_distance/railtie'
2
+ require 'has_distance/distance'
@@ -0,0 +1,183 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Store" do
4
+ before :all do
5
+ @default_config = Store.distance_config.clone
6
+ Store.send(:alias_method, :lat, :latitude)
7
+ Store.send(:alias_method, :lon, :longitude)
8
+ end
9
+
10
+ before :each do
11
+ Store.distance_config = @default_config.clone
12
+ end
13
+
14
+ context :has_distance do
15
+ context :defaults do
16
+ it 'latitude name' do
17
+ Store.distance_config.lat_name.should == 'latitude'
18
+ end
19
+
20
+ it 'longitude name' do
21
+ Store.distance_config.lng_name.should == 'longitude'
22
+ end
23
+
24
+ it 'limit' do
25
+ Store.distance_config.limit.should == 12
26
+ end
27
+
28
+ it 'distance' do
29
+ Store.distance_config.distance.should == 20
30
+ end
31
+
32
+ it 'units' do
33
+ Store.distance_config.units.should == :miles
34
+ end
35
+
36
+ it 'column_name' do
37
+ Store.distance_config.column_name.should == :distance
38
+ end
39
+ end
40
+
41
+ it 'returns store' do
42
+ Store.all.size.should > 0
43
+ end
44
+
45
+ it 'responds to has_distance' do
46
+ Store.should respond_to(:has_distance)
47
+ end
48
+
49
+ it 'can be configured with a block' do
50
+ Store.has_distance :distance do |config|
51
+ config.limit = 2
52
+ end
53
+ Store.first.nearby.to_sql.should =~ /LIMIT 2/
54
+ end
55
+
56
+ it 'can specify latitude name' do
57
+ Store.distance_config.lat_name = "lat"
58
+ Store.first.nearby.to_sql.should =~ /\(lat\)/
59
+ end
60
+
61
+ it 'can specify longitude name' do
62
+ Store.distance_config.lng_name = "lon"
63
+ Store.first.nearby.to_sql.should =~ /\(lon\)/
64
+ end
65
+
66
+ it 'can specificy the distance column name' do
67
+ Store.distance_config.column_name = 'dist'
68
+ Store.first.nearby.to_sql.should =~ /AS dist FROM/
69
+ end
70
+
71
+ it 'can configure column name' do
72
+ Store.has_distance :dist do |config|
73
+ config.column_name = :name
74
+ end
75
+ Store.distance_config.column_name.should == :name
76
+ end
77
+
78
+ it 'can configure latitude name' do
79
+ Store.has_distance :dist do |config|
80
+ config.lat_name = 'lat'
81
+ end
82
+ Store.distance_config.lat_name.should == 'lat'
83
+ end
84
+
85
+ it 'can configure longitude name' do
86
+ Store.has_distance :dist do |config|
87
+ config.lng_name = 'lon'
88
+ end
89
+ Store.distance_config.lng_name.should == 'lon'
90
+ end
91
+
92
+ it 'can configure distance' do
93
+ Store.has_distance :dist do |config|
94
+ config.distance = 4
95
+ end
96
+ Store.distance_config.distance.should == 4
97
+ end
98
+
99
+ it 'can configure limit' do
100
+ Store.has_distance :dist do |config|
101
+ config.limit = 3
102
+ end
103
+ Store.distance_config.limit.should == 3
104
+ end
105
+ end
106
+
107
+ context :nearby do
108
+ it 'generates sql for miles units' do
109
+ sql = Store.first.nearby.to_sql
110
+ sql.should == "SELECT *,
111
+ (ACOS(least(1,COS(0.5953003919287299)*COS(-2.0620890579387803)*COS(RADIANS(latitude))*COS(RADIANS(longitude))+
112
+ COS(0.5953003919287299)*SIN(-2.0620890579387803)*COS(RADIANS(latitude))*SIN(RADIANS(longitude))+
113
+ SIN(0.5953003919287299)*SIN(RADIANS(latitude))))*3963.19)
114
+ AS distance FROM \"stores\" GROUP BY id HAVING distance <= 20 LIMIT 12"
115
+ end
116
+
117
+ it 'generates sql for kms units' do
118
+ Store.distance_config.units = :kms
119
+ sql = Store.first.nearby.to_sql
120
+ sql.should == 'SELECT *,
121
+ (ACOS(least(1,COS(0.5953003919287299)*COS(-2.0620890579387803)*COS(RADIANS(latitude))*COS(RADIANS(longitude))+
122
+ COS(0.5953003919287299)*SIN(-2.0620890579387803)*COS(RADIANS(latitude))*SIN(RADIANS(longitude))+
123
+ SIN(0.5953003919287299)*SIN(RADIANS(latitude))))*6376.77271)
124
+ AS distance FROM "stores" GROUP BY id HAVING distance <= 20 LIMIT 12'
125
+ end
126
+
127
+ it 'generates sql for nms units' do
128
+ Store.distance_config.units = :nms
129
+ sql = Store.first.nearby.to_sql
130
+ sql.should == 'SELECT *,
131
+ (ACOS(least(1,COS(0.5953003919287299)*COS(-2.0620890579387803)*COS(RADIANS(latitude))*COS(RADIANS(longitude))+
132
+ COS(0.5953003919287299)*SIN(-2.0620890579387803)*COS(RADIANS(latitude))*SIN(RADIANS(longitude))+
133
+ SIN(0.5953003919287299)*SIN(RADIANS(latitude))))*3443.91795253198)
134
+ AS distance FROM "stores" GROUP BY id HAVING distance <= 20 LIMIT 12'
135
+ end
136
+
137
+ it 'uses miles as default units' do
138
+ Store.distance_config.units.should == :miles
139
+ end
140
+
141
+ it 'has distance column_name for nearby results' do
142
+ stores = Store.first.nearby.limit(2)
143
+ stores.each do |store|
144
+ store.should respond_to(:distance)
145
+ end
146
+
147
+ stores[0].distance.should == 0.0
148
+ stores[1].distance.should == 1.931497125999382
149
+ end
150
+
151
+ it 'distance name can be changed' do
152
+ Store.has_distance :distname
153
+ stores = Store.first.nearby.limit(2)
154
+ stores.each do |store|
155
+ store.should respond_to(:distname)
156
+ store.should_not respond_to(:distance)
157
+ end
158
+
159
+ stores[0].distname.should == 0.0
160
+ stores[1].distname.should == 1.931497125999382
161
+ end
162
+
163
+ it 'can be chained' do
164
+ sql = Store.first.nearby.limit(6).to_sql
165
+ sql.should =~ /LIMIT 6/
166
+ end
167
+
168
+ it 'responds to nearby' do
169
+ Store.first.should respond_to(:nearby)
170
+ end
171
+
172
+ it 'can limit results' do
173
+ sql = Store.first.nearby(limit: 5).to_sql
174
+ sql.should =~ /LIMIT 5/
175
+ end
176
+
177
+ it 'can limit by distance' do
178
+ sql = Store.first.nearby(distance: 8).to_sql
179
+ sql.should =~ /HAVING distance <= 8/
180
+ end
181
+ end
182
+
183
+ end
@@ -0,0 +1,50 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'has_distance'
5
+ require 'sqlite3'
6
+ require 'csv-mapper'
7
+
8
+ ActiveRecord::Base.send :include, HasDistance::Distance::Glue
9
+
10
+ CURRENT_PATH = File.dirname(__FILE__)
11
+ # Requires supporting files with custom matchers and macros, etc,
12
+ # in ./support/ and its subdirectories.
13
+ Dir["#{CURRENT_PATH}/support/**/*.rb"].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+ end
17
+
18
+ ActiveRecord::Base.establish_connection({
19
+ :adapter => 'sqlite3',
20
+ :database => "#{CURRENT_PATH}/support/test.db"
21
+ })
22
+
23
+ ActiveRecord::Schema.define do
24
+ create_table :stores, :force => true do |t|
25
+ t.string :name, :unique => true
26
+ t.string :city
27
+ t.string :state
28
+ t.text :description
29
+ t.decimal :latitude, :precision => 15, :scale => 12
30
+ t.decimal :longitude, :precision => 15, :scale => 12
31
+ t.timestamps
32
+ end
33
+ end
34
+
35
+ include CsvMapper
36
+
37
+ results = import("#{CURRENT_PATH}/support/stores.csv") do
38
+ read_attributes_from_file
39
+ end
40
+
41
+ results.each do |res|
42
+ person = Store.new
43
+ person.name = res.name
44
+ person.city = res.city
45
+ person.state = res.state
46
+ person.description = res.description
47
+ person.latitude = res.latitude
48
+ person.longitude = res.longitude
49
+ person.save
50
+ end
@@ -0,0 +1,3 @@
1
+ class Store < ActiveRecord::Base
2
+ has_distance :distance
3
+ end
@@ -0,0 +1,51 @@
1
+ "name","city","state","description","latitude","longitude","distance"
2
+ "south pas middle","South Pasadena","California","its a school full of sets and rails, theres a nine stair with small rail and a 10 with alot of speed enough for el toro 20
3
+
4
+ Theres a whole bunch of ledges, (but the janitors are anoying as shit)",34.1082,-118.149,0.00013205352794747638
5
+ "Garvanza Skate Park","Los Angeles","California","Nice little park in my neighborhood.",34.1192,-118.18,1.931558412736783
6
+ "burbank middle","Los Angeles","California","an 8 stair rail that koston switch over crooks for cover, also a 20 flat 8 that reynolds, ellington, bastien, nyjah, and ragdoll skate....
7
+
8
+ also a massive 7 flat 2 p-rod varial heels, billy roper kickflips, reynolds f/s flips in a line, chris cole switch frontside heels, richie belton varial kickflips, stefan janoski switch kickflips, adam dyet switch back 180s, furby nollie flips, and corey sheppard pop shovit and 360 flips....
9
+
10
+ fun place..... go on weekends gates are sometimes open!",34.1195,-118.183,2.098052336912497
11
+ "Untitled Spot","Pasadena","California","there is a 14 that matt ball 50-50's- lance mountain also 50-50ies it
12
+
13
+ andrew pott crooks the 14 in oakley our life
14
+
15
+ and mark appleyard frontboards the 19 in an ad
16
+
17
+ don nguyen 50-50's the 19 in his part in cataclyssmic abyss
18
+
19
+ you wont get kicked out usually just go on a weekend",34.1564,-118.119,3.750322659451696
20
+ "LCHS","La Canada Flintridge","California","11 stair with a huge rail. six stair. three stair. if you have never seen this spot in a line you're crazy cuz its always in flick",34.1926,-118.179,6.085378772633055
21
+ "Corner Ledge","Los Angeles","California","Super steep corner ledge that goes up and down. Not for the average skater.",34.0681,-118.25,6.416355069860317
22
+ "Abandoned Roof Top","Los Angeles","California","3,4,5,6 stairs, Manny pad, Obstacles, Huge Car Gap, Stair Gap, Benches.",34.0538,-118.245,6.664110874001224
23
+ "ghetto park","Los Angeles","California","security rarely cums here dars a 4 step a 5 stair with a ledge on da side and sumtims dars a rail u can use as a flatbar or a handrail n dey hav a metal bank manual pad ding fun place to tag or sk8 oohhh and uhh in my other account dat i 4got da password to i put ghetto park 2 blox away frum dis 1 so just ignore dat 1",34.0537,-118.245,6.667989804634197
24
+ "Ledges","Los Angeles","California","The best ledges in the world.
25
+
26
+ whats the real name of this spot?",34.058,-118.249,6.699149306226914
27
+ "Gap to ledge","Los Angeles","California","everybody's seen it, its sick. Dompierre noseblunted it. There's a lot of ledges around this building too",34.056,-118.248,6.723537121070339
28
+ "The 5","Los Angeles","California","5 stairs semi high, drops about 5-6 feet high, manny to ledge drops, ledge grinds, Drop about 7 or 8 feet high",34.0546,-118.247,6.728219504968207
29
+ "The Big 4","Los Angeles","California","Big 4 Block (stairs) , drops, 1-5 feet, gap, sketchy kickers, 7 LONG stair rail, Rent-a-cop, if you're gonna do the 4 hurry it up cause he comes out kinda quick, even at night (9 pm)",34.0481,-118.242,6.757945418766451
30
+ "Ghetto Park","Los Angeles","California","A four step a 5 step, sum ledges a manny pad sumtims dars a rail or flatbar or taggers usually never security",34.053,-118.247,6.789813677709631
31
+ "Piss Benches","Los Angeles","California","Spot under 4th street in downtown, smells like piss",34.0527,-118.255,7.184352704993078
32
+ "Belmont High","Los Angeles","California","3,4,5,6,7,9,Rails,Benches,Manny Pads,Ledges,Cops",34.0618,-118.262,7.225574682229236
33
+ "The Medical Center","Los Angeles","California","5 or 6 Stairs, Huge Slope,2 Big Ledges[you can also grind off them], and a bit to the left theres 2 long ledges, all waxed up",34.057,-118.259,7.22895565092722
34
+ "LA Library","Los Angeles","California","Plenty stairs and gaps",34.0511,-118.256,7.292149005822157
35
+ "Westwood Rail","Los Angeles","California","rail hit by Owen Wilson in Yeah Right among others",34.0162,-118.213,7.344697260081269
36
+ "Lake Street Skatepark","Los Angeles","California","At the skatepark helmets r requierd but dey nevr chek thers a wooden bank with a small quarter pipe in da middle on one side of the skatepark and a wooden quarter pipe on the other side in the middle theres a double bank thing with a flat rail in the middle of it on the north side of the park thers a round rail and a flat rail with a kink, then there are 2 small ledges......then outside of the skatepark which is inside lake street recreation center there is a 7 step, a 9 stair, and a 4 stair....next to te park theres a primary school that has a huge three stair that basiclly look like 3 ledges on top of each other it sorta looks like wallenburg but with one ledge missing so its an overall great place to skate",34.0694,-118.271,7.4865661017791325
37
+ "Downtown Car Wash","Los Angeles","California","The world famous car wash banks",34.0452,-118.264,7.899436666864125
38
+ "Hoover Rail","Glendale","California","17 stair square rail",34.1667,-118.27,8.022526773213709
39
+ "La Fayette Primary School","Los Angeles","California","this is a track skool so u can nevr skate there on a weekday even in summer but on saturdays and sundays u can skate. theres a regular sized ledge thats also waxed for nose/tail slides a manual pad dat starts out as a curb but then get bigger until its beecums a ledge theres also a litttle kid playground so u cud skate down the slide and some picnic tables made for kids so there samll enough to ollie up onto easy. theres also a super secret spot here thats amazing but i wont tell anybody unless they are a pro skater and go with me. other people that have skated this school are daewon song...",34.0664,-118.28,8.042173651511499
40
+ "MacArthur 9","Los Angeles","California","a train drops u off rite in front of these stairs dey r a 9 wit a lot of run up space den up da stairs dars a curb 2 curb ruffly 3ft gap wich can also b used as a manual pad wich is waxed",34.057,-118.276,8.091977811401135
41
+ "Convention Center Ledge","Los Angeles","California","Over waist high hubba.",34.0444,-118.269,8.169599157070497
42
+ "Staples Ledge","Los Angeles","California","Fun little ledge over grass gap. Lots of renta-a-cops.",34.0416,-118.268,8.228412033880597
43
+ "Superior Court","Los Angeles","California","Securitys pretty tite da only day u wont get kiked out is if there closed on a holiday but there are these huge quarter pipe looking things all around. they hav 2 marble ledges so u dont need to wax them to grind and theres also many ledges along with a giant ledge the size of a liquor store rooftop on the sixth street side next to a parking lot entrance some famous people that skated here are two guys sponsored by santa monica airlines and the hundreds, daewon song, jeremy klein, guy mariano, and mark gonzalez",34.0634,-118.285,8.384894775377926
44
+ "Shatto Banks","Los Angeles","California","thers a various banks of different sizes, a 2 step, and n 8 stair....thers security but sumtimes dar isnt or if u fo a little west to vermont and wilshire on the southwest corner there r 2 marble manual pads which r slantly slanted up. some famous skaters dat have skated here are daewon song, and patrick melcher",34.0625,-118.291,8.727435021330509
45
+ "Mineral Wells Ditch","Los Angeles","California","Sweet ditch you've seen in many a skate video. Starts at the top with two big banks and continues into a shallow, mellow downhill ditch. Along the way is a small ledge at one side of the ditch, and a parking block further down.
46
+
47
+ The ditch curves slightly around a corner and under a tree banch into another corner where the ditch angles up and becomes a wall. The top of the wall is waxed and many bangers have been done on it.
48
+
49
+ The surrounding area is a public park and perfect for a picnic with your homies. No BBQs!",34.1469,-118.297,8.886901195094069
50
+ "Hollywood Metro","Los Angeles","California","Metro entrance. Small ledge, 9 stair, 7 stair with fat bar on top of ledge.",34.1016,-118.309,9.175126467591479
51
+ "Normandie Plaza","Los Angeles","California","dis place has lots of security so its fun 2 piss dem off dars a 6 stair, a4,3,n a 5.on da wilshire side in front of mcdonalds ders a 4 stair with a small bank nex 2 it n going south on irolo b4 u hit 7th street thers dis huge manny pad the size of a curb 2 ollie up but its lik ovr 10 ft long",34.061,-118.3,9.246227659434881
Binary file
metadata ADDED
@@ -0,0 +1,179 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: has_distance
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 0
8
+ - 0
9
+ version: 1.0.0
10
+ platform: ruby
11
+ authors:
12
+ - Fernando Barajas
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-08-09 00:00:00 -07:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rails
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 3
30
+ - 0
31
+ - 0
32
+ version: 3.0.0
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rspec
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ segments:
44
+ - 2
45
+ - 3
46
+ - 0
47
+ version: 2.3.0
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: bundler
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ~>
57
+ - !ruby/object:Gem::Version
58
+ segments:
59
+ - 1
60
+ - 0
61
+ - 0
62
+ version: 1.0.0
63
+ type: :development
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: jeweler
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 1
75
+ - 6
76
+ - 4
77
+ version: 1.6.4
78
+ type: :development
79
+ version_requirements: *id004
80
+ - !ruby/object:Gem::Dependency
81
+ name: rcov
82
+ prerelease: false
83
+ requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id005
93
+ - !ruby/object:Gem::Dependency
94
+ name: sqlite3
95
+ prerelease: false
96
+ requirement: &id006 !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ type: :development
105
+ version_requirements: *id006
106
+ - !ruby/object:Gem::Dependency
107
+ name: csv-mapper
108
+ prerelease: false
109
+ requirement: &id007 !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ type: :development
118
+ version_requirements: *id007
119
+ description: Used to find nearby records via latitude/longitude
120
+ email: fernyb@fernyb.net
121
+ executables: []
122
+
123
+ extensions: []
124
+
125
+ extra_rdoc_files:
126
+ - LICENSE.txt
127
+ - README.rdoc
128
+ files:
129
+ - .document
130
+ - .rspec
131
+ - Gemfile
132
+ - Gemfile.lock
133
+ - LICENSE.txt
134
+ - README.rdoc
135
+ - Rakefile
136
+ - VERSION
137
+ - has_distance.gemspec
138
+ - lib/has_distance.rb
139
+ - lib/has_distance/distance.rb
140
+ - lib/has_distance/railtie.rb
141
+ - spec/has_distance_spec.rb
142
+ - spec/spec_helper.rb
143
+ - spec/support/store.rb
144
+ - spec/support/stores.csv
145
+ - spec/support/test.db
146
+ has_rdoc: true
147
+ homepage: http://github.com/fernyb/has_distance
148
+ licenses:
149
+ - MIT
150
+ post_install_message:
151
+ rdoc_options: []
152
+
153
+ require_paths:
154
+ - lib
155
+ required_ruby_version: !ruby/object:Gem::Requirement
156
+ none: false
157
+ requirements:
158
+ - - ">="
159
+ - !ruby/object:Gem::Version
160
+ segments:
161
+ - 0
162
+ version: "0"
163
+ required_rubygems_version: !ruby/object:Gem::Requirement
164
+ none: false
165
+ requirements:
166
+ - - ">="
167
+ - !ruby/object:Gem::Version
168
+ segments:
169
+ - 0
170
+ version: "0"
171
+ requirements: []
172
+
173
+ rubyforge_project:
174
+ rubygems_version: 1.3.7
175
+ signing_key:
176
+ specification_version: 3
177
+ summary: Adds has_distance to ActiveRecord
178
+ test_files: []
179
+