Source filters are easy!

runrig on 2003-01-10T20:57:43

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


Wacky regex

autarch on 2003-01-12T00:41:14

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;
}

Re:Wacky regex

runrig on 2003-01-12T09:28:34

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' :-)

Re:Wacky regex

runrig on 2003-01-13T02:48:04

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.