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.
In a Visual Programming breakthrough, EyeDrops allows you to pour the generated program into various shapes, such as UML diagrams, enabling you to instantly understand how the program works just 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 apply its /usr/games/banner command to the program's source text 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:
'' =~
+( ((
'(')).'?'.'{'.('`'|'%').('['^'-').('`'|'!').
('`'|',').'"'.('['^'+').('['^')').('`'|')').
('`'|'.').('['^'/').('{'^'[').'\\'.'"'.('`'|
'(').('`'|'%').('`'|',').('`'|',').('`'|'/')
.+( ((
'{' ))
^(( '['
)) ).(
'[' ^((
',') )).
('`' |'/')
.(('[')^ (')')).(
'`'|',').('`'|'$').'\\'.
'\\'.('`'|"\.").'\\'.
'"'.';'.('!'^'+'
).+ ((
'"' ))
.'}'.')');$:='"'|'#';$:="\?"&
'!';$:='*'|'~';$:='%'&'$';$:=
'"'|'#';$:='?'&'!';$:='*'|'~'
;$:='%'&'$';$:='"'|'#';$:='?'
&(( '!'
));
$:=
'*'|
"\~";
$:=('%')&
'$';$:='"'
|('#');$:=
'?'&"\!";
($:)
=(( ((
'*' )) ))|
'~';$:='%'&'$';$:='"'|'#';$:= ('?')&
'!';$:='*'|'~';$:='%'&'$';$:= '"'|'#';
$:='?'&'!';$:='*'|'~';$:='%'& '$';$:
='"'|'#';$:='?'&'!';$:=('*')| '~'
;$:
=(( ((
'%' ))
))&'$';$:='"'|'#';$:='?'&'!';
$:='*'|'~';$:='%'&'$';$:='"'|
'#';$:='?'&'!';$:='*'|'~';$:=
'%'&'$';$:='"'|'#';$:='?'&'!'
;$: =(
((
'*')
))|+
'~';
$:= "\%"&
'$';$:='"'|'#';$:='?'&'!';$:=
'*'|'~';$:='%'&'$';$:='"'|'#'
;$:='?'&'!';$:='*'|"\~";$:=
'%'&'$';$:='"'|'#';$:='?'
&((
((
((
'!'))))));$:='*'|'~';$:=('%')&
'$';$:='"'|'#';$:='?'&'!';$:='*'|
'~';$:='%'&'$';$:='"'|'#';$:=('?')&
'!';$:='*'|'~';$:='%'&'$';$:='"'|'#'
;($:)= ((
'?')) &+
'!'
;$:
=(
'*')|
'~';$:=
'%'&"\$";$:=
'"'|'#'
;($:)
=(( ((
'?' ))
))&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:=('?')&
'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&"\!";
$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&('!');$:=
'*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:="\*"|
'~' ;(
$:
)=((
'%')
)&((
'$' ));$:
='"'|'#';$:='?'&'!';$:=('*')|
'~';$:='%'&'$';$:='"'|'#';$:=
'?'&'!';$:='*'|'~';$:="\%"&
'$';$:='"'|'#';$:='?'&'!'
;$:
='*'|'~';
$:='%'&"\$";$:=
'"'|'#';$:='?'&'!';
$:='*'|'~';$:='%'&"\$";
$:='"'| (( '#'));
($:) =( '?')
&(( (( '!'
))) ); $:
=(( (( ((
'*' )) ))
)) |+ '~'
;( $: )=((
(( (( '%')))
))) &'$';$:='"'|
(( "\#"));$:=
'?'&'!';
$:= ((
'*' ))
|'~';$:='%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|'~';
$:='%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|('~');$:=
'%'&'$';$:='"'|'#';$:='?'&'!';$:='*'|'~';$:="\%"&
'$';$:='"'|'#';$:='?'&'!';$:='*'|'~';$:='%'&"\$";
$:=
'"' |+
'#' ;(
$:)='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";$:=
'?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:="\?"&
'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&"\!";
$:='*'|'~';$:='%'&'$';$:='"'|'#';$:='?'&('!');$:=
'*'
|"\~";$:=
'%'&'$';$:='"'|
'#';$:='?'&"\!";$:=
'*'|'~';$:='%'&"\$";$:=
'"'|'#' ;($:)=
'?'& '!';
$:= '*'
|(( ((
'~' ))
)); $:
=(( '%'
))& '$';
($:)= "\""|
'#';$:='?'&'!';$:=('*')|
'~';$:='%'&'$';$:='"'
|'#';$:='?'&"\!";
$:=('*')|
((
((
'~'))
));$:='%'&
'$';$:=('"')|
'#';$:='?'&'!';$:
='*'|'~';$:="\%"& ((
'$'));$:='"'|'#';
$:='?'&'!';$:='*'
|'~';$:="\%"&
'$';$:
=('"')|
'#';$:='?'&'!';
$:='*'|'~';$:='%'
&'$';$:="\""|
'#';$:
="\?"&
'!';$:=
'*'|'~' ;(
$:)="\%"&
"\$";
$:
=(
'"')|'#';
$:='?'&"\!";$:=
'*'|'~';$:='%'&'$';
$:='"'|'#';$:='?'&"\!";
$:='*'| '~';$:
='%' &'$'
;$: =((
'"' ))
|(( ((
'#' ))
)); $:=
'?' &'!'
;($:) ='*'|
'~';$:='%'&'$';$:=('"')|
'#';$:='?'&'!';$:='*'
|'~';$:='%'&"\$";
$:=('"')|
'#' ;(
$:) =(
'?')&'!';$:='*'|'~';$:=('%')&
'$';$:='"'|'#';$:='?'&'!';$:=
'*'|'~';$:='%'&'$';$:='"'|'#'
;$:='?'&'!';$:='*'|'~';$:='%'
&(( '$'
));
$:=
'"'|
"\#";
$:=('?')&
'!';$:='*'
|('~');$:=
'%'&"\$";
($:)
=(( ((
'"' ))
))|'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:=('"')|
'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";
$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|('#');$:=
'?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|'#';$:="\?"&
'!'
;$:='*'|'~';
$:='%'&('$');$:=
'"'|'#';$:='?'&'!';$:
='*'|'~';$:='%'&"\$";$:=
'"'|'#'; $:="\?"&
'!'; ($:)=
'*'| '~'
;$: =((
(( '%'
))) )&+
'$' ;(
$:) =( ((
'"')))|'#';$:='?'&'!';$:='*'|'~';$:='%'&('$');$:=
'"'|'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:="\""|
'#';$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|"\#";
$:='?'&'!';$:='*'|'~';$:='%'&'$';$:='"'|('#');$:=
'?'
&((
'!')
);$:=
"\*"|
'~';$:
='%'&
"\$";
($:)=
"\""|
"\#";
($:)=
"\?"&
'!';$:
="\*"|
"\~";
($:)=
'%'&
'$' ;(
$:) =(
'"')|'#';$:='?'&'!';$:=('*')|
'~';$:='%'&'$';$:='"'|'#';$:=
'?'&'!';$:='*'|'~';$:='%'&'$'
;$:='"'|'#';$:='?'&'!';$:='*'
|(( ((
((
'~')
))))
);$:
=(( '%'))
&'$';$:='"'|'#';$:='?'&'!';$:
='*'|'~';$:='%'&'$';$:=('"')|
'#';$:='?'&'!';$:='*'|"\~";
$:='%'&'$';$:='"'|'#';$:=
'?'
&'!';
$:='*'|
'~';$:="\%"&
'$';$:=
"\""|
'#' ;$:
="\?"& "\!";
$:="\*"| '~';$:=
'%'&"\$";$:= '"'|'#'
;$:='?'& "\!";
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 encode/decode binary files with sightly.pl.
To encode:
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
REFERENCE
Sightly Encoding
There are 32 characters in the sightly character set:
! " # $ % & ' ( ) * + , - . / (33-47)
: ; < = > ? @ (58-64)
[ \ ] ^ _ ` (91-96)
{ | } ~ (123-126)
A sightly string consists only of characters drawn from this set.
The ascii_to_sightly
function converts an ASCII string (0-255) to a sightly string; the sightly_to_ascii
function does the reverse.
Function Reference
- ascii_to_sightly STRING
-
Given an ascii string STRING, returns a sightly string.
- sightly_to_ascii STRING
-
Given a sightly string STRING, returns an ascii string.
- regex_print_sightly STRING
-
Given an ascii string STRING, returns a sightly-encoded Perl program with a print statement embedded in a regular expression. When run, the program will print STRING.
- regex_eval_sightly STRING
-
Given a Perl program in ascii string STRING, returns an equivalent sightly-encoded Perl program using an eval statement embedded in a regular expression.
- clean_print_sightly STRING
-
Given an ascii string STRING, returns a sightly-encoded Perl program with a print statement executed via eval. When run, the program will print STRING.
- clean_eval_sightly STRING
-
Given a Perl program in ascii string STRING, returns an equivalent sightly-encoded Perl program using an eval statement executed via eval.
- regex_binmode_print_sightly STRING
-
Given an ascii string STRING, returns a sightly-encoded Perl program with a binmode(STDOUT) and a print statement embedded in a regular expression. When run, the program will print STRING. Note that STRING may contain any character in the range 0-255. This function is used to sightly-encode binary files. This function is dodgy because regexs don't seem to like binary zeros; use
clean_binmode_print_sightly
instead. - clean_binmode_print_sightly STRING
-
Given an ascii string STRING, returns a sightly-encoded Perl program with a binmode(STDOUT) and a print statement executed via eval. When run, the program will print STRING. Note that STRING may contain any character in the range 0-255. This function is used to sightly-encode binary files.
- get_builtin_shapes
-
Returns a list of the built-in shape names.
- get_eye_shapes
-
Returns a list of the eye shapes. An eye shape is just a file with a
.eye
extension residing in the same directory asEyeDrops.pm
. - pour_sightly SHAPESTRING PROGSTRING GAP
-
Given a shape string SHAPESTRING, a sightly-encoded program string PROGSTRING, and a GAP between successive shapes, returns a properly shaped program string.
- sightly HASHREF
-
Given a hash reference, HASHREF, describing various attributes, returns a properly shaped program string.
The attributes that HASHREF may contain are:
Shape Describes the shape you want. First, a built-in shape is looked for. Next a I<eye> shape (.eye file in the same directory as EyeDrops.pm) is looked for. Finally a file name is looked for. ShapeString Describes the shape you want. This time you specify a shape string. SourceFile The source file name to convert. SourceString Specify a string instead of a file name. BannerString String to use with built-in Shape 'banner'. Regex Boolean. If set, try to embed source program in a regular expression. Do not set this flag when converting complex programs. Print Boolean. If set, use a print statement instead of the default eval statement. Binary Boolean. Set if encoding a binary file. Gap The number of lines between successive shapes. Width Ignored for .eye file shapes. For built-in shapes, specifies the shape width in characters.
MIGRATION
To aid those migrating from Acme::Bleach and Acme::Buffy, the 'bleach' and 'buffy' shapes are provided.
BUGS
A really diabolical shape with lots of single character lines will defeat the shape-pouring algorithm.
You can eliminate all alphanumerics (via Regex => 1) only for small programs with simple I/O and no regular expressions. To convert complex programs, you must use Regex => 0, which emits a leading unsightly 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.