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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6d3fe76f0ce82837de428e401ce4f6a20a84b97acb2085374a8bf8fe1daba5c8
4
- data.tar.gz: fed058553913c07b27838424dc07b1b63677f28798fae7d5534b55de7c1aa713
3
+ metadata.gz: 9578faf8d4205e8b25b7039b99df9ead3f03f13d82568277930c8824adb48980
4
+ data.tar.gz: 16a5be2783383686f570f598edd8ecf3da6350fb92d5b393618f8be919ab8c79
5
5
  SHA512:
6
- metadata.gz: 0f6aebd3553502127a91f68d5f692bd6311a8c7af0aca22bccc54cec712aa8371696b0f8e19c0c7aaffa9e98c1ee809d478612a5f7c2441452a202bc9f53280a
7
- data.tar.gz: fcf4f4eb0fc85f82ff726ec950936b9c45bdd9aaf85eb06067acac71b250185b6640e89f3536e5e5e1759b93efbee66e855460964ba112aa4f26a77cefae0abe
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
- register_class_with_limit m, 'geometry', ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::SpecializedString
5
- register_class_with_limit m, 'geography', ActiveRecord::ConnectionAdapters::PostgreSQLAdapter::OID::SpecializedString
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
- spatial_importer_from_name(importer_name).create_all(data, :make_valid => make_valid) if data.present?
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, **options)
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
- Nokogiri::XML(@data).css(kml_type).each do |feature|
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, output_dir = Dir.mktmpdir, downcase: false)
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 = "#{output_dir}/#{output_filename}"
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)
@@ -1,3 +1,3 @@
1
1
  module SpatialFeatures
2
- VERSION = "3.0.0"
2
+ VERSION = "3.1.0"
3
3
  end
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.0.0
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-01-29 00:00:00.000000000 Z
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: '4.2'
20
+ version: '6'
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '7.0'
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: '4.2'
30
+ version: '6'
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '7.0'
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: '1.6'
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: '1.6'
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
- rubyforge_project:
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.