in reply to Re^2: Dynamically wrapping ancestor method calls
in thread Dynamically wrapping ancestor method calls

If you assume that the symbol tables of your superclass tree aren't going to change, you could scan them in the same order that perl does (recursively take @ISA from each one and walk up the hierarchy), and thus build up a complete list of possible methods on the subclass.

Since that ordering is documented, you aren't really abusing internals knoweldge to do that.

It seems to me that that should work. It still isn't very nice though. I still like the proxy object, actually. That seems to work pretty well.

Out of interest, may I ask about the the original problem which is being addressed by the automagic wrappering?

Replies are listed 'Best First'.
Re^4: Dynamically wrapping ancestor method calls
by rafl (Friar) on Dec 11, 2006 at 21:21 UTC
    Out of interest, may I ask about the the original problem which is being addressed by the automagic wrappering?

    I'm the author of Audio::XMMSClient. This module provides an asynchronous interface th xmms2's client library. This is quite powerful but not very easy to use, especially very simple scripts or unit tests which don't need the async interface most of the time.

    Therefor I wanted to write a wrapper, Audio::XMMSClient::Sync, around it that does just the same as Audio::XMMSClient does on all method calls, except for those which return some kind of request handle to be used in asynchronous clients. In that case it should just block until the request is completed, unpack the response into some perl structure and return that.

    That way code that looked like that with the async api..

    my $con = Audio::XMMSClient->new(...); $con->connect or die $con->last_error; my $res = $con->medialib_get_info( $some_song ); $res->wait; my $value = $res->value;

    becomes that..

    my $con = Audio::XMMSClient::Sync->new(...); $con->connect or die $con->last_error; my $value = $con->medialib_get_info( $some_song );

    Cheers, Flo

      Ah, I see.

      So you could achieve what you want by putting a wrapper function around the return statements of the relevant methods in Audio::XMMSClient.

      return $s->_process_handle($handle);
      where _process_handle just returns its arg for async behaviour or does the sync-wait-and-return-data for the sync behaviour. You could select between the two either by subclassing (and overriding _process_handle), or even passing in sync => 0/1 to the ctor.

      If that isn't palatable for some reason, this sounds a little bit like a job for that modern buzzword Aspect Oriented Programming. This isn't really my area of expertise, but as I understand it, it allows you to effectively install pre- or post- handlers into your existing codebase, selected by various criteria. Adding handlers to massage the return values of a given class sounds within it's remit.

      I suspect that under the hood it is doing the same symbol table walking we've talked about before, but that should work OK in your case I think.

        That is indeed a solution that would work. Unfortunately Audio::XMMSClient is written in XS. Therefor adding that wrapper around the according return statements would be somewhat painful unless I add some pure-perl wrapper to all XS functions, which I don't want for obvious reasons.

        I already thought of using Moose and register a function to be called after a given function, but unfortunately this has the same problem as the subclassing approach: I need to have a list of all relevant functions. But as this changes frequently as the libxmmsclient API isn't stable yet and there have been large changes merged recently in the development branch I don't really want that.

        Cheers, Flo

Re^4: Dynamically wrapping ancestor method calls
by Limbic~Region (Chancellor) on Dec 11, 2006 at 20:39 UTC
    jbert,
    WRT the original problem, perhaps rafl can explain. When I pressed further on IRC there was no response. Presumably this is because rafl was AFK working on alternatives.

    Cheers - L~R