The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Acme::EyeDrops - Visual Programming in Perl

SYNOPSIS

use Acme::EyeDrops qw(sightly);

print sightly( { Shape       => 'camel',
                 SourceFile  => 'myprog.pl' } );

DESCRIPTION

Acme::EyeDrops converts a Perl program into an equivalent one, but without all those unsightly letters and numbers.

It supports Visual Programming by allowing you to pour the generated program into various shapes, such as UML diagrams, enabling you to instantly understand how the program works by glancing at its new and improved visual representation.

Like Acme::Smirch, but unlike Acme::Bleach and Acme::Buffy, the generated program runs without requiring that Acme::EyeDrops be installed on the target system.

EXAMPLES

Suppose you have a program, helloworld.pl, consisting of:

print "hello world\n";

You can make this program look like a camel with:

print sightly( { Shape       => 'camel',
                 SourceFile  => 'helloworld.pl',
                 Regex       => 1 } );

Instead of using the API above, you may find it more convenient to use the sightly.pl command in the demo directory:

sightly.pl -h    (for help)
sightly.pl -s camel -f helloworld.pl -r >new.pl
cat new.pl
perl new.pl      (should "print hello" world as before)

Notice that the shape 'camel' is just the file 'camel.eye' in the same directory as EyeDrops.pm, so you are free to add your own new shapes as required.

If your boss demands a UML diagram describing the program, you can give him this:

print sightly( { Shape       => 'uml',
                 SourceFile  => 'helloworld.pl',
                 Regex       => 1 } );

If it is a Windows program, you can indicate that too, by combining shapes:

print sightly( { Shape       => 'uml,window',
                 SourceFile  => 'helloworld.pl',
                 Regex       => 1 } );

producing this improved visual representation:

               ''=~('('.'?'.'{'.('`'|'%').('['^'-').(
               (                                    (
               (                                    (
               (                                    (
               (                                    (
               (                                    (
               '`'))))))))))|'!').('`'|',').'"'.('['^
                                 (
                                ( (
                               (   (
                              '+'))))
                                 )
                                 )
               .('['^')').('`'|')').('`'|'.').(('[')^
               (                                    (
               (                                    (
'/'))))).('{'^'[').'\\'.('"').(      '`'|'(').('`'|'%').('`'|"\,").(
(                             (      (                             (
(                             (      (                             (
(                             (      (                             (
(                             (      (                             (
(                             (      (                             (
'`'))))))))))))))))))))|"\,").(      '`'|'/').('{'^'[').('['^"\,").(


'`'|'/').('['^')').('`'|',').('`'|'$').('\\').
'\\'.('`'|'.').'\\'.'"'.';'.('!'^'+').'"'.'}'.
')');$:='"'|'#';$:='?'&'!';$:='*'|'~';$:="\%"&
'$';                  $:                  ='"'
|'#'                  ;(                  $:)=
'?'&                  ((                  '!')
);$:                  =(                  '*')
|'~'                  ;(                  $:)=
'%'&                  ((                  '$')
);$:                  =(                  '"')
|'#'                  ;(                  $:)=
'?'&                  ((                  '!')
);$:                  =(                  '*')
|'~'                  ;(                  $:)=
'%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|('~');$:=
'%'&                  ((                  '$')
);$:                  =(                  '"')
|'#'                  ;(                  $:)=
'?'&                  ((                  '!')
);$:                  =(                  '*')
|'~'                  ;(                  $:)=
'%'&                  ((                  '$')
);$:                  =(                  '"')
|'#'                  ;(                  $:)=
'?'&                  ((                  '!')
);$:                  =(                  '*')
|'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:="\*"|
'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:=('*')|
'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:=('*');

This is a Visual Programming breakthrough in that you can tell that it is a Windows program and see its UML structure too, just by glancing at the code.

For Linux-only, you can use its /usr/games/banner command like this:

print sightly( { Shape       => 'srcbanner',
                 Width       => 70,
                 SourceFile  => 'helloworld.pl',
                 Regex       => 1 } );

The generated program, shown below, is easier to understand than the original because its characters are bigger and easier to read:

''                                        =~ 
+(                                        (( 
'(')).'?'.'{'.('`'|'%').('['^'-').('`'|'!'). 
('`'|',').'"'.('['^'+').('['^')').('`'|')'). 
('`'|'.').('['^'/').('{'^'[').'\\'.'"'.('`'| 
'(').('`'|'%').('`'|',').('`'|',').('`'|'/') 
                   .+(                (( 
                 '{'                    )) 
                ^((                      '['
                ))                       ).(
               '['                       ^(( 
               ',')                      )). 
                ('`'                   |'/')
                .(('[')^           (')')).( 
                  '`'|',').('`'|'$').'\\'.
                   '\\'.('`'|"\.").'\\'. 
                      '"'.';'.('!'^'+'
                                    
               ).+                        (( 
               '"'                        )) 
               .'}'.')');$:='"'|'#';$:="\?"& 
               '!';$:='*'|'~';$:='%'&'$';$:= 
               '"'|'#';$:='?'&'!';$:='*'|'~' 
               ;$:='%'&'$';$:='"'|'#';$:='?' 
               &((                   '!'
                                      )); 
                                       $:= 
                                       '*'| 
                                       "\~";
                                   $:=('%')& 
                                  '$';$:='"' 
                                  |('#');$:=
                                  '?'&"\!"; 
                                    ($:) 

               =((                        (( 
               '*'                        ))         ))|
               '~';$:='%'&'$';$:='"'|'#';$:=       ('?')& 
               '!';$:='*'|'~';$:='%'&'$';$:=      '"'|'#';
               $:='?'&'!';$:='*'|'~';$:='%'&       '$';$: 
               ='"'|'#';$:='?'&'!';$:=('*')|         '~'
               ;$:

               =((                        (( 
               '%'                        )) 
               ))&'$';$:='"'|'#';$:='?'&'!'; 
               $:='*'|'~';$:='%'&'$';$:='"'| 
               '#';$:='?'&'!';$:='*'|'~';$:= 
               '%'&'$';$:='"'|'#';$:='?'&'!' 
               ;$:                     =( 
                                        (( 
                                        '*')
                                        ))|+
                                        '~'; 
               $:=                     "\%"& 
               '$';$:='"'|'#';$:='?'&'!';$:= 
               '*'|'~';$:='%'&'$';$:='"'|'#'
               ;$:='?'&'!';$:='*'|"\~";$:= 
               '%'&'$';$:='"'|'#';$:='?'
               &((
                  
                                          (( 
                                          (( 
                     '!'))))));$:='*'|'~';$:=('%')&
                  '$';$:='"'|'#';$:='?'&'!';$:='*'|
                '~';$:='%'&'$';$:='"'|'#';$:=('?')&
               '!';$:='*'|'~';$:='%'&'$';$:='"'|'#'
               ;($:)=                     (( 
               '?'))                      &+ 
                '!' 
                ;$: 
                  =( 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 



                                                    '*')|
                                                   '~';$:= 
                                                  '%'&"\$";$:=
                                                  '"'|'#' 
                                                   ;($:)
                                                        
               =((                                            ((
               '?'                                            ))
               ))&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:=('?')&
               '!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&"\!";
               $:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&('!');$:=
               '*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:="\*"|
               '~'                     ;( 
                                        $: 
                                        )=((
                                        '%')
                                        )&(( 
               '$'                     ));$: 
               ='"'|'#';$:='?'&'!';$:=('*')| 
               '~';$:='%'&'$';$:='"'|'#';$:=
               '?'&'!';$:='*'|'~';$:="\%"& 
               '$';$:='"'|'#';$:='?'&'!'
               ;$:
                  
                         ='*'|'~'; 
                      $:='%'&"\$";$:= 
                    '"'|'#';$:='?'&'!'; 
                  $:='*'|'~';$:='%'&"\$"; 
                 $:='"'|     ((     '#')); 
                ($:)         =(        '?') 
                &((          ((          '!'
               )))           );           $: 
               =((           ((           (( 
               '*'           ))           )) 
                ))           |+          '~'
                ;(           $:        )=(( 
                 ((          ((     '%'))) 
                  )))        &'$';$:='"'| 
                    ((       "\#"));$:= 
                             '?'&'!'; 
                                   
               $:=                                            ((
               '*'                                            ))
               |'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|'~';
               $:='%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|('~');$:=
               '%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|'~';$:="\%"&
               '$';$:='"'|'#';$:='?'&'!';$:='*'|'~';$:='%'&"\$";
               $:=

               '"'                                            |+
               '#'                                            ;(
               $:)='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";$:=
               '?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:="\?"&
               '!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&"\!";
               $:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&('!');$:=
               '*'

                         |"\~";$:= 
                      '%'&'$';$:='"'| 
                    '#';$:='?'&"\!";$:= 
                  '*'|'~';$:='%'&"\$";$:= 
                 '"'|'#'            ;($:)= 
                '?'&                   '!'; 
                $:=                      '*'
               |((                        (( 
               '~'                        )) 
               ));                        $: 
               =((                       '%' 
                ))&                     '$';
                ($:)=                 "\""| 
                  '#';$:='?'&'!';$:=('*')|
                   '~';$:='%'&'$';$:='"' 
                     |'#';$:='?'&"\!"; 
                         $:=('*')| 
 
 
 
 
 
 
 
 
 
 
 
 
 






                                          (( 
                                          (( 
                                       '~')) 
                                  ));$:='%'& 
                               '$';$:=('"')| 
                           '#';$:='?'&'!';$: 
                       ='*'|'~';$:="\%"&  (( 
                   '$'));$:='"'|'#';
               $:='?'&'!';$:='*'
                 |'~';$:="\%"&
                     '$';$: 
                        =('"')| 
                     '#';$:='?'&'!';
                $:='*'|'~';$:='%' 
                 &'$';$:="\""|
                     '#';$: 
                         ="\?"& 
                             '!';$:=
                               '*'|'~'    ;( 
                                   $:)="\%"& 
                                       "\$"; 
                                          $: 
                                          =( 
                         '"')|'#'; 
                      $:='?'&"\!";$:= 
                    '*'|'~';$:='%'&'$'; 
                  $:='"'|'#';$:='?'&"\!"; 
                 $:='*'|            '~';$: 
                ='%'                   &'$' 
                ;$:                      =((
               '"'                        )) 
               |((                        (( 
               '#'                        )) 
               ));                       $:= 
                '?'                     &'!'
                ;($:)                 ='*'| 
                  '~';$:='%'&'$';$:=('"')|
                   '#';$:='?'&'!';$:='*' 
                     |'~';$:='%'&"\$"; 
                         $:=('"')| 
               '#'                        ;( 
               $:)                        =( 
               '?')&'!';$:='*'|'~';$:=('%')& 
               '$';$:='"'|'#';$:='?'&'!';$:= 
               '*'|'~';$:='%'&'$';$:='"'|'#' 
               ;$:='?'&'!';$:='*'|'~';$:='%' 
               &((                   '$'
                                      )); 
                                       $:= 
                                       '"'| 
                                       "\#";
                                   $:=('?')& 
                                  '!';$:='*' 
                                  |('~');$:=
                                  '%'&"\$"; 
                                    ($:) 

               =((                                            ((
               '"'                                            ))
               ))|'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:=('"')|
               '#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";
               $:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|('#');$:=
               '?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:="\?"&
               '!'

                        ;$:='*'|'~';
                      $:='%'&('$');$:=
                   '"'|'#';$:='?'&'!';$: 
                  ='*'|'~';$:='%'&"\$";$:=
                '"'|'#';           $:="\?"& 
                '!';                   ($:)=
               '*'|                      '~' 
               ;$:                       =(( 
                ((                       '%'
                )))                      )&+
                 '$'                    ;( 
                   $:)                =(                      ((
               '"')))|'#';$:='?'&'!';$:='*'|'~';$:='%'&('$');$:=
               '"'|'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:="\""|
               '#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";
               $:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|('#');$:=
               '?'
               &((

               '!') 
                 );$:= 
                    "\*"| 
                       '~';$:
                           ='%'&
                              "\$"; 
                                 ($:)= 
                                    "\""| 
                                      "\#"; 
                                         ($:)= 
                                            "\?"& 
                                               '!';$:
                                                  ="\*"|
                                                      "\~";
                                                         ($:)= 
                                                            '%'&
                                                                
               '$'                        ;( 
               $:)                        =( 
               '"')|'#';$:='?'&'!';$:=('*')| 
               '~';$:='%'&'$';$:='"'|'#';$:= 
               '?'&'!';$:='*'|'~';$:='%'&'$' 
               ;$:='"'|'#';$:='?'&'!';$:='*' 
               |((                     (( 
                                        (( 
                                        '~')
                                        ))))
                                        );$: 
               =((                     '%')) 
               &'$';$:='"'|'#';$:='?'&'!';$: 
               ='*'|'~';$:='%'&'$';$:=('"')|
               '#';$:='?'&'!';$:='*'|"\~"; 
               $:='%'&'$';$:='"'|'#';$:=
               '?'
                  
                                                    &'!';
                                                   $:='*'| 
                                                  '~';$:="\%"&
                                                  '$';$:= 
                                                   "\""|

                                                        
                  '#'                  ;$:
                ="\?"&                "\!"; 
               $:="\*"|              '~';$:= 
           '%'&"\$";$:=              '"'|'#' 
              ;$:='?'&                "\!";

The shapes 'bleach' and 'buffy' are also provided to aid folks migrating from Acme::Bleach and Acme::Buffy.

Let's get more ambitious and create a big JAPH.

my $src = <<'PROG';
open 0;
$/ = undef;
$x = <0>;
close 0;
$x =~ tr/!-~/#/;
print $x;
PROG
print sightly({ Shape         => 'japh',
                SourceString  => $src,
                Regex         => 1 } );

This works. However, if we were to change:

$x =~ tr/!-~/#/;

to:

$x =~ s/\S/#/g;

the generated program would malfunction in strange ways because it is running inside a regular expression and Perl's regex engine is not reentrant. In this case, we must resort to:

print sightly({ Shape         => 'japh',
                SourceString  => $src,
                Regex         => 0 } );

which runs the generated sightly program via eval instead.

EyeDrops can also convert plain text:

print sightly({ Shape         => 'window',
                SourceString  => "Bill Gates is a pest!\n",
                Regex         => 1,
                Print         => 1 } );

In this example, the generated program will print the SourceString above.

But wait, there's more. You can encode binary files too.

print sightly({ Shape       => 'camel,japh,camel',
                SourceFile  => 'some_binary_file',
                Binary      => 1,
                Print       => 1,
                Gap         => 5 } );

This is prettier than uuencode/uudecode. Here is how you do it with sightly.pl:

sightly.pl -g5 -bps camel,japh,camel -f some_binary_file >fred

To decode:

perl fred >f.tmp

To verify it worked:

cmp f.tmp some_binary_file

The sightly-encoding engine is implemented in the functions ascii_to_sightly and sightly_to_ascii.

BUGS

A really diabolical shape with lots of single character lines will defeat the shape-pouring algorithm.

In the general case, all unsightly alphanumerics are not eliminated because of the need for a leading eval.

AUTHOR

Andrew Savige <andrew.savige@ir.com>

SEE ALSO

Acme::Bleach Acme::Smirch Acme::Buffy

CREDITS

I blame Japhy and Ronald J Kimball and others on the fwp mailing list for exposing the ''=~ trick and Jas Nagra for explaining his Acme::Smirch module.

COPYRIGHT

Copyright (c) 2001 Andrew Savige. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.