rgeo 0.1.16 → 0.1.17

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.
@@ -0,0 +1,38 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Common tools for spatial adapters for ActiveRecord
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 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 'rgeo/active_record/arel_modifications'
38
+ require 'rgeo/active_record/base_modifications'
@@ -0,0 +1,187 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # MysqlSpatial adapter common tools for ActiveRecord
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 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 'rgeo/features'
38
+ require 'rgeo/cartesian'
39
+ require 'rgeo/wkrep'
40
+ require 'rgeo/active_record/common'
41
+
42
+
43
+ module RGeo
44
+
45
+ module ActiveRecord
46
+
47
+
48
+ module MysqlCommon
49
+
50
+
51
+ module AdapterMethods # :nodoc:
52
+
53
+
54
+ def quote(value_, column_=nil)
55
+ if ::RGeo::Features::Geometry.check_type(value_)
56
+ "GeomFromWKB(0x#{::RGeo::WKRep::WKBGenerator.new(:hex_format => true).generate(value_)},#{value_.srid})"
57
+ else
58
+ super
59
+ end
60
+ end
61
+
62
+
63
+ def add_index(table_name_, column_name_, options_={})
64
+ if options_[:spatial]
65
+ index_name_ = index_name(table_name_, :column => Array(column_name_))
66
+ if ::Hash === options_
67
+ index_name_ = options_[:name] || index_name_
68
+ end
69
+ execute "CREATE SPATIAL INDEX #{index_name_} ON #{table_name_} (#{Array(column_name_).join(", ")})"
70
+ else
71
+ super
72
+ end
73
+ end
74
+
75
+
76
+ end
77
+
78
+
79
+ class IndexDefinition < ::ActiveRecord::ConnectionAdapters::IndexDefinition # :nodoc:
80
+
81
+ attr_accessor :spatial
82
+
83
+ end
84
+
85
+
86
+ module ColumnMethods # :nodoc:
87
+
88
+
89
+ def initialize(name_, default_, sql_type_=nil, null_=true)
90
+ super(name_, default_,sql_type_, null_)
91
+ @geometric_type = extract_geometric_type(sql_type_)
92
+ @ar_class = nil
93
+ end
94
+
95
+
96
+ attr_writer :ar_class
97
+
98
+ attr_reader :geometric_type
99
+
100
+
101
+ def geometry?
102
+ type == :geometry
103
+ end
104
+
105
+
106
+ def klass
107
+ type == :geometry ? ::RGeo::Features::Geometry : super
108
+ end
109
+
110
+
111
+ def type_cast(value_)
112
+ self.geometry? ? ColumnMethods.string_to_geometry(value_, @ar_class) : super
113
+ end
114
+
115
+
116
+ def type_cast_code(var_name_)
117
+ self.geometry? ? "::RGeo::ActiveRecord::MysqlCommon::ColumnMethods.string_to_geometry(#{var_name_}, self.class)" : super
118
+ end
119
+
120
+
121
+ private
122
+
123
+ def extract_geometric_type(sql_type_)
124
+ case sql_type_
125
+ when /^geometry$/i then ::RGeo::Features::Geometry
126
+ when /^point$/i then ::RGeo::Features::Point
127
+ when /^linestring$/i then ::RGeo::Features::LineString
128
+ when /^polygon$/i then ::RGeo::Features::Polygon
129
+ when /^geometrycollection$/i then ::RGeo::Features::GeometryCollection
130
+ when /^multipoint$/i then ::RGeo::Features::MultiPoint
131
+ when /^multilinestring$/i then ::RGeo::Features::MultiLineString
132
+ when /^multipolygon$/i then ::RGeo::Features::MultiPolygon
133
+ else nil
134
+ end
135
+ end
136
+
137
+
138
+ def simplified_type(sql_type_)
139
+ sql_type_ =~ /geometry|point|linestring|polygon/i ? :geometry : super
140
+ end
141
+
142
+
143
+ def self.string_to_geometry(str_, ar_class_)
144
+ case str_
145
+ when ::RGeo::Features::Geometry
146
+ str_
147
+ when ::String
148
+ marker_ = str_[4,1]
149
+ little_endian_ = marker_ == "\x01"
150
+ wkt_ = !little_endian_ && marker_ != "\x00"
151
+ srid_ = wkt_ ? 0 : str_[0,4].unpack(little_endian_ ? 'V' : 'N').first
152
+ factory_generator_ = nil
153
+ in_factory_generator_ = ar_class_ ? ar_class_.rgeo_factory_generator : nil
154
+ default_factory_ = ar_class_ ? ar_class_.rgeo_default_factory : nil
155
+ if default_factory_ || in_factory_generator_
156
+ if in_factory_generator_
157
+ default_factory_ ||= factory_generator_.call(:srid => srid_)
158
+ if wkt_
159
+ factory_generator_ = in_factory_generator_
160
+ end
161
+ end
162
+ else
163
+ default_factory_ = ::RGeo::Cartesian.preferred_factory(:srid => srid_)
164
+ if wkt_
165
+ factory_generator_ = ::RGeo::Cartesian.method(:preferred_factory)
166
+ end
167
+ end
168
+ if wkt_
169
+ ::RGeo::WKRep::WKTParser.new(:support_ewkt => true, :default_factory => default_factory_, :factory_generator => factory_generator_).parse(str_)
170
+ else
171
+ ::RGeo::WKRep::WKBParser.new(:default_factory => default_factory_).parse(str_[4..-1])
172
+ end
173
+ else
174
+ nil
175
+ end
176
+ end
177
+
178
+
179
+ end
180
+
181
+
182
+ end
183
+
184
+
185
+ end
186
+
187
+ end
@@ -227,19 +227,24 @@ module RGeo
227
227
  # factory, and will be passed the original object (which may or may
228
228
  # not already be created by this factory), the SFS feature type
229
229
  # (which again may or may not already be the type of the original
230
- # object), a flag indicating whether to keep the subtype if casting
231
- # to a supertype of the current type, and a flag indicating whether
232
- # to force the creation of a new object even if the original is
233
- # already of the desired factory and type.
230
+ # object), and a hash of additional flags. These flags are:
231
+ #
232
+ # <tt>:keep_subtype</tt>::
233
+ # indicates whether to keep the subtype if casting to a supertype
234
+ # of the current type
235
+ # <tt>:force_new</tt>::
236
+ # indicates whether to force the creation of a new object even if
237
+ # the original is already of the desired factory and type.
234
238
  #
235
239
  # It should return either a casted result object, false, or nil.
236
240
  # A nil return value indicates that casting should be forced to
237
241
  # fail (and ::RGeo::Features::cast will return nil).
238
242
  # A false return value indicates that this method declines to
239
243
  # override the casting algorithm, and RGeo should use its default
240
- # algorithm to cast the object.
244
+ # algorithm to cast the object. Therefore, by default, you should
245
+ # return false.
241
246
 
242
- def override_cast(original_, type_, keep_subtype_, force_new_)
247
+ def override_cast(original_, type_, flags_)
243
248
  false
244
249
  end
245
250
 
@@ -0,0 +1,109 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Feature factory interface
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2010 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 Features
40
+
41
+
42
+ # A FactoryGenerator is a callable object (usually a Proc) that
43
+ # takes a configuration as a hash and returns a factory. These are
44
+ # often used, e.g., by parsers to determine what factory the parsed
45
+ # geometry should have.
46
+ #
47
+ # See the call method for a list of common configuration parameters.
48
+ # Different generators will support different parameters. There is
49
+ # no mechanism defined to reflect on the capabilities of a factory
50
+ # generator.
51
+ #
52
+ # Many of the implementations provide a factory method for creating
53
+ # factories. For example, RGeo::Cartesian::preferred_factory can be
54
+ # called to create a factory using the preferred Cartesian
55
+ # implementation. Thus, to get a corresponding factory generator,
56
+ # you can use the <tt>method</tt> method. e.g.
57
+ #
58
+ # factory_generator = ::RGeo::Cartesian.method(:preferred_factory)
59
+ #
60
+ # FactoryGenerator is defined as a module and is provided
61
+ # primarily for the sake of documentation. Implementations need not
62
+ # necessarily include this module itself. Therefore, you should not
63
+ # depend on the kind_of? method to determine if an object is a
64
+ # factory generator.
65
+
66
+ module FactoryGenerator
67
+
68
+
69
+ # Generate a factory given a configuration as a hash.
70
+ #
71
+ # If the generator does not recognize or does not support a given
72
+ # configuration value, the behavior is usually determined by the
73
+ # <tt>:strict</tt> configuration element. If <tt>strict</tt> is
74
+ # set to true, the generator should fail fast and return nil or
75
+ # raise an exception. If it is set to false, the generator should
76
+ # attempt to do the best it can, even if it means returning a
77
+ # factory that does not match the requested configuration.
78
+ #
79
+ # Common parameters are as follows. These are intended as a
80
+ # recommendation only. There is no hard requirement for any
81
+ # particular factory generator to support them.
82
+ #
83
+ # <tt>:strict</tt>::
84
+ # If true, return nil or raise an exception if any configuration
85
+ # was not recognized or not supportable. Otherwise, if false,
86
+ # the generator should attempt to do its best to return some
87
+ # viable factory, even if it does not strictly match the
88
+ # requested configuration. Default is usually false.
89
+ # <tt>:srid</tt>::
90
+ # The SRID for the factory and objects it creates.
91
+ # Default is usually 0.
92
+ # <tt>:support_z_coordinate</tt>::
93
+ # Support the <tt>z_coordinate</tt> capability.
94
+ # Default is usually false.
95
+ # <tt>:support_m_coordinate</tt>::
96
+ # Support the <tt>m_coordinate</tt> capability.
97
+ # Default is usually false.
98
+
99
+ def call(config_={})
100
+ nil
101
+ end
102
+
103
+
104
+ end
105
+
106
+
107
+ end
108
+
109
+ end
@@ -160,7 +160,7 @@ module RGeo
160
160
 
161
161
  # Let the factory override
162
162
  if nfactory_.respond_to?(:override_cast)
163
- override_ = nfactory_.override_cast(obj_, ntype_, keep_subtype_, force_new_)
163
+ override_ = nfactory_.override_cast(obj_, ntype_, :keep_subtype => keep_subtype_, :force_new => force_new_)
164
164
  return override_ unless override_ == false
165
165
  end
166
166
 
@@ -207,8 +207,10 @@ module RGeo
207
207
 
208
208
  # See ::RGeo::Features::Factory#override_cast
209
209
 
210
- def override_cast(original_, ntype_, keep_subtype_, force_new_)
210
+ def override_cast(original_, ntype_, flags_)
211
211
  return nil unless Geos.supported?
212
+ keep_subtype_ = flags_[:keep_subtype]
213
+ force_new_ = flags_[:force_new]
212
214
  if GeometryImpl === original_
213
215
  type_ = original_.geometry_type
214
216
  ntype_ = type_ if keep_subtype_ && type_.include?(ntype_)
@@ -53,14 +53,17 @@ module RGeo
53
53
  # constructor, or set on the object afterwards.
54
54
  #
55
55
  # <tt>:default_factory</tt>::
56
- # The default factory for generated geometries, used when no SRID
57
- # is explicitly specified in the input. If none is provided, the
58
- # default cartesian factory will be used.
59
- # <tt>:factory_from_srid</tt>::
60
- # A Proc that takes an SRID as the sole argument, and returns a
61
- # factory for generated geometries when that SRID is specified in
62
- # the input. If no such Proc is provided, the default_factory is
63
- # used, regardless of the input SRID.
56
+ # The default factory for parsed geometries, used when no factory
57
+ # generator is provided. If no default is provided either, the
58
+ # default cartesian factory will be used as the default.
59
+ # <tt>:factory_generator</tt>::
60
+ # A factory generator that should return a factory based on the
61
+ # srid and dimension settings in the input. The factory generator
62
+ # should understand the configuration options <tt>:srid</tt>,
63
+ # <tt>:support_z_coordinate</tt>, and <tt>:support_m_coordinate</tt>.
64
+ # See RGeo::Features::FactoryGenerator for more information.
65
+ # If no generator is provided, the <tt>:default_factory</tt> is
66
+ # used.
64
67
  # <tt>:support_ewkb</tt>::
65
68
  # Activate support for PostGIS EWKB type codes, which use high
66
69
  # order bits in the type code to signal the presence of Z, M, and
@@ -82,7 +85,7 @@ module RGeo
82
85
 
83
86
  def initialize(opts_={})
84
87
  @default_factory = opts_[:default_factory] || Cartesian.preferred_factory
85
- @factory_from_srid = opts_[:factory_from_srid]
88
+ @factory_generator = opts_[:factory_generator]
86
89
  @support_ewkb = opts_[:support_ewkb] ? true : false
87
90
  @support_wkb12 = opts_[:support_wkb12] ? true : false
88
91
  @ignore_extra_bytes = opts_[:ignore_extra_bytes] ? true : false
@@ -99,21 +102,21 @@ module RGeo
99
102
  @default_factory = value_ || Cartesian.preferred_factory
100
103
  end
101
104
 
102
- # Returns true if this parser has a factory_from_srid procedure.
105
+ # Returns the factory generator, or nil if there is none.
103
106
  # See WKBParser for details.
104
- def has_factory_from_srid?
105
- @factory_from_srid ? true : false
107
+ def factory_generator
108
+ @factory_generator
106
109
  end
107
110
 
108
- # Sets the factory_from_srid. See WKBParser for details.
109
- def factory_from_srid=(value_)
110
- @factory_from_srid = value_
111
+ # Sets the factory_generator. See WKBParser for details.
112
+ def factory_generator=(value_)
113
+ @factory_generator = value_
111
114
  end
112
115
 
113
- # Sets the factory_from_srid to the given block.
116
+ # Sets the factory_generator to the given block.
114
117
  # See WKBParser for details.
115
- def set_factory_from_srid(&block_)
116
- @factory_from_srid = block_
118
+ def to_generate_factory(&block_)
119
+ @factory_generator = block_
117
120
  end
118
121
 
119
122
  # Returns true if this parser supports EWKB.
@@ -215,9 +218,9 @@ module RGeo
215
218
  @cur_has_z = has_z_
216
219
  @cur_has_m = has_m_
217
220
  @cur_dims = 2 + (@cur_has_z ? 1 : 0) + (@cur_has_m ? 1 : 0)
218
- @cur_srid = srid_
219
- if srid_ && @factory_from_srid
220
- @cur_factory = @factory_from_srid.call(srid_)
221
+ @cur_srid = srid_.to_i
222
+ if @factory_generator
223
+ @cur_factory = @factory_generator.call(:srid => @cur_srid, :support_z_coordinate => has_z_, :support_m_coordinate => has_m_)
221
224
  end
222
225
  if @cur_has_z && !@cur_factory.has_capability?(:z_coordinate)
223
226
  raise Errors::ParseError, "Data has Z coordinates but the factory doesn't have z_coordinate capability"