ffi-gdal 1.0.0.beta8 → 1.0.0.beta9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +25 -16
  3. data/.rubocop_todo.yml +13 -18
  4. data/History.md +10 -0
  5. data/ffi-gdal.gemspec +2 -2
  6. data/lib/ffi/gdal/version.rb +1 -1
  7. data/lib/ffi/gdal/warp_options.rb +0 -11
  8. data/lib/ffi/gdal.rb +1 -3
  9. data/lib/ffi/ogr/srs_api.rb +0 -2
  10. data/lib/gdal/color_table_mixins/extensions.rb +1 -3
  11. data/lib/gdal/dataset_mixins/extensions.rb +2 -4
  12. data/lib/gdal/driver.rb +3 -7
  13. data/lib/gdal/geo_transform.rb +1 -3
  14. data/lib/gdal/grid.rb +0 -2
  15. data/lib/gdal/raster_band.rb +2 -1
  16. data/lib/gdal/raster_band_classifier.rb +48 -15
  17. data/lib/gdal/raster_band_mixins/extensions.rb +4 -0
  18. data/lib/ogr/data_source.rb +3 -9
  19. data/lib/ogr/driver.rb +2 -6
  20. data/lib/ogr/envelope.rb +2 -2
  21. data/lib/ogr/error_handling.rb +1 -1
  22. data/lib/ogr/feature.rb +2 -0
  23. data/lib/ogr/field.rb +3 -1
  24. data/lib/ogr/geometries/line_string.rb +0 -3
  25. data/lib/ogr/geometry.rb +1 -3
  26. data/lib/ogr/geometry_mixins/extensions.rb +1 -3
  27. data/lib/ogr/layer_mixins/extensions.rb +2 -4
  28. data/lib/ogr/layer_mixins/ogr_feature_methods.rb +4 -12
  29. data/lib/ogr/layer_mixins/ogr_field_methods.rb +4 -12
  30. data/lib/ogr/layer_mixins/ogr_sql_methods.rb +1 -3
  31. data/spec/integration/gdal/dataset_info_spec.rb +12 -12
  32. data/spec/integration/gdal/raster_band_info_spec.rb +1 -3
  33. data/spec/spec_helper.rb +1 -1
  34. data/spec/unit/gdal/raster_band_classifier_spec.rb +38 -2
  35. data/spec/unit/ogr/feature_spec.rb +1 -1
  36. data/spec/unit/ogr/field_spec.rb +1 -1
  37. data/spec/unit/ogr/spatial_reference_mixins/exporters_spec.rb +12 -12
  38. metadata +17 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f3dc48a3584647ad17acba068529c648efd09a4c
4
- data.tar.gz: 1f92faa1bc794b5e35ba831d072258daf2942618
2
+ SHA256:
3
+ metadata.gz: fdaa59a5ef4022ef21872fc621c9f5ff872b07d40334dc002f4802aae99ec4ba
4
+ data.tar.gz: bcb79fc1ef548adb1b3d32cca73e0762d3b4cbee3bd068fe03fe65d9cf886807
5
5
  SHA512:
6
- metadata.gz: 5de8ff8356431d9a4d149eb9d93e64462e8eb5a0b7c138bc29dd4683b9e8f747b9e5d7a12e9281eeb405faf13bfd965cf8cae4326beef5db6e125e2cea386c9c
7
- data.tar.gz: 34dc5007a0c1f7dc27b9cb698ab244bd7324211d182d9c552d42bdc662311ce8b5b61fcb3c27c3e1f48f539171f1149ee33ecf5fc08498575f74391c5af972b3
6
+ metadata.gz: 9b20b80ea7995d46e3f9cab97f54c558d3810aea8903a27a44446d05be713b51b6e6ca9dfd57ccb72771cabd28ee560a4ac78e13fd9628c5009d5c6b650c11a6
7
+ data.tar.gz: f75a07f4a6139a59d022c59de617629d248b45ea79e3de3916f39066ae1a5e4999851d1ddfad146f80b81c35eef1e691a043315a5ac5686fa9b199a013630376
data/.rubocop.yml CHANGED
@@ -1,6 +1,12 @@
1
1
  ---
2
2
  inherit_from: .rubocop_todo.yml
3
3
 
4
+ Layout/AlignParameters:
5
+ EnforcedStyle: with_fixed_indentation
6
+
7
+ Layout/DotPosition:
8
+ EnforcedStyle: trailing
9
+
4
10
  Lint/UselessAssignment:
5
11
  Exclude:
6
12
  - examples/geometries.rb
@@ -44,30 +50,37 @@ Metrics/ParameterLists:
44
50
  - lib/gdal/warp_operation.rb
45
51
  - lib/ogr/spatial_reference_mixins/coordinate_system_getter_setters.rb
46
52
 
47
- Style/AccessorMethodName:
53
+ Naming/AccessorMethodName:
48
54
  Exclude:
49
55
  - lib/ogr/layer_mixins/ogr_field_methods.rb
50
56
  - lib/ogr/layer_mixins/ogr_query_filter_methods.rb
51
57
  - lib/ogr/spatial_reference_mixins/coordinate_system_getter_setters.rb
52
58
 
53
- Style/AlignParameters:
54
- EnforcedStyle: with_fixed_indentation
59
+ Naming/FileName:
60
+ Exclude:
61
+ - Rakefile
62
+ - lib/ffi-gdal.rb
63
+ - spec/ffi-gdal_spec.rb
64
+
65
+ Naming/PredicateName:
66
+ Exclude:
67
+ - lib/ogr/geometry_mixins/extensions.rb
68
+
69
+ Naming/UncommunicativeMethodParamName:
70
+ Exclude:
71
+ - lib/gdal/raster_band_mixins/io_extensions.rb
72
+ - lib/ogr/geometries/line_string.rb
73
+ - lib/ogr/geometries/line_string_25d.rb
74
+ - lib/ogr/geometries/point.rb
75
+ - lib/ogr/geometries/point_25d.rb
76
+ - lib/ogr/geometry_types/curve.rb
55
77
 
56
78
  Style/Documentation:
57
79
  Enabled: false
58
80
 
59
- Style/DotPosition:
60
- EnforcedStyle: trailing
61
-
62
81
  Style/DoubleNegation:
63
82
  Enabled: false
64
83
 
65
- Style/FileName:
66
- Exclude:
67
- - Rakefile
68
- - lib/ffi-gdal.rb
69
- - spec/ffi-gdal_spec.rb
70
-
71
84
  Style/FormatString:
72
85
  EnforcedStyle: percent
73
86
 
@@ -77,10 +90,6 @@ Style/PercentLiteralDelimiters:
77
90
  '%w': '[]'
78
91
  '%W': '[]'
79
92
 
80
- Style/PredicateName:
81
- Exclude:
82
- - lib/ogr/geometry_mixins/extensions.rb
83
-
84
93
  Style/SymbolArray:
85
94
  Enabled: true
86
95
 
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2017-04-21 10:44:22 -0700 using RuboCop version 0.48.1.
3
+ # on 2018-03-21 17:46:40 -0700 using RuboCop version 0.54.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -10,10 +10,10 @@
10
10
  Metrics/AbcSize:
11
11
  Max: 74
12
12
 
13
- # Offense count: 1
13
+ # Offense count: 3
14
14
  # Configuration parameters: CountComments, ExcludedMethods.
15
15
  Metrics/BlockLength:
16
- Max: 29
16
+ Max: 67
17
17
 
18
18
  # Offense count: 11
19
19
  # Configuration parameters: CountComments.
@@ -24,11 +24,16 @@ Metrics/ClassLength:
24
24
  Metrics/CyclomaticComplexity:
25
25
  Max: 21
26
26
 
27
- # Offense count: 84
27
+ # Offense count: 82
28
28
  # Configuration parameters: CountComments.
29
29
  Metrics/MethodLength:
30
30
  Max: 78
31
31
 
32
+ # Offense count: 2
33
+ # Configuration parameters: CountKeywordArgs.
34
+ Metrics/ParameterLists:
35
+ Max: 9
36
+
32
37
  # Offense count: 6
33
38
  Metrics/PerceivedComplexity:
34
39
  Max: 11
@@ -39,24 +44,14 @@ Style/GuardClause:
39
44
  Exclude:
40
45
  - 'lib/gdal/gridder/point_extracting.rb'
41
46
 
42
- # Adding to allow for targeting ruby 2.3, but the fixes for this cop aren't
43
- # compatible with ruby 2.2. (I want to keep the frozen-string stuff in)
44
- #
45
- # Offense count: 2
46
- # Cop supports --auto-correct.
47
- # Configuration parameters: EnforcedStyle, SupportedStyles.
48
- # SupportedStyles: auto_detection, squiggly, active_support, powerpack, unindent
49
- Style/IndentHeredoc:
47
+ # Offense count: 1
48
+ Style/MixinUsage:
50
49
  Exclude:
51
- - 'spec/integration/gdal/dataset_info_spec.rb'
52
- - 'spec/unit/ogr/spatial_reference_mixins/exporters_spec.rb'
50
+ - 'examples/ogr_layer_to_layer.rb'
53
51
 
54
- # Adding to allow for targeting ruby 2.3, but the fixes for this cop aren't
55
- # compatible with ruby 2.2. (I want to keep the frozen-string stuff in)
56
- #
57
52
  # Offense count: 10
58
53
  # Cop supports --auto-correct.
59
- # Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles.
54
+ # Configuration parameters: AutoCorrect, EnforcedStyle.
60
55
  # SupportedStyles: predicate, comparison
61
56
  Style/NumericPredicate:
62
57
  Exclude:
data/History.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  Format for this file derived from [http://keepachangelog.com](http://keepachangelog.com).
4
4
 
5
+ ## 1.0.0.beta9 / 2018-03-26
6
+
7
+ ### Bug Fixes
8
+
9
+ * [AGDEV-30729] Change `OGERR_NONE` to use a lambda.
10
+
11
+ ### Improvements
12
+
13
+ * Fix some new rubocops.
14
+
5
15
  ## 1.0.0.beta8 / 2017-04-24
6
16
 
7
17
  ### Improvements
data/ffi-gdal.gemspec CHANGED
@@ -1,7 +1,6 @@
1
- # coding: utf-8
2
1
  # frozen_string_literal: true
3
2
 
4
- lib = File.expand_path('../lib', __FILE__)
3
+ lib = File.expand_path('lib', __dir__)
5
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
5
  require 'ffi/gdal/version'
7
6
 
@@ -23,6 +22,7 @@ Gem::Specification.new do |spec|
23
22
  spec.add_dependency 'log_switch', '~> 1.0.0'
24
23
  spec.add_dependency 'multi_xml'
25
24
  spec.add_dependency 'narray', '~> 0.6.0'
25
+ spec.add_dependency 'numo-narray'
26
26
 
27
27
  spec.add_development_dependency 'bundler', '~> 1.6'
28
28
  spec.add_development_dependency 'byebug'
@@ -2,6 +2,6 @@
2
2
 
3
3
  module FFI
4
4
  module GDAL
5
- VERSION = '1.0.0.beta8'
5
+ VERSION = '1.0.0.beta9'
6
6
  end
7
7
  end
@@ -7,48 +7,37 @@ module FFI
7
7
  class WarpOptions < FFI::Struct
8
8
  layout :warp_operation_options, :pointer,
9
9
  :warp_memory_limit, :double,
10
-
11
10
  :resample_alg, FFI::GDAL::Warper::ResampleAlg,
12
11
  :working_data_type, FFI::GDAL::GDAL::DataType,
13
12
  :source_dataset, GDAL.find_type(:GDALDatasetH),
14
13
  :destination_dataset, GDAL.find_type(:GDALDatasetH),
15
-
16
14
  :band_count, :int,
17
15
  :source_bands, :pointer,
18
16
  :destination_bands, :pointer,
19
17
  :source_alpha_band, :int,
20
18
  :destination_alpha_band, :int,
21
-
22
19
  :source_no_data_real, :pointer,
23
20
  :source_no_data_imaginary, :pointer,
24
21
  :destination_no_data_real, :pointer,
25
22
  :destination_no_data_imaginary, :pointer,
26
-
27
23
  :progress, GDAL.find_type(:GDALProgressFunc),
28
24
  :progress_arg, :pointer,
29
25
  :transformer, Alg.find_type(:GDALTransformerFunc),
30
26
  :transformer_arg, :pointer,
31
-
32
27
  :source_per_band_validity_mask_function, :pointer,
33
28
  :source_per_band_validity_mask_function_arg, :pointer,
34
-
35
29
  :source_validity_mask_function, Warper.find_type(:GDALMaskFunc),
36
30
  :source_validity_mask_function_arg, :pointer,
37
-
38
31
  :source_density_mask_function, Warper.find_type(:GDALMaskFunc),
39
32
  :source_density_mask_function_arg, :pointer,
40
-
41
33
  :destination_density_mask_function, Warper.find_type(:GDALMaskFunc),
42
34
  :destination_density_mask_function_arg, :pointer,
43
-
44
35
  :destination_validity_mask_function, Warper.find_type(:GDALMaskFunc),
45
36
  :destination_validity_mask_function_arg, :pointer,
46
-
47
37
  :pre_warp_chunk_processor, callback(%i[pointer pointer], CPL::Error::CPLErr),
48
38
  :pre_warp_processor_arg, :pointer,
49
39
  :post_warp_chunk_processor, callback(%i[pointer pointer], CPL::Error::CPLErr),
50
40
  :post_warp_processor_arg, :pointer,
51
-
52
41
  :cutline, :pointer,
53
42
  :cutline_blend_distance, :double
54
43
 
data/lib/ffi/gdal.rb CHANGED
@@ -36,9 +36,7 @@ module FFI
36
36
  def self.find_lib(lib)
37
37
  lib_file_name = "#{lib}.#{FFI::Platform::LIBSUFFIX}*"
38
38
 
39
- if ENV['GDAL_LIBRARY_PATH']
40
- return Dir[File.join(ENV['GDAL_LIBRARY_PATH'], lib_file_name)]
41
- end
39
+ return Dir[File.join(ENV['GDAL_LIBRARY_PATH'], lib_file_name)] if ENV['GDAL_LIBRARY_PATH']
42
40
 
43
41
  search_paths.map do |search_path|
44
42
  Dir.glob(search_path).map do |path|
@@ -39,7 +39,6 @@ module FFI
39
39
  # -----------------------------------------------------------------------
40
40
  # Constants
41
41
  # -----------------------------------------------------------------------
42
- # rubocop:disable Metrics/BlockLength
43
42
  SRS_UL = FFI::ConstGenerator.new('SRS_UL') do |gen|
44
43
  gen.include FFI::GDAL._file_with_constants('ogr_srs_api.h')
45
44
  gen.const :SRS_UL_METER, '%s', nil, :METER_LABEL, &:inspect
@@ -96,7 +95,6 @@ module FFI
96
95
  gen.const :SRS_UL_INDIAN_CHAIN, '%s', nil, :INDIAN_CHAIN_LABEL, &:inspect
97
96
  gen.const :SRS_UL_INDIAN_CHAIN_CONV, '%s', nil, :METER_TO_INDIAN_CHAIN, &:to_f
98
97
  end
99
- # rubocop:enable Metrics/BlockLength
100
98
 
101
99
  SRS_UL.calculate
102
100
 
@@ -6,9 +6,7 @@ module GDAL
6
6
  module ColorTableMixins
7
7
  module Extensions
8
8
  def color_entries_for(color_number)
9
- unless (1..4).to_a.include? color_number
10
- raise "Invalid ColorEntry number 'color#{color_number}'"
11
- end
9
+ raise "Invalid ColorEntry number 'color#{color_number}'" unless (1..4).to_a.include? color_number
12
10
 
13
11
  Array.new(color_entry_count) do |i|
14
12
  color_entry(i).send("color#{color_number}".to_sym)
@@ -258,7 +258,7 @@ module GDAL
258
258
  spatial_ref = OGR::SpatialReference.new(projection)
259
259
  begin
260
260
  spatial_ref.auto_identify_epsg!
261
- rescue
261
+ rescue StandardError
262
262
  OGR::UnsupportedSRS
263
263
  end
264
264
  end
@@ -276,9 +276,7 @@ module GDAL
276
276
  layer.create_field(OGR::FieldDefinition.new(field_name, :OFTInteger))
277
277
  band = raster_band(band_number)
278
278
 
279
- unless band
280
- raise GDAL::InvalidBandNumber, "Unknown band number: #{band_number}"
281
- end
279
+ raise GDAL::InvalidBandNumber, "Unknown band number: #{band_number}" unless band
282
280
 
283
281
  pixel_value_field = layer.feature_definition.field_index(field_name)
284
282
  options = { pixel_value_field: pixel_value_field }
data/lib/gdal/driver.rb CHANGED
@@ -27,9 +27,7 @@ module GDAL
27
27
  def self.by_name(name)
28
28
  driver_ptr = FFI::GDAL::GDAL.GDALGetDriverByName(name)
29
29
 
30
- if driver_ptr.null?
31
- raise InvalidDriverName, "'#{name}' is not a valid driver name."
32
- end
30
+ raise InvalidDriverName, "'#{name}' is not a valid driver name." if driver_ptr.null?
33
31
 
34
32
  new(driver_ptr)
35
33
  end
@@ -39,9 +37,7 @@ module GDAL
39
37
  # @return [GDAL::Driver]
40
38
  # @raise [GDAL::InvalidDriverIndex] If driver at +index+ does not exist.
41
39
  def self.at_index(index)
42
- if index > count
43
- raise InvalidDriverIndex, "index must be between 0 and #{count - 1}."
44
- end
40
+ raise InvalidDriverIndex, "index must be between 0 and #{count - 1}." if index > count
45
41
 
46
42
  driver_ptr = FFI::GDAL::GDAL.GDALGetDriver(index)
47
43
 
@@ -176,7 +172,7 @@ module GDAL
176
172
  def copy_dataset(source_dataset, destination_path, progress_block = nil, progress_arg = nil, strict: true,
177
173
  **options)
178
174
  source_dataset_ptr = make_dataset_pointer(source_dataset)
179
- raise GDAL::OpenFailure, "Source dataset couldn't be read" if source_dataset_ptr && source_dataset_ptr.null?
175
+ raise GDAL::OpenFailure, "Source dataset couldn't be read" if source_dataset_ptr&.null?
180
176
 
181
177
  options_ptr = GDAL::Options.pointer(options)
182
178
 
@@ -170,9 +170,7 @@ module GDAL
170
170
  def compose(other_geo_transform)
171
171
  other_ptr = GDAL._pointer(GDAL::GeoTransform, other_geo_transform)
172
172
 
173
- unless other_ptr
174
- raise GDAL::NullObject, "Unable to access pointer for '#{other_geo_transform}'"
175
- end
173
+ raise GDAL::NullObject, "Unable to access pointer for '#{other_geo_transform}'" unless other_ptr
176
174
 
177
175
  new_gt_ptr = self.class.new_pointer
178
176
  FFI::GDAL::GDAL.GDALComposeGeoTransforms(@c_pointer, other_ptr, new_gt_ptr)
data/lib/gdal/grid.rb CHANGED
@@ -33,7 +33,6 @@ module GDAL
33
33
  # @param progress_block [Proc]
34
34
  # @param progress_arg [FFI::Pointer]
35
35
  # @return [FFI::MemoryPointer] Pointer to the grid data.
36
- # rubocop:disable Metrics/ParameterLists
37
36
  def create(points, extents, data_pointer, output_size = { x: 256, y: 256 },
38
37
  progress_block = nil, progress_arg = nil)
39
38
  points = points.to_a if points.is_a? NArray
@@ -69,7 +68,6 @@ module GDAL
69
68
  progress_arg # pProgressArg
70
69
  )
71
70
  end
72
- # rubocop:enable Metrics/ParameterLists
73
71
 
74
72
  private
75
73
 
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'narray'
4
+ require 'numo/narray'
4
5
  require_relative '../gdal'
5
6
  require_relative 'raster_band_mixins/algorithm_extensions'
6
7
  require_relative 'raster_band_mixins/algorithm_methods'
@@ -140,7 +141,7 @@ module GDAL
140
141
  def category_names=(names)
141
142
  names_pointer = GDAL._string_array_to_pointer(names)
142
143
 
143
- !!FFI::GDAL::GDAL.GDALSetRasterCategoryNames(@c_pointer, names_pointer)
144
+ FFI::GDAL::GDAL.GDALSetRasterCategoryNames(@c_pointer, names_pointer)
144
145
  end
145
146
 
146
147
  # The no data value for a band is generally a special marker value used to
@@ -51,20 +51,22 @@ module GDAL
51
51
  # @param range_count [Fixnum] The number of ranges to create.
52
52
  # @return [Array<Hash>, nil]
53
53
  def equal_count_ranges(range_count)
54
- sorted_pixels = @raster_band.to_na.sort
55
- no_data = @raster_band.no_data_value[:value]
56
- sorted_and_masked_pixels = no_data ? sorted_pixels[sorted_pixels.ne(no_data)] : sorted_pixels
57
- return [] if sorted_and_masked_pixels.empty?
54
+ pixels = @raster_band.to_nna
55
+ masked_pixels = masked_pixels(pixels)
56
+
57
+ return [] if masked_pixels.empty?
58
58
 
59
+ sorted_and_masked_pixels = masked_pixels.to_a.sort
59
60
  range_size = (sorted_and_masked_pixels.size / range_count).to_i
60
61
 
61
- log "Masked pixel count/total pixel count: #{sorted_and_masked_pixels.size}/#{sorted_pixels.size}"
62
+ log "Masked pixel count/total pixel count: #{sorted_and_masked_pixels.size}/#{pixels.size}"
62
63
  log "Min pixel value: #{sorted_and_masked_pixels.min}"
63
64
  log "Max pixel value: #{sorted_and_masked_pixels.max}"
64
65
  log "Range size: #{range_size}"
65
66
 
66
67
  break_values = Array.new(range_count) { |i| sorted_and_masked_pixels[range_size * i] }.uniq
67
68
  log "Break values: #{break_values}"
69
+
68
70
  return if break_values.uniq.size != range_count
69
71
 
70
72
  breakpoint_calculator = lambda do |range_number|
@@ -85,27 +87,58 @@ module GDAL
85
87
  # values, so if you don't want to overwrite the Dataset you're working with,
86
88
  # you should copy it first.
87
89
  def classify!
88
- nodata_value = @raster_band.no_data_value[:value]
89
- band_pixels = @raster_band.to_na
90
- new_band_pixels = GDAL._narray_from_data_type(@raster_band.data_type, @raster_band.x_size, @raster_band.y_size)
91
- new_band_pixels[band_pixels.eq(nodata_value)] = nodata_value if nodata_value
92
- data_pixels = nodata_value ? band_pixels.ne(nodata_value) : band_pixels
90
+ band_pixels = @raster_band.to_nna
91
+ new_band_pixels = band_pixels.clone
92
+ data_pixels = if nodata_value
93
+ nodata_is_nan? ? ~band_pixels.isnan : band_pixels.ne(nodata_value)
94
+ else
95
+ Numo::Bit.cast(band_pixels.new_ones)
96
+ end
93
97
 
94
98
  @ranges.each do |r|
95
- new_band_pixels[
96
- data_pixels.
97
- and(band_pixels.le(r[:range].max)).
98
- and(band_pixels.ge(r[:range].min))
99
- ] = r[:map_to]
99
+ new_band_pixels[data_pixels & band_pixels.le(r[:range].max) & band_pixels.ge(r[:range].min)] = r[:map_to]
100
100
  end
101
101
 
102
+ mask_nan(new_band_pixels, data_pixels) if nodata_is_nan?
102
103
  @raster_band.write_xy_narray(new_band_pixels)
103
104
  end
104
105
 
106
+ # @return [Numeric] NODATA value for the @raster_band.
107
+ def nodata_value
108
+ @raster_band.no_data_value[:value]
109
+ end
110
+
111
+ # @return [Boolean] True if NODATA is NaN.
112
+ def nodata_is_nan?
113
+ nodata_value.is_a?(Float) && nodata_value.nan?
114
+ end
115
+
105
116
  private
106
117
 
118
+ # @param pixels [Numo::NArray]
119
+ # @return [Numo::NArray]
120
+ def masked_pixels(pixels)
121
+ no_data = @raster_band.no_data_value[:value]
122
+
123
+ if no_data
124
+ mask = no_data.is_a?(Float) && no_data.nan? ? ~pixels.isnan : pixels.ne(no_data)
125
+ pixels[mask]
126
+ else
127
+ pixels
128
+ end
129
+ end
130
+
107
131
  def range_for_type(min, max)
108
132
  min.to_data_type(@raster_band.data_type)..max.to_data_type(@raster_band.data_type)
109
133
  end
134
+
135
+ # Set nodata pixels to 0 and set the nodata value to 0.
136
+ #
137
+ # @param new_band_pixels [Numo::NArray]
138
+ # @param data_pixels [Numo::Bit]
139
+ def mask_nan(new_band_pixels, data_pixels)
140
+ new_band_pixels[~data_pixels] = 0
141
+ @raster_band.no_data_value = 0
142
+ end
110
143
  end
111
144
  end
@@ -37,6 +37,10 @@ module GDAL
37
37
  narray.to_type(narray_type)
38
38
  end
39
39
 
40
+ def to_nna
41
+ Numo::NArray[to_a]
42
+ end
43
+
40
44
  # Each pixel of the raster projected using the dataset's geo_transform.
41
45
  # The output NArray is a 3D array where the inner-most array is a the
42
46
  # lat an lon, those are contained in an array per pixel line, and finally
@@ -112,9 +112,7 @@ module OGR
112
112
  # @param options [Hash] Driver-specific options.
113
113
  # @return [OGR::Layer]
114
114
  def create_layer(name, geometry_type: :wkbUnknown, spatial_reference: nil, **options)
115
- unless can_create_layer?
116
- raise OGR::UnsupportedOperation, 'This data source does not support creating layers.'
117
- end
115
+ raise OGR::UnsupportedOperation, 'This data source does not support creating layers.' unless can_create_layer?
118
116
 
119
117
  spatial_ref_ptr = GDAL._pointer(OGR::SpatialReference, spatial_reference) if spatial_reference
120
118
  options_obj = GDAL::Options.pointer(options)
@@ -122,9 +120,7 @@ module OGR
122
120
  layer_ptr = FFI::OGR::API.OGR_DS_CreateLayer(@c_pointer, name,
123
121
  spatial_ref_ptr, geometry_type, options_obj)
124
122
 
125
- unless layer_ptr
126
- raise OGR::InvalidLayer, "Unable to create layer '#{name}'."
127
- end
123
+ raise OGR::InvalidLayer, "Unable to create layer '#{name}'." unless layer_ptr
128
124
 
129
125
  @layers << OGR::Layer.new(layer_ptr)
130
126
 
@@ -149,9 +145,7 @@ module OGR
149
145
  # @param index [Fixnum]
150
146
  # @return +true+ if successful, otherwise raises an OGR exception.
151
147
  def delete_layer(index)
152
- unless can_delete_layer?
153
- raise OGR::UnsupportedOperation, 'This data source does not support deleting layers.'
154
- end
148
+ raise OGR::UnsupportedOperation, 'This data source does not support deleting layers.' unless can_delete_layer?
155
149
 
156
150
  ogr_err = FFI::OGR::API.OGR_DS_DeleteLayer(@c_pointer, index)
157
151
 
data/lib/ogr/driver.rb CHANGED
@@ -74,9 +74,7 @@ module OGR
74
74
 
75
75
  data_source_ptr = FFI::OGR::API.OGR_Dr_Open(@c_pointer, file_name, update)
76
76
 
77
- if data_source_ptr.null?
78
- raise OGR::InvalidDataSource, "Unable to open data source at #{file_name}"
79
- end
77
+ raise OGR::InvalidDataSource, "Unable to open data source at #{file_name}" if data_source_ptr.null?
80
78
 
81
79
  OGR::DataSource.new(data_source_ptr, nil)
82
80
  end
@@ -124,9 +122,7 @@ module OGR
124
122
  def copy_data_source(source_data_source, new_file_name, **options)
125
123
  source_ptr = GDAL._pointer(OGR::DataSource, source_data_source)
126
124
 
127
- if source_ptr.nil? || source_ptr.null?
128
- raise OGR::InvalidDataSource, source_data_source
129
- end
125
+ raise OGR::InvalidDataSource, source_data_source if source_ptr.nil? || source_ptr.null?
130
126
 
131
127
  options_ptr = GDAL::Options.pointer(options)
132
128
 
data/lib/ogr/envelope.rb CHANGED
@@ -71,7 +71,7 @@ module OGR
71
71
 
72
72
  # @param new_z_min [Float]
73
73
  def z_min=(new_z_min)
74
- return nil unless @c_struct.is_a? FFI::OGR::Envelope3D
74
+ return unless @c_struct.is_a? FFI::OGR::Envelope3D
75
75
 
76
76
  @c_struct[:min_z] = new_z_min
77
77
  end
@@ -85,7 +85,7 @@ module OGR
85
85
 
86
86
  # @param new_z_max [Float]
87
87
  def z_max=(new_z_max)
88
- return nil unless @c_struct.is_a? FFI::OGR::Envelope3D
88
+ return unless @c_struct.is_a? FFI::OGR::Envelope3D
89
89
 
90
90
  @c_struct[:max_z] = new_z_max
91
91
  end
@@ -25,7 +25,7 @@ module OGR
25
25
  # @return [Proc]
26
26
  def error_class_map(error_class)
27
27
  {
28
- OGRERR_NONE: proc { true },
28
+ OGRERR_NONE: ->(_msg) { true },
29
29
  OGRERR_NOT_ENOUGH_DATA: ->(msg) { raise_exception(OGR::NotEnoughData, msg) },
30
30
  OGRERR_NOT_ENOUGH_MEMORY: ->(msg) { raise_exception(::NoMemoryError, msg) },
31
31
  OGRERR_UNSUPPORTED_GEOMETRY_TYPE: ->(msg) { raise_exception(OGR::UnsupportedGeometryType, msg) },
data/lib/ogr/feature.rb CHANGED
@@ -392,6 +392,7 @@ module OGR
392
392
 
393
393
  formatted_tz = OGR._format_time_zone_for_ruby(time_zone_flag_ptr.read_int)
394
394
 
395
+ # rubocop:disable Style/DateTime
395
396
  if formatted_tz
396
397
  DateTime.new(
397
398
  year_ptr.read_int,
@@ -412,6 +413,7 @@ module OGR
412
413
  second_ptr.read_int
413
414
  )
414
415
  end
416
+ # rubocop:enable Style/DateTime
415
417
  end
416
418
 
417
419
  # @return [String]
data/lib/ogr/field.rb CHANGED
@@ -52,7 +52,7 @@ module OGR
52
52
 
53
53
  # TODO: This blows up when another value type has been set.
54
54
  def string
55
- return '' if @c_struct[:string] && @c_struct[:string].null?
55
+ return '' if @c_struct[:string]&.null?
56
56
 
57
57
  @c_struct[:string].read_string
58
58
  end
@@ -186,6 +186,7 @@ module OGR
186
186
 
187
187
  formatted_tz = OGR._format_time_zone_for_ruby(c_date[:tz_flag].to_i)
188
188
 
189
+ # rubocop:disable Style/DateTime
189
190
  DateTime.new(c_date[:year],
190
191
  c_date[:month],
191
192
  c_date[:day],
@@ -193,6 +194,7 @@ module OGR
193
194
  c_date[:minute],
194
195
  c_date[:second],
195
196
  formatted_tz)
197
+ # rubocop:enable Style/DateTime
196
198
  end
197
199
 
198
200
  # @param new_date [Date, Time, DateTime]
@@ -6,8 +6,6 @@ module OGR
6
6
  class LineString
7
7
  include OGR::Geometry
8
8
  include GeometryTypes::Curve
9
-
10
- # rubocop:disable Metrics/ParameterLists
11
9
  def self.approximate_arc_angles(center_x, center_y, z, primary_radius, secondary_radius,
12
10
  rotation, start_angle, end_angle, max_angle_step_size_degrees = 0)
13
11
  geometry_ptr = FFI::GDAL::GDAL.OGR_G_ApproximateArcAngles(
@@ -25,7 +23,6 @@ module OGR
25
23
 
26
24
  new(geometry_ptr)
27
25
  end
28
- # rubocop:enable Metrics/ParameterLists
29
26
 
30
27
  def initialize(geometry_ptr = nil, spatial_reference: nil)
31
28
  geometry_ptr ||= OGR::Geometry.create(:wkbLineString)
data/lib/ogr/geometry.rb CHANGED
@@ -619,9 +619,7 @@ module OGR
619
619
 
620
620
  linear_ring = OGR::LinearRing.new
621
621
 
622
- if line_string.spatial_reference
623
- linear_ring.spatial_reference = line_string.spatial_reference.clone
624
- end
622
+ linear_ring.spatial_reference = line_string.spatial_reference.clone if line_string.spatial_reference
625
623
 
626
624
  linear_ring.import_from_wkt(line_string.to_wkt.tr('LINESTRING', 'LINEARRING'))
627
625
  linear_ring.close_rings! if close_rings
@@ -70,9 +70,7 @@ module OGR
70
70
  # field = FieldDefinition.new('Name', :OFTString)
71
71
  # field.width = 32
72
72
 
73
- unless layer
74
- raise OGR::InvalidLayer, "Unable to create layer '#{layer_name}'."
75
- end
73
+ raise OGR::InvalidLayer, "Unable to create layer '#{layer_name}'." unless layer
76
74
 
77
75
  feature = layer.create_feature(layer_name)
78
76
  feature.geometry = self
@@ -24,7 +24,7 @@ module OGR
24
24
 
25
25
  begin
26
26
  yield feature
27
- rescue
27
+ rescue StandardError
28
28
  feature.destroy!
29
29
  raise
30
30
  end
@@ -52,7 +52,7 @@ module OGR
52
52
 
53
53
  begin
54
54
  yield feature_ptr
55
- rescue
55
+ rescue StandardError
56
56
  FFI::OGR::API.OGR_F_Destroy(feature_ptr)
57
57
  raise
58
58
  end
@@ -128,7 +128,6 @@ module OGR
128
128
  # I've tried refactoring chunks of this out to separate methods and
129
129
  # performance suffers greatly. Since this is a key part of gridding (at
130
130
  # least at this point), it needs to be as fast as possible.
131
- # rubocop:disable Metrics/BlockLength
132
131
  each_feature_pointer do |feature_ptr|
133
132
  field_values = field_indices.map.with_index do |j, attribute_index|
134
133
  FFI::OGR::API.send("OGR_F_GetFieldAs#{with_attributes.values[attribute_index].capitalize}", feature_ptr, j)
@@ -211,7 +210,6 @@ module OGR
211
210
  "Not sure how to extract point_values for a #{geom_type}"
212
211
  end
213
212
  end
214
- # rubocop:enable Metrics/BlockLength
215
213
 
216
214
  log "#point_values took #{Time.now - start}s"
217
215
 
@@ -25,9 +25,7 @@ module OGR
25
25
  # @param feature [OGR::Feature] [description]
26
26
  # @return [Boolean]
27
27
  def create_feature(feature)
28
- unless can_sequential_write?
29
- raise OGR::UnsupportedOperation, 'This layer does not support feature creation.'
30
- end
28
+ raise OGR::UnsupportedOperation, 'This layer does not support feature creation.' unless can_sequential_write?
31
29
 
32
30
  ogr_err = FFI::OGR::API.OGR_L_CreateFeature(@c_pointer, feature.c_pointer)
33
31
 
@@ -41,9 +39,7 @@ module OGR
41
39
  # @raise [OGR::Failure] When trying to delete a feature with an ID that
42
40
  # does not exist.
43
41
  def delete_feature(feature_id)
44
- unless can_delete_feature?
45
- raise OGR::UnsupportedOperation, 'This layer does not support feature deletion.'
46
- end
42
+ raise OGR::UnsupportedOperation, 'This layer does not support feature deletion.' unless can_delete_feature?
47
43
 
48
44
  ogr_err = FFI::OGR::API.OGR_L_DeleteFeature(@c_pointer, feature_id)
49
45
 
@@ -63,9 +59,7 @@ module OGR
63
59
  #
64
60
  # @param new_feature [OGR::Feature, FFI::Pointer]
65
61
  def feature=(new_feature)
66
- unless can_random_write?
67
- raise OGR::UnsupportedOperation, '#feature= not supported by this Layer'
68
- end
62
+ raise OGR::UnsupportedOperation, '#feature= not supported by this Layer' unless can_random_write?
69
63
 
70
64
  new_feature_ptr = GDAL._pointer(OGR::Feature, new_feature)
71
65
  raise OGR::InvalidFeature if new_feature_ptr.nil? || new_feature_ptr.null?
@@ -79,9 +73,7 @@ module OGR
79
73
  # be <= +feature_count+, but no checking is done to ensure.
80
74
  # @return [OGR::Feature, nil]
81
75
  def feature(index)
82
- unless can_random_read?
83
- raise OGR::UnsupportedOperation, '#feature(index) not supported by this Layer'
84
- end
76
+ raise OGR::UnsupportedOperation, '#feature(index) not supported by this Layer' unless can_random_read?
85
77
 
86
78
  feature_pointer = FFI::OGR::API.OGR_L_GetFeature(@c_pointer, index)
87
79
  return nil if feature_pointer.null?
@@ -12,9 +12,7 @@ module OGR
12
12
  # different form, depending on the limitations of the format driver.
13
13
  # @return [Boolean]
14
14
  def create_field(field_definition, approx_ok = false)
15
- unless can_create_field?
16
- raise OGR::UnsupportedOperation, 'This layer does not support field creation.'
17
- end
15
+ raise OGR::UnsupportedOperation, 'This layer does not support field creation.' unless can_create_field?
18
16
 
19
17
  field_definition_ptr = GDAL._pointer(OGR::FieldDefinition, field_definition)
20
18
  ogr_err = FFI::OGR::API.OGR_L_CreateField(@c_pointer, field_definition_ptr, approx_ok)
@@ -26,9 +24,7 @@ module OGR
26
24
  #
27
25
  # @return +true+ if successful, otherwise raises an OGR exception.
28
26
  def delete_field(field_id)
29
- unless can_delete_field?
30
- raise OGR::UnsupportedOperation, 'This driver does not support field deletion.'
31
- end
27
+ raise OGR::UnsupportedOperation, 'This driver does not support field deletion.' unless can_delete_field?
32
28
 
33
29
  ogr_err = FFI::OGR::API.OGR_L_DeleteField(@c_pointer, field_id)
34
30
 
@@ -39,9 +35,7 @@ module OGR
39
35
  # which they should be reordered. I.e. [0, 2, 3, 1, 4].
40
36
  # @return [Boolean]
41
37
  def reorder_fields(*new_order)
42
- unless can_reorder_fields?
43
- raise OGR::UnsupportedOperation, 'This driver does not support field reordering.'
44
- end
38
+ raise OGR::UnsupportedOperation, 'This driver does not support field reordering.' unless can_reorder_fields?
45
39
 
46
40
  return false if new_order.empty?
47
41
  return false if new_order.any? { |i| i > feature_definition.field_count }
@@ -58,9 +52,7 @@ module OGR
58
52
  # @param old_position [Fixnum]
59
53
  # @param new_position [Fixnum]
60
54
  def reorder_field(old_position, new_position)
61
- unless can_reorder_fields?
62
- raise OGR::UnsupportedOperation, 'This driver does not support field reordering.'
63
- end
55
+ raise OGR::UnsupportedOperation, 'This driver does not support field reordering.' unless can_reorder_fields?
64
56
 
65
57
  ogr_err = FFI::OGR::API.OGR_L_ReorderField(@c_pointer, old_position, new_position)
66
58
 
@@ -37,9 +37,7 @@ module OGR
37
37
 
38
38
  # @return [Boolean]
39
39
  def transact
40
- unless supports_transactions?
41
- raise OGR::UnsupportedOperation, 'This layer does not support transactions.'
42
- end
40
+ raise OGR::UnsupportedOperation, 'This layer does not support transactions.' unless supports_transactions?
43
41
 
44
42
  ogr_err = yield
45
43
 
@@ -79,18 +79,18 @@ RSpec.describe 'Dataset Info', type: :integration do
79
79
 
80
80
  context 'param is an valid projection string' do
81
81
  let(:wkt) do
82
- <<-WKT
83
- GEOGCS["WGS 84",
84
- DATUM["WGS_1984",
85
- SPHEROID["WGS 84",6378137,298.257223563,
86
- AUTHORITY["EPSG",7030]],
87
- TOWGS84[0,0,0,0,0,0,0],
88
- AUTHORITY["EPSG",6326]],
89
- PRIMEM["Greenwich",0,AUTHORITY["EPSG",8901]],
90
- UNIT["DMSH",0.0174532925199433,AUTHORITY["EPSG",9108]],
91
- AXIS["Lat",NORTH],
92
- AXIS["Long",EAST],
93
- AUTHORITY["EPSG",4326]]
82
+ <<~WKT
83
+ GEOGCS["WGS 84",
84
+ DATUM["WGS_1984",
85
+ SPHEROID["WGS 84",6378137,298.257223563,
86
+ AUTHORITY["EPSG",7030]],
87
+ TOWGS84[0,0,0,0,0,0,0],
88
+ AUTHORITY["EPSG",6326]],
89
+ PRIMEM["Greenwich",0,AUTHORITY["EPSG",8901]],
90
+ UNIT["DMSH",0.0174532925199433,AUTHORITY["EPSG",9108]],
91
+ AXIS["Lat",NORTH],
92
+ AXIS["Long",EAST],
93
+ AUTHORITY["EPSG",4326]]
94
94
  WKT
95
95
  end
96
96
 
@@ -58,9 +58,7 @@ RSpec.describe 'Raster Band Info', type: :integration do
58
58
 
59
59
  describe '#color_table' do
60
60
  it 'is a GDAL::ColorTable' do
61
- if subject.color_table
62
- expect(subject.color_table).to be_a GDAL::ColorTable
63
- end
61
+ expect(subject.color_table).to be_a GDAL::ColorTable if subject.color_table
64
62
  end
65
63
  end
66
64
 
data/spec/spec_helper.rb CHANGED
@@ -9,7 +9,7 @@ SimpleCov.start do
9
9
  add_group 'ext', 'lib/ext'
10
10
  end
11
11
 
12
- $LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
12
+ $LOAD_PATH.unshift File.expand_path('lib', __dir__)
13
13
  require 'ffi-gdal'
14
14
  require 'byebug'
15
15
 
@@ -98,8 +98,8 @@ RSpec.describe GDAL::RasterBandClassifier do
98
98
  end
99
99
 
100
100
  context 'all nodata pixels' do
101
- let(:band_narray) { NArray.byte(0) }
102
- before { allow(raster_band).to receive(:to_na).and_return(band_narray) }
101
+ let(:band_narray) { Numo::Int8.new(3, 5).fill(0) }
102
+ before { allow(raster_band).to receive(:to_nna).and_return(band_narray) }
103
103
 
104
104
  it 'returns an empty Array' do
105
105
  expect(subject.equal_count_ranges(10)).to eq([])
@@ -196,4 +196,40 @@ RSpec.describe GDAL::RasterBandClassifier do
196
196
  end
197
197
  end
198
198
  end
199
+
200
+ describe '#masked_pixels' do
201
+ let(:pixels) { dataset.raster_band(1).to_nna }
202
+ let(:raster_band) { double 'Band', no_data_value: { value: nodata_value } }
203
+
204
+ before { subject.instance_variable_set(:@raster_band, raster_band) }
205
+
206
+ context 'nodata is NaN' do
207
+ let(:nodata_value) { Float::NAN }
208
+ let(:pixels) { Numo::DFloat.cast(dataset.raster_band(1).to_nna) }
209
+
210
+ before do
211
+ pixels[pixels.eq(0)] = nodata_value
212
+ end
213
+
214
+ it 'removes all nodata values' do
215
+ expect(subject.send(:masked_pixels, pixels).isnan.count_true).to eq 0
216
+ end
217
+ end
218
+
219
+ context 'nodata is a number' do
220
+ let(:nodata_value) { 0 }
221
+
222
+ it 'removes all nodata values' do
223
+ expect(subject.send(:masked_pixels, pixels).eq(0).count_true).to eq 0
224
+ end
225
+ end
226
+
227
+ context 'nodata is nil' do
228
+ let(:nodata_value) { nil }
229
+
230
+ it 'returns the original pixels' do
231
+ expect(subject.send(:masked_pixels, pixels)).to eq pixels
232
+ end
233
+ end
234
+ end
199
235
  end
@@ -275,7 +275,7 @@ RSpec.describe OGR::Feature do
275
275
  end
276
276
 
277
277
  describe '#set_field_date_time + #field_as_date_time' do
278
- let(:date_time) { DateTime.now }
278
+ let(:date_time) { DateTime.now } # rubocop:disable Style/DateTime
279
279
 
280
280
  context 'to a valid index' do
281
281
  it 'adds the field' do
@@ -184,7 +184,7 @@ RSpec.describe OGR::Field do
184
184
 
185
185
  describe '#date= + #date' do
186
186
  context 'valid date' do
187
- let(:now) { DateTime.now }
187
+ let(:now) { DateTime.now } # rubocop:disable Style/DateTime
188
188
 
189
189
  it 'sets the date' do
190
190
  subject.date = now
@@ -109,18 +109,18 @@ RSpec.describe OGR::SpatialReference do
109
109
  subject { described_class.new_from_epsg(4322) }
110
110
 
111
111
  it 'returns a well-known text String' do
112
- expect(subject.to_pretty_wkt).to eq <<-WKT.strip
113
- GEOGCS["WGS 72",
114
- DATUM["WGS_1972",
115
- SPHEROID["WGS 72",6378135,298.26,
116
- AUTHORITY["EPSG","7043"]],
117
- TOWGS84[0,0,4.5,0,0,0.554,0.2263],
118
- AUTHORITY["EPSG","6322"]],
119
- PRIMEM["Greenwich",0,
120
- AUTHORITY["EPSG","8901"]],
121
- UNIT["degree",0.0174532925199433,
122
- AUTHORITY["EPSG","9122"]],
123
- AUTHORITY["EPSG","4322"]]
112
+ expect(subject.to_pretty_wkt).to eq <<~WKT.strip
113
+ GEOGCS["WGS 72",
114
+ DATUM["WGS_1972",
115
+ SPHEROID["WGS 72",6378135,298.26,
116
+ AUTHORITY["EPSG","7043"]],
117
+ TOWGS84[0,0,4.5,0,0,0.554,0.2263],
118
+ AUTHORITY["EPSG","6322"]],
119
+ PRIMEM["Greenwich",0,
120
+ AUTHORITY["EPSG","8901"]],
121
+ UNIT["degree",0.0174532925199433,
122
+ AUTHORITY["EPSG","9122"]],
123
+ AUTHORITY["EPSG","4322"]]
124
124
  WKT
125
125
  end
126
126
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-gdal
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.beta8
4
+ version: 1.0.0.beta9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Loveless
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-28 00:00:00.000000000 Z
11
+ date: 2018-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -66,6 +66,20 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.6.0
69
+ - !ruby/object:Gem::Dependency
70
+ name: numo-narray
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: bundler
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -530,7 +544,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
530
544
  version: 1.3.1
531
545
  requirements: []
532
546
  rubyforge_project:
533
- rubygems_version: 2.6.11
547
+ rubygems_version: 2.7.6
534
548
  signing_key:
535
549
  specification_version: 4
536
550
  summary: FFI wrapper for GDAL/OGR.