Reputation: 168081
Often, I have a recursive routine within a method that is only called by that method or within the recursive routine itself:
def foo
...
bar
...
end
def bar
...
bar
...
end
But since bar
is not used anywhere else, I do not want to define it as a method but somehow put it inside the method that calls it like this:
def foo
...
bar {# some way to mark the recursive routine
...
bar # some way to call the recursive routine
...
}
...
end
Is this possible?
Upvotes: 1
Views: 200
Reputation: 79562
Easy with a lambda/proc:
def foo(n)
fact = lambda do |i|
i.zero? ? 1 : i * fact.call(i-1)
end
fact.call(n)
end
foo(4) # => 24
You can also use a protected or private method.
If performance is a real concern, creating an object (the lambda) each time will be slower, and calling a lambda is also slower, closure and all. My fruity
gem gives me a 3.3x slowdown on this trivial example; the penalty should be much less for cases that actually do something more involved. Just be sure that performance really is an issue; you know what they say about premature optimization...
Upvotes: 4
Reputation: 20408
@coreyward 's answer is good, but there's another trick you could use to limit the scope of the recursive function using lambda.
def foo
...
bar = lambda do |arg|
...
bar.call(...)
...
end
bar.call(...)
...
end
Since bar is lexically scoped within foo, no other method can see it or call it, but the lambda which bar refers to can see bar since it closes over the lexical scope where it's defined.
Upvotes: 0
Reputation: 80041
Sounds like you're trying to do functional programming in an object-oriented language. You might be better served by creating a small class with a single responsibility:
class Routiner
def foo(*args)
# occasionally...
do_work(some_data)
end
protected
def do_work(data)
# ...work work work
do_work(more_data) if some_condition
end
end
Routiner.new.foo('bar', 'baz', 'bat')
Upvotes: 2