# Delegating to a lazily loaded object in Ruby

I have an API that takes a class as a configuration parameter, but I don't want to load the class (I'm using Rails) at the time that I'm setting up the API. I figured I could get around this by passing it an object that acts like the class in every way (by delegating to it) but doesn't actually reference the class, and thus load the class. until it us used.

This is what it expects:

MyAPI.configure.model = UserModel


But I'd like to give it something like:

MyAPI.configure.model = ->{ UserModel }


This is what I have. It works as well as expected but I have a feeling I take better advantage of Ruby's features and/or the standard library.

def lazy_delegate(&block)

delegate = BasicObject.new

def delegate.method_missing(message, *args)
@target ||= @target_block.call
@target.send message, *args
end

def delegate.__target__=(block)
@target_block = block
end

delegate.__target__ = block

delegate
end


I'm using this like:

MyAPI.configure.model = lazy_delegate{ UserModel }


Is there a better way to accomplish this? Does Ruby's standard library have anything that would make this cleaner?

• I don't get it? What is your question? – Mas Adit Mar 25 '12 at 8:13
• Question is "Is there a better way to accomplish this? Does Ruby's standard library have anything that would make this cleaner?". I added it explicitly. Thanks – nicholaides Mar 26 '12 at 23:23

You could pass in a string instead of a proc and use Object.const_get().

class_const = Object.const_get 'String'
=> String
class_const.new "hello"
=> "hello"


With a call-able constructor.

constructor = class_const.public_method :new
=> #<Method: Class#new>
constructor.call "ohai"
=> "ohai"


You need to guard against NameErrors.

Object.const_get('NotThere')
NameError: uninitialized constant NotThere


A lazy load method to build the dependency (Error checking elided for clarity).

def model
@model ||= build_model('arg1', 'arg2')
end

def build_model(*args)
Object.const_get(self.configure.model_name).send(:new, *args)
end