Reputation: 5148
I am looking to do some method chaining. I have the following code:
class MyClass
attr_accessor :handler
def do_a
puts 'i just did a'
self.handler = 'a'
self
end
def do_b_if_a
puts 'i just did b' if handler == 'a'
end
end
So the following works:
irb > test = MyClass.new
=> #<MyClass:0x007fa44ced9a70 @handler=nil>
irb > test.do_a
'i just did a'
irb > test.do_a.do_b_if_a
'i just did a'
'i just did b'
What I DONT want to work is when I call do_a the first time it sets the handler, which means now do_b_if_a can be called at any time. But I only want it to be called when it is chained with do_a, how do I do that?
Upvotes: 2
Views: 136
Reputation: 31574
Doesn't get you all the way there, but you could define do_b_if_a
as a singleton method that gets added when to_a
is called:
class MyClass
def do_a
puts 'i just did a'
self.tap{|s| def s.do_b_if_a; puts 'i just did b' end}
end
end
You could take a look at Kernel.caller if you want to take certain actions based on the call stack. However, you might get punched in the face by another developer if you don't have a good reason for doing so, lol.
Upvotes: 0
Reputation: 434615
I think you're tracking state in the wrong place. You'd be better off with something similar to ActiveRecord's query interface, for example:
class MyClass
attr_accessor :handler
def do_a
puts 'i just did a'
with_handler 'a'
end
def do_b_if_a
puts 'i just did b' if handler == 'a'
end
private
def with_handler(h)
o = dup
o.handler = h
o
end
end
That way you always have an instance of MyClass but you have a throw-away copy that keeps track of its history. This is similar to cHao's approach but it doesn't need an extra decorator class as MyClass can decorate itself.
Upvotes: 0
Reputation: 3634
As cHao said, you shouldn't try to method call patterns. But I can also think of another way to do this:
def do_a
puts "i just did a"
do_b_if_a(true)
end
def do_b_if_a(did_a=false)
puts "i just did b" if did_a
end
do_a # prints "i just did a"
do_b_if_a # does nothing
Sure, you can call do_b_if_a(true)
, but then it just makes it more flexible ;)
Upvotes: 0
Reputation: 86506
In general, you don't want to care (and in most cases, you don't even get to know) if your methods are called in a certain way. That way lies madness. Magic call sequences make for a hell of a time debugging and testing.
What you could do, though...instead of having do_a
return self
, wrap a decorator around it that defines do_b
, and return the decorator. At that point, your original MyClass
can't do_b
, cause it doesn't know how. But the thingie returned from do_a
can.
(Now, you can still say like a = test.do_a
and then a.do_b
, but you can't really get around that without parsing the Ruby code yourself.)
Upvotes: 1