mongoid_geo 0.1.0

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.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 YOURNAME
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.textile ADDED
@@ -0,0 +1,123 @@
1
+ h1. Mongoid geo
2
+
3
+ A Geo extension for Mongoid.
4
+
5
+ "MongoDB Geospatial Indexing":http://www.mongodb.org/display/DOCS/Geospatial+Indexing
6
+
7
+ * Supports Mongoid 1.7 sphere distance calculations and
8
+ * Adds a set of geo related inflections
9
+ * Adds nearSphere inclusion method
10
+
11
+ h2. Status
12
+
13
+ This gem has so far just the initial design and has not been tested. Feel free to help in the effort. Thanks!
14
+
15
+ h2. Fields
16
+
17
+ When setting a geo-location array, the setter should try to convert the value to an array of floats
18
+
19
+ Old/Manual style:
20
+
21
+ <pre>
22
+ class Person
23
+ field :locations, :type => Array
24
+
25
+ def locations= args
26
+ @locations = args.kind_of?(String) ? args.split(",").map(&:to_f) : args
27
+ end
28
+ end
29
+ </pre>
30
+
31
+ With _mongoid-geo_, becomes:
32
+
33
+ <pre>
34
+ class Person
35
+ field :locations, :type => Array, :geo => true
36
+ end
37
+
38
+ p = Person.new
39
+ # set via String or Strings
40
+ p.locations = "45.1, -3.4"
41
+ p.locations = "45.1", "-3.4"
42
+
43
+ assert([45.1, -3.4], p.locations)
44
+ </pre>
45
+
46
+ h2. Extra Geo Inclusions
47
+
48
+ Find all addresses near a point using spherical distance calculation
49
+
50
+ h3. nearSphere
51
+
52
+ <pre>
53
+ base.where(:locations.nearSphere => [ 72, -44 ])
54
+ # => :locations => { "$nearSphere" : [ 72, -44 ] }
55
+ </pre>
56
+
57
+ h2. Extra Geo Inflections
58
+
59
+ h3. nearMax
60
+
61
+ Find all addresses near a point using spherical distance calculation
62
+
63
+ <pre>
64
+ base.where(:locations.nearMax => [[ 72, -44 ], 5])
65
+ # => { $near: [50, 40] , $maxDistance: 3 }
66
+
67
+ base.where(:locations.nearMax(:sphere) => [[ 72, -44 ], 5])
68
+ # => { $nearSphere: [50, 40] , $maxDistanceSphere: 3 }
69
+ </pre>
70
+
71
+ h3. withinBox
72
+
73
+ <pre>
74
+ box = [[50, 40], [30,55]]
75
+ base.where(:locations.withinBox => box)
76
+ # => locations: {"$within" : {"$box" : box}
77
+
78
+ base.where(:locations.withinBox(:sphere) => box)
79
+ # => locations: {"$within" : {"$boxSphere" : box}
80
+ </pre>
81
+
82
+ You can also use a Hash to define the box
83
+
84
+ <pre>
85
+ places.where(:location.withinBox => {:lower_left => [50, 40], :upper_right => [30,55]})
86
+ </pre>
87
+
88
+ Or use an Object (which must have the methods #lower_left and #upper_right that return the points of the bounding box)
89
+
90
+ <pre>
91
+ box = (Struct.new :lower_left, :upper_right).new
92
+ box.lower_left = [50, 40]
93
+ box.upper_right = [30,55]
94
+ places.where(:location.withinBox => box)
95
+ </pre>
96
+
97
+ h3. withinCenter
98
+
99
+ <pre>
100
+ center = [50, 40]
101
+ radius = 4
102
+
103
+ # places: {"$within" : {"$centerSphere" : [center, radius]}
104
+ places.where(:location.withinCenter(:sphere) => [center, radius])
105
+
106
+ # places: {"$within" : {"$center" : [center, radius]}
107
+ places.where(:location.withinCenter => [center, radius])
108
+ </pre>
109
+
110
+ You can also use a Hash to define the box
111
+
112
+ <pre>
113
+ places.where(:location.withinCenter => {:center => [50, 40], :radius => 4})
114
+ </pre>
115
+
116
+ Or use an Object (which must have the methods #lower_left and #upper_right that return the points of the bounding box)
117
+
118
+ <pre>
119
+ circle = (Struct.new :center, :radius).new
120
+ circle.center = [50, 40]
121
+ circle.radius = 4
122
+ places.where(:location.withinCenter => circle)
123
+ </pre>
data/Rakefile ADDED
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ require 'rubygems'
3
+ begin
4
+ require 'bundler/setup'
5
+ rescue LoadError
6
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
7
+ end
8
+
9
+ require 'rake'
10
+ require 'rake/rdoctask'
11
+
12
+ require 'rspec/core'
13
+ require 'rspec/core/rake_task'
14
+
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ task :default => :spec
18
+
19
+ Rake::RDocTask.new(:rdoc) do |rdoc|
20
+ rdoc.rdoc_dir = 'rdoc'
21
+ rdoc.title = 'Mongoid Geo'
22
+ rdoc.options << '--line-numbers' << '--inline-source'
23
+ rdoc.rdoc_files.include('README.rdoc')
24
+ rdoc.rdoc_files.include('lib/**/*.rb')
25
+ end
@@ -0,0 +1,6 @@
1
+ require 'mongoid/geo/criterion/complex'
2
+ require 'mongoid/geo/criterion/inclusion'
3
+ require 'mongoid/geo/criterion/outer_operator'
4
+ require 'mongoid/geo/criterion/twin_operators'
5
+ require 'mongoid/geo/inflections'
6
+ require 'mongoid/geo/criteria_helpers'
@@ -0,0 +1,29 @@
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
+ case k
10
+ when Mongoid::Criterion::Complex
11
+ hsh[k.key] ||= {}
12
+ hsh[k.key].merge!(k.make_hash(v))
13
+ when Mongoid::Criterion::OuterOperator
14
+ hsh[k.key] ||= {}
15
+ hsh[k.key].merge!(k.make_hash(v))
16
+ when Mongoid::Criterion::TwinOperators
17
+ raise "TwinOperators expects an array with a value for each of the twin operators" if !v.kind_of?(Array) && !v.size == 2
18
+ hsh[k.key] ||= {}
19
+ hsh[k.key].merge!(k.make_hash(v))
20
+ else
21
+ hsh[k] = v
22
+ end
23
+ end
24
+ hsh
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ # Complex criterion are used when performing operations on symbols to get
5
+ # get a shorthand syntax for where clauses.
6
+ #
7
+ # Example:
8
+ #
9
+ # <tt>{ :field => { "$lt" => "value" } }</tt>
10
+ # becomes:
11
+ # <tt> { :field.lt => "value }</tt>
12
+ class Complex
13
+
14
+ def make_hash v
15
+ {"$#{operator}" => v}
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ module Inclusion
5
+ # Adds a criterion to the +Criteria+ that specifies values to do
6
+ # geospacial searches by. The field must be indexed with the "2d" option.
7
+ #
8
+ # @example Adding the criterion.
9
+ # criteria.near(:field1 => [30, -44])
10
+ #
11
+ # @param [ Hash ] attributes The fields with lat/long values.
12
+ #
13
+ # @return [ Criteria ] A new criteria with the added selector.
14
+ def nearSphere(attributes = {})
15
+ update_selector(attributes, "$nearSphere")
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ # Complex criterion are used when performing operations on symbols to get
5
+ # get a shorthand syntax for where clauses.
6
+ #
7
+ # Example:
8
+
9
+ # {:outer_operator => 'within', :operator => 'center' }
10
+ # { :location => { "$within" => { "$center" => [ [ 50, -40 ], 1 ] } } }
11
+ class OuterOperator
12
+ attr_accessor :key, :outer_op, :operator
13
+
14
+ # Create the new complex criterion.
15
+ def initialize(opts = {})
16
+ @key = opts[:key]
17
+ @operator = opts[:operator]
18
+ @outer_op = opts[:outer_op]
19
+ end
20
+
21
+ def make_hash v
22
+ v = extract_box(v) if !v.kind_of?(Array) && operator =~ /box/
23
+ v = extract_circle(v) if !v.kind_of?(Array) && operator =~ /center/
24
+ {"$#{outer_op}" => {"$#{operator}" => v } }
25
+ end
26
+
27
+ def hash
28
+ [@outer_op, [@operator, @key]].hash
29
+ end
30
+
31
+ def eql?(other)
32
+ self == (other)
33
+ end
34
+
35
+ def ==(other)
36
+ return false unless other.is_a?(self.class)
37
+ self.outer_op == other.outer_op && self.key == other.key && self.operator == other.operator
38
+ end
39
+
40
+ protected
41
+
42
+ def extract_circle(v)
43
+ case v
44
+ when Hash
45
+ [v[:center], v[:radius]]
46
+ else
47
+ v.respond_to?(:center) ? [v.center, v.radius] : raise("Can't extract box from: #{v}, must have :center and :radius methods or hash keys")
48
+ end
49
+ end
50
+
51
+ def extract_box v
52
+ case v
53
+ when Hash
54
+ [v[:lower_left], v[:upper_right]]
55
+ else
56
+ v.respond_to?(:lower_left) ? [v.lower_left, v.upper_right] : raise("Can't extract box from: #{v}, must have :lower_left and :upper_right methods or hash keys")
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Criterion #:nodoc:
4
+ # Complex criterion are used when performing operations on symbols to get
5
+ # get a shorthand syntax for where clauses.
6
+ #
7
+ # Example:
8
+
9
+ # {:opA => 'near', :opB => 'maxDistance' }
10
+ # :location => { $near => [50,50], $maxDistance => 5 }
11
+ class TwinOperators
12
+ attr_accessor :key, :op_a, :op_b
13
+
14
+ # Create the new complex criterion.
15
+ def initialize(opts = {})
16
+ @key = opts[:key]
17
+ @op_a = opts[:op_a]
18
+ @op_b = opts[:op_b]
19
+ end
20
+
21
+ def make_hash v
22
+ {"$#{op_a}" => v.first, "$#{op_b}" => v.last }
23
+ end
24
+
25
+ def hash
26
+ [@op_a, @op_b, @key].hash
27
+ end
28
+
29
+ def eql?(other)
30
+ self == (other)
31
+ end
32
+
33
+ def ==(other)
34
+ return false unless other.is_a?(self.class)
35
+ self.op_a == other.op_a && self.op_b == other.op_b && self.key == other.key
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,23 @@
1
+ module Mongoid #:nodoc
2
+ # This module defines behaviour for fields.
3
+ module Fields
4
+ module ClassMethods #:nodoc
5
+ def create_accessors(name, meth, options = {})
6
+ generated_field_methods.module_eval do
7
+ define_method(meth) { read_attribute(name) }
8
+ options
9
+ define_method("#{meth}=") do |value|
10
+ value = if options[:type] == Array && options[:geo]
11
+ value.kind_of?(String) ? value.split(",") : value
12
+ end.map(&:to_f)
13
+ write_attribute(name, value)
14
+ end
15
+ define_method("#{meth}?") do
16
+ attr = read_attribute(name)
17
+ (options[:type] == Boolean) ? attr == true : attr.present?
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Symbol #:nodoc:
5
+ module Inflections #:nodoc:
6
+
7
+ # $nearSphere $centerSphere
8
+ # nearMax
9
+ # - { $near : [50,50] , $maxDistance : 5 }
10
+ # withinBox
11
+ # - {"$within" : {"$box" : box}
12
+ # withinCenter
13
+ # - {"$within" : {"$center" : [center, radius]}}})
14
+
15
+ def nearSphere
16
+ Criterion::Complex.new(:operator => 'nearSphere', :key => self)
17
+ end
18
+
19
+ def nearMax calc = :flat
20
+ Criterion::TwinOperators.new(:op_a => get_op(calc, 'near'), :op_b => get_op(calc, 'maxDistance'), :key => self)
21
+ end
22
+
23
+ def withinBox calc = :flat
24
+ Criterion::OuterOperator.new(:outer_op => 'within', :operator => get_op(calc, 'box'), :key => self)
25
+ end
26
+
27
+ def withinCenter calc = :flat
28
+ Criterion::OuterOperator.new(:outer_op => 'within', :operator => get_op(calc, 'center'), :key => self)
29
+ end
30
+
31
+ private
32
+
33
+ def get_op calc, operator
34
+ calc.to_s == 'sphere' ? "#{operator}Sphere" : operator
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,2 @@
1
+ require 'mongoid/geo/criteria'
2
+ require 'mongoid/geo/fields'
@@ -0,0 +1 @@
1
+ require 'mongoid/geo'
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mongoid_geo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease: !!null
6
+ platform: ruby
7
+ authors: []
8
+ autorequire: !!null
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2011-02-05 00:00:00.000000000 +01:00
12
+ default_executable: !!null
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: mongoid
16
+ requirement: &2159951560 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0.rc.6
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2159951560
25
+ - !ruby/object:Gem::Dependency
26
+ name: bson_ext
27
+ requirement: &2159950420 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 1.1.6
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2159950420
36
+ description: Geo spatial extension on Mongoid 2, to add more geo-spatial capabilities
37
+ email: !!null
38
+ executables: []
39
+ extensions: []
40
+ extra_rdoc_files: []
41
+ files:
42
+ - lib/mongoid/geo/criteria.rb
43
+ - lib/mongoid/geo/criteria_helpers.rb
44
+ - lib/mongoid/geo/criterion/complex.rb
45
+ - lib/mongoid/geo/criterion/inclusion.rb
46
+ - lib/mongoid/geo/criterion/outer_operator.rb
47
+ - lib/mongoid/geo/criterion/twin_operators.rb
48
+ - lib/mongoid/geo/fields.rb
49
+ - lib/mongoid/geo/inflections.rb
50
+ - lib/mongoid/geo.rb
51
+ - lib/mongoid_geo.rb
52
+ - MIT-LICENSE
53
+ - Rakefile
54
+ - README.textile
55
+ has_rdoc: true
56
+ homepage: https://github.com/kristianmandrup/mongoid-geo
57
+ licenses: []
58
+ post_install_message: !!null
59
+ rdoc_options: []
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project: !!null
76
+ rubygems_version: 1.5.0
77
+ signing_key: !!null
78
+ specification_version: 3
79
+ summary: Adds extra convenience methods for geo-spatial operations etc.
80
+ test_files: []