On Tue, Apr 26, 2011 at 11:33:57AM +0200, Simone Carletti wrote:
> 
> Also, in my mind a callback method should have two important properties:
> 
>    1. it should be an optional method and you should be free to define it or
>    not
>    2. it should not be already defined, otherwise you always have to care
>    about not overriding the original implementation.

Hello Simone,

when I look at Wikipedia

  http://en.wikipedia.org/wiki/Callback_%28computer_programming%29

"In computer programming, a callback is a reference to executable code, or a 
piece of executable code, that is passed as an argument to other code."


> You said #consume is a callback. But currently, when I wrote the following
> custom participant
> 
>     class Alpha < Ruote::StorageParticipant
>       def consume(workitem)
>         #  ...
>         super
>       end
>     end
> 
> I must be sure to call #super, otherwise I permanently loose all the logic
> defined within the original StorageParticipant#consume method.

Loosing the prisoners from their logic.


> Ideally, I would love to be able to write something like
> 
>     class Alpha < Ruote::StorageParticipant
>       def on_consume(workitem)
>         #  ...
>       end
>     end

If the #on_consume did not previously exist (and is only called if it exists). 
Then, granted, you have some kind of callback where the "executable code" is 
passed as argument (body) of the method definition.

Can we really call that a callback ? There is no way to distinguish it from 
regular method overriding.


> and have Ruote automatically invoke the method if defined. This means the
> original StorageParticipant#consume should be modified to
> 
>     def consume(workitem)
>       # call the callback if available
>       on_consume(workitem) if respond_to?(:on_consume)
> 
>       doc = workitem.to_h
>       doc.merge!(
>         'type' => 'workitems',
>         '_id' => to_id(doc['fei']),
>         'participant_name' => doc['participant_name'],
>         'wfid' => doc['fei']['wfid'])
>       doc['store_name'] = @store_name if @store_name
>       @context.storage.put(doc)
>     end
> 
> This opens the door to several additional features. For instance, we can
> have after/before callbacks.
> 
>     class Alpha < Ruote::StorageParticipant
>       def before_consume(workitem)
>         #  ...
>       end
>       def after_consume(workitem)
>         #  ...
>       end
>     end

I guess that it brings us back to

  http://groups.google.com/group/openwferu-users/msg/89b3ca2dc5f07d1a

I'll try to re-express my idea (maybe I will fail again) :

participants are the callbacks you reference from process definitions. The 
engine knows how to deal with classical expressions like sequence, concurrence, 
cursor, etc, ... For steps themselves, he has to be fed with "external code", 
contained in participants.

So, sorry, the "callback" I was mentioning is one level higher than the one you 
want.

Still, I don't know if we can call a "callback" what you described. It's 
vanilla inheritance and overriding (with an ersatz of introspection).


> It would be cool to be able to attach callbacks to the Ruote core as well,
> regardless the participant you use.
> Again, I'll try to formulate a more concrete proposal as soon as possible.

Sounds like real callbacks.

Starting from a use case is a good idea.

Let's look at what ruote has in store to help you.

Engine#on_error= and Engine#on_terminate=

  http://ruote.rubyforge.org/configuration.html#engine_on

In the process definitions there are various "on_"s

  http://ruote.rubyforge.org/common_attributes.html#on_error
  http://ruote.rubyforge.org/common_attributes.html#on_cancel
  http://ruote.rubyforge.org/common_attributes.html#on_timeout

There is also the listen expression

  http://ruote.rubyforge.org/exp/listen.html

(note, I'm experimenting with listen and errors 
https://github.com/jmettraux/ruote/commit/7790c6a410f6e18a1339b67f564d44ee5ba936c1
 these days)

If you really need to implement something you could do :

---8<---
class WorkitemPrinter

  def initialize(context)
    @context = context
    @context.worker.subscribe(:all, self) if context.worker
  end

  def notify(message)
    p message['workitem'] if message['action'] == 'dispatch'
  end
end

# ...

engine.add_service('wi_printer', nil, 'WorkitemPrinter')
--->8---

(note : I'm not super happy with the add_service method, it will probably get 
revised soon)

This sets up a 'service' that prints any workitem (the raw Hash form) that gets 
dispatched [to a participant].


> Also, I'll double check your code. I didn't notice you can override a single
> method even if aliased. I'll try it.

I am glad I double-checked and asked Ruby (1.8.7 and 1.9.2), you seemed very 
convinced.


Best regards,

-- 
John Mettraux - http://jmettraux.wordpress.com

-- 
you received this message because you are subscribed to the "ruote users" group.
to post : send email to [email protected]
to unsubscribe : send email to [email protected]
more options : http://groups.google.com/group/openwferu-users?hl=en

Reply via email to