When I write Perl, on my own, it looks like the following. This is Perl written in the “functional” style I advocate.

The code takes a listing of simple definitions:

    tree
    noun
    something organic with leaves

        _etc._

and turns it into LaTeX Beamer–class slide markup.

    
    \frame{
        \frametitle{tree       }
        \begin{itemize}
            \item tree
              \pause
        \item noun
        \pause
        \item
    something organic with leaves
        \end{itemize}
    }
    

When the Beamer LaTeX code is complied with pdflatex it produces a slide show that winds up looking something like…

You can see how something like this is handy for someone studying their GRE Vocabulary builder. Code after the jump.

#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
use vars qw/$end_of_document $word $part $meaning/;

=head1 NAME

wordlst_to_beamer.pl - A plaintext to LaTeX-Beamer dialect converter

=head1 SYNOPSIS

wordlst_to_beamer definition_file
       
=head1 DESCRIPTION

This program takes a simply formatted text file that contains a series of "
blocks"
.  Each block is equivalent to one definition ( see SOURCE DEFINITION ).  
Each definition is then taken to be a "slide" in LaTeX Beamer style.

The purpose of doing so is to make each slide, effectively, a flash card.  
The word is printed, pause, part of speech given, pause, and then the
definition given.
 
=head1 SOURCE DEFINITION

The text file that is given as an argument to the program should be a collection
of definitions separated by a double carriage return.

 tree
 noun
 a living thing with leaves

 happy
 adjective
 a feeling like you want to dance Charleston

I<etc.>

=head1 SUBROUTINES

Given the beautiful functional style in which this code was written and the
relative brevity of each routine, the code serves as sufficient documentation.

=cut

&main();

########################################################################
# Subroutines
########################################################################

sub main
{
  &report_status(
    &produce_beamer_body(
      &test_contents_integrity (
        &load_contents_of_file(
          &test_validity_of_file (
            &get_file_to_operate_on(
              &load_environment()
              ))))));
}

########################################################################

sub report_status
{
        unless ( $_[0] )
        {
                print "Successfully ran.\n"
        }
        else
        {
                die "Error!\n"
        }
}

########################################################################

sub produce_beamer_body
{
        (my $latex_output_file = $_[0]->{file} ) =~ s/..*$// ;

        open (LATEX, ">$latex_output_file.tex");
       
        # A technique to tell Perl not to paginate
        # ( i.e. re-print LATEX_TOP format ) again
       
        my $ltx = select LATEX;
        $= = 9990;
        select $ltx;
       
        my ($ds) = $_[0]->{data_structure};
       
        my @order = sort { $a  <=> $b } ( keys ( %$ds ) );
        for ( @order )
        {
                $word    = $ds->{$_}[0];
                $part    = $ds->{$_}[1];
                $meaning = $ds->{$_}[2];
                chomp($word, $part, $meaning);
                write (LATEX);
        }

        print LATEX $end_of_document;
        close LATEX;

  return $?
}

########################################################################

sub test_contents_integrity
{
        my $content_string         = join (, @{+ $_[0]->{contents} } );
        my @clustered_contents_ray = split ( /\n\n/, $content_string);

        my $counter      = 0;
        my $cell_counter = 0;
       
        my %data_structure;
       
        for ( @clustered_contents_ray )
        {
                $counter++;
                my @temp_array = split ( /\n/, $_);
               
                if ( scalar ( @temp_array ) != 3 )
                {
                        print "There was something amiss with entry:\n$_";
                        exit 1;
                }
                else
                {
                        $cell_counter +=3;
                }
                $data_structure{$counter} = \@temp_array;
        }
       
  if ( ($cell_counter % 3) == 0 )
        {
                $_[0]->{‘data_structure’} = \%data_structure;
                return $_[0];
        }
        else
        {
                die "Data structure was anomalous."
        }
}

########################################################################

sub load_contents_of_file
{
        my $f = $_[0]->{file_fullpath};
        open ( IN, $f ) or die ("Could not open $f because [$!]");
        my @contents = <IN>;
        close IN;
        $_[0]->{contents} = \@contents;
        return $_[0];
}

#########################################################################

sub test_validity_of_file
{
        my $f = $_[0]->{file_fullpath};
        die ("Could not read file [$f][$!]") unless ( -r $f );
        return $_[0];
}

#########################################################################

sub get_file_to_operate_on
{
        my $filename = shift( @ARGV ) || ;
        my $default_filename=‘hit_parade_list_1.txt’;
       
        my $payload = {};
       
        if ( $filename =~ /\w/)
        {
                chomp $filename;
                $payload->{file} = $filename
        }
        else
        {
                $payload->{file} = $default_filename
        }
       
        $payload->{file_fullpath} =
                 join ( "/", (`pwd` =~ /(.*)\n/),
                 $filename ? $filename : $default_filename);
               
        return $payload;
}

########################################################################

sub load_environment
{
       
format LATEX_TOP=
\documentclass{beamer}
\begin{document}
.

format LATEX =
\frame{
    \frametitle{@<<<<<<<<<<<<<<}
$word
    \begin{itemize}
        \item @<<<<<<<<<<<<<<<
$word
          \pause
    \item @<<<<<<<<<<<<
$part
    \pause
    \item
@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$meaning
    \end{itemize}
}
.

$end_of_document = <<EOF

\end{document};

EOF
;
       
}

6 Responses to “How I write Perl”

  1. stevengharms.com » Blog Archive » Benefits of “Functional Perl”: ease of modification Says:

    […] an earlier post I provided code demonstrating my “functional” Perl idiom. The purpose of that code was to take a very simply formatted text file and to turn it into LaTeX […]

  2. zeek Says:

    Calling functions like this:

    &function();

    is a Perl4 leftover and deprecated in Perl5.

  3. steven Says:

    Zeek: You’re absolutely correct. You may derive from this that I have been migrating / editing a lot of Perl 5.00 code where the previous authors’ history hadn’t quite worn out. A simple perl -pe command has fixed my code to your recommendation.

  4. Mark Says:

    The formatting looks OK from far away, but the naming conventions, OMFG. I don’t know what to say.

    Giving variables names like ‘data_structure’ and ‘temp_array’ is just wrong. And what is a ‘ray’ in the context of your program? @clustered_contents_ray ??

    And using the special variables to refer to input, without ever naming them, is bad practice. I’m talking about your use of things like $[0]->{contents}, where $[0] is never given a name.

    Also it’s considered bad practice to use $_ as much as you are. Name your variables.

    Also perl5 has some new idioms you should take advantage of. Instead of:

    if ( scalar ( @temp_array ) != 3 )
    {
    print “There was something amiss with entry:n$_”;
    exit 1;
    }
    }
    else

    You can say:

    die “There was something amiss with entry:n$_nn”
    unless (@temp_array == 3);

    Still very clear. No ‘else’ needed either, if your program is exiting. And give $_ a name.

  5. Mark Says:

    Not surprisingly, the comment formatting was messed up on my post. When reading, insert indentation, backslashes and the occasional other missing character (underscore after dollar sign, in some places) where necessary.

  6. steven Says:

    Wow, I’m really surprised this post is generating this much commentary. You never know what’s going to attract people.

    My key focus in this post was to underscore how much I like to run main() as a “stack” of functions. The independent sub-strata of the code were not my key focuses.

    I’ll agree that the “consequent first” if statement is preferable ( I think I had something there in the else condition originally ). You don’t see it in this code, but I use it, a lot.

    But I certainly don’t think using $_ is as abhorrent as you make it out to be. If a reader understands the Perl iterators and knows that $_ is automatically set, why not take advantage? Your opinion that this is “not best practice” is in opposition to Joseph Hall’s Effective Perl Programming which encourages the practice.

    As far as naming convention goes, they’re a bit wordy and admittedly a bit uninformative, but given the very limited scope of this post their naming wasn’t a huge focus ( there’s only one array with the very primitive source data ) there’s only one HoA, etc.

Leave a Reply