http://qs321.pair.com?node_id=735078

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

I was trying to figure out what hashes were in some code. It was a new code base that I needed to become familiar with (no docs, naturally).

This command line does a pretty good job of making a hierarchical listing from the code. What would you do better?

rgrep -e'->' * | perl -ne '/(\S{3,80}->\S{5,80})/;print $1,"\n"' | pe +rl -pe's/^\(//' | perl -pe 's/^\+\+|^\-\-//' | sort | uniq | less

It only picks up -> derefs but everyone here (ed:at the office) seems to code that way, so it's a win for me.

ed2: I didn't give an example of the output, which ends up looking something like this:

... $people->{login}->{chair}->{color}=something $people->{login}->{chair}->{height}->(blah) $people->{login}->{chair}->{wheels} =~ etc $people->{login}->{desk}->{paperclips} $people->{login}->{desk}->{stapler} ...

Replies are listed 'Best First'.
Re: Print all derefs and method calls in a directory (Friday golf)
by ikegami (Patriarch) on Jan 09, 2009 at 04:57 UTC

    It only picks up -> derefs but everyone here seems to code that way, so it's a win for me.

    I don't believe that's true. I do

    for (@$list) { ... }

    and

    for (keys %$table) { ... }

    and

    $grid[$x][$y]

    regularly. I even do

    our $buf; local *buf = $ref;

    often enough. All of those contains derefs. Three of them aren't even possible to do with the arrow.

      Unless I'm missing something, the examples you have are fairly simply structured - I'm having to deal with calls like:
      $people->{login}->{chair}->{height}
      and each level is tampered with by a different module.

      So in your examples I'd be seeing: for (@{$people->{login}->{desk}->{paperclips}){}

        There are four derefences in

        @{$people->{login}->{desk}->{paperclips}}

        but only three arrows.

        The rest of your post doesn't relate to what I said, so I have no comment on it save that I rarely have paths that long.

        for my $employee (@$employees) { for my $desk (@{ $employee->{desks} }) { $paperclips += $desk->{paperclips}; } }

        Four dereferences, but only two arrows. And the output of your script doesn't illustrate the structure at all. Data::Dumper will do that to some extent.

Re: Print all derefs and method calls in a directory (Friday golf)
by JavaFan (Canon) on Jan 09, 2009 at 09:44 UTC
    It seems to miss cases like:
    $foo ->[2]; # Space before or after -> print $_->{bar}; # Only two non-space chars before -> $sum += $_->[0] for @array; # Only three non-space chars after ->
    And since you aren't using warnings, you don't get a warning if you try to print an undefined $1.

    OTOH, it would find a deref in:

    perl -ne '/(\S{3,80}->\S{5,80})/;print $1,"\n"'
    Don't tell me you never write code like that!

    But I'm baffled by the fact you're searching for '->' when you need to figure out which hashes are in some code.

      Assuming rgrep does what I thik it does, $1 will never be undef since he pre-filters the lines.

      (Nevermind, the patterns are different, so it's possible.)

        Unless 'rgrep' does something completely different from 'egrep', 'fgrep' or 'grep', you're wrong:
        $ cat foo $foo ->[2]; print $_->{bar}; $sum += $_->[0] for @array; $ fgrep -e '->' foo | perl -nwe '/(\S{3,80}->\S{5,80})/;print $1,"\n"' Use of uninitialized value $1 in print at -e line 1, <> line 1. Use of uninitialized value $1 in print at -e line 1, <> line 2. Use of uninitialized value $1 in print at -e line 1, <> line 3. $
        He does prefilter the line. But the filter is just for '->' while the pattern requires context around the '->'.
Re: Print all derefs and method calls in a directory (Friday golf)
by ikegami (Patriarch) on Jan 09, 2009 at 10:20 UTC

    Addressing the golfing request,

    # 123 rgrep -e'->' * | perl -ne '/(\S{3,80}->\S{5,80})/;print $1,"\n"' | pe +rl -pe's/^\(//' | perl -pe 's/^\+\+|^\-\-//' | sort | uniq

    is sufficiently equivalent to

    # 68 perl -ne's/^(\(|[+-]{2})//g,say for/(\S{3,80}->\S{5,80})/' *|sort -u

    And since you already assume that you can't have two dereferencing expressions on the same line,

    # 67 perl -ne's/^(\(|[+-]{2})//g,say for/\S{3,80}->\S{5,80}/g' *|sort -u
      Since you're using 'say', you have to use '-E' instead of '-e'.

      Note also that [+-]{2} is not equivalent to \+\+|-- as the former matches "-+" while the latter doesn't. Also, the original code will remove a leading "(--" from the line, while your code will not (it will either remove a leading '(' or a leading '--', '-+', '+-' or '--'). Finally, a /g modifier is useless if the pattern is anchored to the beginning of the string. And, if you're golfing, you shouldn't make a capture if you aren't using the result.

      Your s/// could be written as:

      s/^\(?([-+])\1//
      My entry (untested):
      perl -nE'/\(?([-+])\1.*?(\S{3,80}->\S{5,80})/&&say$2' *|sort -u
      I do think the 80 is a bit arbitrary, and
      perl -nE'/\(?([-+])\1.*?(\S{3,}->\S{5,})/&&say$2' *|sort -u
      is not only shorter, but likely to be preferred.

        Since you're using 'say', you have to use '-E' instead of '-e'.

        Oops!

        it will either remove a leading '(' or a leading '--', '-+', '+-' or '--')

        Oops!

        [+-]{2} is not equivalent to \+\+|--

        Indeed, but I deemed it acceptable.

        if you're golfing, you shouldn't make a capture if you aren't using the result.

        Not until Perl6. /...(?:...|...)/ is longer than /...(...|...)/. (Multiplying out the leading subexpression would have been shorter, but that's not the issue you raised.)

        I take your 69 and give you 51:

        perl -nE'/[-+(]*(\S{3,}->\S{5,})/&&say$1' *|sort -u
Re: Print all derefs and method calls in a directory (Friday golf)
by dragonchild (Archbishop) on Jan 09, 2009 at 18:40 UTC
    This is a job for PPI or -MO=Deparse.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?