Forwarding Class Methods in Ruby
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
2
3
4
5
6
7
8
9
10
11
12
13
14
require 'logger'
require 'forwardable'
class SpecialLogger
extend SingleForwardable
@logger = Logger.new(STDOUT)
@logger.level = Logger::INFO
def_delegators :@logger, :debug, :info, :warn, :error, :fatal
end
SpecialLogger.warn("Oh no!")
# W, [2014-12-29T15:07:39.704559 #41608] WARN -- : Oh no!
Works perfectly, and in just a few quick, extremely readable, lines of code.