How to hook a callback through inheritance

S

Satsou Sa

Hello,

I've got some troubles with Ruby about callbacks (and inheritance). Here
is my code:

class Lmao
def initialize
@str = "HAHAHAHAHAHHAHAHAH"
@before_laughing = []
end

def self.inherited(base)
base.extend(Callbacks)
end

def laughing
@before_laughing.each {|method| send(method) }
@str
end
end

module Callbacks
def before_laughing(*methods)
@before_laughing = methods
end
end

class Lol < Lmao
before_laughing :downcase_please

def downcase_please
@str.downcase!
end
end

a = Lol.new
a.laughing # => "HAHAHAHAHAHHAHAHAH"

And as you can see, my before laughing callback don't work... because
the array @before_laughing is empty. I believe this can be fixed by
editing the way I save *methods into an Lol's instance method (from
inside Callbacks). But I don't really see how...

If you know the solution, thanks for your light!
 
S

Satsou Sa

Thanks to **Mon_Ouie**, the solution is:

class Lmao
def initialize
@str = "HAHAHAHAHAHHAHAHAH"
end

def self.inherited(base)
base.extend(Callbacks)
end

def laughing
self.class.callbacks_before_laughing.each {|method| send(method)
}
@str
end
end

module Callbacks
def before_laughing(*methods)
@before_laughing = methods
end

def callbacks_before_laughing
@before_laughing
end
end

class Lol < Lmao
before_laughing :downcase_please

def downcase_please
@str.downcase!
end
end

Pretty awesome.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

The problem is that before_laughing is being invoked as a class method on
Lol. So when you say "before_laughing :downcase_please", you aren't setting
@before_laughing on instances of Lol, but rather on Lol itself.

I suppose one way to do this is to leave the instance var on the class, then
just ask the class for its contents and execute them the same way. With this
implementation, that means you can't add callbacks for individual objects,
though.


class Lmao
def initialize
@str = "HAHAHAHAHAHHAHAHAH"
end

def self.inherited(base)
base.extend Callbacks
end

def laughing
self.class.before_laughing.each do |method|
send method
end
@str
end
end

module Callbacks
def before_laughing(*methods)
if methods.empty?
@before_laughing ||= Array.new
else
@before_laughing = methods
end
end
end

class Lol < Lmao
before_laughing :downcase_please

def downcase_please
@str.downcase!
end
end

a = Lol.new
a.laughing # => "hahahahahahhahahah"
 
S

Satsou Sa

Josh Cheek wrote in post #971483:
The problem is that before_laughing is being invoked as a class method
on
Lol. So when you say "before_laughing :downcase_please", you aren't
setting
@before_laughing on instances of Lol, but rather on Lol itself.
Okay.

I suppose one way to do this is to leave the instance var on the
class, then just ask the class for its contents and execute them
the same way.

Using your code, I have the same result then Mon_Ouie, with one less
method in the code and no errors when a callback isn't called. It's just
so cool.
With this implementation, that means you can't add callbacks
for individual objects, though.

However, I am not sure to understand this point. I believe I can do it.
Here I tried to add different callbacks on different classes (and every
thing is working find):
?> a = Lol.new
?> b = Lool.new
?> c = Loool.new
=> "hahahahahahhahahah_ok"

But if I understand correctly, I can not do so by class instance...
Well, okay. For my needs, it's just perfect anyway. Thank you!!
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

However, I am not sure to understand this point. I believe I can do it.
Here I tried to add different callbacks on different classes (and every
thing is working find):
I mean that you can't add a callback for a given instance of the class.
Every instance of Lol will have the same before_laughing callbacks. It
shouldn't be too much more work to give them the ability to have such
behaviour, if you need it, I just thought I should point it out since your
initial implementation seemed to assume that the @before_laughing was set on
each instance.
 
M

masa

It may be too late but how about this?

----
class Lmao
def initialize
@str = "HAHAHAHAHAHHAHAHAH"
end
def laughing
@str
end
=begin
def self.inherited(base)
base.extend(Callbacks)
end
=end
end

module Callbacks
def before_laughing(*methods)
define_method:)laughing) do
methods.each do |m|
send(m)
end
super
end
end
end

class Lol < Lmao
extend Callbacks
before_laughing :downcase_please
def downcase_please
@str.downcase!
end
end

a = Lol.new
p a.laughing
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,128
Latest member
ElwoodPhil
Top