http://www.perlmonks.org?node_id=708332

NOW UPDATE with templates..!!!

I build this program to generate a LaTeX code structure that I could use for my assignments at University. It comes with several options like margins, font size, document type, paragraphs formats, table of contents and bibliography. At present is in the early stages of development.

I plan to expand it in future releases. At the moment I am working towards using the template toolkit for the code generation as adviced by some of the perlmonks which are undoubtebly helpful.

History:

Now UPDATED to release version 0.08 (previous version 0.02)

Includes the template toolkit for code generation thanks to the advice and help of CountZero and linuxer were most helpful in this project.

The project is still in the development stages. However it has good functionality.

The Perl Code: latex-wizard-0.08-tt.pl

use Tk; use warnings; use strict; use Template; my ( $file, $title, $maketitle, $author ); my ( $type, $fontSizeCheckButton, $geometry ); my ( $pdftex, $paper, $font, $fontSize ); my ( @spinbox, $spinbox, $sizeSpin, $i ); my ( $frameIncludes, $margin, %margin, $includes, %includes ); my ( $contents, $frontmatter, $backmatter, $mainmatter, $citeExample); $i = 0; my $mw = MainWindow -> new; $mw -> bind('<Key-Escape>' => sub { exit } ); # use escape key to exit # **************** M A I N D E T A I L S F R A M E **************** my $frameMain = $mw -> Frame( -label => 'MAIN DETAILS', -borderwidth => 2, -relief => 'groove') -> pack(-side => 'top', -fill => 'x'); $frameMain -> Label( -text => 'LaTeX filename') -> pack(-side => 'left'); my $entryFile = $frameMain -> Entry( -textvariable => \$file) -> pack(-side => 'left', -fill => 'x', -expand => 1); $entryFile -> insert('end', "default.tex"); $entryFile -> focus; $frameMain -> Label( -text => 'Title') -> pack(-side => 'left'); my $entryTitle = $frameMain -> Entry( -textvariable => \$title) -> pack(-side => 'left', -fill => 'x', -expand => 1); $frameMain -> Label( -text => 'Author') -> pack(-side => 'left'); my $entryAuthor = $frameMain -> Entry( -textvariable => \$author) -> pack(-side => 'left', -fill => 'x', -expand => 1); # *************** D O C U M E N T C L A S S ***************** my $frameDocClass = $mw -> Frame( -label => 'DOCUMENT CLASS', -borderwidth => 2, -relief => 'groove') -> pack(-side => 'top', -fill => 'x'); my $frameType = $frameDocClass -> Frame(-label => 'TYPE', -borderwidth => 2, -relief => 'groove'); my $framePaper = $frameDocClass -> Frame(-label => 'PAPER (uncheck = d +efault)', -borderwidth => 2, -relief => 'groove'); my $frameFont = $frameDocClass -> Frame(-label => 'FONT SIZE', -borderwidth => 2, -relief => 'groove'); $frameDocClass -> Checkbutton( -text => 'use pdf', -variable => \$pdftex, -onvalue => "pdftex, ", -offvalue => "", ) -> pack(-side => 'left'); foreach (qw/article book report/) { $frameType -> Radiobutton( -text => $_, -value => $_, -variable => \$type) -> pack(-side => 'left'); } foreach (qw/a4paper letter/) { $framePaper -> Radiobutton( -text => $_, -value => $_.", ", -variable => \$paper) -> pack(-side => 'left'); } $frameFont -> Checkbutton( -text => 'customize', -variable => \$fontSizeCheckButton, -onvalue => "on", -offvalue => "off", -command => sub { if ($fontSizeCheckButton eq "on") { $sizeSpin -> configure(-state = +> 'normal') } else { $sizeSpin -> configure(-state = +> 'disabled') } } ) -> pack(-side => 'left'); $frameFont -> Label ( -text => '') -> pack(-side => 'left'); $sizeSpin = $frameFont -> Spinbox( -width => 6, -from => 10, -to => 14, -textvariable => \$fontSize, -state => 'disabled') -> pack(-side => 'left'); # ************************ G E O M E T R Y *************************** my $frameGeometry = $mw -> Frame; $frameGeometry = $mw -> Frame( -label => 'GEOMETRY', -borderwidth => 2, -relief => 'groove') -> pack(-side => 'top', -fill => 'x'); $frameGeometry -> Checkbutton( -text => 'customize', -variable => \$geometry, -onvalue => "on", -offvalue => "off", -command => sub { foreach (@spinbox) { if ($geometry eq "on") { $_ -> configure(-state => ' +normal') } else { $_ -> configure(-state => ' +disabled') } } } ) -> pack(-side => 'left'); foreach (qw/left right top bottom/) { $frameGeometry -> Label ( -text => $_) -> pack(-side => 'left'); $spinbox[$i] = $frameGeometry -> Spinbox( -text => 0, -textvariable => \$margin{$_}, -state => 'disable', -width => 6, -increment => .1, -from => 0, -to => 100) -> pack(-side => "left"); $i++ } # ********************* I N C L U D E S ****************************** $frameIncludes = $mw -> Frame; $frameIncludes = $mw -> Frame( -label => 'INCLUDES', -borderwidth => 2, -relief => 'groove') -> pack(-side => 'top', -fill => 'x'); foreach (qw/graphicx contents bibliography titledParagraph pdfBookmark +s/) { $frameIncludes -> Checkbutton( -text => $_, -variable => \$includes{$_}, -onvalue => 1, -offvalue => "") -> pack(-side => 'left');} $mw -> Button(-text => 'Execute', -command => \&execute ) -> pack(-side => 'bottom'); $frameMain -> pack(); $frameDocClass -> pack; $frameType -> pack(-side=>'left'); $framePaper -> pack(-side=>'left'); $frameFont -> pack(-side=>'left'); $frameGeometry -> pack; $frameIncludes -> pack; MainLoop; sub execute { &load_template_vars; &execute_template; } sub load_template_vars { if ( $title ) { $title = "\\title{"."$title"."}\n"; $maketitle = "\\maketitle\n"; } if ( $author ) { $author = "\\author{"."$author"."}\n"; } $geometry = "\\usepackage[left = $margin{left}cm, right = $margin{ +right}cm, top = $margin{top}cm, bottom = $margin{bottom}cm]{geometry} +\n" if $geometry; $includes{pdfBookmarks} = "\\usepackage[bookmarks, colorlinks, pla +inpages=false, pdfpagelabels]{hyperref}\n" if $includes{pdfBookmarks}; $includes{graphicx} = "\\usepackage[pdftex]{graphicx}\n" if $inclu +des{graphicx}; $includes{titledParagraph} = '\\makeatletter \\renewcommand\\paragraph{\\@startsection{paragraph}{4}{\\z@}% {-3.25ex \\@plus-1ex \\@minus-.2ex +}% {0.5ex \\@plus0.2ex}% {\\normalfont\\large\\bfseries}} \\makeatother'."\n" if $includes{titledParagraph}; if ( $includes{contents} ) { $frontmatter = "\\frontmatter\n"; $mainmatter = "\\mainmatter\n"; $backmatter = "\\backmatter\n"; $contents = "\\tableofcontents\n"; } if ( $includes{bibliography} ) { $citeExample = "% Here is a Reference Example ~\\cite{example} +\n"; $includes{bibliography} = "\\addcontentsline{toc}{section}{Bib +liography} \\begin{thebibliography}{99} \\bibitem{example} This is an example \\end{thebibliography}\n"; } } sub execute_template { my $config = { INTERPOLATE => 1, # expand "$var" in plain text POST_CHOMP => 1, # cleanup whitespaces EVAL_PERL => 1, # evaluate Perl code blocks }; my $tt = Template->new($config); my $input = 'latex.tt'; my $vars = { title => $title, maketitle => $maketitle, author => $author, pdftex => $pdftex, fontSize => $fontSize, paper => $paper, type => $type, geometry => $geometry, pdfBookmarks => $includes{pdfBookmarks}, graphicx => $includes{graphicx}, titlepar => $includes{titledParagraph}, contents => $contents, frontmatter => $frontmatter, mainmatter => $mainmatter, backmatter => $backmatter, cite => $citeExample, bibliography => $includes{bibliography} }; $tt->process($input, $vars, $file) || die $tt->error( ); exit }

The template file: latex.tt

\documentclass[[% pdftex %][% paper %][% fontSize %]pt]{[% type %]} [% geometry %] [% pdfBookmarks %] [% graphicx %] [% titlepar %] [% title %] [% author %] \begin{document} [% frontmatter %] [% maketitle %] [% contents %] [% mainmatter %] % H E R E B E G I N S Y O U R D O C U M E N T [% cite %] [% backmatter %] [% bibliography %] \end{document}

A sample output: default.tex

\documentclass[pdftex, a4paper, 11pt]{book} \usepackage[left = 3cm, right = 3cm, top = 2.5cm, bottom = 2.5cm]{geom +etry} \usepackage[bookmarks, colorlinks, plainpages=false, pdfpagelabels]{hy +perref} \usepackage[pdftex]{graphicx} \makeatletter \renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}% {-3.25ex \@plus-1ex \@minus-.2ex}% {0.5ex \@plus0.2ex}% {\normalfont\large\bfseries}} \makeatother \title{My Book} \author{Milarepa} \begin{document} \frontmatter \maketitle \tableofcontents \mainmatter % H E R E B E G I N S Y O U R D O C U M E N T % Here is a Reference Example ~ te{example} \backmatter \addcontentsline{toc}{section}{Bibliography} \begin{thebibliography}{99} \bibitem{example} This is an example \end{thebibliography} \end{document}


Replies are listed 'Best First'.
Re: LaTeX Wizard
by CountZero (Bishop) on Sep 01, 2008 at 22:21 UTC
    A nice start!

    Now read about templating systems and you can easily expand this.

    CountZero

    A program should be light and agile, its subroutines connected like a string of pearls. The spirit and intent of the program should be retained throughout. There should be neither too little or too much, neither needless loops nor useless variables, neither lack of structure nor overwhelming rigidity." - The Tao of Programming, 4.1 - Geoffrey James

      Thank you, really helpful advice...!!!
Re: LaTeX Wizard
by FunkyMonk (Chancellor) on Sep 01, 2008 at 21:31 UTC
    I hate it when anyone calls an output file IN :-(

    Oh, one copy is enough, btw.

      Ahhhh...., Yep, sorry.... I will look into that.

      Thanks..!!!

Re: LaTeX Wizard
by linuxer (Curate) on Sep 02, 2008 at 07:50 UTC
      Thank you for the observation. I will look into that and make sure the script runs with those clauses.

      Thank you

Re: LaTeX Wizard
by linuxer (Curate) on Sep 03, 2008 at 08:45 UTC

    If you declare multiple variables, do it like this:

    use strict; my ( $var1, $var2, $var3 ); # or my ( $var4, $var5 ) = ( 4, 'five' );
    or use vars:
    use strict; use vars qw( $var1 $var2 $var3 $var4 $var5 ); $var4 = 4; $var5 = 'five';

    update: Check out our for the successor of vars.

    --8<--
    my $frameFileName = $mw -> Frame; $frameFileName = $mw -> Frame( qw(list of frame parameters) );

    Why are you calling $mw->Frame two times, when you overwrite the first result?
    You do this several times for various objects.

    my $frameFileName = $mw -> Frame( qw(list of frame parameters) );

    That should be enough!

    Update: as vars is obsolete, corresponding part striked out. Thanks toolic++ for pointing that out.

      or use vars:
      The documentation for vars claims it is obsolete:
      vars - Perl pragma to predeclare global variable names (obsolete)
      Actually I was wandering about all this my, my, my....., I think I was trap into my ego ;-) . Thank you for pointing out the solution and helping me stay away from egotistical tendencies ;-)

      Thanks for your other observation about calling the object twices.

      Now I got a question on execute subroutine, is there any way to this more neatly, I feel all this prints makes the code cluttered.

      Thanks

        For printing multiple lines of static content (static that you don't have to check a condition if you want to print that), you can use HERE-documents.
        Or you give a list of strings as arguments to that print (within this you can even check the conditions, if you must to):

        # it interpolates variables print OUT <<"END_OF_PRINT"; Hello $world. many lines many lines END_OF_PRINT
        print OUT "string1\n", "string2\n", "string3\n", ;

        But all these solutions lead to CountZero's answer. Have you already considered his tip about using a templating system?

        You create a template with all the static content you have.
        In place of the non-static content you set up placeholders.
        Inside your Perl-Code you load your template with the corresponding
        template system and define the content for the placeholders.
        Then you print the generated output.
        The details are related to the template system you choose.

        Additional point (not related to the templates):

        If you open a file for writing, you should check that the open was successful:

        open OUT, '>', $file or die "$file: open for writing failed: $!\n";

        You should also check the success of all prints and the final close on that handle OUT.

        print OUT "text bla bla\n" or die "$file: print failed: $!\n"; close OUT or die "$file: close failed: $!\n";

        If you manage to reduce the number of prints these checks aren't too bad ;o)

Re: LaTeX Wizard
by LesleyB (Friar) on Sep 13, 2008 at 15:14 UTC

    Great work but, please, how about some <readmore> tags in the longer lengths of code?

      Yes, you are right. I think it looks much better with readmore.

      Thank you.

Re: LaTeX Wizard
by omouse (Initiate) on Sep 02, 2008 at 15:39 UTC
    So you don't use an editor like Emacs or VIM that have template/snippet modes? Weird.
      I stop using Emacs a few weeks ago. I really had trouble using the tab key, specially when I wanted to indent the code. I try to reconfigure the cperl-mode, but couldn't make it work. Now I am using UltraEdit and I hope that's not a sin ;-)

      Thank you for your comment, I didn't know Emacs had a snippet mode.

      I only been in this community for about two or three days and I found you all really helpful even though sometimes I get a stern reprimand, I think that's because of my lack discipline. I hope I can get better and better with your honest and fair advice.

      Thank you all.