rgeo-geojson 2.1.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ea734285d614e1301d41808430a05d9dbb4e8552159b037ea653556e88fd79e3
4
- data.tar.gz: 7561c7640b2a74b82bb4f20a1995f641071fd698eb2cee50e77395c3209b9bdf
3
+ metadata.gz: 448049463c510bdeb2fa366eaa3834566962116632675ccb509134cc54875fc0
4
+ data.tar.gz: 7a6c7b327824850c164d3fca314347256e9b8513574afae86687361e92b00c26
5
5
  SHA512:
6
- metadata.gz: a67279b3edd9290fb455b8ffde0fa0b5f0207f938fc805c0d2caa53a71b895bb1fb09ef990a9b98786be9cc343a65c16107745193d7be934efe619341b4909c9
7
- data.tar.gz: 4775eacc655a9cd60c927644c483e0ac522b5e94dcbb36ca2867168ba97bc1fa59a24c7fbcf364d5933b0105cbc4112982b7322da1160a6f67804755875eefd2
6
+ metadata.gz: d6009ac4f8cdd344ca8403235a20d40c71b9dcf891c17a3646650a8b307d863dd5bf2b63d1ce58bcd768f7d394a572f5f14f822ea294818a7c42e307839e0bb6
7
+ data.tar.gz: 8a53d85316ec32a69a36a287bc6a5f44702427f2b54b9720da82e91fa599aa33e6fd7ccf600f06a1c01442675cf8b267c749506c32151f798c310e4c6060286e
data/History.md CHANGED
@@ -1,3 +1,9 @@
1
+ ### 2.2.0 / 2024-07-22
2
+
3
+ * Delegation to inner geometry for a feature (#53)
4
+ * MultiJson rather than JSON (#46)
5
+ * Conversion methods for better integration with core (#56)
6
+
1
7
  ### 2.1.1 / 2018-11-27
2
8
 
3
9
  * Freeze strings
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # rgeo-geojson
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rgeo-geojson.svg)](http://badge.fury.io/rb/rgeo-geojson)
4
- [![Build Status](https://travis-ci.org/rgeo/rgeo-geojson.svg?branch=master)](https://travis-ci.org/rgeo/rgeo-geojson)
4
+ [![CI](https://github.com/rgeo/rgeo-geojson/workflows/CI/badge.svg)](https://github.com/rgeo/rgeo-geojson/actions?query=workflow%3ACI+branch%3Amaster+event%3Apush)
5
5
 
6
6
  `rgeo-geojson` is an extension to [RGeo](https://github.com/rgeo/rgeo)
7
7
  that provides GeoJSON encoding and decoding.
@@ -6,7 +6,6 @@ module RGeo
6
6
  # the RGeo::Feature::Factory and the RGeo::GeoJSON::EntityFactory to
7
7
  # be used) so that you can encode and decode without specifying those
8
8
  # settings every time.
9
-
10
9
  class Coder
11
10
  # Create a new coder settings object. The geo factory is passed as
12
11
  # a required argument.
@@ -41,7 +40,6 @@ module RGeo
41
40
  # appropriate JSON library installed.
42
41
  #
43
42
  # Returns nil if nil is passed in as the object.
44
-
45
43
  def encode(object)
46
44
  if @entity_factory.is_feature_collection?(object)
47
45
  {
@@ -60,13 +58,12 @@ module RGeo
60
58
  # Decode an object from GeoJSON. The input may be a JSON hash, a
61
59
  # String, or an IO object from which to read the JSON string.
62
60
  # If an error occurs, nil is returned.
63
-
64
61
  def decode(input)
65
62
  if input.is_a?(IO)
66
63
  input = input.read rescue nil
67
64
  end
68
65
  if input.is_a?(String)
69
- input = JSON.parse(input)
66
+ input = MultiJson.load(input)
70
67
  end
71
68
  return unless input.is_a?(Hash)
72
69
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGeo
4
+ # This module is here to fill the gap between what is a GeometryCollection (GIS)
5
+ # and a FeatureCollection (GeoJSON).
6
+ #
7
+ # Note for contributors, you can rely on `@features` to be defined and
8
+ # you can consider working with an Enumerable wrapping `@features`. See
9
+ # GeoJSON::FeatureCollection.
10
+ module GeoJSON::CollectionMethods
11
+ # There is tight coupling between {FeatureCollection} and this, hence the
12
+ # guard.
13
+ private_class_method def self.included(base)
14
+ return if base.to_s == "RGeo::GeoJSON::FeatureCollection"
15
+
16
+ raise Error::RGeoError, "#{self.class} must only be used by FeatureCollection"
17
+ end
18
+
19
+ private def method_missing(symbol, *args)
20
+ return super unless any? { |feature| feature.respond_to?(symbol) }
21
+
22
+ raise Error::UnsupportedOperation, "Method FeatureCollection##{symbol} " \
23
+ "is not defined. You may consider filing an issue or opening a pull " \
24
+ "request at https://github.com/rgeo/rgeo-geojson"
25
+ end
26
+
27
+ def contains?(geometry)
28
+ any? { |feature| feature.contains?(geometry) }
29
+ end
30
+
31
+ def intersects?(geometry)
32
+ any? { |feature| feature.intersects?(geometry) }
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RGeo
4
+ # This module serves to provide handy methods when using GeoJSON. The methods
5
+ # provided eases the passage between entities and GeoJSON String/Hash.
6
+ module GeoJSON::ConversionMethods
7
+ # Convert a geometry to a GeoJSON Hash
8
+ def as_geojson
9
+ GeoJSON.encode(self)
10
+ end
11
+ alias as_json as_geojson
12
+
13
+ # Convert a geometry to a GeoJSON String
14
+ def to_geojson
15
+ ::MultiJson.dump(as_geojson)
16
+ end
17
+ alias to_json to_geojson
18
+ end
19
+
20
+ # These convenience methods are added directly into the module rather than
21
+ # including the module above into the Feature::Instance module which is in
22
+ # every geometry implementation. This is due to a behavior in ruby versions
23
+ # <3.0.2 where dynamically included modules will not be included automatically
24
+ # in the ancestor tree.
25
+ # See https://bugs.ruby-lang.org/issues/9573 for more information.
26
+ module Feature
27
+ module Instance
28
+ # Convert a geometry to a GeoJSON Hash
29
+ def as_geojson
30
+ GeoJSON.encode(self)
31
+ end
32
+ alias as_json as_geojson
33
+
34
+ # Convert a geometry to a GeoJSON String
35
+ def to_geojson
36
+ ::MultiJson.dump(as_geojson)
37
+ end
38
+ alias to_json to_geojson
39
+ end
40
+
41
+ module Factory::Instance
42
+ # Parses a GeoJSON String/Hash, or an IO object from which
43
+ # the JSON string is read and returns the corresponding
44
+ # feature. Returns nil if unable to parse.
45
+ def parse_geojson(input)
46
+ GeoJSON.decode(input, geo_factory: self)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -1,7 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "collection_methods"
4
+ require_relative "conversion_methods"
5
+
3
6
  module RGeo
7
+ module CastOverlay
8
+ def self.included(base)
9
+ # The original {RGeo::Feature.cast} would copy a GeoJSON::Feature, which
10
+ # fails most operations. When casting, we MUST get a geometry.
11
+ original_cast = base.method(:cast)
12
+ base.define_singleton_method(:cast) do |obj, *params|
13
+ if obj.class == GeoJSON::Feature
14
+ original_cast.call(obj.geometry, *params)
15
+ else
16
+ original_cast.call(obj, *params)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ Feature.include(CastOverlay)
22
+
4
23
  module GeoJSON
24
+ # Simplify usage of inner geometries for Feature and FeatureCollection
25
+ # objets. Including class must contain a `#geometry` method.
26
+ module DelegateToGeometry
27
+ private def method_missing(symbol, *args)
28
+ return geometry.public_send(symbol, *args) if geometry
29
+
30
+ super
31
+ end
32
+
33
+ private def respond_to_missing?(symbol, *)
34
+ geometry&.respond_to?(symbol) || super
35
+ end
36
+ end
37
+
5
38
  # This is a GeoJSON wrapper entity that corresponds to the GeoJSON
6
39
  # "Feature" type. It is an immutable type.
7
40
  #
@@ -11,11 +44,12 @@ module RGeo
11
44
  # implementation need not subclass or even duck-type this class.
12
45
  # the entity factory mediates all interaction between the GeoJSON
13
46
  # engine and features.
14
-
15
47
  class Feature
48
+ include DelegateToGeometry
49
+ include ConversionMethods
50
+
16
51
  # Create a feature wrapping the given geometry, with the given ID
17
52
  # and properties.
18
-
19
53
  def initialize(geometry, id = nil, properties = {})
20
54
  @geometry = geometry
21
55
  @id = id
@@ -41,7 +75,6 @@ module RGeo
41
75
  # are all equal.
42
76
  # This method uses the eql? method to test geometry equality, which
43
77
  # may behave differently than the == operator.
44
-
45
78
  def eql?(other)
46
79
  other.is_a?(Feature) && @geometry.eql?(other.geometry) && @id.eql?(other.feature_id) && @properties.eql?(other.instance_variable_get(:@properties))
47
80
  end
@@ -50,37 +83,31 @@ module RGeo
50
83
  # are all equal.
51
84
  # This method uses the == operator to test geometry equality, which
52
85
  # may behave differently than the eql? method.
53
-
54
86
  def ==(other)
55
87
  other.is_a?(Feature) && @geometry == other.geometry && @id == other.feature_id && @properties == other.instance_variable_get(:@properties)
56
88
  end
57
89
 
58
90
  # Returns the geometry contained in this feature, which may be nil.
59
-
60
91
  attr_reader :geometry
61
92
 
62
93
  # Returns the ID for this feature, which may be nil.
63
-
64
94
  def feature_id
65
95
  @id
66
96
  end
67
97
 
68
98
  # Returns a copy of the properties for this feature.
69
-
70
99
  def properties
71
100
  @properties.dup
72
101
  end
73
102
 
74
103
  # Gets the value of the given named property.
75
104
  # Returns nil if the given property is not found.
76
-
77
105
  def property(key)
78
106
  @properties[key.to_s]
79
107
  end
80
108
  alias [] property
81
109
 
82
110
  # Gets an array of the known property keys in this feature.
83
-
84
111
  def keys
85
112
  @properties.keys
86
113
  end
@@ -95,16 +122,17 @@ module RGeo
95
122
  # FeatureCollection implementation need not subclass or even
96
123
  # duck-type this class. The entity factory mediates all interaction
97
124
  # between the GeoJSON engine and feature collections.
98
-
99
125
  class FeatureCollection
100
126
  include Enumerable
127
+ include CollectionMethods
128
+ include ConversionMethods
101
129
 
102
130
  # Create a new FeatureCollection with the given features, which must
103
131
  # be provided as an Enumerable.
104
-
105
132
  def initialize(features = [])
106
133
  @features = []
107
134
  features.each { |f| @features << f if f.is_a?(Feature) }
135
+ @features.freeze
108
136
  end
109
137
 
110
138
  def inspect
@@ -123,7 +151,6 @@ module RGeo
123
151
  # features in the same order.
124
152
  # This methods uses the eql? method to test geometry equality, which
125
153
  # may behave differently than the == operator.
126
-
127
154
  def eql?(other)
128
155
  other.is_a?(FeatureCollection) && @features.eql?(other.instance_variable_get(:@features))
129
156
  end
@@ -132,25 +159,21 @@ module RGeo
132
159
  # features in the same order.
133
160
  # This methods uses the == operator to test geometry equality, which
134
161
  # may behave differently than the eql? method.
135
-
136
162
  def ==(other)
137
163
  other.is_a?(FeatureCollection) && @features == other.instance_variable_get(:@features)
138
164
  end
139
165
 
140
166
  # Iterates or returns an iterator for the features.
141
-
142
167
  def each(&block)
143
168
  @features.each(&block)
144
169
  end
145
170
 
146
171
  # Returns the number of features contained in this collection.
147
-
148
172
  def size
149
173
  @features.size
150
174
  end
151
175
 
152
176
  # Access a feature by index.
153
-
154
177
  def [](index)
155
178
  @features[index]
156
179
  end
@@ -164,60 +187,51 @@ module RGeo
164
187
  # Create and return a new feature, given geometry, ID, and
165
188
  # properties hash. Note that, per the GeoJSON spec, geometry and/or
166
189
  # properties may be nil.
167
-
168
190
  def feature(geometry, id = nil, properties = nil)
169
191
  Feature.new(geometry, id, properties || {})
170
192
  end
171
193
 
172
194
  # Create and return a new feature collection, given an enumerable
173
195
  # of feature objects.
174
-
175
196
  def feature_collection(features = [])
176
197
  FeatureCollection.new(features)
177
198
  end
178
199
 
179
200
  # Returns true if the given object is a feature created by this
180
201
  # entity factory.
181
-
182
202
  def is_feature?(object)
183
203
  object.is_a?(Feature)
184
204
  end
185
205
 
186
206
  # Returns true if the given object is a feature collection created
187
207
  # by this entity factory.
188
-
189
208
  def is_feature_collection?(object)
190
209
  object.is_a?(FeatureCollection)
191
210
  end
192
211
 
193
212
  # Run Enumerable#map on the features contained in the given feature
194
213
  # collection.
195
-
196
214
  def map_feature_collection(object, &block)
197
215
  object.map(&block)
198
216
  end
199
217
 
200
218
  # Returns the geometry associated with the given feature.
201
-
202
219
  def get_feature_geometry(object)
203
220
  object.geometry
204
221
  end
205
222
 
206
223
  # Returns the ID of the given feature, or nil for no ID.
207
-
208
224
  def get_feature_id(object)
209
225
  object.feature_id
210
226
  end
211
227
 
212
228
  # Returns the properties of the given feature as a hash. Editing
213
229
  # this hash does not change the state of the feature.
214
-
215
230
  def get_feature_properties(object)
216
231
  object.properties
217
232
  end
218
233
 
219
234
  # Return the singleton instance of EntityFactory.
220
-
221
235
  def self.instance
222
236
  @instance ||= new
223
237
  end
@@ -13,9 +13,8 @@ module RGeo
13
13
  # RGeo::GeoJSON::EntityFactory for more information. By default,
14
14
  # encode supports objects of type RGeo::GeoJSON::Feature and
15
15
  # RGeo::GeoJSON::FeatureCollection.
16
-
17
16
  def encode(object, opts = {})
18
- Coder.new(opts).encode(object)
17
+ coder(opts).encode(object)
19
18
  end
20
19
 
21
20
  # High-level convenience routine for decoding an object from GeoJSON.
@@ -33,8 +32,8 @@ module RGeo
33
32
  # RGeo::GeoJSON::EntityFactory, which generates objects of type
34
33
  # RGeo::GeoJSON::Feature or RGeo::GeoJSON::FeatureCollection.
35
34
  # See RGeo::GeoJSON::EntityFactory for more information.
36
- def decode(input_, opts = {})
37
- Coder.new(opts).decode(input_)
35
+ def decode(input, opts = {})
36
+ coder(opts).decode(input)
38
37
  end
39
38
 
40
39
  # Creates and returns a coder object of type RGeo::GeoJSON::Coder
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RGeo
4
4
  module GeoJSON
5
- VERSION = "2.1.1"
5
+ VERSION = "2.2.0"
6
6
  end
7
7
  end
data/lib/rgeo/geo_json.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "rgeo"
4
- require "rgeo/geo_json/version"
5
- require "rgeo/geo_json/entities"
6
- require "rgeo/geo_json/coder"
7
- require "rgeo/geo_json/interface"
8
- require "json"
4
+ require_relative "geo_json/version"
5
+ require_relative "geo_json/conversion_methods"
6
+ require_relative "geo_json/entities"
7
+ require_relative "geo_json/coder"
8
+ require_relative "geo_json/interface"
9
+ require "multi_json"
data/lib/rgeo-geojson.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rgeo/geo_json"
3
+ require_relative "rgeo/geo_json"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgeo-geojson
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.1
4
+ version: 2.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Azuma
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2018-11-28 00:00:00.000000000 Z
12
+ date: 2024-07-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rgeo
@@ -26,19 +26,19 @@ dependencies:
26
26
  - !ruby/object:Gem::Version
27
27
  version: 1.0.0
28
28
  - !ruby/object:Gem::Dependency
29
- name: bundler
29
+ name: multi_json
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - "~>"
33
33
  - !ruby/object:Gem::Version
34
- version: '1.6'
35
- type: :development
34
+ version: '1.15'
35
+ type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - "~>"
40
40
  - !ruby/object:Gem::Version
41
- version: '1.6'
41
+ version: '1.15'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: minitest
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -72,6 +72,7 @@ description: Convert RGeo data to and from GeoJSON. rgeo-geojson is an extension
72
72
  email:
73
73
  - dazuma@gmail.com
74
74
  - parhameter@gmail.com
75
+ - kfdoggett@gmail.com
75
76
  executables: []
76
77
  extensions: []
77
78
  extra_rdoc_files: []
@@ -82,12 +83,14 @@ files:
82
83
  - lib/rgeo-geojson.rb
83
84
  - lib/rgeo/geo_json.rb
84
85
  - lib/rgeo/geo_json/coder.rb
86
+ - lib/rgeo/geo_json/collection_methods.rb
87
+ - lib/rgeo/geo_json/conversion_methods.rb
85
88
  - lib/rgeo/geo_json/entities.rb
86
89
  - lib/rgeo/geo_json/interface.rb
87
90
  - lib/rgeo/geo_json/version.rb
88
91
  homepage: https://github.com/rgeo/rgeo-geojson
89
92
  licenses:
90
- - BSD
93
+ - BSD-3-Clause
91
94
  metadata: {}
92
95
  post_install_message:
93
96
  rdoc_options: []
@@ -104,8 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
107
  - !ruby/object:Gem::Version
105
108
  version: '0'
106
109
  requirements: []
107
- rubyforge_project:
108
- rubygems_version: 2.7.8
110
+ rubygems_version: 3.5.2
109
111
  signing_key:
110
112
  specification_version: 4
111
113
  summary: Convert RGeo data to and from GeoJSON.