rgeo 0.1.20 → 0.1.21

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 (55) hide show
  1. data/History.rdoc +10 -0
  2. data/README.rdoc +38 -35
  3. data/Version +1 -1
  4. data/lib/active_record/connection_adapters/mysql2spatial_adapter.rb +1 -3
  5. data/lib/active_record/connection_adapters/mysqlspatial_adapter.rb +4 -4
  6. data/lib/active_record/connection_adapters/postgis_adapter.rb +426 -0
  7. data/lib/active_record/connection_adapters/spatialite_adapter.rb +488 -0
  8. data/lib/rgeo.rb +10 -29
  9. data/lib/rgeo/active_record/arel_modifications.rb +1 -0
  10. data/lib/rgeo/active_record/base_modifications.rb +27 -10
  11. data/lib/rgeo/active_record/common.rb +128 -0
  12. data/lib/rgeo/active_record/mysql_common.rb +14 -51
  13. data/lib/rgeo/cartesian/factory.rb +2 -2
  14. data/lib/rgeo/coord_sys.rb +1 -1
  15. data/lib/rgeo/coord_sys/proj4.rb +3 -2
  16. data/lib/rgeo/error.rb +0 -3
  17. data/lib/rgeo/feature.rb +1 -3
  18. data/lib/rgeo/feature/factory_generator.rb +8 -0
  19. data/lib/rgeo/geography/factory.rb +2 -2
  20. data/lib/rgeo/geography/interface.rb +3 -3
  21. data/lib/rgeo/geos/zm_factory.rb +2 -2
  22. data/lib/rgeo/wkrep/wkb_parser.rb +35 -36
  23. data/lib/rgeo/wkrep/wkt_parser.rb +36 -38
  24. data/test/active_record/common_setup_methods.rb +129 -0
  25. data/test/active_record/readme.txt +10 -0
  26. data/test/active_record/tc_mysqlspatial.rb +22 -71
  27. data/test/active_record/tc_postgis.rb +282 -0
  28. data/test/active_record/tc_spatialite.rb +198 -0
  29. data/test/coord_sys/tc_proj4.rb +12 -5
  30. data/test/projected_geography/tc_geometry_collection.rb +1 -1
  31. data/test/projected_geography/tc_line_string.rb +1 -1
  32. data/test/projected_geography/tc_multi_line_string.rb +1 -1
  33. data/test/projected_geography/tc_multi_point.rb +1 -1
  34. data/test/projected_geography/tc_multi_polygon.rb +2 -2
  35. data/test/projected_geography/tc_point.rb +4 -4
  36. data/test/projected_geography/tc_polygon.rb +1 -1
  37. data/test/simple_mercator/tc_geometry_collection.rb +1 -1
  38. data/test/simple_mercator/tc_line_string.rb +1 -1
  39. data/test/simple_mercator/tc_multi_line_string.rb +1 -1
  40. data/test/simple_mercator/tc_multi_point.rb +1 -1
  41. data/test/simple_mercator/tc_multi_polygon.rb +2 -2
  42. data/test/simple_mercator/tc_point.rb +4 -4
  43. data/test/simple_mercator/tc_polygon.rb +1 -1
  44. data/test/simple_mercator/tc_window.rb +1 -1
  45. data/test/spherical_geography/tc_geometry_collection.rb +1 -1
  46. data/test/spherical_geography/tc_line_string.rb +1 -1
  47. data/test/spherical_geography/tc_multi_line_string.rb +1 -1
  48. data/test/spherical_geography/tc_multi_point.rb +1 -1
  49. data/test/spherical_geography/tc_multi_polygon.rb +2 -2
  50. data/test/spherical_geography/tc_point.rb +4 -4
  51. data/test/spherical_geography/tc_polygon.rb +1 -1
  52. data/test/tc_oneoff.rb +3 -3
  53. data/test/wkrep/tc_wkb_parser.rb +14 -14
  54. data/test/wkrep/tc_wkt_parser.rb +37 -45
  55. metadata +10 -3
data/lib/rgeo.rb CHANGED
@@ -79,6 +79,13 @@
79
79
  # an industry standard (if somewhat legacy) file format commonly used for
80
80
  # providing geographic data sets.
81
81
  #
82
+ # The RGeo::ActiveRecord module contains ActiveRecord connection adapters
83
+ # for handling spatial data with MySQL Spatial, SpatiaLite, and PostGIS.
84
+ # See the RGeo::ActiveRecord rdocs for more information on using these
85
+ # adapters. However, you do not need to access or require this module
86
+ # directly from code. ActiveRecord will load these adapters automatically
87
+ # when they are requested.
88
+ #
82
89
  # === Loading the library
83
90
  #
84
91
  # After installing the RGeo gem, you can load the library with:
@@ -102,42 +109,16 @@
102
109
  # require 'rgeo/shapefile'
103
110
  # require 'rgeo/wkrep'
104
111
  #
105
- # === Spatial connection adapters for ActiveRecord
106
- #
107
- # RGeo also provides ActiveRecord connection adapters for common spatial
108
- # databases. You can specify and use these connection adapters in the same
109
- # way you use any other connection adapter, for example by specifying the
110
- # adapter name in a Rails application's database.yml file. You do not need
111
- # to require any files to gain access to these adapters. RGeo makes them
112
- # available to ActiveRecord automatically.
113
- #
114
- # These adapters are:
115
- #
116
- # <tt>mysqlspatial</tt>::
117
- # An adapter based on the standard mysql adapter. It extends the stock
118
- # adapter to provide support for spatial columns in MySQL, mapping the
119
- # values properly to RGeo spatial objects. Like the standard mysql
120
- # adapter, this requires the mysql gem (version 2.8 or later).
121
- # <tt>mysql2spatial</tt>::
122
- # An adapter for MySQL spatial based on the mysql2 adapter. It requires
123
- # the mysql2 gem (version 0.2.6 or later).
124
- # <tt>spatialite</tt>::
125
- # An adapter for the SpatiaLite extension to Sqlite3. It is based on
126
- # the stock sqlite3 adapter, and requires the sqlite3-ruby gem.
127
- # <b>(INCOMPLETE)</b>
128
- # <tt>postgis</tt>::
129
- # An adapter for the PostGIS extension to Postgresql. It is based on
130
- # the stock postgres adapter, and requires the pg gem.
131
- # <b>(INCOMPLETE)</b>
112
+ # You do not need to explicitly require any files for access to the
113
+ # spatial ActiveRecord adapters. ActiveRecord will load them
114
+ # automatically when they are referenced.
132
115
 
133
116
  module RGeo
134
117
 
135
118
  autoload(:Cartesian, 'rgeo/cartesian')
136
119
  autoload(:CoordSys, 'rgeo/coord_sys')
137
120
  autoload(:Error, 'rgeo/error')
138
- autoload(:Errors, 'rgeo/error')
139
121
  autoload(:Feature, 'rgeo/feature')
140
- autoload(:Features, 'rgeo/feature')
141
122
  autoload(:GeoJSON, 'rgeo/geo_json')
142
123
  autoload(:Geography, 'rgeo/geography')
143
124
  autoload(:Geos, 'rgeo/geos')
@@ -68,6 +68,7 @@ module Arel
68
68
 
69
69
  VISITORS['postgis'] = ::Arel::Visitors::PostgreSQL
70
70
  VISITORS['mysqlspatial'] = ::Arel::Visitors::MySQL
71
+ VISITORS['mysql2spatial'] = ::Arel::Visitors::MySQL
71
72
  VISITORS['spatialite'] = ::Arel::Visitors::SQLite
72
73
 
73
74
  end
@@ -58,11 +58,6 @@ module ActiveRecord
58
58
  # obtain a factory with those properties. This factory is the one
59
59
  # associated with the actual geometry properties of the ActiveRecord
60
60
  # object.
61
- #
62
- # === ActiveRecord::Base::rgeo_default_factory
63
- #
64
- # The default factory used to load RGeo geometry objects from the
65
- # database. This is used when there is no rgeo_factory_generator.
66
61
 
67
62
  class Base
68
63
 
@@ -70,11 +65,14 @@ module ActiveRecord
70
65
  self.attribute_types_cached_by_default << :geometry
71
66
 
72
67
 
73
- class_attribute :rgeo_default_factory, :instance_writer => false
74
- self.rgeo_default_factory = nil
75
-
76
68
  class_attribute :rgeo_factory_generator, :instance_writer => false
77
- self.rgeo_factory_generator = nil
69
+ self.rgeo_factory_generator = ::Proc.new do |config_|
70
+ if config_.delete(:geographic)
71
+ ::RGeo::Geography.spherical_factory(config_)
72
+ else
73
+ ::RGeo::Cartesian.preferred_factory(config_)
74
+ end
75
+ end
78
76
 
79
77
 
80
78
  # This is a convenient way to set the rgeo_factory_generator by
@@ -92,7 +90,7 @@ module ActiveRecord
92
90
  def columns
93
91
  unless defined?(@columns) && @columns
94
92
  columns_without_rgeo_modification.each do |column_|
95
- column_.ar_class = self if column_.respond_to?(:ar_class=)
93
+ column_.set_ar_class(self) if column_.respond_to?(:set_ar_class)
96
94
  end
97
95
  end
98
96
  @columns
@@ -104,4 +102,23 @@ module ActiveRecord
104
102
  end
105
103
 
106
104
 
105
+ module ConnectionAdapters # :nodoc:
106
+
107
+ class TableDefinition # :nodoc:
108
+
109
+ ::RGeo::ActiveRecord::GEOMETRY_TYPES.each do |type_|
110
+ method_ = <<-END_METHOD
111
+ def #{type_}(*args_)
112
+ opts_ = args_.extract_options!
113
+ args_.each{ |name_| column(name_, '#{type_}', opts_) }
114
+ end
115
+ END_METHOD
116
+ class_eval(method_, __FILE__, __LINE__-5)
117
+ end
118
+
119
+ end
120
+
121
+ end
122
+
123
+
107
124
  end
@@ -34,5 +34,133 @@
34
34
  ;
35
35
 
36
36
 
37
+ require 'rgeo/feature'
38
+ require 'rgeo/cartesian'
39
+ require 'rgeo/geography'
40
+
41
+
42
+ module RGeo
43
+
44
+
45
+ # RGeo provides ActiveRecord connection adapters for common spatial
46
+ # databases. They cause ActiveRecord to make spatial database fields
47
+ # available as RGeo feature objects instead of internally-coded data.
48
+ # They also provide extensions to the schema management APIs for
49
+ # creating spatial columns and spatial indexes.
50
+ #
51
+ # You can specify and use these connection adapters in the same way you
52
+ # use any other connection adapter, for example by specifying the
53
+ # adapter name in a Rails application's database.yml file. You do not
54
+ # need to require any files to gain access to these adapters. RGeo
55
+ # makes them available to ActiveRecord automatically.
56
+ #
57
+ # The RGeo::ActiveRecord module itself is a namespace for the internal
58
+ # adapter implementation. You generally do not need to interact with
59
+ # this module yourself.
60
+ #
61
+ # Following is a list of the adapters supported by RGeo.
62
+ #
63
+ # === mysqlspatial
64
+ #
65
+ # An adapter based on the standard mysql adapter. It extends the stock
66
+ # adapter to provide support for spatial columns in MySQL, mapping the
67
+ # values properly to RGeo spatial objects. Like the standard mysql
68
+ # adapter, this requires the mysql gem (version 2.8 or later).
69
+ #
70
+ # In a database.yml configuration, mysqlspatial uses the same config
71
+ # parameters as the stock mysql adapter.
72
+ #
73
+ # STATUS: The mysqlspatial adapter is fairly complete, and there are no
74
+ # known functionality holes at this time. However, it is not yet
75
+ # well-tested.
76
+ #
77
+ # === mysql2spatial
78
+ #
79
+ # An adapter for MySQL spatial based on the mysql2 adapter. It requires
80
+ # the mysql2 gem (version 0.2.6 or later).
81
+ #
82
+ # In a database.yml configuration, mysql2spatial uses the same config
83
+ # parameters as the stock mysql2 adapter.
84
+ #
85
+ # STATUS: The mysql2spatial adapter is fairly complete, and there are
86
+ # no known functionality holes at this time. However, it is not yet
87
+ # well-tested.
88
+ #
89
+ # === spatialite
90
+ #
91
+ # An adapter for the SpatiaLite extension to Sqlite3. It is based on
92
+ # the stock sqlite3 adapter, and requires the sqlite3-ruby gem.
93
+ #
94
+ # In a database.yml configuration, in addition to the config parameters
95
+ # used by the stock sqlite3 adapter, spatialite recognizes the
96
+ # following parameters:
97
+ #
98
+ # <tt>libspatialite</tt>::
99
+ # The path to the libspatialite shared library. By default, the
100
+ # adapter tries to look for this library in several usual places,
101
+ # including /usr/local, /usr/local/spatialite, /opt/local, /usr,
102
+ # and a few others. If it does not find libspatialite installed in
103
+ # one of these locations, it will raise an exception. If your
104
+ # library is installed in a different place, you can explicitly
105
+ # provide the path using this configuration key.
106
+ #
107
+ # STATUS: The spatialite adapter works in principle, but there are a
108
+ # few known holes in the functionality. Notably, things that require
109
+ # the alter_table mechanism may not function properly, because the
110
+ # current sqlite3 implementation doesn't properly preserve triggers.
111
+ # This includes, among other things, removing columns. However, most
112
+ # simple things work, including creating tables with geometric columns,
113
+ # adding geometric columns to existing tables, and creating and
114
+ # removing spatial R*tree indexes. Note that this adapter is not yet
115
+ # well-tested.
116
+ #
117
+ # === postgis
118
+ #
119
+ # An adapter for the PostGIS extension to Postgresql. It is based on
120
+ # the stock postgresql adapter, and requires the pg gem.
121
+ #
122
+ # In a database.yml configuration, postgis uses the same config
123
+ # parameters as the stock postgresql adapter.
124
+ #
125
+ # STATUS: The postgis adapter works in principle, but there are a
126
+ # few known holes in the functionality. Notably, getting index info
127
+ # doesn't recognize spatial (GiST) indexes. Also be aware that this
128
+ # adapter is not yet well-tested.
129
+
130
+ module ActiveRecord
131
+
132
+ # Additional column types for geometries.
133
+ GEOMETRY_TYPES = [:geometry, :point, :line_string, :polygon, :geometry_collection, :multi_line_string, :multi_point, :multi_polygon].freeze
134
+
135
+ module Common # :nodoc:
136
+
137
+ class IndexDefinition < ::Struct.new(:table, :name, :unique, :columns, :lengths, :spatial) # :nodoc:
138
+ end
139
+
140
+ class << self
141
+
142
+ def geometric_type_from_name(name_)
143
+ case name_.downcase
144
+ when 'geometry' then ::RGeo::Feature::Geometry
145
+ when 'point' then ::RGeo::Feature::Point
146
+ when 'linestring' then ::RGeo::Feature::LineString
147
+ when 'polygon' then ::RGeo::Feature::Polygon
148
+ when 'geometrycollection' then ::RGeo::Feature::GeometryCollection
149
+ when 'multipoint' then ::RGeo::Feature::MultiPoint
150
+ when 'multilinestring' then ::RGeo::Feature::MultiLineString
151
+ when 'multipolygon' then ::RGeo::Feature::MultiPolygon
152
+ else nil
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+
160
+ end
161
+
162
+ end
163
+
164
+
37
165
  require 'rgeo/active_record/arel_modifications'
38
166
  require 'rgeo/active_record/base_modifications'
@@ -42,7 +42,7 @@ require 'rgeo/active_record/common'
42
42
 
43
43
  module RGeo
44
44
 
45
- module ActiveRecord # :nodoc:
45
+ module ActiveRecord
46
46
 
47
47
 
48
48
  module MysqlCommon # :nodoc:
@@ -76,29 +76,25 @@ module RGeo
76
76
  end
77
77
 
78
78
 
79
- class IndexDefinition < ::ActiveRecord::ConnectionAdapters::IndexDefinition # :nodoc:
80
-
81
- attr_accessor :spatial
82
-
83
- end
84
-
85
-
86
79
  module ColumnMethods # :nodoc:
87
80
 
88
81
 
89
82
  def initialize(name_, default_, sql_type_=nil, null_=true)
90
83
  super(name_, default_,sql_type_, null_)
91
- @geometric_type = extract_geometric_type(sql_type_)
92
- @ar_class = nil
84
+ @geometric_type = ::RGeo::ActiveRecord::Common.geometric_type_from_name(sql_type_)
85
+ @ar_class = ::ActiveRecord::Base
93
86
  end
94
87
 
95
88
 
96
- attr_writer :ar_class
89
+ def set_ar_class(val_)
90
+ @ar_class = val_
91
+ end
92
+
97
93
 
98
94
  attr_reader :geometric_type
99
95
 
100
96
 
101
- def geometry?
97
+ def spatial?
102
98
  type == :geometry
103
99
  end
104
100
 
@@ -109,32 +105,17 @@ module RGeo
109
105
 
110
106
 
111
107
  def type_cast(value_)
112
- self.geometry? ? ColumnMethods.string_to_geometry(value_, @ar_class) : super
108
+ type == :geometry ? ColumnMethods.string_to_geometry(value_, @ar_class) : super
113
109
  end
114
110
 
115
111
 
116
112
  def type_cast_code(var_name_)
117
- self.geometry? ? "::RGeo::ActiveRecord::MysqlCommon::ColumnMethods.string_to_geometry(#{var_name_}, self.class)" : super
113
+ type == :geometry ? "::RGeo::ActiveRecord::MysqlCommon::ColumnMethods.string_to_geometry(#{var_name_}, self.class)" : super
118
114
  end
119
115
 
120
116
 
121
117
  private
122
118
 
123
- def extract_geometric_type(sql_type_)
124
- case sql_type_
125
- when /^geometry$/i then ::RGeo::Feature::Geometry
126
- when /^point$/i then ::RGeo::Feature::Point
127
- when /^linestring$/i then ::RGeo::Feature::LineString
128
- when /^polygon$/i then ::RGeo::Feature::Polygon
129
- when /^geometrycollection$/i then ::RGeo::Feature::GeometryCollection
130
- when /^multipoint$/i then ::RGeo::Feature::MultiPoint
131
- when /^multilinestring$/i then ::RGeo::Feature::MultiLineString
132
- when /^multipolygon$/i then ::RGeo::Feature::MultiPolygon
133
- else nil
134
- end
135
- end
136
-
137
-
138
119
  def simplified_type(sql_type_)
139
120
  sql_type_ =~ /geometry|point|linestring|polygon/i ? :geometry : super
140
121
  end
@@ -146,29 +127,11 @@ module RGeo
146
127
  str_
147
128
  when ::String
148
129
  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_)
130
+ factory_generator_ = ar_class_.rgeo_factory_generator
131
+ if marker_ == "\x00" || marker_ == "\x01"
132
+ ::RGeo::WKRep::WKBParser.new(factory_generator_, :default_srid => str_[0,4].unpack(marker_ == "\x01" ? 'V' : 'N').first).parse(str_[4..-1])
170
133
  else
171
- ::RGeo::WKRep::WKBParser.new(:default_factory => default_factory_).parse(str_[4..-1])
134
+ ::RGeo::WKRep::WKTParser.new(factory_generator_, :support_ewkt => true).parse(str_)
172
135
  end
173
136
  else
174
137
  nil
@@ -100,14 +100,14 @@ module RGeo
100
100
  # See ::RGeo::Feature::Factory#parse_wkt
101
101
 
102
102
  def parse_wkt(str_)
103
- WKRep::WKTParser.new(:default_factory => self).parse(str_)
103
+ WKRep::WKTParser.new(self).parse(str_)
104
104
  end
105
105
 
106
106
 
107
107
  # See ::RGeo::Feature::Factory#parse_wkb
108
108
 
109
109
  def parse_wkb(str_)
110
- WKRep::WKBParser.new(:default_factory => self).parse(str_)
110
+ WKRep::WKBParser.new(self).parse(str_)
111
111
  end
112
112
 
113
113
 
@@ -1,6 +1,6 @@
1
1
  # -----------------------------------------------------------------------------
2
2
  #
3
- # GEOS wrapper for RGeo
3
+ # Coordinate systems for RGeo
4
4
  #
5
5
  # -----------------------------------------------------------------------------
6
6
  # Copyright 2010 Daniel Azuma
@@ -54,7 +54,7 @@ module RGeo
54
54
 
55
55
 
56
56
  def inspect # :nodoc:
57
- "#<#{self.class}:0x#{object_id.to_s(16)} #{_canonical_str.inspect}>"
57
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{canonical_str.inspect}>"
58
58
  end
59
59
 
60
60
 
@@ -78,8 +78,9 @@ module RGeo
78
78
  # system.
79
79
 
80
80
  def eql?(rhs_)
81
- rhs_.is_a?(Proj4) && rhs_._canonical_hash == canonical_hash
81
+ rhs_.class == self.class && rhs_.canonical_hash == canonical_hash
82
82
  end
83
+ alias_method :==, :eql?
83
84
 
84
85
 
85
86
  # Returns the "canonical" string definition for this coordinate
data/lib/rgeo/error.rb CHANGED
@@ -63,8 +63,5 @@ module RGeo
63
63
 
64
64
  end
65
65
 
66
- # Deprecated alias
67
- Errors = Error
68
-
69
66
 
70
67
  end
data/lib/rgeo/feature.rb CHANGED
@@ -68,9 +68,6 @@ module RGeo
68
68
  module Feature
69
69
  end
70
70
 
71
- # Deprecated alias
72
- Features = Feature
73
-
74
71
 
75
72
  end
76
73
 
@@ -95,3 +92,4 @@ require 'rgeo/feature/multi_curve'
95
92
  require 'rgeo/feature/multi_line_string'
96
93
  require 'rgeo/feature/multi_surface'
97
94
  require 'rgeo/feature/multi_polygon'
95
+ require 'rgeo/feature/factory_generator'