mongoid-geospatial 3.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +49 -0
  4. data/.travis.yml +19 -0
  5. data/Gemfile +30 -0
  6. data/Guardfile +16 -0
  7. data/MIT-LICENSE +20 -0
  8. data/README.md +519 -0
  9. data/Rakefile +17 -0
  10. data/lib/mongoid/geospatial.rb +106 -0
  11. data/lib/mongoid/geospatial/ext/rgeo_spherical_point_impl.rb +18 -0
  12. data/lib/mongoid/geospatial/fields/box.rb +6 -0
  13. data/lib/mongoid/geospatial/fields/circle.rb +18 -0
  14. data/lib/mongoid/geospatial/fields/geometry_field.rb +41 -0
  15. data/lib/mongoid/geospatial/fields/line.rb +6 -0
  16. data/lib/mongoid/geospatial/fields/point.rb +143 -0
  17. data/lib/mongoid/geospatial/fields/polygon.rb +6 -0
  18. data/lib/mongoid/geospatial/helpers/delegate.rb +30 -0
  19. data/lib/mongoid/geospatial/helpers/spatial.rb +19 -0
  20. data/lib/mongoid/geospatial/helpers/sphere.rb +18 -0
  21. data/lib/mongoid/geospatial/version.rb +6 -0
  22. data/lib/mongoid/geospatial/wrappers/georuby.rb +33 -0
  23. data/lib/mongoid/geospatial/wrappers/rgeo.rb +43 -0
  24. data/mongoid-geospatial.gemspec +22 -0
  25. data/spec/models/address.rb +69 -0
  26. data/spec/models/alarm.rb +12 -0
  27. data/spec/models/bar.rb +13 -0
  28. data/spec/models/bus.rb +12 -0
  29. data/spec/models/event.rb +17 -0
  30. data/spec/models/farm.rb +13 -0
  31. data/spec/models/person.rb +97 -0
  32. data/spec/models/phone.rb +8 -0
  33. data/spec/models/place.rb +13 -0
  34. data/spec/models/river.rb +22 -0
  35. data/spec/mongoid/geospatial/fields/box_spec.rb +10 -0
  36. data/spec/mongoid/geospatial/fields/circle_spec.rb +10 -0
  37. data/spec/mongoid/geospatial/fields/line_spec.rb +40 -0
  38. data/spec/mongoid/geospatial/fields/point_spec.rb +254 -0
  39. data/spec/mongoid/geospatial/fields/polygon_spec.rb +84 -0
  40. data/spec/mongoid/geospatial/geospatial_spec.rb +143 -0
  41. data/spec/mongoid/geospatial/helpers/core_spec.rb +27 -0
  42. data/spec/mongoid/geospatial/helpers/delegate_spec.rb +54 -0
  43. data/spec/mongoid/geospatial/helpers/spatial_spec.rb +36 -0
  44. data/spec/mongoid/geospatial/helpers/sphere_spec.rb +26 -0
  45. data/spec/mongoid/geospatial/wrappers/georuby_spec.rb +66 -0
  46. data/spec/mongoid/geospatial/wrappers/rgeo_spec.rb +121 -0
  47. data/spec/spec_helper.rb +64 -0
  48. data/spec/support/authentication.rb +29 -0
  49. data/spec/support/mongod.conf +3 -0
  50. data/spec/support/mongoid.yml +19 -0
  51. metadata +164 -0
@@ -0,0 +1,27 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ def self.from_array(ary)
4
+ ary[0..1].map(&:to_f)
5
+ end
6
+
7
+ def self.from_hash(hsh)
8
+ fail 'Hash must have at least 2 items' if hsh.size < 2
9
+ [from_hash_x(hsh), from_hash_y(hsh)]
10
+ end
11
+
12
+ def self.from_hash_y(hsh)
13
+ v = (Mongoid::Geospatial.lat_symbols & hsh.keys).first
14
+ return hsh[v].to_f if !v.nil? && hsh[v]
15
+ fail "Hash must contain #{Mongoid::Geospatial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
16
+ fail "Hash cannot contain #{Mongoid::Geospatial.lng_symbols.inspect} as the second item if there is no #{Mongoid::Geospatial.lat_symbols.inspect}" if Mongoid::Geospatial.lng_symbols.index(hsh.keys[1])
17
+ hsh.values[1].to_f
18
+ end
19
+
20
+ def self.from_hash_x(hsh)
21
+ v = (Mongoid::Geospatial.lng_symbols & hsh.keys).first
22
+ return hsh[v].to_f if !v.nil? && hsh[v]
23
+ fail "Hash cannot contain #{Mongoid::Geospatial.lat_symbols.inspect} as the first item if there is no #{Mongoid::Geospatial.lng_symbols.inspect}" if Mongoid::Geospatial.lat_symbols.index(keys[0])
24
+ values[0].to_f
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Fields do
4
+
5
+ context 'delegate' do
6
+
7
+ before do
8
+ Bus.create_indexes
9
+ end
10
+
11
+ context 'x, y helpers' do
12
+
13
+ let(:bus) { Bus.create!(name: 'Far', location: [7, 8]) }
14
+
15
+ it 'should set instance method x' do
16
+ expect(bus.x).to eq(7)
17
+ end
18
+
19
+ it 'should set instance method y' do
20
+ expect(bus.y).to eq(8)
21
+ end
22
+
23
+ it 'should set instance method x=' do
24
+ bus.x = 9
25
+ expect(bus.x).to eq(9)
26
+ end
27
+
28
+ it 'should set instance method y=' do
29
+ bus.y = 9
30
+ expect(bus.y).to eq(9)
31
+ end
32
+
33
+ end
34
+
35
+ it 'should set instance methods x= and y=' do
36
+ bus = Bus.create!(name: 'B', location: [7, 7])
37
+ bus.x = 9; bus.y = 9
38
+ expect(bus.location.to_a).to eq([9, 9])
39
+ end
40
+
41
+ it 'should work fine with default values' do
42
+ event = Event.create!(name: 'Bvent')
43
+ event.x = 9; event.y = 9
44
+ expect(event.location.to_a).to eq([9, 9])
45
+ end
46
+
47
+ it 'should not work fine with nils' do
48
+ bus = Bus.create!(name: 'B', location: nil)
49
+ expect { bus.x = 9; bus.y = 9 }.to raise_error(NoMethodError)
50
+ end
51
+
52
+ end
53
+
54
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Fields do
4
+
5
+ context 'spatial' do
6
+
7
+ before do
8
+ Bar.create_indexes
9
+ end
10
+
11
+ it 'should created indexes' do
12
+ expect(Bar.collection.indexes[location: '2d']).not_to be_nil
13
+ end
14
+
15
+ it 'should set spatial fields' do
16
+ expect(Bar.spatial_fields).to eql([:location])
17
+ end
18
+
19
+ it 'should set some class methods' do
20
+ far = Bar.create!(name: 'Far', location: [7, 7])
21
+ near = Bar.create!(name: 'Near', location: [2, 2])
22
+ expect(Bar.nearby([1, 1])).to eq([near, far])
23
+ end
24
+
25
+ # it "should set some class methods" do
26
+ # far = Bar.create!(name: "Far", location: [7,7])
27
+ # near = Bar.create!(name: "Near", location: [2,2])
28
+ # Bar.near_location([1,1]).should eq([near, far])
29
+ # end
30
+
31
+ end
32
+
33
+ context 'geom' do
34
+ end
35
+
36
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Fields do
4
+
5
+ context 'spatial' do
6
+
7
+ before do
8
+ Alarm.create_indexes
9
+ end
10
+
11
+ it 'should created indexes' do
12
+ expect(Alarm.collection.indexes[spot: '2dsphere']).not_to be_nil
13
+ end
14
+
15
+ it 'should set spatial fields' do
16
+ expect(Alarm.spatial_fields).to eql([:spot])
17
+ end
18
+
19
+ it 'should work fine indexed' do
20
+ far = Alarm.create!(name: 'Far', spot: [7, 7])
21
+ expect(far.spot).to be_instance_of(Mongoid::Geospatial::Point)
22
+ end
23
+
24
+ end
25
+
26
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Geospatial::Point do
4
+
5
+ it 'should not interfer with mongoid' do
6
+ Place.create!(name: "Moe's")
7
+ expect(Place.count).to eql(1)
8
+ end
9
+
10
+ it 'should not respond to distance before loading external gem' do
11
+ bar = Place.create!(location: [5, 5])
12
+ expect(bar.location).not_to respond_to(:distance)
13
+ end
14
+
15
+ describe 'queryable' do
16
+
17
+ before do
18
+ Mongoid::Geospatial.with_georuby!
19
+ Place.create_indexes
20
+ end
21
+
22
+ describe '(de)mongoize' do
23
+
24
+ it 'should mongoize array' do
25
+ geom = Place.new(location: [10, -9]).location
26
+ expect(geom.class).to eql(Mongoid::Geospatial::Point)
27
+ expect(geom.to_geo.class).to eql(GeoRuby::SimpleFeatures::Point)
28
+ expect(geom.x).to be_within(0.1).of(10)
29
+ expect(geom.to_geo.y).to be_within(0.1).of(-9)
30
+ end
31
+
32
+ it 'should mongoize hash' do
33
+ geom = Place.new(location: { x: 10, y: -9 }).location
34
+ expect(geom.class).to eql(Mongoid::Geospatial::Point)
35
+ expect(geom.to_geo.class).to eql(GeoRuby::SimpleFeatures::Point)
36
+ end
37
+
38
+ it 'should accept a GeoRuby point' do
39
+ point = GeoRuby::SimpleFeatures::Point.from_x_y 1, 2
40
+ bar = Place.create!(location: point)
41
+ expect(bar.location.x).to be_within(0.1).of(1)
42
+ expect(bar.location.y).to be_within(0.1).of(2)
43
+ end
44
+
45
+ it 'should calculate 3d distances by default' do
46
+ bar = Place.create! location: [-73.77694444, 40.63861111]
47
+ bar2 = Place.create! location: [-118.40, 33.94] # ,:unit=>:mi, :spherical => true)
48
+ expect(bar.location.geo_distance(bar2.location).to_i).to be_within(1).of(3_973_808)
49
+ end
50
+
51
+ describe 'simple features' do
52
+
53
+ it 'should mongoize lines' do
54
+ river = River.new(course: [[1, 2], [3, 4], [5, 6]])
55
+ expect(river.course.to_geo).to be_instance_of(GeoRuby::SimpleFeatures::LineString)
56
+ end
57
+
58
+ it 'should mongoize polygon' do
59
+ farm = Farm.new(area: [[1, 2], [3, 4], [5, 6]])
60
+ expect(farm.area.to_geo).to be_instance_of(GeoRuby::SimpleFeatures::Polygon)
61
+ end
62
+
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'RGeo Wrapper' do
4
+
5
+ before(:all) do
6
+ # Mongoid::Geospatial.send(:remove_const, 'Point')
7
+ # Mongoid::Geospatial.send(:remove_const, 'Polygon')
8
+ # Mongoid::Geospatial.send(:remove_const, 'Line')
9
+
10
+ # load "#{File.dirname(__FILE__)}/../../../lib/mongoid/geospatial/fields/point.rb"
11
+ # load "#{File.dirname(__FILE__)}/../../../lib/mongoid/geospatial/fields/polygon.rb"
12
+ # load "#{File.dirname(__FILE__)}/../../../lib/mongoid/geospatial/fields/line.rb"
13
+
14
+ # Object.send(:remove_const, 'Bar')
15
+ # load "#{File.dirname(__FILE__)}/../../models/bar.rb"
16
+
17
+ # Object.send(:remove_const, 'Farm')
18
+ # load "#{File.dirname(__FILE__)}/../../models/farm.rb"
19
+
20
+ # Object.send(:remove_const, 'River')
21
+ # load "#{File.dirname(__FILE__)}/../../models/river.rb"
22
+ end
23
+
24
+ describe Mongoid::Geospatial::Point do
25
+ it 'should not interfer with mongoid' do
26
+ Bar.create!(name: "Moe's")
27
+ expect(Bar.count).to eql(1)
28
+ end
29
+
30
+ it 'should not respond to distance before loading external' do
31
+ bar = Bar.create!(location: [5, 5])
32
+ expect(bar.location).not_to respond_to(:distance)
33
+ end
34
+ end
35
+
36
+ describe Mongoid::Geospatial::Polygon do
37
+ it 'should not interfer with mongoid' do
38
+ Farm.create!(name: 'Springfield Nuclear Power Plant')
39
+ expect(Farm.count).to eql(1)
40
+ end
41
+
42
+ it 'should not respond to to_geo before loading external' do
43
+ farm = Farm.create!(area: [[5, 5], [6, 5], [6, 6], [5, 6]])
44
+ expect(farm.area).not_to respond_to(:to_geo)
45
+ end
46
+ end
47
+
48
+ describe Mongoid::Geospatial::Line do
49
+ it 'should not interfer with mongoid' do
50
+ River.create!(name: 'Mississippi')
51
+ expect(River.count).to eql(1)
52
+ end
53
+
54
+ it 'should not respond to to_geo before loading external' do
55
+ river = River.create!(course: [[5, 5], [6, 5], [6, 6], [5, 6]])
56
+ expect(river.course).not_to respond_to(:to_geo)
57
+ end
58
+ end
59
+
60
+ describe 'queryable' do
61
+
62
+ before do
63
+ Mongoid::Geospatial.with_rgeo!
64
+ Bar.create_indexes
65
+ Farm.create_indexes
66
+ River.create_indexes
67
+ end
68
+
69
+ describe '(de)mongoize' do
70
+
71
+ describe Mongoid::Geospatial::Point do
72
+ it 'should mongoize array' do
73
+ geom = Bar.new(location: [10, -9]).location
74
+ expect(geom.class).to eql(Mongoid::Geospatial::Point)
75
+ expect(geom.to_rgeo.class).to eql(RGeo::Geographic::SphericalPointImpl)
76
+ expect(geom.x).to be_within(0.1).of(10)
77
+ expect(geom.to_rgeo.y).to be_within(0.1).of(-9)
78
+ end
79
+
80
+ it 'should mongoize hash' do
81
+ geom = Bar.new(location: { x: 10, y: -9 }).location
82
+ expect(geom.class).to eql(Mongoid::Geospatial::Point)
83
+ expect(geom.to_rgeo.class).to eql(RGeo::Geographic::SphericalPointImpl)
84
+ end
85
+
86
+ it 'should accept an RGeo object' do
87
+ point = RGeo::Geographic.spherical_factory.point 1, 2
88
+ bar = Bar.create!(location: point)
89
+ expect(bar.location.x).to be_within(0.1).of(1)
90
+ expect(bar.location.y).to be_within(0.1).of(2)
91
+ end
92
+
93
+ it 'should calculate 3d distances by default' do
94
+ bar = Bar.create! location: [-73.77694444, 40.63861111]
95
+ bar2 = Bar.create! location: [-118.40, 33.94] # ,:unit=>:mi, :spherical => true)
96
+ expect(bar.location.rgeo_distance(bar2.location).to_i).to be_within(1).of(3_978_262)
97
+ end
98
+ end
99
+
100
+ describe Mongoid::Geospatial::Polygon do
101
+ it 'should mongoize array' do
102
+ geom = Farm.create!(area: [[5, 5], [6, 5], [6, 6], [5, 6]]).area
103
+ expect(geom.class).to eql(Mongoid::Geospatial::Polygon)
104
+ expect(geom.to_rgeo.class).to eql(RGeo::Geographic::SphericalPolygonImpl)
105
+ expect(geom.to_rgeo.to_s)
106
+ .to eq 'POLYGON ((5.0 5.0, 6.0 5.0, 6.0 6.0, 5.0 6.0, 5.0 5.0))'
107
+ end
108
+ end
109
+
110
+ describe Mongoid::Geospatial::Line do
111
+ it 'should mongoize array' do
112
+ geom = River.create!(course: [[5, 5], [6, 5], [6, 6], [5, 6]]).course
113
+ expect(geom.class).to eql(Mongoid::Geospatial::Line)
114
+ expect(geom.to_rgeo.class).to eql(RGeo::Geographic::SphericalLineStringImpl)
115
+ expect(geom.to_rgeo.to_s)
116
+ .to eq 'LINESTRING (5.0 5.0, 6.0 5.0, 6.0 6.0, 5.0 6.0)'
117
+ end
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,64 @@
1
+ # require 'pry'
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
4
+
5
+ MODELS = File.join(File.dirname(__FILE__), 'models')
6
+ SUPPORT = File.join(File.dirname(__FILE__), 'support')
7
+ $LOAD_PATH.unshift(MODELS)
8
+ $LOAD_PATH.unshift(SUPPORT)
9
+
10
+ if ENV['CI']
11
+ # require "simplecov"
12
+ require 'coveralls'
13
+ Coveralls.wear!
14
+ # SimpleCov.formatter = Coveralls::SimpleCov::Formatter
15
+ # SimpleCov.start do
16
+ # add_filter "spec"
17
+ # end
18
+ end
19
+
20
+ require 'mongoid'
21
+ # require "mocha"
22
+ require 'rspec'
23
+ require 'mongoid/geospatial'
24
+
25
+ # These environment variables can be set if wanting to test against a database
26
+ # that is not on the local machine.
27
+ ENV['MONGOID_SPEC_HOST'] ||= 'localhost'
28
+ ENV['MONGOID_SPEC_PORT'] ||= '27018'
29
+
30
+ # These are used when creating any connection in the test suite.
31
+ HOST = ENV['MONGOID_SPEC_HOST']
32
+ PORT = ENV['MONGOID_SPEC_PORT'].to_i
33
+
34
+ LOGGER = Logger.new($stdout)
35
+
36
+ if RUBY_VERSION >= '1.9.2'
37
+ YAML::ENGINE.yamler = 'syck'
38
+ end
39
+
40
+ puts "Running with Mongoid v#{Mongoid::VERSION}"
41
+
42
+ Mongoid.configure do |config|
43
+ config.connect_to('mongoid_geo_test')
44
+ end
45
+
46
+ # Autoload every model for the test suite that sits in spec/app/models.
47
+ Dir[File.join(MODELS, '*.rb')].sort.each do |file|
48
+ name = File.basename(file, '.rb')
49
+ autoload name.camelize.to_sym, name
50
+ end
51
+
52
+ Dir[File.join(SUPPORT, '*.rb')].each { |file| require File.basename(file) }
53
+
54
+ def bson_object_id_class
55
+ Moped::BSON::ObjectId
56
+ end
57
+
58
+ RSpec.configure do |config|
59
+ # config.mock_with(:mocha)
60
+
61
+ config.before(:each) do
62
+ Mongoid.purge!
63
+ end
64
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+ module Support #:nodoc:
3
+ # module Authentication
4
+ # extend self
5
+
6
+ # def configured?
7
+ # begin
8
+ # master_uri = "mongodb://mongoid:test@localhost:27017/mongoid_geospatial_test"
9
+ # Mongo::Connection.from_uri(master_uri)
10
+ # true
11
+ # rescue Mongo::AuthenticationError => e
12
+ # false
13
+ # end
14
+ # end
15
+
16
+ # def message
17
+ # %Q{
18
+ # ---------------------------------------------------------------------
19
+ # A user needs to be configured for authentication, otherwise some
20
+ # configuration specs will not get run. You may set it up from the
21
+ # mongo console:
22
+
23
+ # $ use mongoid_geospatial_test;
24
+ # $ db.addUser("mongoid", "test");
25
+ # ---------------------------------------------------------------------
26
+ # }
27
+ # end
28
+ # end
29
+ end
@@ -0,0 +1,3 @@
1
+ dbpath = /usr/local/var/mongodb
2
+ master = true
3
+ bind_ip = 127.0.0.1
@@ -0,0 +1,19 @@
1
+ test:
2
+ database: mongoid_geospatial_test
3
+ host: localhost
4
+ port: 27018
5
+ slaves:
6
+ # - host: localhost
7
+ # port: 27018
8
+ # - host: localhost
9
+ # port: 27019
10
+ # allow_dynamic_fields: false
11
+ # include_root_in_json: true
12
+ # parameterize_keys: false
13
+ # persist_in_safe_mode: false
14
+ # raise_not_found_error: false
15
+ # reconnect_time: 5
16
+ # autocreate_indexes: false
17
+ # persist_types: false
18
+ # option_no_exist: false
19
+ # skip_version_check: false