Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

How to use __DATA__ efficiently, help!

by Anonymous Monk
on Feb 09, 2011 at 18:55 UTC ( [id://887252]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks!
A few questions here, first on the code I posted is about which line is more efficient and why the commented one is giving me a uninitialized error:
$data = do { local $/; <DATA> }; #do{$data = $data . $_ } while (<DATA>); #gives a uninitialized value +in concatenation
I would like to use "__DATA__" twice is that possible? Also I need to pass the values of variables ($date - $location) into the html inside the "__DATA__", any suggestion? If I run this I am getting the second "__DATA__" printed with the rest of the html code. My goal here is to separate as much as I can the HTML from the Perl.
Here is the code sample I am using:
#!/usr/bin/perl use strict; use warnings; use Date::Calc qw( Today Today_and_Now Date_to_Days Add_Delta_Days Del +ta_Days Decode_Date_US ); my $display=qq(); my $data = qq(); my $date = sprintf "%02d/%02d/%04d", (Date::Calc::Today())[1,2,0]; my $location = "BR"; $display .= qq(\n\nStart Display\n\n); $data = do { local $/; <DATA> }; #do{$data = $data . $_ } while (<DATA>); #gives a uninitialized value +in concatenation $display .= $data; $display .=" <tr> <td>more data</td> </tr> <tr> <td>end of rows</td> </tr> </table>\n"; print $display; __DATA__ <table width="100%" border="0" bgcolor="#ffffff" cellpadding="0" cells +pacing="0"> <tr> <td colspan="2">&nbsp;</td> </tr> <tr> <td width="60%">All Names List from:</td> <td width="40%" align="left"><b>$date</b></td> </tr> <tr> <td width="100%" colspan="2">&nbsp;</td> </tr> </table> __DATA__ <table width="100%" border="0" bgcolor="#ffffff" cellpadding="0" cells +pacing="2"> <tr> <td><b>Name</b></td> <td><b>Address</b></td> <td><b>Phone</b></td> <td><b>Email</b></td> <td><b>$location</b></td> </tr> <tr> <td colspan="5">&nbsp;</td> </tr>
Thanks for looking!

Replies are listed 'Best First'.
Re: How to use __DATA__ efficiently, help!
by Your Mother (Archbishop) on Feb 09, 2011 at 21:11 UTC

    What Tommy just said. This the Wrong Way™ to do it. That said, I do exactly this sometimes with Template by using named blocks. Here's a runnable example-

    use warnings; use strict; use Template; use CGI qw( header ); print header(); my $tt2 = Template->new( TRIM => 1 ); my @actions = qw( foo bar ); my @titles = ( "O HAI", "O NOES", "KTHXBAI" ); $tt2->process(\*DATA, { title => $titles[rand@titles], my_action => $actions[rand @actions], }) or warn $tt2->error; __DATA__ [%~BLOCK foo %] This is my foo. There are many foos like it but this one is mine. [%~END %] [%~BLOCK bar %] This is my barbaz. This is my qux. This is for coding, this is for... +uh... [%~END %] [%~# TEMPLATE ----------%] <html lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" / +> <title>[% title | html %]</title> </head> <body> <header> <h1>[% title | html %]</h1> </header> <article> [% PROCESS $my_action %] <aside>Action: [% my_action | html %]</aside> </article> <footer> <small> License: <a itemprop="license" href="http://perlfoundation.org/artistic_license_2_0">Artistic 2.0</a +> </small> </footer> </body> </html>
Re: How to use __DATA__ efficiently, help!
by ELISHEVA (Prior) on Feb 09, 2011 at 20:02 UTC

    This is how you can fake multiple data sections:

    my @aData; { #set the record divider to __DATA__ :-) local $/='__DATA__'; @aData = <DATA>; chomp @aData; #get rid of __DATA__ from end of record } print STDERR "------------DATA #1 ----------------\n$aData[0]" . "------------DATA #2 ----------------\n$aData[1]";

    outputs

      Would this be easier if it was done using HTML::Template? Has anyone done such using this method?

        For one or two variables and code that you know doesn't have any $myvar strings that aren't supposed to be interpreted as a variable, your (OP's?) approach is likely fine. This is fairly simple and short code:

        my $date='**2010-02-09**'; my $line = $aData[0]; $line =~ s/\$date/$date/g; print STDERR "------------DATA #1 ----------------\n$line"; $date='**1910-02-09**'; $line = $aData[0]; $line =~ s/\$date/$date/g; print STDERR "------------DATA #2 ----------------\n$line";

        However, it won't scale well. It will quickly become difficult to manage. Furthermore, the more variables the more likely you are going to have some random unintended substitutions. At that point you would be very wise to use a module like HTML::Template. Think of it as your solution with all the problems and corner cases debugged for you in advance.

Re: How to use __DATA__ efficiently, help!
by Tommy (Chaplain) on Feb 09, 2011 at 21:08 UTC

    You're going to quickly outgrow this method of generating html output from logically calculated values. Interspersing code with content is good for the quick and dirty jobs, but it won't work out very well for you at all as you continue to grow your code and improve upon it.

    I invite you to consider a templating engine, such as Template::Toolkit or others mentioned already in response to your question. There is a slight learning curve, but I can assure you with almost complete certainty that once you get to the point where you are actively using and deriving benefit from a templating solution that allows for the separation of code and content, you will won't ever go back to the more primitive and less elegant practice of doing otherwise.

    --
    Tommy
Re: How to use __DATA__ efficiently, help!
by CountZero (Bishop) on Feb 09, 2011 at 19:07 UTC
    Data::Section will give you the possibility to access multiple sections in your __DATA__ area.

    The unitialized value warning (it is not an error message, just a warning only) is probably because you have empty lines in your __DATA__ area. I wouldn't worry about it too much.

    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

      it is not an error message

      He made an error (concatenated two variable without giving either a value) and Perl issued a message in response to that error. How is that message not an error message? It's simply not an (immediately) fatal error.

      is probably because you have empty lines in your __DATA__ area.

      No, he gets the warning before even executing <DATA> because he's using a bottom tested loop.

        He made an error (concatenated two variable without giving either a value) and Perl issued a message in response to that error.

        Then we have different definitions of error and warning.

        The OP concatenated nothing to nothing (and thus wastes a cycle of that loop) but his output is still correct. In my book that is not an error, but it does warrant a warning as it can be written better.

        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

Re: How to use __DATA__ efficiently, help!
by bart (Canon) on Feb 09, 2011 at 21:14 UTC
    Split the DATA section into 2 parts? I think that's better done using here-docs. Granted, the strings will be intertwined in between the chunks of Perl code instead of at the end, but that doesn't have to be a disadvantage; especially with lots and lots of html snippets. I think having to count in order to know what string you're using where is a bad situation as soon as it is no longer trivial.

    And perhaps you should reconsider using a templating system, for example, Template Toolkit. At least the html data will be organized by the page layout, and not by the code flow — which can be like spaghetti code, if you want to follow how a page is built.

Re: How to use __DATA__ efficiently, help!
by shawnhcorey (Friar) on Feb 09, 2011 at 19:50 UTC
    my $data = '';  # set to the empty string
    do{ $data = $data . $_ } while (<DATA>);
    Always initialize your variables.

      Actually, that wouldn't help here, as it's not the undefined $data that Perl is complaining about, but the undefined $_.

Re: How to use __DATA__ efficiently, help!
by PyrexKidd (Monk) on Feb 10, 2011 at 01:33 UTC

    I agree with the other commenter. HTML::Template would be ideal for your situation. Additionally this allow you to abstract the HTML from your perl code and focus on the perl in your perl scripts. IMHO it is more readable to have your data in separate files.

    Something like this:

    #!/usr/bin/perl use strict; use warnings; my $TEMPLATE_PATH = "/some/path/"; my $template_name = "data.tmpl" my $tmpl = new HTML::Template( path => [ "$TEMPLATE_PATH", ], filename => "$template_name", die_on_bad_params => 0, ); $tmpl->params( data1 => 'true', ); open my $OUTPUT, '>', \my $output; print $OUTPUT $tmpl->output(); close $OUTPUT; print $string, "\n";

    tmplate1.tmpl:

    <tmple_if name'data1'> <table width="100%" border="0" bgcolor="#ffffff" cellpadding="0" +cellspacing="0"> <tr> <td colspan="2">&nbsp;</td> </tr> <tr> <td width="60%">All Names List from:</td> <td width="40%" align="left"><b>$date</b></td> </tr> <tr> <td width="100%" colspan="2">&nbsp;</td> </tr> </table> </tmpl_if> <tmpl_if name='data2'> <table width="100%" border="0" bgcolor="#ffffff" cellpadding="0" cel +lspacing="2"> <tr> <td><b>Name</b></td> <td><b>Address</b></td> <td><b>Phone</b></td> <td><b>Email</b></td> <td><b>$location</b></td> </tr> <tr> <td colspan="5">&nbsp;</td> </tr> </tmpl_it>

    You can obviously tailor this more to specifically suit your needs.

      Thank you all, thats the way to go!
Re: How to use __DATA__ efficiently, help!
by Anonyrnous Monk (Hermit) on Feb 09, 2011 at 19:14 UTC
    #do{$data = $data . $_ } while (<DATA>); #gives a uninitialized value +in concatenation

    You get the "uninitialized value" warning because the do {...} executes once before a value is being assigned to $_.  Just turn it around:

    my $data; while (<DATA>) { $data .= $_ }

    BTW, note that $data .= "foo" (or $data = $data . "foo" for that matter) is a special case that does not generate an "uninitialzed value" warning, even if $data is undefined initially:

    $ perl -we 'my $foo; $foo = $foo . "foo"' # no warning

    while this does, of course:

    $ perl -we 'my $foo; my $bar = $foo . "foo"' Use of uninitialized value $foo in concatenation (.) or string at -e l +ine 1.
      I found a way to " values of variables ($date - $location) into the html inside the "__DATA__"". I can do this, just hope I am not breaking any rules:
      while (<DATA>) { $_.=s/<--date\/\/>/$date/; $_.=s/<--loc\/\/>/$location/; $data .= $_ }
      But how to use multiple sets of "__DATA__" still stands.
        But how to use multiple sets of "__DATA__" still stands.

        The answer is simple: you can't. There's only one __DATA__ section. At least in the main package.

        In other words, you'd have to use some separator, e.g. an empty line (if that doesn't occur otherwise in the data), and then split it up into sets yourself.

        You could in theory put different __DATA__ sections in different modules (i.e. different packages in different files), and then access them as Foo::DATA, etc., but you might as well just put the data sets in normal files and read them from there...

        # File Set1.pm package Set1; 1; __DATA__ foo1 foo2 foo3 # File Set2.pm package Set2; 1; __DATA__ bar1 bar2 bar3 # main script #!/usr/bin/perl -w use strict; use Set1; use Set2; print "Set 1:\n"; while (<Set1::DATA>) { print } print "Set 2:\n"; while (<Set2::DATA>) { print }

        Output:

        Set 1: foo1 foo2 foo3 Set 2: bar1 bar2 bar3
        I am getting weird numbers in the middle of the html code; 1 and 11, using:
        while (<DATA>) { $_.=s/<--date\/\/>/$date/; $_.=s/<--loc\/\/>/$location/; $data .= $_ }
        Any ideas why?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://887252]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2025-03-20 19:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    When you first encountered Perl, which feature amazed you the most?










    Results (62 votes). Check out past polls.