rgeo-ar 0.6.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.
- checksums.yaml +7 -0
- data/History.rdoc +98 -0
- data/README.rdoc +95 -0
- data/lib/rgeo/active_record/adapter_test_helper.rb +186 -0
- data/lib/rgeo/active_record/ar_factory_settings.rb +229 -0
- data/lib/rgeo/active_record/arel_spatial_queries.rb +215 -0
- data/lib/rgeo/active_record/common_adapter_elements.rb +177 -0
- data/lib/rgeo/active_record/geometry_mixin.rb +108 -0
- data/lib/rgeo/active_record/spatial_expressions.rb +314 -0
- data/lib/rgeo/active_record/task_hacker.rb +105 -0
- data/lib/rgeo/active_record/version.rb +39 -0
- data/lib/rgeo/active_record.rb +83 -0
- data/lib/rgeo-activerecord.rb +36 -0
- data/test/support/fake_record.rb +124 -0
- data/test/tc_basic.rb +109 -0
- data/test/test_helper.rb +10 -0
- metadata +133 -0
@@ -0,0 +1,215 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Various Arel hacks to support spatial queries
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010-2012 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module ActiveRecord
|
40
|
+
|
41
|
+
|
42
|
+
# A set of common Arel visitor hacks for spatial ToSql visitors.
|
43
|
+
# Generally, a spatial ActiveRecord adapter should provide a custom
|
44
|
+
# ToSql Arel visitor that includes and customizes this module.
|
45
|
+
# See the existing spatial adapters (i.e. postgis, spatialite,
|
46
|
+
# mysqlspatial, and mysql2spatial) for usage examples.
|
47
|
+
|
48
|
+
module SpatialToSql
|
49
|
+
|
50
|
+
|
51
|
+
# Map a standard OGC SQL function name to the actual name used by
|
52
|
+
# a particular database. This method should take a name and
|
53
|
+
# return either the changed name or the original name.
|
54
|
+
|
55
|
+
def st_func(standard_name_)
|
56
|
+
standard_name_
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
# Visit the SpatialNamedFunction node. This operates similarly to
|
61
|
+
# the standard NamedFunction node, but it performs function name
|
62
|
+
# mapping for the database, and it also uses the type information
|
63
|
+
# in the node to determine when to cast string arguments to WKT,
|
64
|
+
|
65
|
+
def visit_RGeo_ActiveRecord_SpatialNamedFunction(node_, *args)
|
66
|
+
name_ = st_func(node_.name)
|
67
|
+
exprs_ = []
|
68
|
+
node_.expressions.each_with_index do |expr_, index_|
|
69
|
+
exprs_ << (node_.spatial_argument?(index_) ? visit_in_spatial_context(expr_, *args) : visit(expr_, *args))
|
70
|
+
end
|
71
|
+
"#{name_}(#{node_.distinct ? 'DISTINCT ' : ''}#{exprs_.join(', ')})#{node_.alias ? " AS #{visit(node_.alias, *args)}" : ''}"
|
72
|
+
end
|
73
|
+
|
74
|
+
|
75
|
+
# Generates SQL for a spatial node.
|
76
|
+
# The node must be a string (in which case it is treated as WKT),
|
77
|
+
# an RGeo feature, or a spatial attribute.
|
78
|
+
|
79
|
+
def visit_in_spatial_context(node_, *args)
|
80
|
+
case node_
|
81
|
+
when ::String
|
82
|
+
"#{st_func('ST_WKTToSQL')}(#{visit_String(node_, *args)})"
|
83
|
+
when ::RGeo::Feature::Instance
|
84
|
+
visit_RGeo_Feature_Instance(node_, *args)
|
85
|
+
when ::RGeo::Cartesian::BoundingBox
|
86
|
+
visit_RGeo_Cartesian_BoundingBox(node_, *args)
|
87
|
+
else
|
88
|
+
visit(node_, *args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
# This node wraps an RGeo feature and gives it spatial expression
|
97
|
+
# constructors.
|
98
|
+
|
99
|
+
class SpatialConstantNode
|
100
|
+
|
101
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
102
|
+
|
103
|
+
|
104
|
+
# The delegate should be the RGeo feature.
|
105
|
+
|
106
|
+
def initialize(delegate_)
|
107
|
+
@delegate = delegate_
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
# Return the RGeo feature
|
112
|
+
|
113
|
+
attr_reader :delegate
|
114
|
+
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
# :stopdoc:
|
120
|
+
|
121
|
+
|
122
|
+
# Hack Arel Attributes dispatcher to recognize geometry columns.
|
123
|
+
# This is deprecated but necessary to support legacy Arel versions.
|
124
|
+
|
125
|
+
if ::Arel::Attributes.method_defined?(:for)
|
126
|
+
module ArelAttributesLegacyClassMethods
|
127
|
+
def for(column_)
|
128
|
+
column_.type == :spatial ? Attribute : super
|
129
|
+
end
|
130
|
+
end
|
131
|
+
::Arel::Attributes.extend(ArelAttributesLegacyClassMethods)
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
# Make sure the standard Arel visitors can handle RGeo feature objects
|
136
|
+
# by default.
|
137
|
+
|
138
|
+
::Arel::Visitors::Visitor.class_eval do
|
139
|
+
def visit_RGeo_ActiveRecord_SpatialConstantNode(node_, *args)
|
140
|
+
if respond_to?(:visit_in_spatial_context)
|
141
|
+
visit_in_spatial_context(node_.delegate, *args)
|
142
|
+
else
|
143
|
+
visit(node_.delegate, *args)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
::Arel::Visitors::Dot.class_eval do
|
148
|
+
alias :visit_RGeo_Feature_Instance :visit_String
|
149
|
+
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
150
|
+
end
|
151
|
+
::Arel::Visitors::DepthFirst.class_eval do
|
152
|
+
alias :visit_RGeo_Feature_Instance :terminal
|
153
|
+
alias :visit_RGeo_Cartesian_BoundingBox :terminal
|
154
|
+
end
|
155
|
+
::Arel::Visitors::ToSql.class_eval do
|
156
|
+
alias :visit_RGeo_Feature_Instance :visit_String
|
157
|
+
alias :visit_RGeo_Cartesian_BoundingBox :visit_String
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# Add tools to build spatial structures in the AST.
|
162
|
+
# This stuff requires Arel 2.1 or later.
|
163
|
+
|
164
|
+
if defined?(::Arel::Nodes::NamedFunction)
|
165
|
+
|
166
|
+
# Allow chaining of predications from named functions
|
167
|
+
# (Some older versions of Arel didn't do this.)
|
168
|
+
::Arel::Nodes::NamedFunction.class_eval do
|
169
|
+
include ::Arel::Predications unless include?(::Arel::Predications)
|
170
|
+
end
|
171
|
+
|
172
|
+
# Allow chaining of spatial expressions from attributes
|
173
|
+
::Arel::Attribute.class_eval do
|
174
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
# A NamedFunction subclass that keeps track of the spatial-ness of
|
179
|
+
# the arguments and return values, so that it can provide context to
|
180
|
+
# visitors that want to interpret syntax differently when dealing with
|
181
|
+
# spatial elements.
|
182
|
+
|
183
|
+
class SpatialNamedFunction < ::Arel::Nodes::NamedFunction
|
184
|
+
|
185
|
+
include ::RGeo::ActiveRecord::SpatialExpressions
|
186
|
+
|
187
|
+
def initialize(name_, expr_, spatial_flags_=[], aliaz_=nil)
|
188
|
+
super(name_, expr_, aliaz_)
|
189
|
+
@spatial_flags = spatial_flags_
|
190
|
+
end
|
191
|
+
|
192
|
+
def spatial_result?
|
193
|
+
@spatial_flags.first
|
194
|
+
end
|
195
|
+
|
196
|
+
def spatial_argument?(index_)
|
197
|
+
@spatial_flags[index_+1]
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
else
|
203
|
+
|
204
|
+
# A dummy SpatialNamedFunction for pre-2.1 versions of Arel.
|
205
|
+
class SpatialNamedFunction; end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
# :startdoc:
|
211
|
+
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Common tools for spatial adapters for ActiveRecord
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010-2012 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
require 'active_support/core_ext/class' # Workaround for a missing require in ActiveRecord 3.2.1
|
38
|
+
require 'active_record'
|
39
|
+
|
40
|
+
# Force AbstractAdapter to autoload
|
41
|
+
if ::ActiveRecord::ConnectionAdapters::AbstractAdapter
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
module RGeo
|
46
|
+
|
47
|
+
module ActiveRecord
|
48
|
+
|
49
|
+
|
50
|
+
# Some default column constructors specifications for most spatial
|
51
|
+
# databases. Individual adapters may add to or override this list.
|
52
|
+
|
53
|
+
DEFAULT_SPATIAL_COLUMN_CONSTRUCTORS = {
|
54
|
+
:spatial => {:type => 'geometry'}.freeze,
|
55
|
+
:geometry => {}.freeze,
|
56
|
+
:point => {}.freeze,
|
57
|
+
:line_string => {}.freeze,
|
58
|
+
:polygon => {}.freeze,
|
59
|
+
:geometry_collection => {}.freeze,
|
60
|
+
:multi_line_string => {}.freeze,
|
61
|
+
:multi_point => {}.freeze,
|
62
|
+
:multi_polygon => {}.freeze,
|
63
|
+
}.freeze
|
64
|
+
|
65
|
+
|
66
|
+
# Index definition struct with a spatial flag field.
|
67
|
+
|
68
|
+
class SpatialIndexDefinition < Struct.new(:table, :name, :unique, :columns, :lengths, :orders, :where, :spatial)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
# Returns a feature type module given a string type.
|
73
|
+
|
74
|
+
def self.geometric_type_from_name(name_)
|
75
|
+
case name_.to_s
|
76
|
+
when /^geometry/i then ::RGeo::Feature::Geometry
|
77
|
+
when /^point/i then ::RGeo::Feature::Point
|
78
|
+
when /^linestring/i then ::RGeo::Feature::LineString
|
79
|
+
when /^polygon/i then ::RGeo::Feature::Polygon
|
80
|
+
when /^geometrycollection/i then ::RGeo::Feature::GeometryCollection
|
81
|
+
when /^multipoint/i then ::RGeo::Feature::MultiPoint
|
82
|
+
when /^multilinestring/i then ::RGeo::Feature::MultiLineString
|
83
|
+
when /^multipolygon/i then ::RGeo::Feature::MultiPolygon
|
84
|
+
else nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# :stopdoc:
|
90
|
+
|
91
|
+
|
92
|
+
# Provide methods for each geometric subtype during table definitions.
|
93
|
+
|
94
|
+
::ActiveRecord::ConnectionAdapters::TableDefinition.class_eval do
|
95
|
+
|
96
|
+
alias_method :method_missing_without_rgeo_modification, :method_missing
|
97
|
+
|
98
|
+
def method_missing(method_name_, *args_, &block_)
|
99
|
+
if @base.respond_to?(:spatial_column_constructor) && (info_ = @base.spatial_column_constructor(method_name_))
|
100
|
+
info_ = info_.dup
|
101
|
+
type_ = (info_.delete(:type) || method_name_).to_s
|
102
|
+
opts_ = args_.extract_options!.merge(info_)
|
103
|
+
args_.each do |name_|
|
104
|
+
column(name_, type_, opts_)
|
105
|
+
end
|
106
|
+
else
|
107
|
+
method_missing_without_rgeo_modification(method_name_, *args_, &block_)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
|
113
|
+
|
114
|
+
# Provide methods for each geometric subtype during table changes.
|
115
|
+
|
116
|
+
::ActiveRecord::ConnectionAdapters::Table.class_eval do
|
117
|
+
|
118
|
+
alias_method :method_missing_without_rgeo_modification, :method_missing
|
119
|
+
|
120
|
+
def method_missing(method_name_, *args_, &block_)
|
121
|
+
if @base.respond_to?(:spatial_column_constructor) && (info_ = @base.spatial_column_constructor(method_name_))
|
122
|
+
info_ = info_.dup
|
123
|
+
type_ = (info_.delete(:type) || method_name_).to_s
|
124
|
+
opts_ = args_.extract_options!.merge(info_)
|
125
|
+
args_.each do |name_|
|
126
|
+
@base.add_column(@table_name, name_, type_, opts_)
|
127
|
+
end
|
128
|
+
else
|
129
|
+
method_missing_without_rgeo_modification(method_name_, *args_, &block_)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# Hack schema dumper to output spatial index flag
|
137
|
+
|
138
|
+
::ActiveRecord::SchemaDumper.class_eval do
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
alias_method :_old_indexes_method, :indexes
|
143
|
+
|
144
|
+
def indexes(table_, stream_)
|
145
|
+
if (indexes_ = @connection.indexes(table_)).any?
|
146
|
+
add_index_statements_ = indexes_.map do |index_|
|
147
|
+
statement_parts_ = [
|
148
|
+
('add_index ' + index_.table.inspect),
|
149
|
+
index_.columns.inspect,
|
150
|
+
(':name => ' + index_.name.inspect),
|
151
|
+
]
|
152
|
+
statement_parts_ << ':unique => true' if index_.unique
|
153
|
+
statement_parts_ << ':spatial => true' if index_.respond_to?(:spatial) && index_.spatial
|
154
|
+
index_lengths_ = (index_.lengths || []).compact
|
155
|
+
statement_parts_ << (':length => ' + ::Hash[*index_.columns.zip(index_.lengths).flatten].inspect) unless index_lengths_.empty?
|
156
|
+
' ' + statement_parts_.join(', ')
|
157
|
+
end
|
158
|
+
stream_.puts add_index_statements_.sort.join("\n")
|
159
|
+
stream_.puts
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
|
165
|
+
|
166
|
+
# Tell ActiveRecord to cache spatial attribute values so they don't get
|
167
|
+
# re-parsed on every access.
|
168
|
+
|
169
|
+
::ActiveRecord::Base.attribute_types_cached_by_default << :spatial
|
170
|
+
|
171
|
+
|
172
|
+
# :startdoc:
|
173
|
+
|
174
|
+
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Geometry mixin for JSON serialization
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2010-2012 Daniel Azuma
|
7
|
+
#
|
8
|
+
# All rights reserved.
|
9
|
+
#
|
10
|
+
# Redistribution and use in source and binary forms, with or without
|
11
|
+
# modification, are permitted provided that the following conditions are met:
|
12
|
+
#
|
13
|
+
# * Redistributions of source code must retain the above copyright notice,
|
14
|
+
# this list of conditions and the following disclaimer.
|
15
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer in the documentation
|
17
|
+
# and/or other materials provided with the distribution.
|
18
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
19
|
+
# contributors to this software, may be used to endorse or promote products
|
20
|
+
# derived from this software without specific prior written permission.
|
21
|
+
#
|
22
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
23
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
24
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
25
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
26
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
27
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
28
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
29
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
30
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
31
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
32
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
33
|
+
# -----------------------------------------------------------------------------
|
34
|
+
;
|
35
|
+
|
36
|
+
|
37
|
+
module RGeo
|
38
|
+
|
39
|
+
module ActiveRecord
|
40
|
+
|
41
|
+
|
42
|
+
# This module is mixed into all geometry objects. It provides an
|
43
|
+
# as_json method so that ActiveRecord knows how to generate JSON
|
44
|
+
# for a geometry-valued field.
|
45
|
+
|
46
|
+
module GeometryMixin
|
47
|
+
|
48
|
+
|
49
|
+
# The default JSON generator Proc. Renders geometry fields as WKT.
|
50
|
+
DEFAULT_JSON_GENERATOR = ::Proc.new{ |geom_| geom_.to_s }
|
51
|
+
|
52
|
+
@json_generator = DEFAULT_JSON_GENERATOR
|
53
|
+
|
54
|
+
|
55
|
+
# Set the style of JSON generation used for geometry fields in an
|
56
|
+
# ActiveRecord model by default. You may pass nil to use
|
57
|
+
# DEFAULT_JSON_GENERATOR, a proc that takes a geometry as the
|
58
|
+
# argument and returns an object that can be converted to JSON
|
59
|
+
# (i.e. usually a hash or string), or one of the following symbolic
|
60
|
+
# values:
|
61
|
+
#
|
62
|
+
# <tt>:wkt</tt>::
|
63
|
+
# Well-known text format. (Same as DEFAULT_JSON_GENERATOR.)
|
64
|
+
# <tt>:geojson</tt>::
|
65
|
+
# GeoJSON format. Requires the rgeo-geojson gem.
|
66
|
+
|
67
|
+
def self.set_json_generator(value_=nil, &block_)
|
68
|
+
if block_ && !value_
|
69
|
+
value_ = block_
|
70
|
+
elsif value_ == :geojson
|
71
|
+
require 'rgeo/geo_json'
|
72
|
+
value_ = ::Proc.new{ |geom_| ::RGeo::GeoJSON.encode(geom_) }
|
73
|
+
end
|
74
|
+
if value_.is_a?(::Proc)
|
75
|
+
@json_generator = value_
|
76
|
+
else
|
77
|
+
@json_generator = DEFAULT_JSON_GENERATOR
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Given a feature, returns an object that can be serialized as JSON
|
83
|
+
# (i.e. usually a hash or string), using the current json_generator.
|
84
|
+
# This is used to generate JSON for geometry-valued ActiveRecord
|
85
|
+
# fields by default.
|
86
|
+
|
87
|
+
def self.generate_json(geom_)
|
88
|
+
@json_generator.call(geom_)
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Serializes this object as JSON for ActiveRecord.
|
93
|
+
|
94
|
+
def as_json(opts_=nil)
|
95
|
+
GeometryMixin.generate_json(self)
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
::RGeo::Feature::MixinCollection::GLOBAL.for_type(::RGeo::Feature::Geometry).
|
108
|
+
add(::RGeo::ActiveRecord::GeometryMixin)
|