Stories
Slash Boxes
Comments
NOTE: use Perl; is on undef hiatus. You can read content, but you can't post it. More info will be forthcoming forthcomingly.

All the Perl that's Practical to Extract and Report

use Perl Log In

Log In

[ Create a new account ]

runrig (3385)

runrig
  dougwNO@SPAMcpan.org

Just another perl hacker somewhere near Disneyland

I have this homenode [perlmonks.org] of little consequence on Perl Monks [perlmonks.org] that you probably have no interest in whatsoever.

I also have some modules [cpan.org] on CPAN [cpan.org] some of which are marginally [cpan.org] more [cpan.org] useful [cpan.org] than others.

Journal of runrig (3385)

Friday January 10, 2003
03:57 PM

Source filters are easy!

[ #9892 ]
At the last OC.pm[oc.pm.org] meeting, a module was demonstrated (XML::EasySlice) which would allow easy traversal and creation of XML tags/nodes/documents. It's not the answer to everything (and I hope that doesn't delay the authors from putting it on CPAN), but it certainly simplified some tasks. Something like this would create all the tags needed through autoloaded method calls, and set the content for the last node:

$doc->orders->order->order_id->es_value(100)

I didn't ask at the time what to do about namespaces (since perl doesn't allow ':' as part of a bareword, but does allow it in a dynamic method call where the method name is a variable), but through the magic of source filtering, I came up with this to allow something like $doc->foo:bar (of course, allowing this does break certain other constructs, so just don't do those):

package MethodFilter;
use Filter::Util::Call;

sub import {
  filter_add(
    sub {
      s/(?<=->)((\w+):(\w+))/
        $meth = __PACKAGE__ . "::_${2}_${3}";
        $$meth = $1;
        "\$$meth";
      /eg if ($status = filter_read()) > 0;
      $status;
    }
  );
}

1;

I'm sure you could even do this with Filter::Simple, but this seems simple enough. And as for the lack of 'use strict', it started out that way, but it adds too much clutter for such a short bit of code...
(Hey, I finally got around to making an entry!)

Update: Simplified regex from autarch's reply. Used to be:

s/(?<=->)((\w+):(\w+))
        (?{
          $tmp = __PACKAGE__ . "::_${2}_${3}";
          $$tmp = $1;
        })
/\$$tmp/gx

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
 Full
 Abbreviated
 Hidden
More | Login | Reply
Loading... please wait.
  • Why use such a strange regex (specifically (?{...}) )?

    What's wrong with just doing the work in the right side of the substitution with /e?

    s/(?<=->)((\w+):(\w+))/$meth = __PACKAGE__ .. "::_${2}_${3}"; $$meth = $1; "\$$meth"/eg

    or even better, move it out of the substitution altogether:

    my $pack = __PACKAGE__;
    while ( s/(?<=->)((\w+):(\w+))/\$${pack}::_${2}_${3}/g )
    {
         ${"${pack}::_${2}_${3}"} = $1;
    }

    • I did try that second one using a while loop, and the substitution is ok, but it only iterates over the loop once with the last substitution. I agree the first one is probably more straight forward. I guess I've just been itching to try out the (?{}) regex code block thing, and forgot about '/e' :-)
      • I guess we both have trouble remembering that s/// returns the number of substitutions made, and so s///g doesn't iterate like m//g does. The while loop does work if you leave off the '/g' modifier, but then its just not as efficient as stuffing the code inside the substitution.