spatial_features 3.0.0 → 3.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.
- checksums.yaml +4 -4
- data/README.md +15 -0
- data/config/initializers/mime_types.rb +1 -0
- data/config/initializers/register_oids.rb +6 -2
- data/lib/spatial_features/download.rb +0 -7
- data/lib/spatial_features/has_spatial_features/feature_import.rb +8 -3
- data/lib/spatial_features/has_spatial_features.rb +1 -1
- data/lib/spatial_features/importers/base.rb +2 -1
- data/lib/spatial_features/importers/file.rb +2 -2
- data/lib/spatial_features/importers/kml.rb +9 -1
- data/lib/spatial_features/unzip.rb +3 -5
- data/lib/spatial_features/version.rb +1 -1
- metadata +25 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9578faf8d4205e8b25b7039b99df9ead3f03f13d82568277930c8824adb48980
|
4
|
+
data.tar.gz: 16a5be2783383686f570f598edd8ecf3da6350fb92d5b393618f8be919ab8c79
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 772ab77070751ca764ab8a06cf5260038be3cae8461c6e9c7fa894e644d2164cd8905281c43d0eab48b7ab2f06227b01da809687ec4ffb7bc1ade359c7097eea
|
7
|
+
data.tar.gz: da9f6d66e79f85362f4c6af9e3dc8400b4f6fb51bf0cb5ba84114ccb47b4541e59614d162271877c6d20d9d342fbc9a86b48de7e8a5a1de15b27c7136c09f3b3
|
data/README.md
CHANGED
@@ -181,3 +181,18 @@ add_column :features, :tilegeom, :geometry
|
|
181
181
|
add_index :features, :tilegeom, :using => :gist
|
182
182
|
Feature.update_all('tilegeom = ST_Transform(geom, 3857)')
|
183
183
|
```
|
184
|
+
|
185
|
+
## Testing
|
186
|
+
|
187
|
+
Create a postgres database:
|
188
|
+
```bash
|
189
|
+
createdb spatial_features_test
|
190
|
+
```
|
191
|
+
|
192
|
+
There are multiple gemfiles available for testing against different Rails versions. Set `BUNDLE_GEMFILE` to target them, e.g.
|
193
|
+
|
194
|
+
```bash
|
195
|
+
bundle install
|
196
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle install
|
197
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_0.gemfile bundle exec rspec
|
198
|
+
```
|
@@ -1,4 +1,5 @@
|
|
1
1
|
Mime::Type.register "application/vnd.geo+json", :geojson
|
2
|
+
Mime::Type.register "application/vnd.bounds+json", :bounds
|
2
3
|
Mime::Type.register "application/vnd.mapbox-vector-tile", :mvt
|
3
4
|
Mime::Type.register "application/vnd.google-earth.kml+xml", :kml
|
4
5
|
Mime::Type.register "application/vnd.google-earth.kmz", :kmz
|
@@ -1,8 +1,12 @@
|
|
1
1
|
module PostGISTypes
|
2
2
|
def initialize_type_map(m = type_map)
|
3
3
|
super
|
4
|
-
|
5
|
-
|
4
|
+
%w[
|
5
|
+
geography
|
6
|
+
geometry
|
7
|
+
].each do |geo_type|
|
8
|
+
m.register_type geo_type, ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::SpecializedString.new(geo_type.to_sym)
|
9
|
+
end
|
6
10
|
end
|
7
11
|
end
|
8
12
|
|
@@ -2,13 +2,6 @@ require 'open-uri'
|
|
2
2
|
|
3
3
|
module SpatialFeatures
|
4
4
|
module Download
|
5
|
-
# file can be a url, path, or file, any of which can return be a zipped archive
|
6
|
-
def self.read(file, unzip: nil, **unzip_options)
|
7
|
-
file = Download.open_each(file, unzip: unzip, **unzip_options).first
|
8
|
-
path = ::File.path(file)
|
9
|
-
return ::File.read(path)
|
10
|
-
end
|
11
|
-
|
12
5
|
# file can be a url, path, or file, any of which can return be a zipped archive
|
13
6
|
def self.open(file)
|
14
7
|
file = Kernel.open(file)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'digest/md5'
|
2
|
+
require 'fileutils'
|
2
3
|
|
3
4
|
module SpatialFeatures
|
4
5
|
module FeatureImport
|
@@ -21,9 +22,10 @@ module SpatialFeatures
|
|
21
22
|
|
22
23
|
def update_features!(skip_invalid: false, **options)
|
23
24
|
options = options.reverse_merge(spatial_features_options)
|
25
|
+
tmpdir = options.fetch(:tmpdir) { Dir.mktmpdir("ruby_spatial_features") }
|
24
26
|
|
25
27
|
ActiveRecord::Base.transaction do
|
26
|
-
imports = spatial_feature_imports(options[:import], options[:make_valid])
|
28
|
+
imports = spatial_feature_imports(options[:import], options[:make_valid], options[:tmpdir])
|
27
29
|
cache_key = Digest::MD5.hexdigest(imports.collect(&:cache_key).join)
|
28
30
|
|
29
31
|
return if features_cache_key_matches?(cache_key)
|
@@ -49,6 +51,8 @@ module SpatialFeatures
|
|
49
51
|
else
|
50
52
|
raise ImportError, e.message, e.backtrace
|
51
53
|
end
|
54
|
+
ensure
|
55
|
+
FileUtils.remove_entry(tmpdir) if Dir.exist?(tmpdir)
|
52
56
|
end
|
53
57
|
|
54
58
|
def update_features_cache_key(cache_key)
|
@@ -73,10 +77,11 @@ module SpatialFeatures
|
|
73
77
|
|
74
78
|
private
|
75
79
|
|
76
|
-
def spatial_feature_imports(import_options, make_valid)
|
80
|
+
def spatial_feature_imports(import_options, make_valid, tmpdir)
|
77
81
|
import_options.flat_map do |data_method, importer_name|
|
78
82
|
Array.wrap(send(data_method)).flat_map do |data|
|
79
|
-
|
83
|
+
next unless data.present?
|
84
|
+
spatial_importer_from_name(importer_name).create_all(data, :make_valid => make_valid, :tmpdir => tmpdir)
|
80
85
|
end
|
81
86
|
end.compact
|
82
87
|
end
|
@@ -56,7 +56,7 @@ module SpatialFeatures
|
|
56
56
|
within_buffer(other, 0, options)
|
57
57
|
end
|
58
58
|
|
59
|
-
def within_buffer(other, buffer_in_meters = 0,
|
59
|
+
def within_buffer(other, buffer_in_meters = 0, options = {})
|
60
60
|
return none if other.is_a?(ActiveRecord::Base) && other.new_record?
|
61
61
|
|
62
62
|
# Cache only works on single records, not scopes.
|
@@ -5,10 +5,11 @@ module SpatialFeatures
|
|
5
5
|
class Base
|
6
6
|
attr_reader :errors
|
7
7
|
|
8
|
-
def initialize(data, make_valid: false)
|
8
|
+
def initialize(data, make_valid: false, tmpdir: nil)
|
9
9
|
@make_valid = make_valid
|
10
10
|
@data = data
|
11
11
|
@errors = []
|
12
|
+
@tmpdir = tmpdir
|
12
13
|
end
|
13
14
|
|
14
15
|
def features
|
@@ -8,7 +8,7 @@ module SpatialFeatures
|
|
8
8
|
|
9
9
|
FILE_PATTERNS = [/\.kml$/, /\.shp$/, /\.json$/, /\.geojson$/]
|
10
10
|
def self.create_all(data, **options)
|
11
|
-
Download.open_each(data, unzip: FILE_PATTERNS, downcase: true).map do |file|
|
11
|
+
Download.open_each(data, unzip: FILE_PATTERNS, downcase: true, tmpdir: options[:tmpdir]).map do |file|
|
12
12
|
new(data, **options, current_file: file)
|
13
13
|
end
|
14
14
|
rescue Unzip::PathNotFound
|
@@ -23,7 +23,7 @@ module SpatialFeatures
|
|
23
23
|
# If no `current_file` is passed then we just take the first valid file that we find.
|
24
24
|
def initialize(data, *args, current_file: nil, **options)
|
25
25
|
begin
|
26
|
-
current_file ||= Download.open_each(data, unzip: FILE_PATTERNS, downcase: true).first
|
26
|
+
current_file ||= Download.open_each(data, unzip: FILE_PATTERNS, downcase: true, tmpdir: options[:tmpdir]).first
|
27
27
|
rescue Unzip::PathNotFound
|
28
28
|
raise ImportError, INVALID_ARCHIVE
|
29
29
|
end
|
@@ -15,7 +15,7 @@ module SpatialFeatures
|
|
15
15
|
|
16
16
|
def each_record(&block)
|
17
17
|
{'Polygon' => 'POLYGON', 'LineString' => 'LINE', 'Point' => 'POINT'}.each do |kml_type, sql_type|
|
18
|
-
|
18
|
+
kml_document.css(kml_type).each do |feature|
|
19
19
|
if placemark = feature.ancestors('Placemark').first
|
20
20
|
name = placemark.css('name').text
|
21
21
|
metadata = extract_metadata(placemark)
|
@@ -35,6 +35,14 @@ module SpatialFeatures
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
def kml_document
|
39
|
+
@kml_document ||= begin
|
40
|
+
doc = Nokogiri::XML(@data)
|
41
|
+
raise ImportError, "Invalid KML document (root node was '#{doc.root&.name}')" unless doc.root&.name.to_s.casecmp?('kml')
|
42
|
+
doc
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
38
46
|
def blank_feature?(feature)
|
39
47
|
feature.css('coordinates').text.blank?
|
40
48
|
end
|
@@ -16,21 +16,19 @@ module SpatialFeatures
|
|
16
16
|
return Array(paths)
|
17
17
|
end
|
18
18
|
|
19
|
-
def self.extract(file_path,
|
19
|
+
def self.extract(file_path, tmpdir: nil, downcase: false)
|
20
|
+
tmpdir ||= Dir.mktmpdir
|
20
21
|
[].tap do |paths|
|
21
22
|
entries(file_path).each do |entry|
|
22
23
|
next if entry.name =~ IGNORED_ENTRY_PATHS
|
23
24
|
output_filename = entry.name
|
24
25
|
output_filename = output_filename.downcase if downcase
|
25
|
-
path = "#{
|
26
|
+
path = "#{tmpdir}/#{output_filename}"
|
26
27
|
FileUtils.mkdir_p(File.dirname(path))
|
27
28
|
entry.extract(path)
|
28
29
|
paths << path
|
29
30
|
end
|
30
31
|
end
|
31
|
-
rescue => e
|
32
|
-
FileUtils.remove_entry(output_dir)
|
33
|
-
raise(e)
|
34
32
|
end
|
35
33
|
|
36
34
|
def self.names(file_path)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spatial_features
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Wallace
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2022-
|
12
|
+
date: 2022-05-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -17,20 +17,20 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '
|
20
|
+
version: '6'
|
21
21
|
- - "<"
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: '
|
23
|
+
version: '8'
|
24
24
|
type: :runtime
|
25
25
|
prerelease: false
|
26
26
|
version_requirements: !ruby/object:Gem::Requirement
|
27
27
|
requirements:
|
28
28
|
- - ">="
|
29
29
|
- !ruby/object:Gem::Version
|
30
|
-
version: '
|
30
|
+
version: '6'
|
31
31
|
- - "<"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '8'
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: delayed_job_active_record
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
@@ -91,16 +91,16 @@ dependencies:
|
|
91
91
|
name: nokogiri
|
92
92
|
requirement: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - "
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
96
|
+
version: '0'
|
97
97
|
type: :runtime
|
98
98
|
prerelease: false
|
99
99
|
version_requirements: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - "
|
101
|
+
- - ">="
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
103
|
+
version: '0'
|
104
104
|
- !ruby/object:Gem::Dependency
|
105
105
|
name: pg
|
106
106
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,6 +129,20 @@ dependencies:
|
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: '3.5'
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: pry-byebug
|
134
|
+
requirement: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
type: :development
|
140
|
+
prerelease: false
|
141
|
+
version_requirements: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
132
146
|
description: Adds spatial methods to a model.
|
133
147
|
email:
|
134
148
|
- contact@culturecode.ca
|
@@ -189,8 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
203
|
- !ruby/object:Gem::Version
|
190
204
|
version: '0'
|
191
205
|
requirements: []
|
192
|
-
|
193
|
-
rubygems_version: 2.7.6.3
|
206
|
+
rubygems_version: 3.0.3
|
194
207
|
signing_key:
|
195
208
|
specification_version: 4
|
196
209
|
summary: Adds spatial methods to a model.
|