Beautifying Perl
I totally fell in love with Ruby ever since I started using it more than a year ago. The language’s syntax and constructs are very, very elegant (with a few exceptions… I’m talking about you, StringIO.new.is_a?(IO) == false). The ‘do’ blocks are simply brilliant, they make working with closures a breeze and aesthetically pleasing. Ruby’s Array, Enumerable and Hash classes make heavy use of this.
Compared to Ruby’s syntax, Perl’s seems like something from the 80s. Perl is often the target of “my-code-is-more-unreadable-than-yours-but-I-can-do-it-in-fewer-lines” jokes. I can write readable and maintainable code, but no matter what I do, it’s still nowhere near Ruby’s level. All the referencing and dereferencing of arrrays and hashes makes things ugly. %, $ and @ everywhere, urgh. And working with collections takes more code than in Ruby. I can’t tell you how many times I had to write stuff like this:
-
my $foo_is_ok;
-
foreach my $value (@foo) {
-
if ($value satisfies some condition) {
-
$foo_is_ok = 1;
-
last;
-
}
-
}
-
if ($foo_is_ok) {
-
…
-
}
In Ruby I can just do:
-
if foo.any? { |x| …some expression involving x… }
-
…
-
end
There’s List::Util but they deliberately left out the ‘any’ function because it’s “easy to implement”. Urgh. -_-
I write a lot of text parsers in Perl. And each time I have to manually strip newlines from a read line with:
Seriously, why can’t I call ‘$foo->strip()’ or something like in Python or Ruby?
And print(). In 99% of the cases I want to print a newline as well, so I have to write print "$foo\n"; Why is there no puts()-like function that automatically prints the newline as well? It would save me a few keystrokes.
But no more. I’ve had enough. Enter the Peanuts library. Now you can write:
-
use Peanuts;
-
-
my $array = Array(["hello", "world", "foo", "bar"]);
-
puts $array
-
->map(sub{ $_ . "!" })
-
->findAll(sub{ /o/ })
-
->reject(sub{ /f/ })
-
->join(‘, ‘);
This would print “hello!, world!\n”.
Other Ruby-isms include:
-
use Peanuts;
-
-
my $s = String(" hello world ");
-
puts $s->strip(); # => "hello world"; This is actually a new String object.
-
puts $s->Strip(); # in-place version of strip()
-
-
my $h = Hash({ x => ‘y’ });
-
$h->merge({ foo => ‘bar’, a => ‘b’ });
-
$h->Merge({ baka => ‘baka’ }); # in-place version of merge()
-
-
-
package MyClass;
-
sub foo {}
-
Package()->aliasMethod(‘bar’, ‘foo’); # Now we have an alias! No ugly Perl symbol table messing syntax!
-
Package()->chainMethod(‘foo’, ‘trees’); # Like Rails’s alias_method_chain; now
-
# we have foo_with_trees() and foo_without_trees()
The source code is at this SVN repository:
http://public.railsplugins.net/repos/peanuts/trunk
It is licensed under the MIT license.

plutard said,
November 30, 2007 @ 1:41 am
Why the camel-case method names? That’s so un-perlish *and*
un-rubyish.
Andrew Cholakian said,
November 30, 2007 @ 7:03 am
Is there a reason you can’t use chomp() to cut off the newlines in perl? Unless you don’t know if $/ will match the EOL character for the strings you’re processing you should be fine.
I’m totally with you on elegance. I get the same longing for ruby everytime I write a line of PHP at work.
I completely hate PHP’s sorting mechanism usort. Check out the docs here http://us.php.net/usort
You could rewrite those 8 lines of sorting code into one with ruby. Also, passing a function by using a string as usort does? How much uglier can it get. Procs and closures rule!
Hongli said,
November 30, 2007 @ 9:36 am
plutard: There doesn’t seem to be an authoritative Perl naming convention. I’ve seen different modules using different conventions. I use camel case in all my Perl projects though.
Andrew: I don’t know whether the line contains an end-of-line. It might be \r or \r\n (or perhaps something weird, like \r\r\n) or no newline at all.
Kevin Hartmann said,
June 2, 2008 @ 4:16 pm
1) For your first example, is there any reason you can’t write something like the example below?
if ( grep {$_ satisfies some condition) } @foo) {
# do something
}
2) For removing newlines, use the chomp() function: it will remove the newline for your platform, regardless of whether that’s a \r\n, \n, or whatever.
$line =~ s/[\r\n]//g;
For removing leading whitespace, you need to remember that tabs are whitespace, too.
#$line =~ s/^[\s\t]*//;
So, the standard perlish way to remove newlines and strip leading whitespace would be:
chomp($line);
$line =~ s/^\s//g;
3) Why is the module called “Peanuts”? Perl has too many poor choices for names already:
grep instead of “any”, for example. Give your module a name that explains at a glance
what it’s trying to do.
Hongli said,
June 3, 2008 @ 7:49 am
1) and 2) Yeah, I’m aware of that. But I prefer object-oriented APIs, they’re easier on the eye IMO. Plus I can chain such operations in the “correct” order (i.e. $foo->grep(…)->map(..) instead of grep(map(..))).
3) I don’t think there’s a name that can explain what this library does, without being ridiculously long.