[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: 10-fyi-autom4te-trace-patterns.patch

From: Russ Allbery
Subject: Re: 10-fyi-autom4te-trace-patterns.patch
Date: 04 Aug 2001 18:13:12 -0700
User-agent: Gnus/5.0807 (Gnus v5.8.7) XEmacs/21.1 (Channel Islands)

Akim Demaille <address@hidden> writes:

> I'm sorry for the noise in the patch below.  I struggled with `do' to
> load files, but couldn't find a means to simulate `source'.  Simply
> stated, if there is a file containing `$foo = 42', I'm unable to read
> this file and have the `my $foo' variable of the caller be changed.
> Lexically scoped variables and `do' seem to be incompatible.

You should be able to put the file you're loading with do into another
namespace with a package directive in the file... does that not work for
what you're trying to do?

> +  # I'm having fun with grep and map, but it's not extremely safe here...
> +  # First of all, I still don't understand why I can't use `map' for
> +  # instance to get @PATTERNS: `chop' thinks it's in a scalar context
> +  # and returns 1 instead of `$_' :(.
> +  #
> +  # A potential bad bug is that the grep for $forbidden and $allowed
> +  # *do modify @PATTERNS!  So when $FORBIDDEN is computed, @PATTERNS
> +  # still contains the forbidden patterns, but without the leading
> +  # `forbid:'.  So if some use forbids `allow:FOO', @ALLOW will receive
> +  # `FOO', which is _bad_.  But since `:' is not valid in macro names,
> +  # this is science fiction.
> +  #
> +  # Still, if someone could teach me how to write this properly... --akim

The problem that you're having with chop (and well, first off, you don't
want to be using chop; you want to be using chomp instead, which only
removes newlines and is therefore safer than chop which will remove the
last character no matter what it is) is that you're using it inside the
code block of a map or grep, so it *is* in a scalar context.

What you actually want to do is chomp a list.  And as it happens, chomp
can take a list as an argument.  So instead just write:

    my @patterns = new IO::File ("$tmp/patterns")->getlines;
    chomp @patterns;

and that will do exactly what you want.

Second, with these lines:

> +  my $forbidden = join ('|', grep { s/^forbid:// } @patterns) || "^\$";
> +  my $allowed   = join ('|', grep { s/^allow:// }  @patterns) || "^\$";

remember that $_ inside the code block of a grep or map is an *alias* for
the corresponding element of the list.  You're assuming that grep makes a
copy of @patterns and then applies the code block to it, when what
actually happens is that grep iterates over @patterns and makes $_ an
alias for each element in turn.  So the s/// pattern is affecting the
original list.

What you want in this case so far as I can tell is to grap all of the
patterns in @patterns beginning with "forbid:" (or "allow:") and store
them in a variable, separated by |, with the prefix removed.  Try:

    my $forbidden = join ('|', map { /^forbid:(.*)/ } @patterns) || "^\$";
    my $allowed   = join ('|', map { /^allow:(.*)/ }  @patterns) || "^\$";

This code is slightly more straightforward, IMO, if written as three
separate commands, but that approach will get it on one line (which has
other benefits for readability, so it's probably a wash).  What that's
doing instead is using a pattern match to extract the portion that you're
interested in rather than a substitution to remove the portion that you
don't want, and then using the behavior of m// in a list context to return
the result of the pattern match.

The three-line clearer version is:

    my @forbidden = grep { /^forbid:/ } @patterns;
    for (@forbidden) { s/^forbid:// }
    my $forbidden = join ('|', @forbidden) || "^\$";

Russ Allbery (address@hidden)             <>

reply via email to

[Prev in Thread] Current Thread [Next in Thread]