has_distance 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +99 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +24 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/has_distance.gemspec +75 -0
- data/lib/has_distance/distance.rb +126 -0
- data/lib/has_distance/railtie.rb +14 -0
- data/lib/has_distance.rb +2 -0
- data/spec/has_distance_spec.rb +183 -0
- data/spec/spec_helper.rb +50 -0
- data/spec/support/store.rb +3 -0
- data/spec/support/stores.csv +51 -0
- data/spec/support/test.db +0 -0
- metadata +179 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
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
|
data/lib/has_distance.rb
ADDED
@@ -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
|
data/spec/spec_helper.rb
ADDED
@@ -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,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
|
+
|