3
\$\begingroup\$

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?

asked Mar 21, 2012 at 18:24
\$\endgroup\$
2
  • 1
    \$\begingroup\$ I don't get it? What is your question? \$\endgroup\$ Commented Mar 25, 2012 at 8:13
  • \$\begingroup\$ 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 \$\endgroup\$ Commented Mar 26, 2012 at 23:23

1 Answer 1

1
\$\begingroup\$

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
answered Mar 28, 2012 at 12:44
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.