Marty O'Brien > Acme-AsciiArtinator > Acme::AsciiArtinator

Download:
Acme-AsciiArtinator-0.04.tar.gz

Dependencies

Annotate this POD

CPAN RT

Open  0
View/Report Bugs
Module Version: 0.04   Source  

NAME ^

Acme::AsciiArtinator - Embed Perl code in ASCII artwork

VERSION ^

0.04

SYNOPSIS ^

    use Acme::AsciiArtinator;
    asciiartinate( { art_file  => "ascii.file",
                     code_file => "code.pl",
                     output    => "output.pl" } );

DESCRIPTION ^

Embeds Perl code (or at least gives it a good college try) into a piece of ASCII artwork by replacing the non-whitespace (we'll refer to non-whitespace a lot in this document, so let's just call it darkspace for convenience) characters of an ASCII file with the characters of a Perl script. If necessary, the code is modified (padded) so that blocks of contiguous characters (keywords, quoted strings, alphanumeric literals, etc.) in the code are aligned with at least the minimum number of contiguous darkspace characters in the artwork.

EXAMPLE ^

Suppose we have a file called spider.pl with the following code:

    &I();$N=<>;@o=(map{$z=${U}x($x=1+$N-$_);
    ' 'x$x.($".$F)x$_.($B.$z.$P.$z.$F).($B.$")x$_.$/}
    0..$N);@o=(@o,($U.$F)x++$N.($"x3).($B.$U)x$N.$/);
    print@o;
    sub I{($B,$F,$P,$U)=qw(\\ / | _);}
    while($_=pop@o){y'/\\'\/';@o||y#_# #;$t++||y#_ # _#;print}

What this code does is read one value from standard input and draws a spider web of the given size:

    $ echo 5 | perl spiders.pl
          \______|______/
          /\_____|_____/\
         / /\____|____/\ \
        / / /\___|___/\ \ \
       / / / /\__|__/\ \ \ \
      / / / / /\_|_/\ \ \ \ \
    _/_/_/_/_/_/   \_\_\_\_\_\_
     \ \ \ \ \ \___/ / / / / /
      \ \ \ \ \/_|_\/ / / / /
       \ \ \ \/__|__\/ / / /
        \ \ \/___|___\/ / /
         \ \/____|____\/ /
          \/_____|_____\/
          /      |      \

Suppose we also have a file called spider.ascii that looks like:

               ;               ,
             ,;                 '.
            ;:                   :;
           ::                     ::
           ::                     ::
           ':                     :
            :.                    :
         ;' ::                   ::  '
        .'  ';                   ;'  '.
       ::    :;                 ;:    ::
       ;      :;.             ,;:     ::
       :;      :;:           ,;"      ::
       ::.      ':;  ..,.;  ;:'     ,.;:
        "'"...   '::,::::: ;:   .;.;""'
            '"""....;:::::;,;.;"""
        .:::.....'"':::::::'",...;::::;.
       ;:'.'""'"";.,;:::::;.'"""""". ':;
      ::'         ;::;:::;::..         :;
     ::.        ,;:::::::::::;:..       ::
     ;'     ,;;:;::::::::::::::;";..    ':.
    ::     ;:"  ::::::"__'::::::  ":     ::
     :.    ::   ::::::;__:::::::  ::    .;
      ;    ::   :::::::__:::::::   :    ;
       '   ::   ::::::....:::::'  ,:   '
        '  ::    :::::::::::::"   ::
           ::     ':::::::::"'    ::
           ':       """""""'      ::
            ::                   ;:
            ':;                 ;:"
              ';              ,;'
                "'           '"            

And now suppose that we think it would be pretty cool if the code that draws spider webs on the screen actually looked like a spider. Well, this is a job for the Acme::AsciiArtinator.

Let's code up a quick script that just says:

    use Acme::AsciiArtinator;
    asciiartinate( art_file => "spiders.ascii",
                   code_file => "spiders.pl",
                   output => "spider-art.pl" );

and run it.

If this works (and it might not, for a variety of reasons), we will get a new file called spider-art.pl that looks something like:

               &               I
             ()                 ;$
            N=                   <>
           ;;                     ;;
           ;;                     ;;
           ;;                     ;
            ;;                    ;
         ;; ;;                   ;;  ;
        ;;  ;;                   ;;  ;;
       ;;    ;;                 ;@    o=
       (      map             {$z     =$
       {U      }x(           $x=      1+
       $N-      $_)  ;' 'x  $x.     ($".
        $F)x$_   .($B.$z.$ P.   $z.$F).
            ($B.$")x$_.$/}0..$N);@
        o=(@o,($U.$F)x++$N.($"x3).($B.$U
       )x$N.$/);;;;print@o;;;sub I{( $B,
      $F,         $P,$U)=qw(\\          /
      |         _);;}while($_=pop       @o
     ){     y'/\\'\/';;;@o||y#_# #;;    ;;;
    ;$     t++  ||y#_ # _#;print  }#     ##
     ##    ##   ################  ##    ##
      #    ##   ################   #    #
       #   ##   ################  ##   #
        #  ##    ##############   ##
           ##     ############    ##
           ##       ########      ##
            ##                   ##
            ###                 ###
              ##              ###
                ##           ##

Hey, that was pretty cool! Let's see if it works.

    $ echo 6 | perl spider-art.pl
           \_______|_______/
           /\______|______/\
          / /\_____|_____/\ \
         / / /\____|____/\ \ \
        / / / /\___|___/\ \ \ \
       / / / / /\__|__/\ \ \ \ \
      / / / / / /\_|_/\ \ \ \ \ \
    _/_/_/_/_/_/_/   \_\_\_\_\_\_\_
     \ \ \ \ \ \ \___/ / / / / / /
      \ \ \ \ \ \/_|_\/ / / / / /
       \ \ \ \ \/__|__\/ / / / /
        \ \ \ \/___|___\/ / / /
         \ \ \/____|____\/ / /
          \ \/_____|_____\/ /
           \/______|______\/
           /       |       \

UNDER THE HOOD ^

To fill in the shape of the spider, we inserted whitespace, semi-colons, sharps, and maybe the occasional { } pair into the original code. Certain blocks of text, like print, while, and y#_ # _# are kept intact since splitting them would cause the program to either fail to compile or to behave differently.

The ASCII Artinator tokenizes the code and does its best to identify

1. Character strings that must not be divided

These include alphanumeric literals, quoted strings, and most regular expressions.

2. Places in the code where it is OK to insert padding.
3. Places in the ASCII artwork where there are multiple consecutive darkspace characters

The next step is to try to align the tokens from the code with enough contiguous blocks of darkspace in the art. When a token is misaligned, we attempt to align it by inserting some padding at some point in the code before that token.

There are currently two ways that we pad the code. Each time there is a need to pad the code, we randomly choose a padding method and randomly choose an eligible position for padding.

1. Inserting semi-colons at the beginning or end of a statement

In general, we can put as many semi-colons as we like at the beginning or end of statements. The following lines of code should all do the same thing:

    $a=$b+$c;$d=4
    $a=$b+$c;;;;;;$d=4;;;;;;
    ;;;;;;;;;$a=$b+$c;;;;;;;;$d=4;
2. Putting braces around a variable name.

In general, we can replace $name with ${name} and the code will run the same.

There are several other interesting ways to pad code (putting parentheses around expressions, adding and or-ing zeros to expressions, using quoted strings in a void context) that may be put to use in future versions of this module.

When all tokens from the code are successfully aligned with the blocks of darkspace from the artwork, we can paste the code on top of the art and write the output file.

Sometimes we insert too many characters without successfully aligning the tokens and darkspace blocks (and actually in the spider example, this happens about 90% of the time). If this happens, we will start over and retry up to 100 times.

BEST PRACTICES ^

Certain coding practices will increase the chance that Acme::AsciiArtinator will be able to embed your code in the artwork of your choice. In no particular order, here are some suggestions:

OPTIONS ^

The asciiartinate method supports the following options:

art_file => filename
art_string => string
art => string

Specifies the ASCII artwork that we'll try to embed code into. At least one of art, art_string, art_file must be specified.

code_file => filename
code_string => string
code => string

Specifies the Perl code that we will try to embed into the art. At least one of code, code_string, code_file must be specified.

output => filename

Specifies the output file for the embedded code. If omitted, output is written to the file "ascii-art.pl" in the current directory.

compile_check => 0 | 1

Runs the Perl interpreter with the -cw flags on the original code string and asserts that the code compiles.

debug => 0 | 1

Causes the ASCII Artinator to display verbose messages about what it is trying to do while it is doing what it is trying to do.

test_argv1 => [ @args ], test_argv2 => [ @args ] , test_argv3 => ...

Executes the original and the artinated code and compares the output to make sure that the artination process did not change the behavior of the code. A separate test will be conducted for every test_argv<NNN> parameter passed to the asciiartinate method. The arguments associated with each parameter will be passed to the code as command-line arguments.

test_input1 => [ @data ], test_input2 => [ @data ], test_input3 => ...

Executes the original and the artinated code and compares the output to make sure that the artination process did not change the behavior of the code. A separate test will be conducted for every test_input<NNN> parameter passed to the asciiartinate method. The data associated with each parameter will be passed to the standard input of the code.

TODO ^

Lots of future enhancements are possible:

BUGS ^

Probably lots.

SEE ALSO ^

If you liked this module, you might also get a kick out of Acme::EyeDrops.

AUTHOR ^

Marty O'Brien, <mob@cpan.org>

LICENSE AND COPYRIGHT ^

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.

syntax highlighting: