activerecord-spatial 0.0.1

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 (47) hide show
  1. checksums.yaml +15 -0
  2. data/.gitignore +16 -0
  3. data/Gemfile +21 -0
  4. data/Guardfile +17 -0
  5. data/MIT-LICENSE +23 -0
  6. data/README.rdoc +169 -0
  7. data/Rakefile +28 -0
  8. data/activerecord-spatial.gemspec +26 -0
  9. data/lib/activerecord-spatial.rb +32 -0
  10. data/lib/activerecord-spatial/active_record.rb +14 -0
  11. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/adapter_extensions.rb +36 -0
  12. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/postgis.rb +24 -0
  13. data/lib/activerecord-spatial/active_record/connection_adapters/postgresql/unknown_srid.rb +21 -0
  14. data/lib/activerecord-spatial/active_record/models/geography_column.rb +17 -0
  15. data/lib/activerecord-spatial/active_record/models/geometry_column.rb +17 -0
  16. data/lib/activerecord-spatial/active_record/models/spatial_column.rb +22 -0
  17. data/lib/activerecord-spatial/active_record/models/spatial_ref_sys.rb +20 -0
  18. data/lib/activerecord-spatial/associations.rb +292 -0
  19. data/lib/activerecord-spatial/spatial_columns.rb +345 -0
  20. data/lib/activerecord-spatial/spatial_function.rb +201 -0
  21. data/lib/activerecord-spatial/spatial_scope_constants.rb +114 -0
  22. data/lib/activerecord-spatial/spatial_scopes.rb +297 -0
  23. data/lib/activerecord-spatial/version.rb +5 -0
  24. data/lib/tasks/test.rake +45 -0
  25. data/test/accessors_geographies_tests.rb +149 -0
  26. data/test/accessors_geometries_tests.rb +151 -0
  27. data/test/adapter_tests.rb +44 -0
  28. data/test/associations_tests.rb +656 -0
  29. data/test/database.yml +17 -0
  30. data/test/fixtures/bars.yml +16 -0
  31. data/test/fixtures/blorts.yml +37 -0
  32. data/test/fixtures/foo3ds.yml +17 -0
  33. data/test/fixtures/foo_geographies.yml +16 -0
  34. data/test/fixtures/foos.yml +16 -0
  35. data/test/fixtures/zortables.yml +36 -0
  36. data/test/geography_column_tests.rb +40 -0
  37. data/test/geometry_column_tests.rb +40 -0
  38. data/test/models/bar.rb +17 -0
  39. data/test/models/blort.rb +12 -0
  40. data/test/models/foo.rb +17 -0
  41. data/test/models/foo3d.rb +17 -0
  42. data/test/models/foo_geography.rb +16 -0
  43. data/test/models/zortable.rb +17 -0
  44. data/test/spatial_scopes_geographies_tests.rb +106 -0
  45. data/test/spatial_scopes_tests.rb +444 -0
  46. data/test/test_helper.rb +272 -0
  47. metadata +138 -0
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NzVhNGNkYTg1MTBkYTM3MGFmYjI2NTBkOTEyMzRlNDhmZDZhMTM3ZQ==
5
+ data.tar.gz: !binary |-
6
+ MmUyYzQ0ZjU3ZDllYjhjOGFhNWY3ZmU5OTY1NDRkMjk2YzY1NmFlOQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ Yjk3MzU1MTllMzdkOWM4OWI2ZGQwNjUzYWQyMzI3ZTQ4MjAzNGRjZWYyN2Vi
10
+ YjNkYjZlYzAwNzk3MTFkZWEzMGMwMjNmODE2ZTgzYzI1NzFlNjEzMWIzZjRh
11
+ NjFlY2QxMzI1MTY5MTJiMTYzMzgwNGVjZWZjMDU2NTZlNWFhZGE=
12
+ data.tar.gz: !binary |-
13
+ OGI3NjI0ZDI5M2JjOWJiOWYxZDExYTJkMTNmMzg1NDYyNjZkZjhmZjA5NmIy
14
+ OGM4OTIxYWYxMTExYWQ3MGZjNmJkNmY0NTEzMzM4MTZlNTc2YTRjYjBhMDlm
15
+ NzgxOGIxYTUxMDQ0MGRhNTBhNjE0YzE4ZGQ4ZGU3YmQxMDBlNDI=
data/.gitignore ADDED
@@ -0,0 +1,16 @@
1
+ *.orig
2
+ .*.swp
3
+ .*.swo
4
+ *.tmp
5
+ *.patch
6
+ *~
7
+ .DS_Store
8
+ Thumbs.db
9
+ Gemfile.lock
10
+ Gemfile.local
11
+ Guardfile.local
12
+ debug.log
13
+ test/local_database.yml
14
+ doc/
15
+ pkg/
16
+ coverage/
data/Gemfile ADDED
@@ -0,0 +1,21 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ if RUBY_PLATFORM == "java"
6
+ gem "activerecord-jdbcpostgresql-adapter"
7
+ else
8
+ gem "pg"
9
+ end
10
+
11
+ gem "rdoc", "~> 3.12"
12
+ gem "rake", "~> 10.0"
13
+ gem "minitest"
14
+ gem "minitest-reporters"
15
+ gem "guard-minitest"
16
+ gem "simplecov"
17
+
18
+ if File.exists?('Gemfile.local')
19
+ instance_eval File.read('Gemfile.local')
20
+ end
21
+
data/Guardfile ADDED
@@ -0,0 +1,17 @@
1
+
2
+ guard 'minitest', :test_folders => 'test', :test_file_patterns => '*_tests.rb' do
3
+ watch(%r|^test/(.+)_tests\.rb|)
4
+
5
+ watch(%r|^lib/(.*)([^/]+)\.rb|) do |m|
6
+ "test/#{m[1]}#{m[2]}_tests.rb"
7
+ end
8
+
9
+ watch(%r|^test/test_helper\.rb|) do
10
+ "test"
11
+ end
12
+ end
13
+
14
+ if File.exists?('Guardfile.local')
15
+ instance_eval File.read('Guardfile.local')
16
+ end
17
+
data/MIT-LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2013 2167961 Ontario Inc., Zoocasa <code@zoocasa.com>
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
data/README.rdoc ADDED
@@ -0,0 +1,169 @@
1
+
2
+ = ActiveRecord Spatial
3
+
4
+ ActiveRecord Spatial is a collection of spatially-aware extensions that help
5
+ ActiveRecord work the spatial tables. This gem used to be integrated with our
6
+ geos-extensions gem available at https://github.com/zoocasa/geos-extensions but
7
+ we have separated the two and extended ActiveRecord Spatial's capabilities
8
+ in the process.
9
+
10
+ At the moment, ActiveRecord Spatial is focused completely on PostgreSQL and
11
+ PostGIS databases. This may change in the future, but for our purposes,
12
+ PostGIS is our spatial database of choice and we haven't really had the need
13
+ to use any of the alternatives such as Spatialite or the MySQL spatial
14
+ extensions.
15
+
16
+ == Features
17
+
18
+ * automatic detection of geometry columns and just-in-time conversions
19
+ for input and output to and from WKB when using PostGIS. This allows
20
+ you to do stuff like this with your ActiveRecord models:
21
+
22
+ m = MyModel.find(12345)
23
+
24
+ m.the_geom
25
+ # => spits out the untouched geometry value as a string in WKB
26
+
27
+ m.the_geom_geos
28
+ # => spits out the geometry wrapped in a Geos::Geometry object
29
+
30
+ m.the_geom = 'POINT(0 0)'
31
+ # => setters will automatically make conversions from any of the formats
32
+ # that the Geos.read can recognize, so Google Maps formats, WKT, WKB,
33
+ # etc. are all converted automatically.
34
+
35
+ m.the_geom_wkt
36
+ # => automatically converts to a WKT string
37
+
38
+ m.the_geom_wkb_bin
39
+ # => automatically converts to WKB in binary
40
+
41
+ There's also some funky SRID handling code that will automatically
42
+ look in the geometry_columns table to make conversions for you when
43
+ necessary. Saving WKT as "SRID=default; POINT(0 0)" for instance will
44
+ automatically set the SRID when saving the ActiveRecord, or the SRID
45
+ can be specified manually.
46
+
47
+ * multiple geometry columns are supported and detected for
48
+ automatically. These column accessors are all generated dynamically at
49
+ run time.
50
+
51
+ * automatic generation of named scopes for ActiveRecord models. The
52
+ usual suspects are supported such as +st_contains+, +st_intersects+, etc.
53
+
54
+ * ordering scopes are also included such as +order_by_st_area+,
55
+ +order_by_st_length+, etc.
56
+
57
+ * together, the various spatial scopes let you chain together scopes to build
58
+ geospatial queries:
59
+
60
+ neighbourhood = Neighbourhood.find(12345)
61
+ my_model = MyModel.active.
62
+ recent.
63
+ st_within(neighbourhood.the_geom_geos.envelope).
64
+ st_dwithin(point, 0.1).
65
+ order_by_st_area.
66
+ all(
67
+ :limit => 10
68
+ )
69
+
70
+ * spatial associations via the +has_many_spatially+ association method. This
71
+ method essentially operates like a standard +has_many+ association with
72
+ the added ability to define a spatial relationship with the +:relationship+
73
+ option rather than relying on direct equality. This allows you to set up
74
+ relationships like the following:
75
+
76
+ class Neighbourhood < ActiveRecord::Base
77
+ has_many_spatially :cities,
78
+ :relationship => :contains
79
+ end
80
+
81
+ class City < ActiveRecord::Base
82
+ has_many_spatially :neighbourhoods,
83
+ :relationship => :within
84
+ end
85
+
86
+ Neighbourhood.first.cities
87
+ #=> All cities that the neighbourhood is within
88
+
89
+ City.first.neighbourhoods
90
+ #=> All neighbourhoods contained by the city
91
+
92
+ City.includes(:neighbourhoods).first.neighbourhoods
93
+ #=> Eager loading works too
94
+
95
+
96
+ See the documentation for ActiveRecordSpatial::Associations for details.
97
+
98
+ == Running ActiveRecord Tests
99
+
100
+ The test helper attempts to install PostGIS on the test database, but in the
101
+ event that it cannot find your PostGIS files you can either help to guide
102
+ the PostGIS detection by setting a +POSTGIS_PATH+ environment variable that
103
+ points to your +postgis.sql+ and +spatial_ref_sys.sql+ files.
104
+
105
+ You can set up local database settings in the test/local_database.yml file.
106
+ See the test/database.yml file for example settings.
107
+
108
+ == ActiveRecord Versions Supported
109
+
110
+ We're starting to standardize on Rails 3+ for our purposes, so future versions
111
+ this gem function on versions of Rails 3 and above. To use spatial scopes on
112
+ previous versions of ActiveRecord, see our geos-extensions gem available at
113
+ https://github.com/zoocasa/geos-extensions . We have pulled the ActiveRecord
114
+ extensions out of that gem and are instead packaging them here, thus allowing
115
+ you to use the actual Geos extensions in an unfettered way. If you wish to
116
+ use the spatial extensions with versions of Rails prior to 3, see versions of
117
+ the geos-extensions gem prior to version 0.3.0 where the split occured.
118
+
119
+ == PostGIS and PostgreSQL Versions Supported
120
+
121
+ As of this writing, things look good for PostgreSQL 9.1 and 9.2 for both
122
+ PostGIS 1.5 and 2.0. Some features are only available in PostGIS 2.0, such
123
+ as the +st_3dintersects+ scope and the like, as that spatial relationship
124
+ function was added in PostGIS 2.0.
125
+
126
+ PostgreSQL 9.0 and below are currently not supported as some of the SQL we
127
+ produce to create the spatial queries is not supported in older PostgreSQL
128
+ versions.
129
+
130
+ In any event, it is recommended that you use current versions of both
131
+ PostgreSQL and PostGIS where possible.
132
+
133
+ == Migrating from geos-extensions
134
+
135
+ There are a few changes with ActiveRecord Spatial that aren't backwards
136
+ compatible with older versions of geos-extensions. The migration path is
137
+ pretty easy all the same and should only require a handful of changes for
138
+ most projects.
139
+
140
+ * The Geos::ActiveRecord module has been renamed to ActiveRecordSpatial.
141
+ This means you'll have to include ActiveRecordSpatial::SpatialColumns into
142
+ your models instead of Geos::ActiveRecord::SpatialColumns, for instance.
143
+
144
+ * ActiveRecordSpatial::SpatialScopes is no longer automatically included
145
+ when ActiveRecordSpatial::SpatialColumns is included. This allows you to
146
+ optionally include SpatialScopes, as sometimes folks just don't want to use
147
+ our spatial scopes.
148
+
149
+ * In an effort to move away from PostgreSQL/PostGIS-specifics (even if we're
150
+ not fully there yet), we've removed the PostgreSQLSpatialColumn class and
151
+ made everything use ActiveRecordSpatial::GeometryColumn and
152
+ ActiveRecordSpatial::GeographyColumn ActiveRecord models directly. These
153
+ are full-fledged ActiveRecord models now and can be accessed as such, but
154
+ they should be considered read-only models (and are marked as such). In
155
+ PostGIS 2.0+, for instance, these are both read-only views.
156
+
157
+ * The pseudo constant methods for UNKNOWN_SRID and POSTGIS and such are now
158
+ real constants under ActiveRecordSpatial.
159
+
160
+ * The +order_by_*+ scopes have all been renamed to +order_by_st_*+ to better
161
+ reflect that they are calling ST functions, to improve consistency with
162
+ the relationship scopes, and to lessen potential name clashes with other
163
+ existing scopes that may be named with similar conventions.
164
+
165
+ == License
166
+
167
+ This gem is licensed under an MIT-style license. See the +MIT-LICENSE+ file for
168
+ details.
169
+
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+
2
+ # -*- ruby -*-
3
+
4
+ require 'rubygems'
5
+ require 'rubygems/package_task'
6
+ require 'rake/testtask'
7
+ require 'rdoc/task'
8
+ require 'bundler/gem_tasks'
9
+
10
+ $:.push File.expand_path(File.dirname(__FILE__), 'lib')
11
+
12
+ version = ActiveRecordSpatial::VERSION
13
+
14
+ desc 'Test ActiveRecord Spatial'
15
+ Rake::TestTask.new(:test) do |t|
16
+ t.test_files = FileList['test/**/*_tests.rb']
17
+ t.verbose = !!ENV['VERBOSE_TESTS']
18
+ t.warning = !!ENV['WARNINGS']
19
+ end
20
+
21
+ desc 'Build docs'
22
+ Rake::RDocTask.new do |t|
23
+ t.main = 'README.rdoc'
24
+ t.title = "ActiveRecord Spatial #{version}"
25
+ t.rdoc_dir = 'doc'
26
+ t.rdoc_files.include('README.rdoc', 'MIT-LICENSE', 'lib/**/*.rb')
27
+ end
28
+
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ require File.expand_path('../lib/activerecord-spatial/version', __FILE__)
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "activerecord-spatial"
7
+ s.version = ActiveRecordSpatial::VERSION
8
+
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.authors = ["J Smith"]
11
+ s.description = "ActiveRecord Spatial gives AR the ability to work with PostGIS columns."
12
+ s.summary = s.description
13
+ s.email = "code@zoocasa.com"
14
+ s.extra_rdoc_files = [
15
+ "README.rdoc"
16
+ ]
17
+ s.files = `git ls-files`.split($\)
18
+ s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
19
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
20
+ s.homepage = "https://github.com/zoocasa/activerecord-spatial"
21
+ s.require_paths = ["lib"]
22
+
23
+ s.add_dependency("rails", [">= 3.2"])
24
+ s.add_dependency("geos-extensions", [">= 0.3.0.dev"])
25
+ end
26
+
@@ -0,0 +1,32 @@
1
+
2
+ require 'geos-extensions'
3
+
4
+ require 'activerecord-spatial/active_record/connection_adapters/postgresql/adapter_extensions'
5
+
6
+ module ActiveRecordSpatial
7
+ BASE_PATH = File.dirname(__FILE__)
8
+
9
+ class << self
10
+ def geometry_columns?
11
+ ::ActiveRecord::Base.connection.geometry_columns?
12
+ end
13
+
14
+ def geography_columns?
15
+ ::ActiveRecord::Base.connection.geography_columns?
16
+ end
17
+
18
+ def default_column_name
19
+ @default_column_name ||= :the_geom
20
+ end
21
+
22
+ # Allows you to modify the default geometry column name for all of
23
+ # ActiveRecordSpatial. This is useful when you have a common column name
24
+ # for all of your geometry columns, such as +wkb+, +feature+, +geom+, etc.
25
+ def default_column_name=(column_name)
26
+ @default_column_name = column_name
27
+ end
28
+ end
29
+ end
30
+
31
+ require 'activerecord-spatial/active_record'
32
+
@@ -0,0 +1,14 @@
1
+
2
+ module ActiveRecordSpatial
3
+ autoload :SpatialFunction, 'activerecord-spatial/spatial_function'
4
+ autoload :SpatialColumns, 'activerecord-spatial/spatial_columns'
5
+ autoload :SpatialScopeConstants, 'activerecord-spatial/spatial_scope_constants'
6
+ autoload :SpatialScopes, 'activerecord-spatial/spatial_scopes'
7
+ autoload :SpatialColumn, 'activerecord-spatial/active_record/models/spatial_column'
8
+ autoload :SpatialRefSys, 'activerecord-spatial/active_record/models/spatial_ref_sys'
9
+ autoload :GeometryColumn, 'activerecord-spatial/active_record/models/geometry_column'
10
+ autoload :GeographyColumn, 'activerecord-spatial/active_record/models/geography_column'
11
+ end
12
+
13
+ require 'activerecord-spatial/associations'
14
+
@@ -0,0 +1,36 @@
1
+
2
+ require 'active_record/connection_adapters/postgresql_adapter'
3
+
4
+ module ActiveRecord
5
+ module ConnectionAdapters
6
+ class PostgreSQLColumn
7
+ def simplified_type_with_spatial_type(field_type)
8
+ if field_type =~ /^geometry(\(|$)/
9
+ :geometry
10
+ elsif field_type =~ /^geography(\(|$)/
11
+ :geography
12
+ else
13
+ simplified_type_without_spatial_type(field_type)
14
+ end
15
+ end
16
+ alias_method_chain :simplified_type, :spatial_type
17
+ end
18
+
19
+ class PostgreSQLAdapter
20
+ def geometry_columns?
21
+ true
22
+ end
23
+
24
+ def geography_columns?
25
+ ActiveRecordSpatial::POSTGIS[:lib] >= '1.5'
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ module ActiveRecordSpatial
32
+ autoload :POSTGIS, 'activerecord-spatial/active_record/connection_adapters/postgresql/postgis'
33
+ autoload :UNKNOWN_SRID, 'activerecord-spatial/active_record/connection_adapters/postgresql/unknown_srid'
34
+ autoload :UNKNOWN_SRIDS, 'activerecord-spatial/active_record/connection_adapters/postgresql/unknown_srid'
35
+ end
36
+
@@ -0,0 +1,24 @@
1
+
2
+ module ActiveRecordSpatial
3
+ POSTGIS = begin
4
+ if (version_string = ::ActiveRecord::Base.connection.select_rows("SELECT postgis_full_version()").flatten.first).present?
5
+ hash = {
6
+ :use_stats => version_string =~ /USE_STATS/
7
+ }
8
+
9
+ {
10
+ :lib => /POSTGIS="([^"]+)"/,
11
+ :geos => /GEOS="([^"]+)"/,
12
+ :proj => /PROJ="([^"]+)"/,
13
+ :libxml => /LIBXML="([^"]+)"/
14
+ }.each do |k, v|
15
+ hash[k] = version_string.scan(v).flatten.first
16
+ end
17
+
18
+ hash.freeze
19
+ else
20
+ {}.freeze
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,21 @@
1
+
2
+ module ActiveRecordSpatial
3
+ UNKNOWN_SRIDS = begin
4
+ if ActiveRecordSpatial::POSTGIS[:lib] >= '2.0'
5
+ {
6
+ :geography => 0,
7
+ :geometry => 0
8
+ }.freeze
9
+ else
10
+ {
11
+ :geography => 0,
12
+ :geometry => -1
13
+ }.freeze
14
+ end
15
+ end
16
+
17
+ UNKNOWN_SRID = begin
18
+ ActiveRecordSpatial::UNKNOWN_SRIDS[:geometry]
19
+ end
20
+ end
21
+