I was playing with
Filter::Simple and reading
up on Programming by Example
http://lieber.www.media.mit.edu/people/lieber/PBE/ and came
up with this toy module. I have a feeling that this could be much better implemented, and actually become useful. Welcome comments, improvements, criticism!
package Example;
use Filter::Simple;
use Text::ParseWords;
use Text::Balanced qw(extract_codeblock);
FILTER {
my $text=$_;
my $output='';
# find a subroutine
while ($text=~m[\A(.*?\bsub\s+.*?)(\{.*)$]sg) {
$output.=$1;
$code=$2;
# extract a codeblock to examine.
my ($ex, $re)=extract_codeblock($code, '{}');
# does it include the example(...,...) statement
if ($ex=~s{\bexample\s*\((.*)\);?\s*$}{my \@args=\@_;}m) {
# find the example arguments, and create a hash
# to generalise them using a regex:
my @args=quotewords(',',0,$1);
my $arg_num=0;
my %args=map {$_,"\$args[".$arg_num++."]"} @args;
my $arg_re=join '|',
map { "$_" }
sort {length($b) <=> length($a) }@args;
# above so that if there are 2 arguments
# one of which includes the other, the
# longest will be applied first!
# Apply the regex to everthing within the codeblock.
$ex=~s{($arg_re)} {$args{$1}}g;
}
$output.="$ex";
$text=$re;
}
$_=$output.$text;
#print ; # uncomment this line to see the filtered source
};
1 ;
=head1 NAME
Example.pm
=head1 DESCRIPTION
A very very badly written demonstration of
=over 4
=item 1
The L<Filter::Simple> module. (Very cool)
=item 2
Programming by example. See http://lieber.www.media.mit.edu/people/li
+eber/PBE/
for more details. Essentially, the idea is that the computer should w
+atch
what is being done, and attempt to extrapolate this into the actual co
+de.
I suspect that the approach I've taken here isn't really the most shin
+ing
example of this...
More in the books "Watch what I do" and "Your Wish is my command",
links from the above site. Also look out for Toon Talk ( http://www.t
+oontalk.com/ )- most easily described as a cross between a programmin
+g language and a computer game.
=back
=head1 USAGE
Note that L<Filter::Simple> and L<Text::Balanced> (both by TheDamian)
+must be
installed.
use Example
In every subroutine that you want to write by example, include a line
+at
the beginning
example(1,2,3);
with the arguments that you pass in. When the program is run every re
+ference
to those arguments will be changed into the relevant argument. Perhap
+s this is
best demonstrated by...
=head1 EXAMPLE
use Example;
sub add {
example(1,11);
print "1+11=";
print 1+11;
}
sub concat {
example("Hello","World");
print "Hello World";
}
add (4, 5);
print "\n";
concat("Bonjour", "Monde");
=head1 ...WHICH BECOMES...
sub add {
my @args=@_;
print "$args[0]+$args[1]=";
print $args[0]+$args[1];
}
sub concat {
my @args=@_;
print "$args[0] $args[1]";
}
add (4, 5);
print "\n";
concat("Bonjour", "Monde");
=head1 BUGS
- Parsing of the comma separated list of example inputs C<example> is
buggy for anything other than simple inputs.
- Though the longest arguments are generalised first, there is no cont
+ext
sensitivity. The example values passed to C<example(..., ...)> should
+ be
written so as not to conflict with anything else in the subroutine...
- With the example above, you couldn't write C<print "1+11=12"> and ha
+ve
L<Example.pm> I<do the right thing>...
=head1 VERSION and AUTHOR
v 0.0000001
status: unstable, untested
hakim@earthling.net
http://www.perlmonks.org -> /msg osfameron
=cut