mongoid_geospatial 1.0.0rc0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. data/.document +5 -0
  2. data/.gitignore +49 -0
  3. data/.rspec +1 -0
  4. data/Gemfile +11 -0
  5. data/README.md +330 -0
  6. data/Rakefile +18 -0
  7. data/lib/mongoid_geospatial/contexts/mongo.rb +115 -0
  8. data/lib/mongoid_geospatial/criteria.rb +5 -0
  9. data/lib/mongoid_geospatial/criterion/complex.rb +19 -0
  10. data/lib/mongoid_geospatial/criterion/inclusion.rb +14 -0
  11. data/lib/mongoid_geospatial/criterion/near_spatial.rb +50 -0
  12. data/lib/mongoid_geospatial/criterion/within_spatial.rb +60 -0
  13. data/lib/mongoid_geospatial/criterion.rb +3 -0
  14. data/lib/mongoid_geospatial/extensions/hash.rb +22 -0
  15. data/lib/mongoid_geospatial/extensions/symbol.rb +46 -0
  16. data/lib/mongoid_geospatial/field_option.rb +16 -0
  17. data/lib/mongoid_geospatial/fields/line_string.rb +18 -0
  18. data/lib/mongoid_geospatial/fields/point.rb +51 -0
  19. data/lib/mongoid_geospatial/fields/polygon.rb +22 -0
  20. data/lib/mongoid_geospatial/finders.rb +5 -0
  21. data/lib/mongoid_geospatial/geospatial/core_ext.rb +27 -0
  22. data/lib/mongoid_geospatial/geospatial/geo_near_results.rb +140 -0
  23. data/lib/mongoid_geospatial/geospatial.rb +86 -0
  24. data/lib/mongoid_geospatial/version.rb +5 -0
  25. data/lib/mongoid_geospatial.rb +16 -0
  26. data/mongoid_geospatial.gemspec +28 -0
  27. data/spec/config/mongod.conf +3 -0
  28. data/spec/config/mongoid.yml +18 -0
  29. data/spec/functional/contexts/mongo_spec.rb +127 -0
  30. data/spec/functional/criterion/inclusion_spec.rb +356 -0
  31. data/spec/functional/mongoid_geospatial_spec.rb +54 -0
  32. data/spec/functional/spatial/geo_near_results_spec.rb +78 -0
  33. data/spec/models/account.rb +19 -0
  34. data/spec/models/acolyte.rb +9 -0
  35. data/spec/models/address.rb +62 -0
  36. data/spec/models/address_component.rb +5 -0
  37. data/spec/models/agent.rb +10 -0
  38. data/spec/models/alert.rb +5 -0
  39. data/spec/models/animal.rb +21 -0
  40. data/spec/models/answer.rb +4 -0
  41. data/spec/models/bar.rb +9 -0
  42. data/spec/models/birthday.rb +13 -0
  43. data/spec/models/book.rb +5 -0
  44. data/spec/models/business.rb +7 -0
  45. data/spec/models/callbacks.rb +57 -0
  46. data/spec/models/category.rb +13 -0
  47. data/spec/models/circus.rb +7 -0
  48. data/spec/models/comment.rb +13 -0
  49. data/spec/models/country_code.rb +6 -0
  50. data/spec/models/description.rb +11 -0
  51. data/spec/models/division.rb +5 -0
  52. data/spec/models/drug.rb +5 -0
  53. data/spec/models/employer.rb +5 -0
  54. data/spec/models/entry.rb +6 -0
  55. data/spec/models/event.rb +20 -0
  56. data/spec/models/farm.rb +10 -0
  57. data/spec/models/favorite.rb +6 -0
  58. data/spec/models/fruits.rb +11 -0
  59. data/spec/models/game.rb +18 -0
  60. data/spec/models/ghost.rb +7 -0
  61. data/spec/models/house.rb +4 -0
  62. data/spec/models/inheritance.rb +90 -0
  63. data/spec/models/league.rb +5 -0
  64. data/spec/models/location.rb +5 -0
  65. data/spec/models/login.rb +6 -0
  66. data/spec/models/membership.rb +4 -0
  67. data/spec/models/mixed_drink.rb +4 -0
  68. data/spec/models/name.rb +13 -0
  69. data/spec/models/namespacing.rb +11 -0
  70. data/spec/models/observed.rb +41 -0
  71. data/spec/models/override.rb +16 -0
  72. data/spec/models/owner.rb +6 -0
  73. data/spec/models/page.rb +5 -0
  74. data/spec/models/page_question.rb +4 -0
  75. data/spec/models/paranoid_post.rb +18 -0
  76. data/spec/models/parents.rb +32 -0
  77. data/spec/models/patient.rb +15 -0
  78. data/spec/models/person.rb +146 -0
  79. data/spec/models/pet.rb +7 -0
  80. data/spec/models/pet_owner.rb +6 -0
  81. data/spec/models/phone.rb +7 -0
  82. data/spec/models/player.rb +23 -0
  83. data/spec/models/post.rb +26 -0
  84. data/spec/models/preference.rb +9 -0
  85. data/spec/models/question.rb +8 -0
  86. data/spec/models/quiz.rb +6 -0
  87. data/spec/models/rating.rb +8 -0
  88. data/spec/models/river.rb +20 -0
  89. data/spec/models/role.rb +5 -0
  90. data/spec/models/service.rb +6 -0
  91. data/spec/models/shelf.rb +5 -0
  92. data/spec/models/slave_address_numbers.rb +14 -0
  93. data/spec/models/survey.rb +5 -0
  94. data/spec/models/tag.rb +6 -0
  95. data/spec/models/tracking_id_validation_history.rb +25 -0
  96. data/spec/models/translation.rb +5 -0
  97. data/spec/models/tree.rb +9 -0
  98. data/spec/models/user.rb +9 -0
  99. data/spec/models/user_account.rb +10 -0
  100. data/spec/models/vet_visit.rb +5 -0
  101. data/spec/models/video.rb +9 -0
  102. data/spec/models/wiki_page.rb +6 -0
  103. data/spec/spec_helper.rb +51 -0
  104. data/spec/support/authentication.rb +29 -0
  105. data/spec/unit/criterion/complex_spec.rb +15 -0
  106. data/spec/unit/criterion/inclusion_spec.rb +0 -0
  107. data/spec/unit/criterion/near_spatial_spec.rb +39 -0
  108. data/spec/unit/criterion/within_spatial_spec.rb +52 -0
  109. metadata +339 -0
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Hash #:nodoc:
5
+ module CriteriaHelpers #:nodoc:
6
+ def expand_complex_criteria
7
+ hsh = {}
8
+ each_pair do |k,v|
9
+ if k.respond_to?(:key) && k.respond_to?(:to_mongo_query)
10
+ hsh[k.key] ||= {}
11
+ hsh[k.key].merge!(k.to_mongo_query(v))
12
+ else
13
+ hsh[k] = v
14
+ end
15
+ end
16
+ hsh
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Symbol #:nodoc:
5
+ module Inflections #:nodoc:
6
+
7
+ # return a class that will accept a value to convert the query correctly for near
8
+ #
9
+ # @param [Symbol] calc This accepts :sphere
10
+ #
11
+ # @return [Criterion::NearSpatial]
12
+
13
+ def near(calc = :flat)
14
+ Criterion::NearSpatial.new(:operator => get_op('near',calc), :key => self)
15
+ end
16
+
17
+ # alias for self.near(:sphere)
18
+ #
19
+ # @return [Criterion::NearSpatial]
20
+ def near_sphere
21
+ self.near(:sphere)
22
+ end
23
+
24
+ # @param [Symbol] shape :box,:polygon,:center,:center_sphere
25
+ #
26
+ # @return [Criterion::WithinSpatial]
27
+ def within(shape)
28
+ shape = get_op(:center,:sphere) if shape == :center_sphere
29
+ Criterion::WithinSpatial.new(:operator => shape.to_s , :key => self)
30
+ end
31
+
32
+ private
33
+
34
+ def get_op operator, calc
35
+ if calc.to_sym == :sphere && Mongoid.master.connection.server_version >= '1.7'
36
+ "#{operator}Sphere"
37
+ elsif calc.to_sym == :sphere
38
+ raise "MongoDB Server version #{Mongoid.master.connection.server_version} does not have Spherical Calculation"
39
+ else
40
+ operator.to_s
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,16 @@
1
+ #require 'ostruct'
2
+
3
+ Mongoid::Fields.option :spatial do |model,field,options|
4
+ options = {} unless options.kind_of?(Hash)
5
+ lat_meth = options[:lat] || :lat
6
+ lng_meth = options[:lng] || :lng
7
+ model.class_eval do
8
+ self.spatial_fields ||= []
9
+ self.spatial_fields << field.name.to_sym if self.spatial_fields.kind_of? Array
10
+
11
+ define_method "distance_from_#{field.name}" do |*args|
12
+ self.distance_from(field.name, *args)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ class LineString
4
+
5
+ include Mongoid::Fields::Serializable
6
+
7
+ def deserialize(object)
8
+ RGeo::Geographic.spherical_factory.line_string *object
9
+ end
10
+
11
+ def serialize(object)
12
+ object.to_a
13
+ end
14
+
15
+
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,51 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ class Point
4
+
5
+ include Mongoid::Fields::Serializable
6
+
7
+ def deserialize(object)
8
+ return unless object && !object.empty?
9
+ RGeo::Geographic.spherical_factory.point *object
10
+ #["x"], object["y"]
11
+ end
12
+
13
+ def serialize(object)
14
+ object.respond_to?(:x) ? [object.x, object.y] : object
15
+ # if object.respond_to? :x
16
+ # { "x" => object.x, "y" => object.y }
17
+ # else
18
+ # { "x" => object[0], "y" => object[1] }
19
+ # end
20
+ end
21
+
22
+ # - self.spacial_fields ||= []
23
+ # - self.spacial_fields << field.name.to_sym if self.spacial_fields.kind_of? Array
24
+ # -
25
+ # - define_method "distance_from_#{field.name}" do |*args|
26
+ # - self.distance_from(field.name, *args)
27
+ # - end
28
+ # -
29
+ # - define_method field.name do
30
+ # - output = self[field.name] || [nil,nil]
31
+ # - output = {lng_meth => output[0], lat_meth => output[1]} unless options[:return_array]
32
+ # - return options[:class].new(output) if options[:class]
33
+ # - output
34
+ # - end
35
+ # -
36
+ # - define_method "#{field.name}=" do |arg|
37
+ # - if arg.kind_of?(Hash) && arg[lng_meth] && arg[lat_meth]
38
+ # - arg = [arg[lng_meth].to_f, arg[lat_meth].to_f]
39
+ # - elsif arg.respond_to?(:to_lng_lat)
40
+ # - arg = arg.to_lng_lat
41
+ # - end
42
+ # - self[field.name]=arg
43
+ # - arg = [nil,nil] if arg.nil?
44
+ # - return arg[0..1] if options[:return_array]
45
+ # - h = {lng_meth => arg[0], lat_meth => arg[1]}
46
+ # - return h if options[:class].blank?
47
+ # - options[:class].new(h)
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,22 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ class Polygon
4
+
5
+ include Mongoid::Fields::Serializable
6
+
7
+ def deserialize(object)
8
+ points = object.map do |pair|
9
+ RGeo::Geographic.spherical_factory.point *pair
10
+ end
11
+ ring = RGeo::Geographic.spherical_factory.linear_ring points
12
+ RGeo::Geographic.spherical_factory.polygon ring
13
+ end
14
+
15
+ def serialize(object)
16
+ object #.flatten
17
+ end
18
+
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid #:nodoc:
2
+ module Finders
3
+ delegate :geo_near, :to => :criteria
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ class Array
2
+ def to_lng_lat
3
+ self[0..1].map(&:to_f)
4
+ end
5
+ end
6
+
7
+ class Hash
8
+ def to_lng_lat
9
+ raise "Hash must have at least 2 items" if self.size < 2
10
+ [to_lng, to_lat]
11
+ end
12
+
13
+ def to_lat
14
+ v = (Mongoid::Geospatial.lat_symbols & self.keys).first
15
+ return self[v].to_f if !v.nil? && self[v]
16
+ raise "Hash must contain #{Mongoid::Geospatial.lat_symbols.inspect} if ruby version is less than 1.9" if RUBY_VERSION.to_f < 1.9
17
+ raise "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(self.keys[1])
18
+ self.values[1].to_f
19
+ end
20
+
21
+ def to_lng
22
+ v = (Mongoid::Geospatial.lng_symbols & self.keys).first
23
+ return self[v].to_f if !v.nil? && self[v]
24
+ raise "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(self.keys[0])
25
+ self.values[0].to_f
26
+ end
27
+ end
@@ -0,0 +1,140 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ class GeoNearResults < Array
4
+ attr_reader :stats, :document, :_original_array, :_original_opts
5
+ attr_accessor :opts
6
+
7
+ def initialize(document,results,opts = {})
8
+ raise "#{document.name} class must include Mongoid::Geospatial::Document" unless document.respond_to?(:spatial_fields_indexed)
9
+ @document = document
10
+ @opts = opts
11
+ @_original_opts = opts.clone
12
+ @stats = results['stats'] || {}
13
+ @opts[:skip] ||= 0
14
+
15
+ @_original_array = results['results'].collect do |result|
16
+ res = Mongoid::Factory.from_db(@document, result.delete('obj'))
17
+ res.geo = {}
18
+ # camel case is awkward in ruby when using variables...
19
+ if result['dis']
20
+ res.geo[:distance] = result.delete('dis').to_f
21
+ end
22
+ result.each do |key,value|
23
+ res.geo[key.snakecase.to_sym] = value
24
+ end
25
+ # dist_options[:formula] = opts[:formula] if opts[:formula]
26
+ @opts[:calculate] = @document.spatial_fields_indexed if @document.spatial_fields_indexed.kind_of?(Array) && @opts[:calculate] == true
27
+ if @opts[:calculate]
28
+ @opts[:calculate] = [@opts[:calculate]] unless @opts[:calculate].kind_of? Array
29
+ @opts[:calculate] = @opts[:calculate].map(&:to_sym) & geo_fields
30
+ if @document.spatial_fields_indexed.kind_of?(Array) && @document.spatial_fields_indexed.size == 1
31
+ primary = @document.spatial_fields_indexed.first
32
+ end
33
+ @opts[:calculate].each do |key|
34
+ res.geo[(key.to_s+'_distance').to_sym] = res.distance_from(key,center,{:unit =>@opts[:unit] || @opts[:distance_multiplier], :spherical => @opts[:spherical]} )
35
+ res.geo[:distance] = res.geo[key] if primary && key == primary
36
+ end
37
+ end
38
+ res
39
+ end
40
+ if @opts[:page]
41
+ start = (@opts[:page]-1)*@opts[:per_page] # assuming current_page is 1 based.
42
+ @_paginated_array = @_original_array.clone
43
+ super(@_paginated_array[@opts[:skip]+start, @opts[:per_page]] || [])
44
+ else
45
+ super(@_original_array[@opts[:skip]..-1] || [])
46
+ end
47
+ end
48
+
49
+ def page(*args)
50
+ new_collection = self.clone
51
+ new_collection.page!(*args)
52
+ new_collection
53
+ end
54
+
55
+ def page!(page, options = {})
56
+ original = options.delete(:original)
57
+ self.opts.merge!(options)
58
+ self.opts[:paginator] ||= Mongoid::Geospatial.paginator
59
+ self.opts[:page] = page
60
+ start = (self.current_page-1)*self.limit_value # assuming current_page is 1 based.
61
+
62
+ if original
63
+ @_paginated_array = @_original_array.clone
64
+ self.replace(@_paginated_array[self.opts[:skip]+start, self.limit_value] || [])
65
+ else
66
+ @_paginated_array ||= self.to_a
67
+ self.replace(@_paginated_array[self.opts[:skip]+start, self.limit_value])
68
+ end
69
+ true
70
+ end
71
+
72
+ def per(num)
73
+ self.page(current_page, :per_page => num)
74
+ end
75
+
76
+ def reset!
77
+ self.replace(@_original_array)
78
+ @opts = @_original_opts
79
+ @_paginated_array = nil
80
+ true
81
+ end
82
+
83
+ def reset
84
+ clone = self.clone
85
+ clone.reset!
86
+ clone
87
+ end
88
+
89
+ def total_entries
90
+ (@_paginated_array) ? @_paginated_array.count : @_original_array.count
91
+ end
92
+ alias_method :total_count, :total_entries
93
+
94
+ def current_page
95
+ page = (@opts[:page]) ? @opts[:page].to_i.abs : 1
96
+ (page < 1) ? 1 : page
97
+ end
98
+
99
+ def limit_value
100
+ if @opts[:per_page]
101
+ @opts[:per_page] = @opts[:per_page].to_i.abs
102
+ else
103
+ @opts[:per_page] = case self.opts[:paginator]
104
+ when :will_paginate
105
+ @document.per_page
106
+ when :kaminari
107
+ Kaminari.config.default_per_page
108
+ else
109
+ Mongoid::Geospatial.default_per_page
110
+ end
111
+ end
112
+ end
113
+ alias_method :per_page, :limit_value
114
+
115
+ def num_pages
116
+ (self.total_entries && @opts[:per_page]) ? (total_entries.to_f / @opts[:per_page]).ceil : nil
117
+ end
118
+ alias_method :total_pages, :num_pages
119
+
120
+ def out_of_bounds?
121
+ self.current_page > self.total_pages
122
+ end
123
+
124
+ def offset
125
+ (self.current_page - 1) * self.per_page
126
+ end
127
+
128
+ # current_page - 1 or nil if there is no previous page
129
+ def previous_page
130
+ self.current_page > 1 ? (self.current_page - 1) : nil
131
+ end
132
+
133
+ # current_page + 1 or nil if there is no next page
134
+ def next_page
135
+ self.current_page < self.total_pages ? (self.current_page + 1) : nil
136
+ end
137
+
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,86 @@
1
+ require 'mongoid_geospatial/geospatial/core_ext'
2
+ require 'mongoid_geospatial/geospatial/geo_near_results'
3
+
4
+ module Mongoid
5
+ module Geospatial
6
+ extend ActiveSupport::Concern
7
+
8
+ LNG_SYMBOLS = [:x, :lon, :long, :lng, :longitude]
9
+ LAT_SYMBOLS = [:y, :lat, :latitude]
10
+
11
+ EARTH_RADIUS_KM = 6371 # taken directly from mongodb
12
+
13
+ EARTH_RADIUS = {
14
+ :km => EARTH_RADIUS_KM,
15
+ :m => EARTH_RADIUS_KM*1000,
16
+ :mi => EARTH_RADIUS_KM*0.621371192, # taken directly from mongodb
17
+ :ft => EARTH_RADIUS_KM*5280*0.621371192,
18
+ :sm => EARTH_RADIUS_KM*0.53995680345572 # sea mile
19
+ }
20
+
21
+ GEO_FACTORY = RGeo::Geographic.spherical_factory
22
+
23
+ included do
24
+ attr_accessor :geo
25
+ cattr_accessor :spatial_fields, :spatial_fields_indexed
26
+ @@spatial_fields = []
27
+ @@spatial_fields_indexed = []
28
+ end
29
+
30
+ module ClassMethods #:nodoc:
31
+ # create spatial index for given field
32
+ # @param [String,Symbol] name
33
+ # @param [Hash] options options for spatial_index
34
+
35
+ def spatial_index name, *options
36
+ self.spatial_fields_indexed << name
37
+ index [[ name, Mongo::GEO2D ]], *options
38
+ end
39
+ end
40
+
41
+ # def distance(p2, opts = {})
42
+ # p1 = self.send(key)
43
+ # Mongoid::Geospatial.distance(p1, p2, opts)
44
+ # end
45
+
46
+
47
+
48
+ # def self.distance(p1,p2,opts = {})
49
+ # opts[:formula] ||= (opts[:spherical]) ? @@spherical_distance_formula : :pythagorean_theorem
50
+ # p1 = p1.to_lng_lat if p1.respond_to?(:to_lng_lat)
51
+ # p2 = p2.to_lng_lat if p2.respond_to?(:to_lng_lat)
52
+
53
+ # rads = Formulas.send(opts[:formula], p1, p2)
54
+
55
+ # if unit = earth_radius[opts[:unit]]
56
+ # opts[:unit] = (rads.instance_variable_get("@radian")) ? unit : unit * RAD_PER_DEG
57
+ # end
58
+
59
+ # rads *= opts[:unit].to_f if opts[:unit]
60
+ # rads
61
+
62
+ # end
63
+ RAD_PER_DEG = Math::PI/180
64
+ mattr_accessor :lng_symbols
65
+ @@lng_symbols = LNG_SYMBOLS.dup
66
+
67
+ mattr_accessor :lat_symbols
68
+ @@lat_symbols = LAT_SYMBOLS.dup
69
+
70
+ mattr_accessor :earth_radius
71
+ @@earth_radius = EARTH_RADIUS.dup
72
+
73
+ mattr_accessor :paginator
74
+ @@paginator = :array
75
+
76
+ mattr_accessor :default_per_page
77
+ @@default_per_page = 25
78
+
79
+ # mattr_accessor :spherical_distance_formula
80
+ # @@spherical_distance_formula = :n_vector
81
+ mattr_accessor :geo_factory
82
+ @@lng_symbols = GEO_FACTORY.dup
83
+
84
+
85
+ end
86
+ end
@@ -0,0 +1,5 @@
1
+ module Mongoid
2
+ module Geospatial
3
+ VERSION = "1.0.0rc0"
4
+ end
5
+ end
@@ -0,0 +1,16 @@
1
+ require 'rgeo'
2
+ require 'mongoid'
3
+ require 'active_support/core_ext/string/inflections'
4
+ require 'active_support/concern'
5
+ require 'mongoid_geospatial/contexts/mongo'
6
+ require 'mongoid_geospatial/criteria'
7
+ require 'mongoid_geospatial/criterion'
8
+ require 'mongoid_geospatial/extensions/hash'
9
+ require 'mongoid_geospatial/extensions/symbol'
10
+ require 'mongoid_geospatial/field_option'
11
+ require 'mongoid_geospatial/fields/point'
12
+ require 'mongoid_geospatial/fields/polygon'
13
+ require 'mongoid_geospatial/fields/line_string'
14
+ require 'mongoid_geospatial/finders'
15
+ require 'mongoid_geospatial/geospatial'
16
+
@@ -0,0 +1,28 @@
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 = %q{mongoid_geospatial simplifies spatial calculations. Adds integration into mongoid so pagination and other function continue to work. It adds symbol extentions to simplify query creation.}
8
+ gem.summary = %q{A Mongoid Extention that simplifies and adds support for MongoDB Geo Spatial Calculations.}
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
+
18
+
19
+ gem.add_dependency('rgeo', ['>= 0.3.5'])
20
+ gem.add_dependency('mongoid', ['>= 2.1.0'])
21
+ gem.add_dependency('activesupport', ["~> 3.0"])
22
+ gem.add_development_dependency('yard', ["~>0.6.0"])
23
+ gem.add_development_dependency('rspec', ['~>2.3'])
24
+ gem.add_development_dependency('rcov', ['>= 0'])
25
+ gem.add_development_dependency('mocha', ['>= 0'])
26
+ gem.add_development_dependency('will_paginate', ['>= 0'])
27
+ gem.add_development_dependency('kaminari', ['>= 0'])
28
+ end
@@ -0,0 +1,3 @@
1
+ dbpath = /usr/local/var/mongodb
2
+ master = true
3
+ bind_ip = 127.0.0.1
@@ -0,0 +1,18 @@
1
+ test:
2
+ database: mongoid_config_test
3
+ host: localhost
4
+ slaves:
5
+ # - host: localhost
6
+ # port: 27018
7
+ # - host: localhost
8
+ # port: 27019
9
+ allow_dynamic_fields: false
10
+ include_root_in_json: true
11
+ parameterize_keys: false
12
+ persist_in_safe_mode: false
13
+ raise_not_found_error: false
14
+ reconnect_time: 5
15
+ autocreate_indexes: false
16
+ persist_types: false
17
+ option_no_exist: false
18
+ skip_version_check: false
@@ -0,0 +1,127 @@
1
+ require "spec_helper"
2
+
3
+ describe Mongoid::Contexts::Mongo do
4
+ describe "#geo_near" do
5
+
6
+ before do
7
+ Bar.delete_all
8
+ Bar.create_indexes
9
+ end
10
+
11
+ let!(:jfk) do
12
+ Bar.create(:name => 'jfk', :location => [-73.77694444, 40.63861111 ])
13
+ end
14
+
15
+ let!(:lax) do
16
+ Bar.create(:name => 'lax', :location => [-118.40, 33.94])
17
+ end
18
+
19
+ it "should work with specifying specific center and different location attribute on collction" do
20
+ Bar.geo_near(lax.location, :spherical => true).should == [lax, jfk]
21
+ Bar.geo_near(jfk.location, :spherical => true).should == [jfk, lax]
22
+ end
23
+ context 'option' do
24
+ context ':num' do
25
+ it "should limit number of results to 1" do
26
+ Bar.geo_near(jfk.location, :num => 1).size.should == 1
27
+ end
28
+ end
29
+
30
+ context ':maxDistance' do
31
+ it "should get 1 item" do
32
+ Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465/Mongoid::Geospatial.earth_radius[:mi]).size.should == 1
33
+ end
34
+ it "should get 2 items" do
35
+ Bar.geo_near(lax.location, :spherical => true, :max_distance => 2480/Mongoid::Geospatial.earth_radius[:mi]).size.should == 2
36
+ end
37
+
38
+ end
39
+
40
+ context ':distance_multiplier' do
41
+ it "should multiply returned distance with multiplier" do
42
+ Bar.geo_near(lax.location, :spherical => true, :distance_multiplier=> Mongoid::Geospatial.earth_radius[:mi]).second.geo[:distance].to_i.should be_within(1).of(2469)
43
+ end
44
+ end
45
+
46
+ context ':unit' do
47
+ it "should multiply returned distance with multiplier" do
48
+ pending
49
+ Bar.geo_near(lax.location, :spherical => true, :unit => :mi).second.geo[:distance].to_i.should be_within(1).of(2469)
50
+ end
51
+
52
+ it "should convert max_distance to radians with unit" do
53
+ Bar.geo_near(lax.location, :spherical => true, :max_distance => 2465, :unit => :mi).size.should == 1
54
+ end
55
+
56
+ end
57
+
58
+ context ':query' do
59
+ it "should filter using extra query option" do
60
+ # two record in the collection, only one's name is Munich
61
+ Bar.geo_near(jfk.location, :query => {:name => jfk.name}).should == [jfk]
62
+ end
63
+ end
64
+
65
+ end
66
+
67
+ context 'criteria chaining' do
68
+ it "should filter by where" do
69
+ Bar.where(:name => jfk.name).geo_near(jfk.location).should == [jfk]
70
+ Bar.any_of({:name => jfk.name},{:name => lax.name}).geo_near(jfk.location).should == [jfk,lax]
71
+ end
72
+
73
+ it 'should skip 1' do
74
+ Bar.skip(1).geo_near(jfk.location).size.should == 1
75
+ end
76
+
77
+ it 'should limit 1' do
78
+ Bar.limit(1).geo_near(jfk.location).size.should == 1
79
+ end
80
+
81
+ end
82
+
83
+ end
84
+
85
+ context ':page' do
86
+ before do
87
+ Bar.delete_all
88
+ Bar.create_indexes
89
+
90
+ 50.times do
91
+ Bar.create({:location => [rand(360)-180,rand(360)-180]})
92
+ end
93
+ end
94
+
95
+ context ":paginator :array" do
96
+ [nil,1,2].each do |page|
97
+ it "page=#{page} should have 25" do
98
+ Bar.geo_near([1,1], :page => page).size.should == 25
99
+ end
100
+ end
101
+
102
+ it "page=3 should have 0" do
103
+ Bar.geo_near([1,1], :page => 20).size.should == 0
104
+ end
105
+
106
+ it "per_page=5" do
107
+ Bar.geo_near([1,1], :page => 1, :per_page => 5).size.should == 5
108
+ end
109
+ end
110
+
111
+ context ":paginator :kaminari" do
112
+ let(:near) {Bar.geo_near([1,1], :page => 1)}
113
+ it "should have current_page" do
114
+ near.current_page.should == 1
115
+ end
116
+
117
+ it "should have num_pages" do
118
+ near.num_pages.should == 2
119
+ end
120
+
121
+ it "should have limit_value" do
122
+ near.limit_value.should == 25
123
+ end
124
+ end
125
+ end
126
+
127
+ end