Recently I had a project where I wanted to make a simple “centralized logger” that could be called from anywhere in a small application. I decided to set up a simple class that I could call from anywhere in the app, re-using the Ruby Logger class’s various write methods (
#warn, and so on).
I experimented with a lot of different solutions for forwarding or delegating a Ruby class method. My first stop was at the Forwardable module, but I couldn’t figure out a way to get it to delegate a class method. I eventually rigged up a somewhat hacky solution with define_method, but I wasn’t very happy with it.
Finally, a co-worker pointed me to SingleForwardable, which can be used to set up delegations for individual objects, classes, or modules. Perfect!
1 require 'logger' 2 require 'forwardable' 3 4 class SpecialLogger 5 extend SingleForwardable 6 7 @logger = Logger.new(STDOUT) 8 @logger.level = Logger::INFO 9 10 def_delegators :@logger, :debug, :info, :warn, :error, :fatal 11 end 12 13 SpecialLogger.warn("Oh no!") 14 # W, [2014-12-29T15:07:39.704559 #41608] WARN -- : Oh no!
Works perfectly, and in just a few quick, extremely readable, lines of code.