http://qs1969.pair.com?node_id=556016

Item Description: Sane source filtering for the rest of us

Review Synopsis:

How many of you have written code that looks something like:

package Some::Class; use strict; use warnings; sub new { my $class = shift; return bless { @_ }, $class; } sub foo { my $self = shift; $self->{foo} = shift if @_; return $self->{foo}; } sub bar { my $self = shift; $self->{bar} = shift if @_; return $self->{bar}; } sub baz { my $self = shift; $self->{baz} = shift if @_; return $self->{baz}; } sub do_something_useful { ... }
Come on, raise your hands. I know I've done this at least a hundred times. Then, I learned about closures and went back and rewrote that code to look something like:
package Some::Class; use strict; use warnings; sub new { my $class = shift; return bless { @_ }, $class; } foreach my $name ( qw( foo bar baz ) ) { no strict 'refs'; *{ __PACKAGE__ . "::$name" } = sub { my $self = shift; $self->{$name} = shift if @_; return $self->{$name}; }; } sub do_something_useful { ... }
Now, instead of 98% of the Perl community being able to maintain my code, I'm down to 0.98%. Several managers I've worked for had made me take out code like that, and for good reason. Just because they hired a Perl expert to write the code doesn't mean that they'll be able to hire someone like that to maintain the code. So, it's back to repetition, right?

<Trumpets sound in the distance /> Module::Compile::TT to the rescue! That code using typeglobs and closures now looks like:

package Some::Class; use strict; use warnings; sub new { my $class = shift; return bless { @_ }, $class; } use tt; [% FOREACH name IN [ 'foo', 'bar', 'baz' ] %] sub [% name %] { my $self = shift; $self->{[% name %]} = shift if @_; return $self->{[% name %]}; } [% END %] no tt; sub do_something_useful { ... }
Whoa! That actually looks readable! Everyone knows how to read TT directives (or they're close enough to your favorite templating module as to be no difference).

But, isn't this a source filter? Well, technically, it is. But, there's a major difference between this and Filter::Simple. Module::Compile::TT compiles this once and installs a .pmc file that you can look at and edit. Or, you could just run TT against this module and see what would happen.

Contrast that to Filter::Simple that won't generates potentially anything and you have no (sane) way of finding out what happened.

The real dealbreaker for me is that I feel pretty sure I could take this to any manager I use to work for and they would all be comfortable with that kind of code in their production codebases. This is code that can be maintained by the masses.