rgeo-geojson 2.1.1 → 2.2.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: 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.