CoVAX has asked for the wisdom of the Perl Monks concerning the following question:
I have some constants (defined with `use constant`) that I am desirous of using in a `here` doc. However no interpolation occurs, so the strings naming the constants literally appear instead of their values. What I have resorted to is: assigning variables the values of the constants, and using the variable names in the here doc. Is there a better way to accomplish the desired behavior?
use constant {
OUT_DIR => 'out',
OUT_FIELDSEP => '=',
OUT_FILENAME => 'ks',
OUT_SUFXSTOR => 'storable',
VAL_MIN => 15,
VAL_MAX => 3600,
};
This does not work as intended:
print <<USAGE;
This program does this and that with the OUT_DIR. The filename is
OUT_FILENAME and the file suffix is OUT_SUFXSTOR.
Fields are separated with the OUT_FIELDSEP character. Enter a value
between VAL_MIN and VAL_MAX.
USAGE
What I've resort to doing:
my $out_dir = OUT_DIR;
my $out_fs = OUT_FIELDSEP;
my $out_fn = OUT_FILENAME;
my $out_sx = OUT_SUFXSTOR;
my $valmin = VAL_MIN;
my $valmax = VAL_MAX;
print <<USAGE;
This program does this and that with the $out_dir. The filename is
$out_fn and the file suffix is $out_sx.
Fields are separated with the $out_fs character. Enter a value
between $valmin and $valmax.
USAGE
Searched for donuts and crumpit. Found content instead.
Re: How to interpolate CONSTANTS in Here docs?
by BrowserUk (Patriarch) on Feb 11, 2015 at 21:55 UTC
|
C:\test>type junk94.pl
#! perl -slw
use strict;
use constant {
OUT_DIR => 'out',
OUT_FIELDSEP => '=',
OUT_FILENAME => 'ks',
OUT_SUFXSTOR => 'storable',
VAL_MIN => 15,
VAL_MAX => 3600,
};
print <<USAGE;
This program does this and that with the @{[OUT_DIR]}. The filename is
@{[OUT_FILENAME]} and the file suffix is @{[OUT_SUFXSTOR]}.
Fields are separated with the @{[OUT_FIELDSEP]} character. Enter a val
+ue
between @{[VAL_MIN]} and @{[VAL_MAX]}.
USAGE
C:\test>junk94
This program does this and that with the out. The filename is
ks and the file suffix is storable.
Fields are separated with the = character. Enter a value
between 15 and 3600.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
| [reply] [d/l] |
|
Thank you for your answer. I'm not understanding the @{[]} syntax, although I do recognize the array index [], the hash {}, and the array @ -- can you explain what is going on, please?
Searched for donuts and crumpit. Found content instead.
| [reply] |
|
#! perl -slw
use strict;
use constant {
OUT_DIR => 'out',
OUT_FIELDSEP => '=',
OUT_FILENAME => 'ks',
OUT_SUFXSTOR => 'storable',
VAL_MIN => 15,
VAL_MAX => 3600,
};
printf <<USAGE, OUT_DIR, OUT_FILENAME, OUT_SUFXSTOR, OUT_FIELDSEP, VAL
+_MIN, VAL_MAX;
This program does this and that with the %s. The filename is
%s and the file suffix is %s.
Fields are separated with the %s character. Enter a value
between %s and %s.
USAGE
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
| [reply] [d/l] |
|
[...] builds a reference to an anonymous array, which is in turn de-referenced by @{...}. It's roundabout, but necessary in this case because the constants built by constant are actually functions, like sub OUT_DIR () { 'out' }, and a function call like OUT_DIR() (or OUT_DIR) isn't interpolated in strings, while scalars ($foo) and arrays (@bar) are, including dereferenced arrayrefs (@{$arrayref} - see e.g. Using References).
| [reply] [d/l] [select] |
|
I'm not understanding the @{[]} syntax, although I do recognize the array index [], the hash {}, and the array @ -- can you explain what is going on, please?
The array index isn't an array index, the hash isn't a hash.
@{ } dereferences an array reference. ${ } dereferences a scalar reference. [ ] constructs an array refrence, \ constructs a scalar reference. So, instead of writing
This program does this and that with the @{[OUT_DIR]}. The filename is
@{[OUT_FILENAME]} and the file suffix is @{[OUT_SUFXSTOR]}.
Fields are separated with the @{[OUT_FIELDSEP]} character. Enter a val
+ue
between @{[VAL_MIN]} and @{[VAL_MAX]}.
as in BrowserUk's example, you could also write
This program does this and that with the ${\OUT_DIR}. The filename is
${\OUT_FILENAME} and the file suffix is ${\OUT_SUFXSTOR}.
Fields are separated with the ${\OUT_FIELDSEP} character. Enter a valu
+e
between ${\VAL_MIN} and ${\VAL_MAX}.
The reference implementation in perl is the author's way of introducing ásbestos gélōs into the language, great fun and a good opportunity to distinguish yourself with expertise, once you grok cause and syntax.
Quick, what does ~@~ mean?
perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
| [reply] [d/l] [select] |
|
"foo @{[ F ]} bar"
you get
my @anon_array = F;
my $anon_ref = \@anon_array;
"foo @{ $anon_ref } bar"
As you can see,
@BLOCK (@{ STATEMENTS }) is an array dereference, not "a hash".
[ LIST ] is an array constructor, not "an array index". It creates an array, assigns the result of LIST, and returns a reference to that array.
| [reply] [d/l] [select] |
Re: How to interpolate CONSTANTS in Here docs?
by AnomalousMonk (Archbishop) on Feb 11, 2015 at 21:49 UTC
|
Interpolation rules for here-docs are the same as for double- and single-quoted strings (double in the OPed example), so one way:
c:\@Work\Perl>perl -wMstrict -le
"use constant OUT_SUFXSTOR => 'storable';
;;
my $str = qq{The file suffix is ${ \ OUT_SUFXSTOR}.};
print qq{'$str'};
"
'The file suffix is storable.'
Update: Then there's also:
c:\@Work\Perl>perl -wMstrict -le
"use constant OUT_SUFXSTOR => 'storable';
;;
my $str = qq{The file suffix is @{[ OUT_SUFXSTOR ]}.};
print qq{'$str'};
"
'The file suffix is storable.'
Give a man a fish: <%-(-(-(-<
| [reply] [d/l] [select] |
Re: How to interpolate CONSTANTS in Here docs?
by Anonymous Monk on Feb 11, 2015 at 23:19 UTC
|
It might be noteworthy that Conway's Perl Best Practices recommends against constant, partly for exactly the reason you're having trouble (they don't interpolate) - a similar issue arises when they're used in hashes, as documented in "Caveats" in constant.
The suggested alternative is Readonly, but it has a few bugs, and I've found Readonly is not really necessary if you just stick to not modifying variables whose names are in $ALL_CAPS (people with a more defensive coding philosophy might disagree).
Of course you are free to disagree with PBP on this point and use constant, in which case I think the solutions given by AnomalousMonk and BrowserUk above are preferable to the following, because they catch errors due to typos in the constant names better. But since this is Perl, and in the spirit of TIMTOWTDI, here's another solution:
my $USAGE=<<'USAGE';
Fields are separated with the OUT_FIELDSEP character. Enter a value
between VAL_MIN and VAL_MAX.
USAGE
$USAGE=~s/\b\Q$_\E\b/$_/ee for
qw/ OUT_FIELDSEP VAL_MIN VAL_MAX /;
| [reply] [d/l] [select] |
|
It might be noteworthy that Conway's Perl Best Practices recommends against constant,
Grrr. That damn book has done infinitely more harm than good. (As predicted!)
It completely misses the point of constant; namely that it works with Perl to optimise your code.
Because constants are defined as invariant subroutines, Perl can optimise away whole chunks of code at compile time:
C:\test>perl -MO=Deparse -Mconstant=DEBUG,1 -le"print 'hi'; DEBUG and
+print 'here'; print 'bye'"
BEGIN { $/ = "\n"; $\ = "\n"; }
use constant (split(/,/, 'DEBUG,1', 0));
print 'hi';
print 'here'; ## When DEBUG is defined; it doesn't need to be teste
+d for at runtime. (No conditional!)
print 'bye';
-e syntax OK
C:\test>perl -MO=Deparse -Mconstant=DEBUG,0 -le"print 'hi'; DEBUG and
+print 'here'; print 'bye'"
BEGIN { $/ = "\n"; $\ = "\n"; }
use constant (split(/,/, 'DEBUG,0', 0));
print 'hi';
'???'; ## And when it's not; both the conditional and the cod
+e it controls are simply optimised away.
print 'bye';
-e syntax OK
Write-once variables are a piss poor substitute; an anathema to Perl; and an abomination.
With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
| [reply] [d/l] |
|
That damn book has done infinitely more harm than good. (As predicted!)
I can't gainsay; and I wouldn't if I could.
Write-once variables are a piss poor substitute; an anathema to Perl; and an abomination.
True, true and true. We would upvote all of this if I were four of me.
perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
| [reply] |
|
FFS, please report these 'bugs' on the tracker. I've cleared up all the valid issues and sped it up to the point that Readonly::XS can be withered. If you've found something new, the only way to get it fixed is to report it.
| [reply] |
A reply falls below the community's threshold of quality. You may see it by logging in. |
|
|