callbacks, events, notification in general

D

Damphyr

OK, bare with me, this is brainstorming of a sorts:
I want to have some kind of event notification from my classes.
Typically what I would do would be to pass a logger object and let the
class log by itself, but I'm not really satisfied with this solution in
most cases.

What I would prefer was define a callback method and give this to the
object. Then I could do whatever I want with it and not only use logs.
Mostly I want to have progress reports.

something like

class A
def set_callback notify
@notify=notify
end
def something
puts "something"
send(@notify) if @notify
end
end

def coocoo
puts "hey"
end
a=A.new
a.something
a.set_callback:)coocoo)
a.something

Now this does exactly what I want and can be wrapped up in a module to
be included for general use.
Question: Is there a "better" solution? What are my alternatives?
Cheers,
V.-


--
http://www.braveworld.net/riva

____________________________________________________________________
http://www.freemail.gr - äùñåÜí õðçñåóßá çëåêôñïíéêïý ôá÷õäñïìåßïõ.
http://www.freemail.gr - free email service for the Greek-speaking.
 
A

ara.t.howard

OK, bare with me, this is brainstorming of a sorts:
I want to have some kind of event notification from my classes.
Typically what I would do would be to pass a logger object and let the
class log by itself, but I'm not really satisfied with this solution in
most cases.

What I would prefer was define a callback method and give this to the
object. Then I could do whatever I want with it and not only use logs.
Mostly I want to have progress reports.

something like

class A
def set_callback notify
@notify=notify
end
def something
puts "something"
send(@notify) if @notify
end
end

def coocoo
puts "hey"
end
a=A.new
a.something
a.set_callback:)coocoo)
a.something

Now this does exactly what I want and can be wrapped up in a module to
be included for general use.
Question: Is there a "better" solution? What are my alternatives?
Cheers,
V.-

harp:~ > cat a.rb
require "observer"

class A
include Observable
def something
changed and notify_observers 42
end
end

class B
def update arg
p arg
end
end

a = A::new
b = B::new

a.add_observer b
a.something


harp:~ > ruby a.rb
42

always a good start to read about the stdlibs! ;-)

cheers.

-a
 
R

Robert Klemme

Damphyr said:
OK, bare with me, this is brainstorming of a sorts:
I want to have some kind of event notification from my classes.
Typically what I would do would be to pass a logger object and let the
class log by itself, but I'm not really satisfied with this solution
in most cases.

What I would prefer was define a callback method and give this to the
object. Then I could do whatever I want with it and not only use logs.
Mostly I want to have progress reports.

something like

class A
def set_callback notify
@notify=notify
end
def something
puts "something"
send(@notify) if @notify
end
end

def coocoo
puts "hey"
end
a=A.new
a.something
a.set_callback:)coocoo)
a.something

Now this does exactly what I want and can be wrapped up in a module to
be included for general use.
Question: Is there a "better" solution? What are my alternatives?
Cheers,
V.-

I find usage of a symbol quite clumsy. One of the drawbacks is that it
cannot address a single instance's method easily. I'd use at least blocks
for this. But why not simply use Observer? It's the exact thing built
for this situation - and it's part of the std distribution.

http://www.ruby-doc.org/stdlib/libdoc/observer/rdoc/index.html

Kind regards

robert
 
J

Jacob Fugal

class A
def set_callback notify
@notify=3Dnotify
end
def something
puts "something"
send(@notify) if @notify
end
end

def coocoo
puts "hey"
end
a=3DA.new
a.something
a.set_callback:)coocoo)
a.something

I second Ara's mention of the Observable module. That said, I'd also
simplify this particular example using a block:

class A
def set_callback( &blk )
@notify =3D blk
end
def something
puts "something"
@notify.call if @notify
end
end

a =3D A.new
a.something
a.set_callback { puts "hey" }
a.something

My general rule of thumb is that if something needs to be *done*, I
register a proc, but if someone needs to *know*, I register an
observer (using Observable).

Jacob Fugal
 
D

Damphyr

harp:~ > cat a.rb
require "observer"

class A
include Observable
def something
changed and notify_observers 42
end
end

class B
def update arg
p arg
end
end

a = A::new
b = B::new

a.add_observer b
a.something


harp:~ > ruby a.rb
42

always a good start to read about the stdlibs! ;-)
Well, actually it would be a good start to remember the names of the
patterns :) .
*Then* I can remember that there is an implementation in the standard
library. I've been staring at the screen for too long I guess.
There is a slight difference though: In Observer the observer is an
object that needs to specify the update method.
I was aiming to provide the notifier with a method, any method, to call.
Mine is a one-to-one callback between instances.
With the observer pattern you get one-to-many and the observer can
observe *any* observable object.
More generic and at the end more practical because I will end up naming
everything the same every time I use it.
Just need to be careful to add one/delete one instead of reassigning the
callback in order to replace an observer.
Cheers,
V.-
--
http://www.braveworld.net/riva

____________________________________________________________________
http://www.freemail.gr - äùñåÜí õðçñåóßá çëåêôñïíéêïý ôá÷õäñïìåßïõ.
http://www.freemail.gr - free email service for the Greek-speaking.
 
R

Robert Klemme

Damphyr said:
Well, actually it would be a good start to remember the names of the
patterns :) .
*Then* I can remember that there is an implementation in the standard
library. I've been staring at the screen for too long I guess.
There is a slight difference though: In Observer the observer is an
object that needs to specify the update method.
I was aiming to provide the notifier with a method, any method, to
call. Mine is a one-to-one callback between instances.
With the observer pattern you get one-to-many and the observer can
observe *any* observable object.
More generic and at the end more practical because I will end up
naming everything the same every time I use it.
Just need to be careful to add one/delete one instead of reassigning
the callback in order to replace an observer.
Cheers,

If you want to use another method, you can use a lambda as adapter:

def observe(observable)
m = lambda {|*a| my_other_method(*a)}
class <<m
alias update call
end
observable.add_observer m
end

Kind regards

robert
 
A

ara.t.howard

Well, actually it would be a good start to remember the names of the
patterns :) .

heh. i'm guilty often on that count too - the design patterns books is pretty
dry reading to be sure.
*Then* I can remember that there is an implementation in the standard
library. I've been staring at the screen for too long I guess. There is a
slight difference though: In Observer the observer is an object that needs
to specify the update method. I was aiming to provide the notifier with a
method, any method, to call. Mine is a one-to-one callback between
instances. With the observer pattern you get one-to-many and the observer
can observe *any* observable object. More generic and at the end more
practical because I will end up naming everything the same every time I use
it. Just need to be careful to add one/delete one instead of reassigning
the callback in order to replace an observer.

you can leverage the exiting code:

harp:~ > cat a.rb
require "yaml"
require "observer"

module SoloObservable
include Observable
module Updateable
attr_accessor "update_method"
attr_accessor "update_context"
def update *a, &b
if Proc === update_method
begin
self.update_context = [a, b]
instance_eval &update_method
ensure
self.update_context = nil
end
else
send update_method, *a, &b
end
end
end
def add_observer observer, cb = nil, &cbb
observer.extend Updateable
observer.update_method = cb || cbb
delete_observers
super observer
end
def notify_observer *a, &b
changed and notify_observers *a, &b
end
end

class A
include SoloObservable
def method_that_notifies() notify_observer 42 end
end

class B
def callback(arg) y "arg" => arg end
end

class C
attr "answer"
def initialize() @answer = "forty-two" end
def klass() self.class.name end
end


a, b, c = [A,B,C].map{|k| k::new}

a.add_observer b, "callback"
a.method_that_notifies

puts

a.add_observer(c){ y "update_context" => update_context.inspect, "klass" => klass, "answer" => answer }
a.method_that_notifies



harp:~ > ruby a.rb
---
arg: 42

---
klass: C
answer: forty-two
update_context: "[[42], nil]"


this allows arbitrary method/block callbacks and confines to a single observer.
blocks are evaluated in instance scope and have access to notification params
via update_context.

hth.

-a
 
P

Payton Swick

Not sure if it's any help, but here's something I've been using in my
code which is sort of the reverse of Observable.

This is actually just a snippet of the whole thing without comments or
some fancy features I added. I may put it up as a gem if there's interest.

module HandlesEvents
attr_reader :handlers

def on_event(*triggers, &handler)
@handlers ||= Hash.new
triggers.each { |trigger| @handlers[trigger] = handler }
end

def handles?(trigger)
@handlers ||= Hash.new
return true unless @handlers[trigger].nil?
false
end

def handle(trigger)
@handlers ||= Hash.new
@handlers[trigger].call(trigger) unless @handlers[trigger].nil?
end
end

-Payton
 
P

Payton Swick

Usage, by the way:

class A
include HandlesEvents
end

a = A.new
a.on_event:)hello, :hi) { puts "Hello world!" }
a.handle:)hello) # => prints "Hello world!"

-Payton

Payton said:
Not sure if it's any help, but here's something I've been using in my
code which is sort of the reverse of Observable.

This is actually just a snippet of the whole thing without comments or
some fancy features I added. I may put it up as a gem if there's interest.

module HandlesEvents
attr_reader :handlers

def on_event(*triggers, &handler)
@handlers ||= Hash.new
triggers.each { |trigger| @handlers[trigger] = handler }
end

def handles?(trigger)
@handlers ||= Hash.new
return true unless @handlers[trigger].nil?
false
end

def handle(trigger)
@handlers ||= Hash.new
@handlers[trigger].call(trigger) unless @handlers[trigger].nil?
end
end

-Payton
OK, bare with me, this is brainstorming of a sorts:
I want to have some kind of event notification from my classes.
Typically what I would do would be to pass a logger object and let the
class log by itself, but I'm not really satisfied with this solution in
most cases.

What I would prefer was define a callback method and give this to the
object. Then I could do whatever I want with it and not only use logs.
Mostly I want to have progress reports.

something like

class A
def set_callback notify
@notify=notify
end
def something
puts "something"
send(@notify) if @notify
end
end

def coocoo
puts "hey"
end
a=A.new
a.something
a.set_callback:)coocoo)
a.something

Now this does exactly what I want and can be wrapped up in a module to
be included for general use.
Question: Is there a "better" solution? What are my alternatives?
Cheers,
V.-
 
I

Ilmari Heikkinen

T24gMi8xLzA2LCBEYW1waHlyIDxkYW1waHlyQGZyZWVtYWlsLmdyPiB3cm90ZToKPiBXaGF0IGFy
ZSBteSBhbHRlcm5hdGl2ZXM/CgpIZXJlJ3MgYSB0aG91Z2h0OgoKY2xhc3MgV3JhcHBlcgogIGlu
c3RhbmNlX21ldGhvZHMuZ3JlcCgvXlteX117MiwyfS8pLmVhY2h7fGltfAogICAgdW5kZWZfbWV0
aG9kIGltCiAgfQogIGF0dHJfYWNjZXNzb3IgOmhhbmRsZXJzCgogIGRlZiBpbml0aWFsaXplKG9i
aikKICAgIEBoYW5kbGVycyB8fD0gSGFzaC5uZXd7fGgsa3wgaFtrXSA9IFtdfQogICAgQG9iaiA9
IG9iagogIGVuZAoKICBkZWYgbWV0aG9kX21pc3NpbmcobW5hbWUsICphcmdzLCAmYmxvY2spCiAg
ICBpZiBtbmFtZS50b19zWzAsM10gPT0gIm9uXyIKICAgICAgQGhhbmRsZXJzW21uYW1lLnRvX3Nb
My4uLTFdXSA8PCBbYmxvY2ssIGFyZ3NdCiAgICBlbHNlCiAgICAgIEBoYW5kbGVyc1ttbmFtZS50
b19zXS5lYWNoe3xoYW5kbGVyLCBoYXJnc3wKICAgICAgICBoYW5kbGVyLmNhbGwoKihoYXJncytb
bW5hbWVdK2FyZ3MpKQogICAgICB9CiAgICAgIEBvYmouc2VuZChtbmFtZSwgKmFyZ3MsICZibG9j
aykKICAgIGVuZAogIGVuZAoKZW5kCgoKdyA9IFdyYXBwZXIubmV3KCJmb28iKQojPT4gImZvbyIK
Cncub25fcmV2ZXJzZXsgcHV0cyAicmV2ZXJzZWQhIiB9Cncub25fc3BsaXR7fG0sc3BsaXR0ZXJ8
IHB1dHMgInNvbWVvbmUncyBzcGxpdHRpbmcgd2l0aCAje3NwbGl0dGVyLmluc3BlY3R9IiB9Cgp3
LnJldmVyc2UKI3JldmVyc2VkIQojPT4gIm9vZiIKCncuc3BsaXQoLy8pCiNzb21lb25lJ3Mgc3Bs
aXR0aW5nIHdpdGggLy8KIz0+IFsiZiIsICJvIiwgIm8iXQo=
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top