How can Perl's Template remove the whitespace following a directive? - perl

I have the following template
[% DEFAULT label = 'null' %]
order: '[% order %]',
name: '[% name %]',
product:'[% product %]',
label : '[% label %]'
which included on a template my.tt file
on Perl I have the following configuration :
my $template = Template->new();
open(my $fh, '>:raw', \$report);
$template->process('my.tt', \%data,$fh) or die $template->error();
print $report;
when i print $report i see on the first line -> new line then the info like below printed, how can i remove the new line char from the first line?
order: 'order1'
name: 'testname'
product: 'testproduct'
label: 'label1'

Simply use -%] instead of %].

Related

Perl Template with strict option: how to check whether a variable is defined?

The following code dies with a var.undef error because var is not defined. It works if I change the STRICT option to 0, but I'd like to keep strict checks, unless it's in an [% IF var %] check in the template. How do I do that?
use strict;
use warnings;
use Template;
my $t = Template->new(STRICT => 1) || die Template->error();
my $template = '[% IF var %][% var %][% END%]';
my $output = '';
$t->process(\$template, {}, \$output) || die $t->error(), "\n";
print "$output\n";
You are sending in an empty hash reference that doesn't contain the var variable that you're asking the template to display.
You can either check in your Perl code to set a sane default (in this example, I just hard-code it into the call to process()):
$t->process(\$template, {var => 55}, $output) || die $t->error(), "\n";
Output:
55
...or, you can tell the template to set its own sane default if the var variable isn't sent on the way in (ie, it's undefined):
my $template = '[% DEFAULT var = "sane" %][% IF var %][% var %][% END%]';
Output:
sane

Submit multiple fasta sequence using WWW::Mechanize

I want to summit multiple protein sequences in fasta format on this server using following perl script
use WWW::Mechanize;
# get the webpage with the form
my $mech = WWW::Mechanize->new();
$mech->show_progress(1);
my $url = "http://harrier.nagahama-i-bio.ac.jp/sosui/sosu/sosuigsubmit.html";
$mech->get($url);
# just checks to see if scripts call properly
sub validateInput{
my $file = shift;
my $inFh = IO::File->new( $file ) || die "can't open input file\n";
close($inFh);
return 1;
}
validateInput($ARGV[0]);
# fill the fields with the appropriate data and submit
my $fields = {
'in' => $ARGV[0],
'value' => 'Exec'
};
$mech->submit_form(
fields => $fields,
);
# print results
print $mech->content();
But every time I getting the result like this
<HTML>
<bR><bR><bR>
<TABLE>
<TR><TD ALIGN=left WIDTH=300>TOTAL PROTEINS</TD><TH>0</TH></TR>
<TR><TD ALIGN=left WIDTH=300>TOTAL MEMBRANE PROTEINS</TD><TH>0</TH></TR>
<TR><TD ALIGN=left WIDTH=300>PERCENTAGE</TD><TH> 0.0 %</TH></TR>
</TABLE>
</HTML>
Which is a result page when you submit form without input. So I suspect that there is some problem with my sequence submission. My input file look like this
>ATCG00420
MQGTLSVWLAKRGLVHRSLGFDYQGIETLQIKPEDWHSIAVILYVYGYNYLRSQCAYDVAPGGLLASVYHLTRIEYGV NQAEEVCIKVFTHRSNPRIPSVFWVWKSTDFQERESYDMLGITYDSHPRLKRILMPESWIGWPLRKDYIAPNFYEIQDAY
>ATCG00360
MSAQSEGNYAEALQNYYEAMRLEIDPYDRSYILYNIGLIHTSNGEHTKALEYYFRALERNPFLPQAFNNMAVICHYRGEQAIQQGDSEMAEAWFAQAAEYWKQAITLTPGNYIEAQNWLTITRRFE
and I am calling my script like this
perl my_script input.seq >output
Thanks for helping me out.
For starters, this line:
'in' => $ARGV[0],
Means that you're sending them a filename, rather than the contents of the file. You'll need to get the contents first, and send those. Libraries like File::Slurper are handy for this.

Parsing a structured text file in Perl

I'm quite new to Perl and I'm having immense difficulty writing a Perl script that will successfully parse a structured text file.
I have a collection of files that look like this:
name:
John Smith
occupation:
Electrician
date of birth:
2/6/1961
hobbies:
Boating
Camping
Fishing
And so on. The field name is always followed by a colon, and all the data associated with those fields is always indented by a single tab (\t).
I would like to create a hash that will directly associate the field contents with the field name, like this:
$contents{$name} = "John Smith"
$contents{$hobbies} = "Boating, Camping, Fishing"
Or something along those lines.
So far I've been able to get all the field names into a hash by themselves, but I've not had any luck wrangling the field data into a form that can be nicely stored in a hash. Clearly substituting/splitting newlines followed by tabs won't work (I've tried, somewhat naively). I've also tried a crude lookahead where I create a duplicate array of lines from the file and using that to figure out where the field boundaries are, but it's not that great in terms of memory consumption.
FWIW, currently I'm going through the file line by line, but I'm not entirely convinced that this is the best solution. Is there any way to do this parsing in a straightforward manner?
Reading the file line by line is a good way to go. Here I am creating a hash of array references. This is how you would just read one file. You could read each file this way and put the hash of arrays into a hash of hashes of array.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my %contents;
my $key;
while(<DATA>){
chomp;
if ( s/:\s*$// ) {
$key = $_;
} else {
s/^\s+//g; # remove extra whitespace
push #{$contents{$key}}, $_;
}
}
print Dumper \%contents;
__DATA__
name:
John Smith
occupation:
Electrician
date of birth:
2/6/1961
hobbies:
Boating
Camping
Fishing
Output:
$VAR1 = {
'occupation' => [
'Electrician'
],
'hobbies' => [
'Boating',
'Camping',
'Fishing'
],
'name' => [
'JohnSmith'
],
'date of birth' => [
'2/6/1961'
]
};
This text file is actually quite close to yaml. And its not difficult to convert it into a valid yaml file:
Once you have a yaml file you can use YAML::Tiny or another module to parse it, which leads to cleaner code:
#!/usr/bin/perl
use strict;
use warnings;
use YAML::Tiny;
use Data::Dumper;
convert( './data.yaml', 'output.yaml' );
parse('output.yaml');
sub parse {
my $yaml = shift;
my $yamlobj = YAML::Tiny->read($yaml);
my $name = $yamlobj->[0]->{name}[0];
my $occ = $yamlobj->[0]{occupation}[0];
my $birth = $yamlobj->[0]{'date of birth'}[0];
my $hobbies = $yamlobj->[0]{hobbies};
my $hobbiestring = join ", ", #$hobbies;
my $contents = {
name => $name,
occupation => $occ,
birth => $birth,
hobbies => $hobbiestring,
};
print "#RESULT:\n\n";
print Dumper($contents);
}
sub convert {
my ( $input, $output ) = #_;
open my $infh, '<', $input or die "$!";
open my $outfh, '>', $output or die "$!";
while ( my $line = <$infh> ) {
$line =~ s/^\s+\K$/-/g;
print $outfh ($line);
}
}

Perl Logic in Template Toolkit

I have a currency value that I would like to format using Locale::Currency::Format however I have no idea how to format it.
Here is my output in Template Toolkit
[% amount %]
I would like this to be outputted using the following method:
currency_format('USD', amount, FMT_SYMBOL)
New to template toolkit so any help is appreciated.
I like Dave Cross' answer, and I agree with both he and codnodder about EVAL_PERL, which I've yet to find necessary as a solution in 7 or 8 years of almost daily TT use.
Personally, I would use:
[%- USE fmt = Class('Locale::Currency::Format'); -%]
<td>[% fmt.currency_format(var1, var2, var3) %]</td>
But if I was using this all the time, I'd be tempted to write a TT plugin wrapper around it.
I can't find Local::Currency::Format on CPAN, so I can't show you exactly how it works with this module. I can, however, show you the general direction you need to go in.
You have several options:
1/ Use currency_format to format the data before it is passed into the template.
my $amount = currency_format('USD', $amount, FMT_SYMBOL);
$tt->process($template_name, { amount => $amount, ... }) or die;
Then in the template you can just use [% amount %].
2/ Pass currency_format as a dynamic variable to the template.
$tt->process($template_name, {
amount => $amount,
currency_format = > \&currency_format,
...
}) or die;
Then in the template, you can use currency_format as a function:
[% currency_format('USD', amount, FMT_SYMBOL) %]
3/ Write a real TT plugin for Local::Currency::Format.
If you have EVAL_PERL enabled in your "controller", you can use
embedded perl to include the module and add a vmethod for example.
E.g.,
use strict;
use Template;
my $tt = Template->new(EVAL_PERL=>1);
my $out;
$tt->process(\*DATA, { amount => 50.34 }, \$out) or die $tt->error, "\n";
print $out;
__DATA__
[% PERL -%]
sub dollars { sprintf('$%0.02f', $_[0]); }
# or:
# use Local::Currency::Format;
# sub dollars { currency_format('USD', $_[0], FMT_SYMBOL); }
$stash->define_vmethod('scalar', 'dollars', \&dollars);
[% END -%]
The amount is [% amount.dollars %].
If you have some access to the "controller", you can add a FILTER.
use strict;
use Template;
#use Local::Currency::Format;
my $tt = Template->new({
#FILTERS => { 'dollars' => sub { currency_format('USD', $_[0], FMT_SYMBOL); } },
FILTERS => { 'dollars' => sub { sprintf('$%0.02f', $_[0]); } },
});
my $out;
$tt->process(\*DATA, { amount => 50.34 }, \$out) or die $tt->error, "\n";
print $out;
__DATA__
The amount is [% amount | dollars %].
EDIT: Note that my use of sprintf to format the currency is just a placeholder. You would replace that with whatever module or method you choose.

How can I use Template Toolkit on a string instead of a file?

I have some strings that I am pulling out of a database and I would like to use Template Toolkit on them, but I can't seem to figure out how to use strings as TT input. Any tips?
Thanks!
-fREW
The documentation explains:
process($template, \%vars, $output, %options)
The process() method is called to process a template. The first parameter indicates the input template as one of: a filename relative to INCLUDE_PATH, if defined; a reference to a text string containing the template text; ...
# text reference
$tt->process(\$text)
|| die $tt->error(), "\n"
From the docs:
# text reference
$text = "[% INCLUDE header %]\nHello world!\n[% INCLUDE footer %]";
$tt->process(\$text)
|| die $tt->error(), "\n";
(Looks like I should have refreshed the page before posting.)
You may find String::TT as a nicer alternative way of doing it. Some teasers from the pod...
use String::TT qw/tt strip/;
sub foo {
my $self = shift;
return tt 'my name is [% self.name %]!';
}
sub bar {
my #args = #_;
return strip tt q{
Args: [% args_a.join(",") %]
}
}
and...
my $scalar = 'scalar';
my #array = qw/array goes here/;
my %hash = ( hashes => 'are fun' );
tt '[% scalar %] [% scalar_s %] [% array_a %] [% hash_h %]';