nysus has asked for the wisdom of the Perl Monks concerning the following question:

So over the past few months, I've tried to be very conscious about to writing better, cleaner code. I think I've improved a great deal but one spot that I frequently encounter that I'm still not quite sure how to handle is HTML generation. So take this line, for example, which makes me feel dirty:

my $load_js = "<script>function load_js(uri) { var script = document. +createElement('script'); script.src = uri; document.head.appendChild( +script); }</script>\n";

I know it's not good practice to mix content with code. But what's the best practice for a line like this? I didn't want to spread it over several lines as that would use up space. A HERE document is just plain ugly to look at in code and eats up space. And I didn't want to introduce any new modules or a template just to generate a few lines of javascript. I vaguely recall others recommend using __DATA__ for this kind of stuff but I guess I just don't see what the advantage to doing that is and it makes you have to go down to the end of the file to see what's happening.

Maybe what I'm going in the example code is perfectly fine. But I have a nagging feeling it isn't. If someone can set me straight and offer suggestions, I'd appreciate it.

PS to the haters: If you think it's in the best interests of the Perl community to tell me how dumb and worthless I am, go for it! I'm here for you.

$PM = "Perl Monk's";
$MCF = "Most Clueless Friar Abbot Bishop Pontiff Deacon Curate Priest";
$nysus = $PM . ' ' . $MCF;
Click here if you love Perl Monks

Replies are listed 'Best First'.
Re: Best practices: Generating HTML content
by 1nickt (Canon) on Dec 23, 2017 at 01:21 UTC

    See your thread from earlier this month where several Monks recommended that you use templates to separate your HTML from your Perl code.

    If I really really need sinppets of HTML in my program for some reason (e.g. because I am avoiding using a JavaSCript framework on the front end), I still use Template to generate them, so the raw HTML is kept apart. In such a case you would have the code you showed in its own something.tt template file, that would be processed with output stored in a reference to a scalar variable. The technique is somewhat convoluted as you wind up with a number of template files, so naming them sensibly and storing them in a logical file structure is important, but for me it's worth it since I don't like to feel dirty.


    The way forward always starts with a minimal test.
      Template can also render in-memory templates via
      my $var; my $template = Template->new; $template->process( \'In-place [% foo %] query', { foo => 42 }, \$var +);

      It comes with a performance penalty though as TT does not cache compiled in-memory templates by default.

      UPD As 1nickt mentions, the penalty can be overcome by compiling the template explicitly:

      my $tt = Template->new; my $compiled = $tt->template( \'In-place [% foo %] query' ); $template->process( $compiled, { foo => 42 }, \$var );

        Hi Dallaylaen,

        TT does not cache compiled templates. This can be overcome but not easily.

        Just to clarify, I assume you mean that the Template Toolkit does not cache compiled templates *persistently* if they originated as a reference to a string, as you showed.

        See the documentation on "Caching and Compiling Options".

        You can cache compiled templates in memory explicitly without even processing them using template():

        $ perl -MTemplate -wE ' my $tt = Template->new; my $compiled = $tt->template(\"In-place [% foo %] query\n"); my $answer = 40; $tt->process( $compiled, {foo => $answer++} ) for 0..2; ' In-place 40 query In-place 41 query In-place 42 query
        And of course you can cache persistently between program runs if you use the right configuration options (and use a template file or filehandle):
        my $tt = Template->new( INCLUDE_PATH => '/some/path', COMPILE_DIR => '/other/path', COMPILE_EXT => '.compiled', ); my $file = 'foo.tt'; my $data = { foo => 42 }; $tt->process( $file, $data ) or die $tt->error; # Template will be compiled and cached at '/other/path/foo.tt.compiled +' # and that file will be used until '/some/path/foo.tt' changes
        I'm sure you knew this, just clarifying for future readers...


        The way forward always starts with a minimal test.
Re: Best practices: Generating HTML content
by marto (Cardinal) on Dec 23, 2017 at 00:52 UTC

    Have you considered using a template solution to separate your HTML/JavaScript etc from your perl code?

      I have moved to templates for larger chunks of code. This particular line (and a couple of other smaller snippets of js) is part of a module in a larger project and it didn’t seem like a good use of resources to pull in another module for three lines of code. It seemed like overkill.

        Does the larger project involve "larger chunks of code", of the sort you've moved to templates for? Probably.

        Does the larget project, therefore, use templates? Hopefully.

        If so, then using the same templating system in this module as in the larger project isn't pulling in anything new, it's just using what will already be loaded as a part of the overall project.

        And, if not, I wouldn't let that stop me from maintaining a clean separation of concerns by using templates in the module anyhow. On the contrary, I'd start with templates in the module, since that appears to be where you're currently writing new code, then expand from there until all of the HTML content in the entire project is produced using templates instead of coming from mixed HTML and Perl frankencode.

Re: Best practices: Generating HTML content
by karlgoethebier (Abbot) on Dec 25, 2017 at 17:15 UTC
Re: Best practices: Generating HTML content
by Dallaylaen (Chaplain) on Dec 24, 2017 at 16:20 UTC

    Hello nysus,

    Have you considered:

    1) Moving here-docs to constants (or "constants" aka my variables that only your module sees)?

    2) using q{ ... } for multi-line/very long strings?

    3) Using sprintf + HTML::Entities/HTML::Escape as a poor man's template?

    I don't think it's time to look at __DATA__ until these options are eliminated...

Re: Best practices: Generating HTML content (constipation)
by Anonymous Monk on Dec 23, 2017 at 04:26 UTC

    You know what you got there?

    You got constipation

    cleaner code starts by seperating data from code

    Ok, you're ditching that idea because its not a lot data, ok, decision made,

    its done,

    but then why does a few lines of javascript include pointless junk like that load_js

    and then why are you cramping about using up space?

    When you go to the bathroom, do you flush the toilet and wash your hands every time or do you worry about using up water?

    Surveys are a poor substitute for the fiber of experience , go write code