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,33 @@
1
+ require 'geo_ruby'
2
+
3
+ module Mongoid
4
+ module Geospatial
5
+ # Wrapper to GeoRuby's Point
6
+ class Point
7
+ delegate :distance, to: :to_geo
8
+
9
+ def to_geo
10
+ return unless valid?
11
+ GeoRuby::SimpleFeatures::Point.xy(x, y)
12
+ end
13
+
14
+ def geo_distance(other)
15
+ to_geo.spherical_distance(other.to_geo)
16
+ end
17
+ end
18
+
19
+ # Wrapper to GeoRuby's Line
20
+ class Line < GeometryField
21
+ def to_geo
22
+ GeoRuby::SimpleFeatures::LineString.from_coordinates(self)
23
+ end
24
+ end
25
+
26
+ # Wrapper to GeoRuby's Polygon
27
+ class Polygon < GeometryField
28
+ def to_geo
29
+ GeoRuby::SimpleFeatures::Polygon.from_coordinates(self)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,43 @@
1
+ require 'rgeo'
2
+ require 'mongoid_geospatial/ext/rgeo_spherical_point_impl'
3
+
4
+ module Mongoid
5
+ module Geospatial
6
+ # Wrapper to Rgeo's Point
7
+ class Point
8
+ def to_rgeo
9
+ RGeo::Geographic.spherical_factory.point x, y
10
+ end
11
+
12
+ def rgeo_distance(other)
13
+ to_rgeo.distance other.to_rgeo
14
+ end
15
+ end
16
+
17
+ # Rgeo's GeometryField concept
18
+ class GeometryField
19
+ private
20
+
21
+ def points
22
+ map do |pair|
23
+ RGeo::Geographic.spherical_factory.point(*pair)
24
+ end
25
+ end
26
+ end
27
+
28
+ # Wrapper to Rgeo's Line
29
+ class Line < GeometryField
30
+ def to_rgeo
31
+ RGeo::Geographic.spherical_factory.line_string points
32
+ end
33
+ end
34
+
35
+ # Wrapper to Rgeo's Polygon
36
+ class Polygon < GeometryField
37
+ def to_rgeo
38
+ ring = RGeo::Geographic.spherical_factory.linear_ring points
39
+ RGeo::Geographic.spherical_factory.polygon ring
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/mongoid/geospatial/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ['Ryan Ong', 'Marcos Piccinini']
6
+ gem.email = ['use@git.hub.com']
7
+ gem.description = 'Mongoid Extension that simplifies MongoDB casting and operations on spatial Ruby objects.'
8
+ gem.summary = 'Mongoid Extension that simplifies MongoDB Geospatial Operations.'
9
+ gem.homepage = 'https://github.com/nofxx/mongoid-geospatial'
10
+
11
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
12
+ gem.files = `git ls-files`.split("\n")
13
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
14
+ gem.name = 'mongoid-geospatial'
15
+ gem.require_paths = ['lib']
16
+ gem.version = Mongoid::Geospatial::VERSION
17
+ gem.license = 'MIT'
18
+
19
+ gem.add_dependency('mongoid', ['>= 3.0.0'])
20
+ gem.add_dependency('activemodel', ['>= 3.2'])
21
+ gem.add_dependency('activesupport', ['>= 3.2'])
22
+ end
@@ -0,0 +1,69 @@
1
+ # Sample spec class
2
+ class Address
3
+ include Mongoid::Document
4
+
5
+ field :_id, type: String, default: -> { street.try(:parameterize) }
6
+
7
+ attr_accessor :mode
8
+
9
+ field :address_type
10
+ field :number, type: Integer
11
+ field :street
12
+ field :city
13
+ field :state
14
+ field :post_code
15
+ field :parent_title
16
+ field :services, type: Array
17
+ field :latlng, type: Array
18
+ field :map, type: Hash
19
+
20
+ embeds_many :locations, validate: false
21
+ embeds_one :code, validate: false
22
+ embeds_one :target, as: :targetable, validate: false
23
+
24
+ embedded_in :addressable, polymorphic: true do
25
+ def extension
26
+ 'Testing'
27
+ end
28
+
29
+ def doctor?
30
+ title == 'Dr'
31
+ end
32
+ end
33
+
34
+ accepts_nested_attributes_for :locations, :code, :target
35
+
36
+ belongs_to :account
37
+
38
+ scope :without_postcode, where(postcode: nil)
39
+ scope :rodeo, where(street: 'Rodeo Dr') do
40
+ def mansion?
41
+ all? { |address| address.street == 'Rodeo Dr' }
42
+ end
43
+ end
44
+
45
+ validates_presence_of :street, on: :update
46
+ validates_format_of :street, with: /\D/, allow_nil: true
47
+
48
+ def set_parent=(set = false)
49
+ self.parent_title = addressable.title if set
50
+ end
51
+
52
+ def <=>(other)
53
+ street <=> other.street
54
+ end
55
+
56
+ class << self
57
+ def california
58
+ where(state: 'CA')
59
+ end
60
+
61
+ def homes
62
+ where(address_type: 'Home')
63
+ end
64
+
65
+ def streets
66
+ all.map(&:street)
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,12 @@
1
+ # Sample spec class
2
+ class Alarm
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name
7
+ field :radius, type: Circle
8
+ field :area, type: Box
9
+ field :spot, type: Point, sphere: true
10
+
11
+ spatial_scope :spot
12
+ end
@@ -0,0 +1,13 @@
1
+ # Sample spec class
2
+ class Bar
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name, type: String
7
+
8
+ geo_field :location
9
+
10
+ has_one :rating, as: :ratable
11
+
12
+ spatial_scope :location
13
+ end
@@ -0,0 +1,12 @@
1
+ # Sample spec class
2
+ class Bus
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name
7
+ field :plates, type: String
8
+ field :location, type: Point, delegate: true
9
+
10
+ spatial_index :location
11
+ spatial_scope :location
12
+ end
@@ -0,0 +1,17 @@
1
+ # Sample spec class
2
+ class Event
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name
7
+ field :date, type: Date
8
+
9
+ field :location, type: Point, delegate: true, default: [7, 7]
10
+
11
+ def self.each_day(start_date, end_date)
12
+ groups = only(:date).asc(:date).where(:date.gte => start_date, :date.lte => end_date).group
13
+ groups.each do |hash|
14
+ yield(hash['date'], hash['group'])
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # Sample spec class
2
+ class Farm
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name, type: String
7
+ field :geom, type: Point, spatial: true
8
+ field :area, type: Polygon, spatial: true
9
+ field :m2, type: Fixnum
10
+
11
+ spatial_index :geom
12
+ spatial_index :area
13
+ end
@@ -0,0 +1,97 @@
1
+ # Sample spec class
2
+ class Person
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ # include Mongoid::Versioning
6
+ include Mongoid::Geospatial
7
+
8
+ attr_accessor :mode
9
+
10
+ class_attribute :somebody_elses_important_class_options
11
+ self.somebody_elses_important_class_options = { keep_me_around: true }
12
+
13
+ field :ssn
14
+ field :title
15
+ field :terms, type: Boolean
16
+ field :pets, type: Boolean, default: false
17
+ field :age, type: Integer, default: 100
18
+ field :dob, type: Date
19
+ field :lunch_time, type: Time
20
+ field :aliases, type: Array
21
+ field :map, type: Hash
22
+ field :score, type: Integer
23
+ field :owner_id, type: Integer
24
+ field :reading, type: Object
25
+ # field :bson_id, type: bson_object_id_class
26
+ field :employer_id
27
+ field :security_code
28
+ field :blood_alcohol_content, type: Float, default: -> { 0.0 }
29
+ field :last_drink_taken_at, type: Date, default: -> { 1.day.ago.in_time_zone('Alaska') }
30
+
31
+ # Geo
32
+ field :location, type: Point
33
+
34
+ index age: 1
35
+ index addresses: 1
36
+ index dob: 1
37
+ index name: 1
38
+ index title: 1
39
+ index({ ssn: 1 }, unique: true)
40
+
41
+ validates_format_of :ssn, without: /\$\$\$/
42
+
43
+ attr_reader :rescored
44
+
45
+ # attr_protected :security_code, :owner_id
46
+
47
+ embeds_many :addresses, as: :addressable do
48
+ def extension
49
+ 'Testing'
50
+ end
51
+
52
+ def find_by_street(street)
53
+ @target.select { |doc| doc.street == street }
54
+ end
55
+ end
56
+
57
+ accepts_nested_attributes_for :addresses
58
+
59
+ scope :minor, -> { where(:age.lt => 18) }
60
+ scope :without_ssn, -> { without(:ssn) }
61
+
62
+ def score_with_rescoring=(score)
63
+ @rescored = score.to_i + 20
64
+ self.score_without_rescoring = score
65
+ end
66
+
67
+ alias_method_chain :score=, :rescoring
68
+
69
+ def update_addresses
70
+ addresses.each do |address|
71
+ address.street = 'Updated Address'
72
+ end
73
+ end
74
+
75
+ def employer=(emp)
76
+ self.employer_id = emp.id
77
+ end
78
+
79
+ class << self
80
+ def accepted
81
+ criteria.where(terms: true)
82
+ end
83
+
84
+ def knight
85
+ criteria.where(title: 'Sir')
86
+ end
87
+
88
+ def old
89
+ criteria.where(age: { '$gt' => 50 })
90
+ end
91
+ end
92
+ end
93
+
94
+ # Inheritance test
95
+ class Doctor < Person
96
+ field :specialty
97
+ end
@@ -0,0 +1,8 @@
1
+ # Sample spec class
2
+ class Phone
3
+ include Mongoid::Document
4
+ field :number
5
+
6
+ embeds_one :country_code
7
+ embedded_in :person
8
+ end
@@ -0,0 +1,13 @@
1
+ # Sample spec class
2
+ class Place
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name, type: String
7
+ field :location, type: Point, spatial: true
8
+
9
+ has_one :rating, as: :ratable
10
+
11
+ spatial_index :location
12
+ spatial_scope :location
13
+ end
@@ -0,0 +1,22 @@
1
+ # Sample spec class
2
+ class River
3
+ include Mongoid::Document
4
+ include Mongoid::Geospatial
5
+
6
+ field :name, type: String
7
+ field :length, type: Integer
8
+ field :discharge, type: Integer
9
+ field :course, type: Line, spatial: true
10
+ # set return_array to true if you do not want a hash returned all the time
11
+ field :source, type: Point, spatial: true
12
+ field :mouth, type: Point, spatial: { lat: 'latitude', lng: 'longitude' }
13
+ field :mouth_array, type: Array, spatial: { return_array: true }
14
+
15
+ # simplified spatial indexing
16
+ # you can only index one field in mongodb < 1.9
17
+ spatial_index :source
18
+ # alternatives
19
+ # index [[ :spatial, Mongo::GEO2D ]], {min:-400, max:400}
20
+ # index [[ :spatial, Mongo::GEO2D ]], {bit:32}
21
+ # index [[ :spatial, Mongo::GEO2D ],:name]
22
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Geospatial::Box do
4
+
5
+ it 'should work' do
6
+ alarm = Alarm.new(area: [[1, 2], [3, 4]])
7
+ expect(alarm.area).to be_a Mongoid::Geospatial::Box
8
+ end
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Geospatial::Circle do
4
+
5
+ it 'should work' do
6
+ alarm = Alarm.new(radius: [[1, 2], 3])
7
+ expect(alarm.radius).to be_a Mongoid::Geospatial::Circle
8
+ end
9
+
10
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mongoid::Geospatial::Line do
4
+
5
+ describe '(de)mongoize' do
6
+
7
+ it 'should support a field mapped as linestring' do
8
+ river = River.new(course: [[5, 5], [6, 5], [6, 6], [5, 6]])
9
+ expect(river.course).to be_a Mongoid::Geospatial::Line
10
+ expect(river.course).to eq([[5, 5], [6, 5], [6, 6], [5, 6]])
11
+ end
12
+
13
+ it 'should support a field mapped as linestring' do
14
+ River.create!(course: [[5, 5], [6, 5], [6, 6], [5, 6]])
15
+ expect(River.first.course).to eq([[5, 5], [6, 5], [6, 6], [5, 6]])
16
+ end
17
+
18
+ it 'should have a bounding box' do
19
+ geom = Mongoid::Geospatial::Line.new [[1, 5], [6, 5], [6, 6], [5, 6]]
20
+ expect(geom.bbox).to eq([[1, 5], [6, 6]])
21
+ end
22
+
23
+ it 'should have a center point' do
24
+ geom = Mongoid::Geospatial::Line.new [[1, 1], [1, 1], [9, 9], [9, 9]]
25
+ expect(geom.center).to eq([5.0, 5.0])
26
+ end
27
+
28
+ it 'should have a radius helper' do
29
+ geom = Mongoid::Geospatial::Line.new [[1, 1], [1, 1], [9, 9], [9, 9]]
30
+ expect(geom.radius(10)).to eq([[5.0, 5.0], 10])
31
+ end
32
+
33
+ it 'should have a radius sphere' do
34
+ geom = Mongoid::Geospatial::Line.new [[1, 1], [1, 1], [9, 9], [9, 9]]
35
+ expect(geom.radius_sphere(10)[1]).to be_within(0.001).of(0.001569)
36
+ end
37
+
38
+ end
39
+
40
+ end