Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

caching formats

by hotpelmen (Scribe)
on Jan 22, 2015 at 18:31 UTC ( [id://1114170]=perlquestion: print w/replies, xml ) Need Help??

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

Hi,

Background: there's a script that generates a standard-width text report by writing report into a file line by line. For most lines in the report it uses common format, but for some lines, based on some unpredictable runtime information, it needs to dynamically define a custom format. These custom formats have unpredictable "pictures", so it is impossible to pre-define all such formats in advance. Dynamic generation of custom formats is done via eval (as described in perlform). Since some lines end up using the same exact custom format, it would be beneficial to try to reuse it instead of generating and eval-ing the same string again and again.

Question: Other than maintaining a separate hash with created format names, what's the best & cheapest method of format caching here, i.e. determining if a format with a given name is already defined and available for assignment to the filehandle? I read that formats use their own namespace but I could not find any information on how to access it. Any help with this specific question would be greatly appreciated.

Replies are listed 'Best First'.
Re: caching formats
by Anonymous Monk on Jan 22, 2015 at 20:53 UTC

    Have you seen formline, maybe that could help you? I think it has several limitations, like not handling pagination IIRC, but it can be used as a kind of printf for formats, so both formats and their inputs can be managed as regular strings, which sounds like it might be an advantage in your situation; I'm not sure if that would outweigh the limitations in your case though. Anyway, an example is given in perlform, here's an example based on that:

    #!/usr/bin/env perl use warnings; use strict; print "--- normal format: ---\n"; my ($foo, $bar, $quz); format STDOUT = | @|||| | @###.## | ^>>>>>> | $foo, $bar, $quz . $quz = "a b c d e f g h i j k"; for my $x (["foo",12.3],["bar",3.3333],["quz",1000.009]) { ($foo, $bar) = @$x; write; } print "--- swrite: ---\n"; sub swrite { my $fmt = shift; local $^A = ""; formline $fmt, @_; return $^A; } my $myformat = <<'_X_'; | @|||| | @###.## | ^>>>>>> | _X_ my $quz2 = "a b c d e f g h i j k"; for my $x (["foo",12.3],["bar",3.3333],["quz",1000.009]) { print swrite($myformat, @$x, $quz2); } __END__ # Output: --- normal format: --- | foo | 12.30 | a b c d | | bar | 3.33 | e f g h | | quz | 1000.01 | i j k | --- swrite: --- | foo | 12.30 | a b c d | | bar | 3.33 | e f g h | | quz | 1000.01 | i j k |
Re: caching formats
by LanX (Saint) on Jan 22, 2015 at 20:04 UTC
    Not sure if I understand your intention, but iirc formats are stored in a special slot of it's glob in the symbol table (stash)

    HTH :)

    Cheers Rolf

    PS: Je suis Charlie!

      Yes, because formats are (I presume ... without looking at the perlguts) associated with some kind of “formatting subroutine” that is constructed by format(), they do have their own namespace ... and that is why I suggested writing the code (using eval) to coin a unique name for each one.   Then, associate whatever name you want to use, with whatever filestream you want to write() to, as previously described.   The effect will be what the OP is looking to do ... it’s just that the way of referring to a format, is by name (a string), and there is then a particular (and somewhat curious) way to tell Perl when to use it.

      As to whether-or-not I would actually use this technology now ... probably not.   HTML-formatting is infinitely nicer than line-printer formatted reports, and HTML-rendering technology is easy to come by now, but it is all (these kids today ...) a fairly-recent invention.   This program is likely to be much older than that.   And still in service, still doing its job.   (Young whippersnappers!)   C’est la guerre.

Re: caching formats
by Anonymous Monk on Jan 22, 2015 at 20:46 UTC
    If i remember correctly, Perl 4 style formats use bare word file handles and global/package variables. Have you looked into the Perl6::Form module.

    TJD

Re: caching formats
by sundialsvc4 (Abbot) on Jan 22, 2015 at 19:29 UTC

    Wow ... a blast from the past.   (Lessee ... ADD 1 TO PERL GIVING PERL. ...)

    As far as I am aware, formats are not “variables,” so you can’t “store” them anywhere.   You always refer to them by name, through $~ ($FORMAT_NAME) and $^ ($FORMAT_TOP_NAME).   This will get you where you want to go here.

    To associate a particular format with a particular output channel, you first select() that channel (see perlfunc), to make it be the “default,” then you assign those variables (see perlvar), which will affect the channel which you just selected.   (Each channel has its own associated format-names, which default to the stream name.)   These two variables always describe the formats for the stream that is currently select()ed.

    If your program first created all of the formats that it needed, assigning each one of them a unique format-name, then it could switch between them simply by-name, using any sort of data-structure to keep track of the names that had been generated.   That’s what you cache:   the (unique ...) names, which should be generated once.

    For instance, let’s say you are using a hash which is (somehow) keyed by “things that you need to have formats for.”   The value for entries in this hash will be format-names.   If exists() tells you that a hash-key already exists, then the value associated with that key is the format-name that you should now use.   If a hash-key does not yet exist, then use eval() to coin a new one ... giving it a new, unique but arbitrary (say, sequential) format-name.   Store this name in the hash, so that the next time you need to format that same thing, you won’t create it again.   In this way, formats are eval’s on-demand, the first time they are needed.   (And of course, if you need to format several things the same way, simply refer to the same name.)

Re: caching formats
by hotpelmen (Scribe) on Jan 26, 2015 at 15:58 UTC
    Thank you all for your responses. As you can see from my original question, keeping format names in a hash as proposed by sundialsvc4 was the solution I was trying to avoid, hopeful that there is more efficient way through direct access to format namespace. Alas, there seems to be none, so storing names in the hash seems to be the only good way to reuse formats in my context.
    I did look at using formline() as illustrated by Anonymous. It allows to avoid ugly eval, but it guarantees that format will be created every time swrite is invoked. Running swrite seems to be pretty much the same thing as running format, except there's no format name associated with it. It is definitely a strong alternative to eval approach when reusing formats is unimportant (e.g. when formats are different for each line). Thanks again everyone!

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (3)
As of 2024-04-25 17:37 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found