Archive
words and words and words
N/A
[rgeo] unable to convert multilinestring with zm geometry to geojson

I encountered a very specific issue when trying to convert the geometries read from shapefiles to geojson, and for some reason this failed.

I had some very simple code to inspect the shapefiles and see what I should do with them. In that process I also wanted to convert the geometries to geojson (for test), as that is the actual goal for me.

So my code iterates over a folder of shape-files, and then just does an inspection of the first element. This should give me an idea of what all the files contain. The code looked like this

Dir[File.join(root_folder, '*.shp')].sort.each do |shapefile|
  puts shapefile

  RGeo::Shapefile::Reader.open(shapefile) do |file|
    puts "File contains #{file.num_records} records."
    record = file.next
    puts "First record geometry WKT  : #{record.geometry.as_text}"
    puts "             coordinates   : #{record.geometry.coordinates}"
    puts "             geometry JSON : #{RGeo::GeoJSON.encode(record.geometry)}"
    puts "             Attributes    : #{record.attributes.inspect}"
    puts 
  end
end

I got the weirdest error when trying to run this code

 gems/rgeo-0.6.0/lib/rgeo/geos/zm_feature_methods.rb:305:in `block in each': no block given (yield) (LocalJumpError)

Apparently one of the shjapefiles contained a MultiLinestring with a z and m coordinate. All zero, so whyyyyy ? But still: rgeo should be able to handle that?

I tracked the code in rgeo and found the following culprit in Rgeo::Geos::ZMMultiLineStringMethods

 each.map(&:coordinates)

Ooooops. Now how could i fix this? I am currently working on an ancient version of rails, and thus also rgeo. I could open an issue to fix it, but still I would not be able to update my own version (mostly because of the activerecord-postgis-adapter).

But, thankfully, we are using ruby and we can hotfix code (reopen the class and fix the bug!). So I added an initializer in config\initializers\fix_rgeo_bug.rb with the following code

module RGeo
  module Geos
    module ZMMultiLineStringMethods # :nodoc:

      # overwrite to fix!
      def coordinates
        puts "COOOORDINATES"
        coords = []
        each do |gm|
          coords << gm.coordinates
        end
        coords 
      end

    end
  end
 end

... and now my code is running smoothly!!

So awesome it is possible in ruby to reopen classes. And that rails has a well controlled loading system and an entry-point before execution to place my own initializers. I have used this a few times before, mainly to fix outdated gems without having to update them, or add very specific behaviour. It is the combination of having readable code, open source code, and then re-opening classes to add my own behaviour or fix bugs. I am still thankful/happy every day to be working in ruby on rails :clap: :clap: :clap:

I wonder if there are other programming languages or frameworks where this is possible?

Now open an issue on rgeo to address this bug :)

More ...
News
Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'

So, unfortunately we have to deploy our rails projects on servers which are managed by our clients, and so this means those are windows servers. Luckily this no longer is a big deal, but I develop on mac and mostly deploy on linux machines (which align). But a new deployment on windows almost always adds some surprises. So we deploy using ruby 2.4 and somewhere in our Gemfile we use eventmachine and on the most recent deployment I suddenly got this weird error:

Unable to load the EventMachine C extension; To use the pure-ruby reactor, require 'em/pure_ruby'

Not sure what they mean here: do I need to adapt the gem-code???? But luckily some googling quickly turned up a solution. Apparently the eventmachine gem is not updated correctly to use ruby 2.4 or 2.5 and the proposed solution is to do

gem uninstall eventmachine  
gem install eventmachine --platform=ruby

instead. This sounds great. In theory. But in practice? I have a bundle Gemfile and after every deploy/bundle I will have to uninstall the eventmachine-1.2.7-x64-mswin32 gem. I do have a script that I run on windows to deploy, and so I could easily add

gem uninstall -aIx eventmachine 
gem install eventmachine --platform=ruby

(the -aIx will remove all eventmachine instances and not care about dependencies)
but this feels a little counter-productive (wrong?) and it did not always seem to work reliably.

So I was looking for ways to describe in my Gemfile how to install the gem with the correct platform. Unfortunately platform has a different meaning inside a Gemfile, and the ruby platform is anything but windows.

But then I had an inspirational moment, why not install the gem from github, in the correct version?

So in my Gemfile I wrote

gem 'eventmachine', '1.2.7', git: 'git@github.com:eventmachine/eventmachine', tag: 'v1.2.7'

Installing the required version directly from git, which does work and does not break my deployment script/routine.

More ...