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 (#debug, #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.