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}
...
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.
| [reply] [d/l] [select] |
|
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}){}
| [reply] [d/l] [select] |
|
@{$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. | [reply] [d/l] [select] |
|
|
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. | [reply] [d/l] [select] |
|
| [reply] [d/l] |
|
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 '->'. | [reply] [d/l] |
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
| [reply] [d/l] [select] |
|
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. | [reply] [d/l] [select] |
|
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
| [reply] [d/l] [select] |
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:
- Does it work?
- Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
| [reply] |
|
|