Search code examples
rubylambdaredissymbolsmonkeypatching

How to override a lambda variable from a subclass in Ruby?


I am using the Redis gem to access redis, and I would like .hgetall to symbolize the keys of the hashes it returns. In this thread, @pletern indicates a method of monkey patching the gem's _hashify method.

However this was a while ago, and the current implementation uses a lambda to Hashify the list returned from Redis, instead of a method. See line 2728

I have been attempting to 'override' this lambda with my own implementation, following something similar what would be used for a method:

class MyRedis < Redis

  private

  Hashify =
    lambda { |array|
      hash = Hash.new
      array.each_slice(2) do |field, value|
        hash[field.to_sym] = value
      end
      hash
    }
end

and in my RedisService:

class RedisService
  class << self

    def hgetall(key)
      redis.hgetall("room:"+room_name)
    end

    private

    def redis
      @@redis ||= MyRedis.new
    end

  end
end

I have played around with my class and not been able to override the Hashify lambda in the gem.


Solution

  • Setting your own Hashify in your subclass doesn't help, because the Ruby interpreter will use the constant defined in Redis, as the methods that call Hashify.call are defined there, too.

    You can override Redis::Hashify, though. This will result in your lambda being used for all Redis connections and in warning: already initialized constant Redis::Hashify

    require 'redis'
    
    Redis::Hashify = lambda do |array|
      Hash.new.tap do |hash|
        array.each_slice(2) do |field, value|
          hash[field.to_sym] = value
        end
      end
    end
    

    Please note writing code that produces warnings is considered bad style by many developers. It might be better to modify the response of Redis#hgetall after you received it. If you don't mind using ActiveSupport, you can use it's Hash#symbolize_keys, for instance.