[Petal] Modifiers and variables

Fergal Daly fergal at esatclear.ie
Mon Aug 16 22:24:00 BST 2004


On Mon, Aug 16, 2004 at 01:58:08PM -0400, William McKee wrote:
> Hey Fergal,
> 
> Good to hear from you.

Good to be contributing again :-)

> > Last year when I was hacking Petal, I changed the modifier code so that it
> > examined the modifier at runtime to see if it was new style or old style.
> > For an old style modifier it just passed in the whole string to the process()
> > method as usual. If it was new style, it parsed the string a set of function
> > arguments and passed them to the new_process method.
> 
> So you've been down this road too.

Yeah, the objective of Petal-CodePerl was to precompile the expressions and
so I needed to find a way to do this for modifiers too. Since you can't
precompile something that's going to do it's own parsing, I made a slightly
modified modifier that let Petal do all the parsing.

> > just changing that last line to
> > 
> > 		if ($module->can("new_process")
> 
> Ahh, so this is how you differentiate between new style and old style
> modifiers.

Yeah,it's totally compatible.

> > 		{
> > 		    # parse_args() is not correct but you get the idea
> >         my @args = parse_args($key); 
> 
> Could we draw this in from the work you did? I tried to find where you
> did that in Petal::CodePerl but couldn't find a parse_args sub. I'm
> guessing you used a different name or didn't extract the code into a
> subroutine. Could you give me a pointer?

No, tthe CodePerl stuff used Parse::RecDescent to do all the parsing so it
creates all the subs for you. Anyway, I don't think an yof that stuff would
work with the current Petal. I was hoping there was a parse_args sub in
Petal and there almost is, it's the first part of Petal::Hash::Var::process().

> If I understand you correctly, this sounds great. Is TALES where
> modifiers and the like are defined? I get TAL/TALES/METAL confused. I
> think that the proposed subroutine would do that. Nonetheless, I'd like
> to see your example (with the exception that the TALES expression cannot
> contain numbers).

Yeah, TALES is the expression syntax, so stuff like paths, strings etc.

The patch attached moves about about 20 lines of code out of process() and
into it's own subroutine called parse_args(). It also changes fetch() in the
manner I explained earlier. Here's an example of a new modifier

#################
package Reflect;
# it just reflects back whatever args it was given
sub parsed_process
{
  my $class = shift;
  my $hash = shift;
  my @args = @_; # already parsed and evaluated

  return "my args were: ".join(", ", @args);
}

use Petal::Hash;

$Petal::Hash::MODIFIERS->{"reflect:"} = "Reflect";

my $h = Petal::Hash->new(
  a => {path => "value"},
);

print $h->get("reflect:'a string' a/path")."\n";

# my args were: 17, value
###############

Here's a more useful one:

################

package Shorten;

sub parsed_process
{
  my $class = shift;
  my $hash = shift; 
  my $string = shift;
  my $len = shift;   

  if (length($string) > $len)
  {
    return substr($string, 0, $len/2 -2)."...".substr($string,-int(($len-1)/2))
  }
}  

use Petal::Hash;

$Petal::Hash::MODIFIERS->{"shorten:"} = "Shorten";

my $h = Petal::Hash->new(
  a => {path => "a rather long string value taht's too long for my liking"},
);

print $h->get("shorten:a/path '30'")."\n";

# a rather long... for my liking

####################

Give it a spin,

F
-------------- next part --------------
--- ./lib/Petal/Hash/Var.pm.orig	2004-08-16 21:50:25.197462328 +0100
+++ ./lib/Petal/Hash/Var.pm	2004-08-16 21:44:40.461870104 +0100
@@ -28,32 +28,26 @@
 our $INTEGER_KEY_RE    = qr/^\d+$/;
 
 
-sub process
+sub parse_args
 {
-    my $class    = shift;
     my $hash     = shift;
-    my $argument = shift;
-    
-    my @tokens = $argument =~ /($TOKEN_RE)/gsm;
-    my $path   = shift (@tokens) or confess "bad syntax for $class: $argument (\$path)";
-    my @path   = split( /$PATH_SEPARATOR_RE/, $path );
-    my @args   = @tokens;
+    my $args     = shift;
 
     # replace variable names by their value
-    for (my $i=0; $i < @args; $i++)
+    for (my $i=0; $i < @$args; $i++)
     {
-	my $arg = $args[$i];
+	my $arg = $args->[$i];
 	if ($arg =~ /^$VARIABLE_RE$/)
 	{
 	    $arg =~ s/$ESCAPED_CHAR_RE/$1/gsm;
 	    if ($arg =~ $PARAM_PREFIX_RE)
 	    {
 		$arg =~ s/$PARAM_PREFIX_RE//;
-		$args[$i] = $arg;
+		$args->[$i] = $arg;
 	    }
 	    else
 	    {
-		$args[$i] = $hash->fetch ($arg);
+		$args->[$i] = $hash->fetch ($arg);
 	    }
 	}
 	else
@@ -61,10 +55,23 @@
 	    $arg =~ s/$BEGIN_QUOTE_RE//;
 	    $arg =~ s/$END_QUOTE_RE//;
 	    $arg =~ s/$ESCAPED_CHAR_RE/$1/gsm;
-	    $args[$i] = $arg;
+	    $args->[$i] = $arg;
 	}
     }
+}    
+
+sub process
+{
+    my $class    = shift;
+    my $hash     = shift;
+    my $argument = shift;
     
+    my @tokens = $argument =~ /($TOKEN_RE)/gsm;
+    my $path   = shift (@tokens) or confess "bad syntax for $class: $argument (\$path)";
+    my @path   = split( /$PATH_SEPARATOR_RE/, $path );
+    my @args   = @tokens;
+
+    parse_args($hash, \@args);
     my $current = $hash;
     my $current_path = '';
     while (@path)
--- ./lib/Petal/Hash.pm.orig	2004-08-16 21:50:15.477939920 +0100
+++ ./lib/Petal/Hash.pm	2004-08-16 21:49:25.629518032 +0100
@@ -183,7 +183,16 @@
     
     my $module = $MODIFIERS->{$mod} || confess "$mod is not a known modifier";
     (defined $module and ref $module and ref $module eq 'CODE') and return $module->($self, $key); 
-    $module->process ($self, $key);
+    if ($module->can("parsed_process"))
+    {
+        my @args = $key =~ /($Petal::Hash::Var::TOKEN_RE)/gsm;
+        Petal::Hash::Var::parse_args($self, \@args);
+        $module->parsed_process($self, @args);
+    }
+    else
+    {
+        $module->process ($self, $key);
+    }
 }
 
 


More information about the Petal mailing list