Acme::PerlMonkify rewrites your code in the style of perlmonks.org

The first time you run a program under Acme::PerlMonkify, the module removes most of the variable, function and file handle names from your source file and replaces them with PerlMonks.org usernames. The code (hopefully) continues to work exactly as it did before, but now it looks like this:

my $Ovid = Benedictine_Monk();
Basavaraj_Khuba($SaveDir, $Ovid);

The easiest way to use this is right from the command prompt:

perl -MAcme::PerlMonkify my_script.pl

package Acme::PerlMonkify; use 5.008; use strict; use warnings; our $strict; our $warnings; our $VERSION = '0.01'; use LWP::Simple; use Cache::FileCache (); use B::Deobfuscate '0.10'; use constant DEBUG => 0; our ( $start_url, $USERNAME, $START ); BEGIN { $start_url = "http://tinymicros.com/pm/index.php?goto=MonkStats&st +art=1"; $USERNAME = "usernames"; $START = "start"; } BEGIN { my $old = \ &B::Deparse::declare_hints; no warnings 'redefine'; *B::Deparse::declare_hints = sub { my $r = $old->( @_ ); no strict 'refs'; ${__PACKAGE__ . "::$1"} = 1 if $r =~ /^use (warnings|strict)/; ${__PACKAGE__ . "::warnings"} = 1 if $^W or ${^WARNING_BITS}; return $r; } } sub cached_get { my $cache = shift; my $start = shift; my $url; ($url = $start_url) =~ s/(?<=start=)\d+/$start/; my $html = $cache->get( $url ); return $html if $html; $html = get( $url ); $cache->set( $url, $html ); return $html; } sub usernames { my $cache = Cache::FileCache->new( { namespace => __PACKAGE__ } ); my $users = $cache->get( $USERNAME ) || {}; my $start = $cache->get( $START ) || 0; # Get the next cached page my $page = cached_get( $cache, $start ); # Update the start parameter so we'll search farther next time. DEBUG and print "$START: $start\n"; my $new_start = $start + 50; $cache->set( $START, $new_start ); # Update the users list my @urls = $page =~ m{<tr>(?>(?!<a\s)(?s:.))+<a\s+([^>]+)>(.+)}ig; for (my $i = 0; $i < @urls; $i += 2) { unless ($urls[$i] =~ m{http://(?:www\.)+perlmonks\.org}) { $urls[$i + 1] = undef; } $urls[$i] = undef; } my @new_users = grep defined, @urls; for (@new_users) { s((?:\s*</[^>]+>)*\s*$)()mi; s/\W/_/g; } @$users{@new_users} = () x @new_users; DEBUG and print "\@new_users: " . @new_users . "\n"; $cache->set( $USERNAME, $users ); DEBUG and print( "%users: ".(0+keys %$users), "\n" ); return join "\n", keys %$users; } sub import { shift; return if @_; my $deparse = B::Deparse->new(qw(-p))->coderef2text( \&B::Deparse::begin_is_use ); $deparse =~ s{^\s*if\s*\(\s*\(\s*\(\s*\(\s*\(\s*(\$\w+)\s+eq\s*'st +rict' \s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'integer'\s*\)\s*\)\s*or\s*\(\s*\$\ +w+\s+eq \s*'bytes'\s*\)\s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'warnings'\s*\)\s*\) +\s*\) \s*{\s*return\s*\(\s*''\s*\)\s*;\s*}\s*^}{ \$Acme::PerlMonkify::strict = 1 if $1 eq 'strict'; \$Acme::PerlMonkify::warnings = 1 if $1 eq 'warnings'; }mx; { no warnings; *B::Deparse::begin_is_use = eval "sub $deparse" or die $@; } open *B::Deobfuscate::DATA, "<", \ usernames(); require O; tie *STDOUT, __PACKAGE__ || die $!; O->import( 'Deobfuscate', "-m/${\qr[\A(?=\w*[[:lower:]]\w*)\w+\z]} +/" ); } sub TIEHANDLE { bless \my $stick, shift } sub PRINT { my $src = $_[1]; local *OUT; open OUT, ">", $0 or die "Cannot monkify '$0'"; select OUT; $| = 1; open STDIN, $0; my $octothorpebang = <STDIN>; print OUT $octothorpebang if $octothorpebang and $octothorpebang = +~ /^\Q#!/; print OUT +(not ($strict or $warnings)) ? qq[warn "So you didn't use str +ict? And no warnings? - Expect the Inquisitors\n";] : not($strict) ? qq[warn "No strict?! Who do you think you are, +[TheDamian]?\n";] : not($warnings) ? qq[use strict;\nwarn "I didn't see you use wa +rnings so I turned them on for you and made them fatal errors";\nuse +warnings FATAL => 'all'; \# Bwuahaha!\n] : "\# Sit! What a good monk you are! Good boy!\nuse strict;\nuse + warnings;\n"; $src =~ s/\A(?:^sub Cache::[\w:]+;\s*)+//gm; print OUT $src; close STDERR; } 1; __END__

Replies are listed 'Best First'.
Re: Acme::PerlMonkify %-}
by sauoq (Abbot) on Jul 28, 2003 at 06:16 UTC

    :-)

    The question burning in my mind is, "Why didn't you run it on itself before posting it?"

    -sauoq
    "My two cents aren't worth a dime.";
    

        "Why didn't you run it on itself before posting it?"

      Just out of curiosity I did just that. Perl complained thusly:

        --$ perl -MAcme::PerlMonkify Acme/PerlMonkify.pm Subroutine cached_get redefined at Acme/PerlMonkify.pm line 35. Subroutine usernames redefined at Acme/PerlMonkify.pm line 51. Subroutine import redefined at Acme/PerlMonkify.pm line 89. Subroutine TIEHANDLE redefined at Acme/PerlMonkify.pm line 113. Subroutine PRINT redefined at Acme/PerlMonkify.pm line 114.
      which is pretty much as I would expect. The resultant code looks like this:
        # Sit! What a good monk you are! Good boy! use strict; use warnings; package Acme::PerlMonkify; BEGIN {${^WARNING_BITS} = "UUUUUUUUUUUU\001"} use strict 'refs'; our $John_M__Dlugosz; sub BEGIN { no strict 'refs'; require 5.008; } use strict; use warnings; our $George_Sherston; our $VERSION = '0.01'; use LWP::Simple; use Cache::FileCache (); use B::Deobfuscate ('0.10'); use constant ('DEBUG', 0); use vars ('$start_url', '$USERNAME', '$START'); sub BEGIN { $screamingeagle = 'http://tinymicros.com/pm/index.php?goto=MonkSta +ts&start=1'; $USERNAME = 'usernames'; $START = 'start'; } sub BEGIN { my $Adam = \&B::Deparse::declare_hints; no warnings ('redefine'); no strict ('refs'); BEGIN {${^WARNING_BITS} = "TUUU\025UUUUUUU\001"} *B::Deparse::declare_hints = sub { my $BazB = &$Adam(@_); no strict 'refs'; ${'Acme::PerlMonkify' . "::$1";} = 1 if $BazB =~ /^use (warnin +gs|strict)/; ${'Acme::PerlMonkify::warnings';} = 1 if $^W or ${^WARNING_BIT +S}; return $BazB; } ; } sub newrisedesigns { my $Jazz = shift @_; my $Ovid = shift @_; my $Zaxo; ($Zaxo = $screamingeagle) =~ s/(?<=start=)\d+/$Ovid/; my $ar0n = $Jazz->get($Zaxo); return $ar0n if $ar0n; $ar0n = &crazyinsomniac($Zaxo); $Jazz->set($Zaxo, $ar0n); return $ar0n; } sub FoxtrotUniform { my $Jazz = 'Cache::FileCache'->new({'namespace', 'Acme::PerlMonkif +y'}); my $bart = $Jazz->get($USERNAME) || {}; my $Ovid = $Jazz->get($START) || 0; my $benn = newrisedesigns($Jazz, $Ovid); '???'; my $dree = $Ovid + 50; $Jazz->set($START, $dree); my(@gmax) = $benn =~ /<tr>(?>(?!<a\s)(?s:.))+<a\s+([^>]+)>(.+)/gi; for (my $jima = 0; $jima < @gmax; $jima += 2) { unless ($gmax[$jima] =~ m[http://(?:www\.)+perlmonks\.org]) { $gmax[$jima + 1] = undef; } $gmax[$jima] = undef; } my(@jynx) = grep(defined($_), @gmax); foreach $_ (@jynx) { s[(?:\s*</[^>]+>)*\s*$][]im; s/\W/_/g; } @$bart{@jynx} = (()) x @jynx; '???'; $Jazz->set($USERNAME, $bart); '???'; return join("\n", keys %$bart); } sub simon_proctor { shift @_; return if @_; my $toma = 'B::Deparse'->new('-p')->coderef2text(\&B::Deparse::beg +in_is_use); $toma =~ s/^\s*if\s*\(\s*\(\s*\(\s*\(\s*\(\s*(\$\w+)\s+eq\s*'stric +t' \s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'integer'\s*\)\s*\)\s*or\s*\(\s*\$\ +w+\s+eq \s*'bytes'\s*\)\s*\)\s*or\s*\(\s*\$\w+\s+eq\s*'warnings'\s*\)\s*\) +\s*\) \s*{\s*return\s*\(\s*''\s*\)\s*;\s*}\s*^/\n \$Acme::PerlMonkify +::strict = 1 if $1 eq 'strict';\n \$Acme::PerlMonkify::warnings = +1 if $1 eq 'warnings';\n /mx; { no warnings; die $@ unless *B::Deparse::begin_is_use = eval "sub $toma"; no warnings; ; } open B::Deobfuscate::DATA, '<', \FoxtrotUniform ; require O; tie *STDOUT, 'Acme::PerlMonkify'; 'O'->import('Deobfuscate', "-m/${\qr/\A(?=\w*[[:lower:]]\w*)\w+\z/ +;}/"); } sub TIEHANDLE { bless \my($ybiC), shift @_; } sub PRINT { my $zdog = $_[1]; local *OUT; die "Cannot monkify '$0'" unless open OUT, '>', $0; select OUT; $| = 1; open STDIN, $0; my $Biker = <STDIN>; print OUT $Biker if $Biker and $Biker =~ /^\#\!/; print OUT !($John_M__Dlugosz || $George_Sherston) ? qq[warn "So yo +u didn't use strict? And no warnings? - Expect the Inquisitors\n";] : + (!$John_M__Dlugosz ? qq[warn "No strict?! Who do you think you are, +[TheDamian]?\n";] : (!$George_Sherston ? qq[use strict;\nwarn "I didn +'t see you use warnings so I turned them on for you and made them fat +al errors";\nuse warnings FATAL => 'all'; # Bwuahaha!\n] : "# Sit! Wh +at a good monk you are! Good boy!\nuse strict;\nuse warnings;\n")); $zdog =~ s/\A(?:^sub Cache::[\w:]+;\s*)+//gm; print OUT $zdog; close STDERR; } '???';

      The really interesting part is if you now re-run the module on another piece of Perl...

        perl -MAcme::PerlMonkify tack_on.pl Global symbol "$screamingeagle" requires explicit package name at Acme +/PerlMonkify.pm line 22. BEGIN not safe after errors--compilation aborted at Acme/PerlMonkify.p +m line 25.Compilation failed in require. BEGIN failed--compilation aborted.

      I'm not sure this was the desired effect...


      Peter @ Berghold . Net

      Sieze the cow! Bite the day!

      Test the code? We don't need to test no stinkin' code! All code posted here is as is where is unless otherwise stated.

      Brewer of Belgian style Ales

        Its a bit of a problem getting this to run on itself (thanks for the reminder on why I didn't do this). Much of the set up work happens at BEGIN time (everything in import()) which then sets up a later CHECK block which produces the text and prints it to the previously tied STDOUT which just redirects the text back into the original file. The thing is - you really are evalling the same code twice in that case and perl isn't terribly nice to deal with in that case. It worked on the scripts I tried it on, I am interested in other failure modes since that's actually a fault of the underlying B::Deobfuscate and I'd want to fix it to cover the patch.

        I did however, change the 'use vars()' to some our() declared variables. Hmm... and how to fix that one...