Erik
Erik

Reputation: 89

ruby: using blocks as normal (inline) expressions?

Looking for a little wisdom from fellow Rubyists. For a while now, I've used the following for convenience in some of my applications, and I'm wondering if there's a language feature I'm just missing:

class Object
  def as_block
    yield
  end
end

There are other uses, but the normal case for me is a conditional assignment that requires a little non-trivial logic. Two obvious ways to do this:

# via a second method:
def foo
  @foo ||= set_foo
end

# via conditional logic:
def foo
  if @foo
    @foo
  else
    # do complicated stuff
  end
end

Both of these approaches seem kind of ugly: in the first case, #set_foo seems extraneous, and the second just looks kind of nasty. So, instead, I like this:

def foo
  @foo ||= as_block do
    # do complicated stuff
  end
end

The problem here (aside from monkey patching Object) is that it's really a dependency (on the monkey patch) that looks like a language feature. That is, something like this really shouldn't be in (say) a Rails initializer---it seems like it should be in a gem, so the dependency can be managed correctly. Then I'm packaging an entire gem to run five lines of code to monkey patch Object...

So, my questions: 1. Anyone else use this, or something like it? 2. Has the Ruby team ever considered including something like this by default? It seems like a really easy way to use blocks as plain old expressions, but it's not there (as far as I know) which makes me wonder if there's some reason for not including it, or... 3. Is there already some better way of doing this that I'm just unaware of?

Thanks!

-E

Upvotes: 1

Views: 109

Answers (2)

Ajedi32
Ajedi32

Reputation: 48368

What you're looking for is begin ... end. This isn't the same thing as a block or Proc, as it's not an object you can pass around or a closure which creates a new scope, but it should serve your purpose just fine:

def foo
  @foo ||= begin
    # do complicated stuff
  end
end

Upvotes: 5

hjing
hjing

Reputation: 4982

You could use a lambda:

def foo
  @foo ||= lambda do
    # do complicated stuff
  end.call
end

Note that it is important to call the lambda to actually execute the expression, ie

def foo
  @foo ||= lambda do
    # do complicated stuff
  end
end

will return a lambda rather than your evaluated expression.

Upvotes: 2

Related Questions