http://qs1969.pair.com?node_id=304144

hackmare has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,

is it possible to re-map a method call to redirect it to another module? I am trying to replace all calls to GD.pm with SVG::GD.pm down the dependency tree by modifying the mail program and not modifying any program that may inherit GD.pm.

The latter provides all the call support for GD.pm but generates SVG (and) implements the GD library.

All this is great, but now I want to use GD::Graph::Bar (for example), and I need to make the change at the main program level only (not within the GD::Graph::Bar namespace). I need the fact that I am using SVG::GD to superscede all calls to the GD module.

GD::Graph::Bar has calls to GD buried deep inside them, and I want to hijack all the GD constructor calls to use the SVG::GD constructor instead. Ingrate that I am, I'm hoping that I can do this from the main namespace so a user can select to use SVG::GD rathern than be forced to use the GD.

(In short, for example, I want to apply s/GD::Image/SVG::GD::Image/g in the source code)

Can this be done? I seem to remember hearing of this being done at one of the yapc's, but don't have the slightest idea where to look. I'm starting to feel way above my head here and would appreciate a nudge in the right direction or towards the right reference.


hackmare.

Replies are listed 'Best First'.
Re: hijacking a module constructor
by broquaint (Abbot) on Nov 03, 2003 at 16:43 UTC
    Assuming nothing too sneaky is going on under the hood of GD::Graph::Bar you should simply be able to alias GD's symbol table to SVG::GD e.g
    *GD:: = *SVG::GD:: if $opts->{SVG};
    So any use of the GD namespace will automagically be using the SVG::GD namespace due to the glob alias.
    HTH

    _________
    broquaint

      Ah. Right. Most useful. Thank you.

      Except now I'm in a quandry.

      My SVG::GD::Image code also imvokes GD::Image in order to continue to support existing GD functionality (all calls to the SVG::GD module are echoed to the GD module so that in the end the user can get an SVG output or a bitmap.

      Is there any way to affect the symbol table everywhere except when GD::Image is called from within the SVG::GD::Image namespace?

      Further over my head

        Simply save yourself a copy of the GD:: namespace:

        *hackmare::GD:: = *GD::; # now use hackmare::GD instead of GD in your own library
        perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
        This can be done, but I think it may be saner to go down another route as suggested by Corion and perrin ...
        $GD::{$_} = $SVG::GD::{$_} for grep !/::$/, keys %SVG::GD::;
        This has a similar effect to the symbol table glob aliasing, but only affects the GD:: symbol table. Again, use with caution as this is even more hackish than the glob alias.
        HTH

        _________
        broquaint

Re: hijacking a module constructor
by perrin (Chancellor) on Nov 03, 2003 at 16:52 UTC
    GD is open source. Why not simply take the code and change it to do what you want? This dynamic remapping idea sounds very fragile to me.

      it might end up being too fragile.

      The problem is that GD is really raster-centric, and I am attempting to generate vector output.

      I think it would unnecessarily pollute the GD API to bring in vector support.

      I'm trying to provide vector-graphics support to people who want to output simple GD-centric programs without burying everyone in excessive dependencies.

      Because GD (not GD.pm) works on a pixel-by-pixel basis, I'm trying to work on both vector entities and pixel-related entities at the same time. And GD is turning out to have some nice,convenient capabilities that look handy to keep - otherwise I'd simply rename GD to something else.

      I'll see soon enough if this turns out to be a fool's errand, but so far, except for this detail, it's looking fairly good.


      hackmare.
Re: hijacking a module constructor
by hardburn (Abbot) on Nov 03, 2003 at 17:17 UTC

    Could you re-bless the reference?

    # $gd defined elsewhere, inititilized to a # GD::Image instance bless $gd, 'SVG::GD::Image';

    This may or may not work.

    ----
    I wanted to explore how Perl's closures can be manipulated, and ended up creating an object system by accident.
    -- Schemer

    : () { :|:& };:

    Note: All code is untested, unless otherwise stated

      You may be right! :(

      Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"
Re: hijacking a module constructor
by Art_XIV (Hermit) on Nov 03, 2003 at 17:06 UTC

    If your GD modules provide an OO-interface (I don't know if they do or don't) then you might just want to make your own class that inherits from GD and override the method in question.

    Check out perltoot in the docs or Damian Conway's book.

    Hanlon's Razor - "Never attribute to malice that which can be adequately explained by stupidity"