mongoid-geospatial 4.0.1 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,12 +2,12 @@
2
2
  #
3
3
  # Just for fun
4
4
  #
5
- $: << File.expand_path("../../lib", __FILE__)
5
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
6
6
 
7
7
  require 'mongoid/geospatial'
8
8
 
9
9
  Mongoid.configure do |config|
10
- config.connect_to("mongoid_geospatial_bench")
10
+ config.connect_to('mongoid_geospatial_bench')
11
11
  end
12
12
 
13
13
  Mongoid::Geospatial.with_georuby!
@@ -36,27 +36,28 @@ Mongoid.purge!
36
36
 
37
37
  Benchmark.bmbm do |b|
38
38
  [100, 1000, 3000].each do |t|
39
- nogeo, cafes = [], []
39
+ nogeo = []
40
+ cafes = []
40
41
  b.report("#{t} W NoGeo") do
41
42
  t.times { nogeo << NoGeo.create(name: 'Boring').id }
42
43
  end
43
44
  b.report("#{t} W Rider") { t.times { Rider.create(name: 'Munro') } }
44
45
 
45
46
  b.report("#{t} W Cafe ") do
46
- t.times { cafes << Cafe.create(name: 'Bacco', spot: [3,3]).id }
47
+ t.times { cafes << Cafe.create(name: 'Bacco', spot: [3, 3]).id }
47
48
  end
48
49
  # puts "---"
49
- b.report("#{t} R NoGeo") { nogeo.each { |id| NoGeo.find(id) }}
50
+ b.report("#{t} R NoGeo") { nogeo.each { |id| NoGeo.find(id) } }
50
51
  # b.report("#{t} R Rider") { t.times { Rider.create(name: 'Munro') } }
51
- b.report("#{t} R Cafe ") { cafes.each { |id| Cafe.find(id) }}
52
- b.report("#{t} R Cafe Georuby") { cafes.each { |id| Cafe.find(id).spot.to_geo }}
53
- b.report("#{t} R Cafe RGeo") { cafes.each { |id| Cafe.find(id).spot.to_rgeo }}
52
+ b.report("#{t} R Cafe ") { cafes.each { |id| Cafe.find(id) } }
53
+ b.report("#{t} R Cafe Georuby") { cafes.each { |id| Cafe.find(id).spot.to_geo } }
54
+ b.report("#{t} R Cafe RGeo") { cafes.each { |id| Cafe.find(id).spot.to_rgeo } }
54
55
  end
55
- b.report("R Cafe GeoRuby") do
56
+ b.report('R Cafe GeoRuby') do
56
57
  cafe = Cafe.first
57
58
  1_000_000.times { cafe.spot.to_geo }
58
59
  end
59
- b.report("R Cafe RGeo") do
60
+ b.report('R Cafe RGeo') do
60
61
  cafe = Cafe.first
61
62
  1_000_000.times { cafe.spot.to_rgeo }
62
63
  end
@@ -6,23 +6,22 @@ require 'mongoid/geospatial/helpers/sphere'
6
6
  require 'mongoid/geospatial/helpers/delegate'
7
7
 
8
8
  module Mongoid
9
-
10
9
  #
11
10
  # Main Geospatial module
12
11
  #
13
12
  # include Mongoid::Geospatial
14
13
  #
15
14
  module Geospatial
16
- autoload :GeometryField, 'mongoid/geospatial/geometry_field'
15
+ autoload :GeometryField, 'mongoid/geospatial/geometry_field'
17
16
 
18
- autoload :Point, 'mongoid/geospatial/fields/point'
19
- autoload :LineString, 'mongoid/geospatial/fields/line_string'
20
- autoload :Polygon, 'mongoid/geospatial/fields/polygon'
17
+ autoload :Point, 'mongoid/geospatial/fields/point'
18
+ autoload :LineString, 'mongoid/geospatial/fields/line_string'
19
+ autoload :Polygon, 'mongoid/geospatial/fields/polygon'
21
20
 
22
- autoload :Box, 'mongoid/geospatial/fields/box'
23
- autoload :Circle, 'mongoid/geospatial/fields/circle'
21
+ autoload :Box, 'mongoid/geospatial/fields/box'
22
+ autoload :Circle, 'mongoid/geospatial/fields/circle'
24
23
 
25
- autoload :VERSION, 'mongoid/geospatial/version'
24
+ autoload :VERSION, 'mongoid/geospatial/version'
26
25
 
27
26
  extend ActiveSupport::Concern
28
27
 
@@ -70,6 +69,7 @@ module Mongoid
70
69
  require 'mongoid/geospatial/wrappers/georuby'
71
70
  end
72
71
 
72
+ # Methods applied to Document's class
73
73
  module ClassMethods
74
74
  #
75
75
  # Create Spatial index for given field
@@ -78,7 +78,8 @@ module Mongoid
78
78
  # @param [String,Symbol] name
79
79
  # @param [Hash] options options for spatial_index
80
80
  #
81
- # http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-geoNearCommand
81
+ # http://www.mongodb.org/display/DOCS/Geospatial+Indexing
82
+ # #GeospatialIndexing-geoNearCommand
82
83
  #
83
84
  def spatial_index(name, options = {})
84
85
  spatial_fields_indexed << name
@@ -92,7 +93,8 @@ module Mongoid
92
93
  # @param [String,Symbol] name
93
94
  # @param [Hash] options options for spatial_index
94
95
  #
95
- # http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-geoNearCommand
96
+ # http://www.mongodb.org/display/DOCS/Geospatial+Indexing
97
+ # #GeospatialIndexing-geoNearCommand
96
98
  def sphere_index(name, options = {})
97
99
  spatial_fields_indexed << name
98
100
  index({ name => '2dsphere' }, options)
@@ -105,7 +107,8 @@ module Mongoid
105
107
  # @param [String,Symbol] name
106
108
  # @param [Hash] options options for spatial_index
107
109
  #
108
- # http://www.mongodb.org/display/DOCS/Geospatial+Indexing#GeospatialIndexing-geoNearCommand
110
+ # http://www.mongodb.org/display/DOCS/Geospatial+Indexing
111
+ # #GeospatialIndexing-geoNearCommand
109
112
  def spatial_scope(field, _opts = {})
110
113
  singleton_class.class_eval do
111
114
  # define_method(:close) do |args|
@@ -114,12 +117,6 @@ module Mongoid
114
117
  end
115
118
  end
116
119
  end
117
-
118
- private
119
- def geo_field(name, options = {})
120
- field name, { type: Mongoid::Geospatial::Point,
121
- spatial: true }.merge(options)
122
- end
123
120
  end
124
121
  end
125
122
  end
@@ -4,10 +4,12 @@ module Mongoid
4
4
  #
5
5
  class Point
6
6
  include Enumerable
7
- attr_reader :x, :y
7
+ attr_accessor :x, :y, :z
8
8
 
9
9
  def initialize(x, y, z = nil)
10
- @x, @y, @z = x, y, z
10
+ @x = x
11
+ @y = y
12
+ @z = z
11
13
  end
12
14
 
13
15
  # Object -> Database
@@ -29,21 +31,33 @@ module Mongoid
29
31
  yield x
30
32
  yield y
31
33
  end
34
+
32
35
  #
33
36
  # Point representation as a Hash
34
37
  #
35
- # @return (Hash)
38
+ # @return [Hash] with { xl => x, yl => y }
39
+ #
36
40
  def to_hsh(xl = :x, yl = :y)
37
41
  { xl => x, yl => y }
38
42
  end
39
43
  alias_method :to_hash, :to_hsh
40
44
 
45
+ #
41
46
  # Helper for [self, radius]
47
+ #
48
+ # @return [Array] with [self, radius]
49
+ #
42
50
  def radius(r = 1)
43
51
  [mongoize, r]
44
52
  end
45
53
 
46
- # Helper for [self, radius / earth radius]
54
+ #
55
+ # Radius Sphere
56
+ #
57
+ # Validates that #x & #y are `Numeric`
58
+ #
59
+ # @return [Array] with [self, radius / earth radius]
60
+ #
47
61
  def radius_sphere(r = 1, unit = :km)
48
62
  radius r.to_f / Mongoid::Geospatial.earth_radius[unit]
49
63
  end
@@ -51,7 +65,9 @@ module Mongoid
51
65
  #
52
66
  # Am I valid?
53
67
  #
54
- # Validates that x & y are `Numeric`
68
+ # Validates that #x & #y are `Numeric`
69
+ #
70
+ # @return [Boolean] if self #x && #y are valid
55
71
  #
56
72
  def valid?
57
73
  x && y && x.is_a?(Numeric) && y.is_a?(Numeric)
@@ -63,10 +79,23 @@ module Mongoid
63
79
  # "x, y"
64
80
  #
65
81
  # @return [String] Point as comma separated String
82
+ #
66
83
  def to_s
67
84
  "#{x}, #{y}"
68
85
  end
69
86
 
87
+ #
88
+ # Point inverse/reverse
89
+ #
90
+ # MongoDB: "x, y"
91
+ # Reverse: "y, x"
92
+ #
93
+ # @return [Array] Point reversed: "y, x"
94
+ #
95
+ def reverse
96
+ [y, x]
97
+ end
98
+
70
99
  #
71
100
  # Distance calculation methods. Thinking about not using it
72
101
  # One needs to choose and external lib. GeoRuby or RGeo
@@ -100,7 +129,7 @@ module Mongoid
100
129
  # Database -> Object
101
130
  # Get it back
102
131
  def demongoize(obj)
103
- obj && Point.new(*obj)
132
+ obj && new(*obj)
104
133
  end
105
134
 
106
135
  #
@@ -122,7 +151,10 @@ module Mongoid
122
151
  # Converts the object that was supplied to a criteria
123
152
  # into a database friendly form.
124
153
  def evolve(obj)
125
- obj.respond_to?(:x) ? obj.mongoize : obj
154
+ case obj
155
+ when Point then obj.mongoize
156
+ else obj
157
+ end
126
158
  end
127
159
 
128
160
  private
@@ -151,9 +183,9 @@ module Mongoid
151
183
  #
152
184
  # @return (Array)
153
185
  #
154
- def from_array(ary)
155
- return nil if ary.empty?
156
- ary.flatten[0..1].map(&:to_f)
186
+ def from_array(array)
187
+ return nil if array.empty?
188
+ array.flatten[0..1].map(&:to_f)
157
189
  end
158
190
 
159
191
  #
@@ -1,5 +1,6 @@
1
1
  module Mongoid
2
2
  module Geospatial
3
+ #
3
4
  #
4
5
  # Main Geometry Array
5
6
  #
@@ -8,8 +9,12 @@ module Mongoid
8
9
  #
9
10
  class GeometryField < Array
10
11
  #
11
- # Determines the multi point geometry bounding box.
12
+ #
13
+ # Determines the 2 points geometry bounding box.
12
14
  # Useful to find map boundaries, and fit to screen.
15
+ # Returns [bottom left, top right]
16
+ #
17
+ # @return [Array] containing 2 points
13
18
  #
14
19
  def bounding_box
15
20
  max_x, min_x = -Float::MAX, Float::MAX
@@ -24,10 +29,26 @@ module Mongoid
24
29
  end
25
30
  alias_method :bbox, :bounding_box
26
31
 
32
+ #
33
+ # Determines the 5 points geometry bounding box.
34
+ # Useful to use with Mongoid #within_geometry
35
+ #
36
+ # Returns a closed ring:
37
+ # [bottom left, top left, top right, bottom right, bottom left]
38
+ #
39
+ # @return [Array] containing 5 points
40
+ #
41
+ def geom_box
42
+ xl, yl = bounding_box
43
+ [xl, [xl[0], yl[1]], yl, [yl[0], xl[1]], xl]
44
+ end
45
+
27
46
  #
28
47
  # Determines the center point of a multi point geometry.
29
48
  # Geometry may be closed or not.
30
49
  #
50
+ # @return [Array] containing 1 point [x,y]
51
+ #
31
52
  def center_point
32
53
  min, max = *bbox
33
54
  [(min[0] + max[0]) / 2.0, (min[1] + max[1]) / 2.0]
@@ -39,6 +60,7 @@ module Mongoid
39
60
  #
40
61
  # @param [Numeric] r radius
41
62
  # @return [Array] [point, r] point and radius in mongoid format
63
+ #
42
64
  def radius(r = 1)
43
65
  [center, r]
44
66
  end
@@ -49,7 +71,7 @@ module Mongoid
49
71
  # point.radius(x) -> [point, x / earth radius]
50
72
  #
51
73
  # @see Point#radius
52
- # @return (Float)
74
+ # @return [Array]
53
75
  #
54
76
  def radius_sphere(r = 1, unit = :km)
55
77
  radius r.to_f / Mongoid::Geospatial.earth_radius[unit]
@@ -59,6 +81,7 @@ module Mongoid
59
81
  #
60
82
  # Database -> Object
61
83
  #
84
+ # @return [Object]
62
85
  def demongoize(obj)
63
86
  obj && new(obj)
64
87
  end
@@ -18,11 +18,15 @@ Mongoid::Fields.option :delegate do |model, field, options|
18
18
  end
19
19
 
20
20
  define_method "#{x_meth}=" do |arg|
21
- self[field.name][0] = arg
21
+ # HACK: Mongoid has detecting an Array changed
22
+ # self[field.name][0] = arg
23
+ send("#{field.name}=", [arg, self[field.name][1]])
22
24
  end
23
25
 
24
26
  define_method "#{y_meth}=" do |arg|
25
- self[field.name][1] = arg
27
+ # self[field.name][1] = arg
28
+ # self[field.name] = [self[field.name][0], arg]
29
+ send("#{field.name}=", [self[field.name][0], arg])
26
30
  end
27
31
  end
28
32
  end
@@ -1,6 +1,6 @@
1
1
  module Mongoid
2
2
  # Mongoid Geospatial version
3
3
  module Geospatial
4
- VERSION = '4.0.1'
4
+ VERSION = '5.0.0'
5
5
  end
6
6
  end
@@ -1,6 +1,10 @@
1
1
  require 'geo_ruby'
2
2
 
3
3
  module Mongoid
4
+ #
5
+ # Wrappers for GeoRuby
6
+ # https://github.com/nofxx/georuby
7
+ #
4
8
  module Geospatial
5
9
  # Wrapper to GeoRuby's Point
6
10
  Point.class_eval do
@@ -2,6 +2,10 @@ require 'rgeo'
2
2
  require 'mongoid/geospatial/ext/rgeo_spherical_point_impl'
3
3
 
4
4
  module Mongoid
5
+ #
6
+ # Wrappers for RGeo
7
+ # https://github.com/rgeo/rgeo
8
+ #
5
9
  module Geospatial
6
10
  # Wrapper to Rgeo's Point
7
11
  Point.class_eval do
@@ -24,7 +28,6 @@ module Mongoid
24
28
 
25
29
  # Rgeo's GeometryField concept
26
30
  GeometryField.class_eval do
27
-
28
31
  def points
29
32
  map do |pair|
30
33
  RGeo::Geographic.spherical_factory.point(*pair)
@@ -4,8 +4,8 @@ require File.expand_path('../lib/mongoid/geospatial/version', __FILE__)
4
4
  Gem::Specification.new do |gem|
5
5
  gem.authors = ['Ryan Ong', 'Marcos Piccinini']
6
6
  gem.email = ['use@git.hub.com']
7
- gem.description = 'Mongoid Extension that simplifies MongoDB casting and operations on spatial Ruby objects.'
8
7
  gem.summary = 'Mongoid Extension that simplifies MongoDB Geospatial Operations.'
8
+ gem.description = 'Mongoid Extension that simplifies MongoDB casting and operations on spatial Ruby objects.'
9
9
  gem.homepage = 'https://github.com/nofxx/mongoid-geospatial'
10
10
 
11
11
  gem.files = `git ls-files`.split("\n")
@@ -15,5 +15,5 @@ Gem::Specification.new do |gem|
15
15
  gem.version = Mongoid::Geospatial::VERSION
16
16
  gem.license = 'MIT'
17
17
 
18
- gem.add_dependency('mongoid', ['>= 4.0.0'])
18
+ gem.add_dependency('mongoid', ['>= 5.0.0.beta'])
19
19
  end
@@ -5,7 +5,7 @@ class Bar
5
5
 
6
6
  field :name, type: String
7
7
 
8
- geo_field :location
8
+ field :location, type: Point, spatial: true
9
9
 
10
10
  has_one :rating, as: :ratable
11
11
 
@@ -4,7 +4,7 @@ class Farm
4
4
  include Mongoid::Geospatial
5
5
 
6
6
  field :name, type: String
7
- field :geom, type: Point, spatial: true
7
+ field :geom, type: Point, sphere: true
8
8
  field :area, type: Polygon, spatial: true
9
9
  field :m2, type: Fixnum
10
10
 
@@ -26,7 +26,8 @@ class Person
26
26
  field :employer_id
27
27
  field :security_code
28
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') }
29
+ field :last_drink_taken_at, type: Date,
30
+ default: -> { 1.day.ago.in_time_zone('Alaska') }
30
31
 
31
32
  # Geo
32
33
  field :location, type: Point
@@ -3,14 +3,14 @@ class River
3
3
  include Mongoid::Document
4
4
  include Mongoid::Geospatial
5
5
 
6
- field :name, type: String
7
- field :length, type: Integer
8
- field :discharge, type: Integer
9
- field :course, type: LineString, spatial: true
6
+ field :name, type: String
7
+ field :length, type: Integer
8
+ field :discharge, type: Integer
9
+ field :course, type: LineString, spatial: true
10
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 }
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
14
 
15
15
  # simplified spatial indexing
16
16
  # you can only index one field in mongodb < 1.9