Acme-AsciiArtinator

 view release on metacpan or  search on metacpan

lib/Acme/AsciiArtinator.pm  view on Meta::CPAN


    # this space intentionally left blank

  }
  return 0;
}

#
# find all misalignments and insert padding into the code
# until all code is aligned or until the padded code is
# too large for the pic.
#
sub pad {
  my @tokens = @{$_[0]};
  my @contexts = @{$_[1]};
  my @blocks = @{$_[2]};

  my $nblocks = 0;
  map { $nblocks += $_ } @blocks;

  my ($needed, $where, $howmuch);
  while ($needed = padding_needed(\@tokens,\@contexts,\@blocks)) {
    ($where,$howmuch) = @$needed;
    if ($where < 0 && $howmuch < 0) {
      if ($DEBUG) {
	print_code_to_pic($Acme::AsciiArtinator::PIC,@tokens);
	sleep 1;
      }
      return;
    }

    my $npad = $howmuch > 1 ? $howmuch - hi_weighted_rand($howmuch-1) : $howmuch;
    while (rand() > 0.95 && $where > 0) {
      $where--;
    }

    while ($where >= 0 && !try_to_pad($where, $npad, \@tokens, \@contexts)) {
      $where-- if rand() > 0.4;
    }

    my $tlength = 0;
    map { $tlength += length $_ } @tokens;
    if ($tlength > $nblocks) {
      print "Padded length exceeds space length.\n";

      if ($DEBUG) {
	print_code_to_pic($Acme::AsciiArtinator::PIC, @tokens);
	print "\n\n";
	sleep 1;
      }

      return;
    }
  }
  ([ @tokens ], [ @contexts ]);
}



#
# can run from command line:
#
#   perl Acme/AsciiArtinator.pm [-d] art-file code-file [output-file]
#
if ($0 =~ /AsciiArtinator.pm/) {
  my $debug = 0;
  my $compile_check = 1;
  my @opts = grep { /^-/ } @ARGV;
  
  @ARGV = grep { !/^-/ } @ARGV;
  foreach my $opt (@opts) {
    $debug = 1 if $opt eq '-d';
    # $compile_check = 1 if $opt eq '-c';
  }

  asciiartinate( art_file => $ARGV[0] ,
	         code_file => $ARGV[1] , 
                 output => $ARGV[2] || "ascii-art.pl",
	         debug => $debug ,
	         'compile-check' => $compile_check );
}

1;

__END__
=head1 NAME

Acme::AsciiArtinator - Embed Perl code in ASCII artwork

=head1 VERSION

0.04

=head1 SYNOPSIS

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

=head1 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 C<non-whitespace> a lot in this
document, so let's just call it
C<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.

=head1 EXAMPLE

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

lib/Acme/AsciiArtinator.pm  view on Meta::CPAN

    @o=(map ... );print@o

than

    print@o=(map ... )

even through the latter code is a little shorter.

=back

=head1 OPTIONS

The C<asciiartinate> method supports the following options:

=over 4

=item art_file => filename

=item art_string => string

=item art => string

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

=item code_file => filename

=item code_string => string

=item code => string

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

=item 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.

=item compile_check => 0 | 1

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

=item 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.

=item 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 C<test_argvE<lt>NNNE<gt>> parameter passed to the 
C<asciiartinate> method. The arguments associated with each
parameter will be passed to the code as command-line arguments.

=item 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 C<test_inputE<lt>NNNE<gt>> parameter passed to the 
C<asciiartinate> method. The data associated with each
parameter will be passed to the standard input of the code.


=back

=head1 TODO

Lots of future enhancements are possible:

=over 4

=item * Use new ways of padding code

=back

=over 4

=item * Take big blocks of filler and fill them with something else. Random quoted strings.

=back

=over 4

=item * Try to align whitespace in the code with whitespace in the art.

=back

=over 4

=item * Have a concept of "grayspace" in the artwork. These are positions where
we can put either whitespace or a character from the code, whichever makes it
easier to align the code.

=back

=over 4

=item * Optionally implement some "best practices" automatically to make the code
more flexible without changing its behavior.

=back

=head1 BUGS

Probably lots.

=head1 SEE ALSO

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

=head1 AUTHOR



( run in 5.235 seconds using v1.01-cache-2.11-cpan-800906f7e73 )