Last week my book PostgreSQL 11 Server Side Programming Quick Start Guide was released.
The book is a Quick Start Guide, that means it goes straight to the point, in this case, programming on the server-side of PostgreSQL.
Why is this related to Perl?
Well, one very cool feature of PostgreSQL is the capability to
execute functions, and therefore triggers and procedures, in pretty
much any programming language available out there. And this of course, means Perl!
In fact, Perl is very well supported in PostgreSQL to the point that the DO statement does allow you to use PL/Perl code instead of the PL/pgSQL one.
The other language I show, as a "foreign" language, in this book, is Java.
My idea was to show to the readers the differences between using a
language like Perl and one that requires a full compile-deploy cycle.
Hope the book can be useful.
Visualizzazione post con etichetta planet-perl-ironman. Mostra tutti i post
Visualizzazione post con etichetta planet-perl-ironman. Mostra tutti i post
martedì 4 dicembre 2018
venerdì 16 giugno 2017
Perl and regexps are too much verbose (!)
A colleague asked me a quick Perl way to check if a string contains only a predefined set of chars excluding a few ones.
Easy pal!
Regexp to the rescue!
Easy pal!
Regexp to the rescue!
Then I was asked for a way that did no use a regular expression, because "you know, regular expression can be somehow verbose".
Gosh!
My answer was simply "you don't use regexps a lot!".
Gosh!
My answer was simply "you don't use regexps a lot!".
I don't believe I have to explain to any (Perl) programmer that regexps have been designed to express in short a whole set of choices,
more in general an alphabet (in the most wider concept).
more in general an alphabet (in the most wider concept).
But let's move on, and after showing a quick and dirty one liner such as:
perl -E 'say "Wrong $_" unless ( /^[0-9]+$/ ); ' -F
I got another strange sentence as "yeah, but I don't like Perl too much, it is somehow verbose as a language".
And again, my answer was: "you don't use it regularly!".
And again, my answer was: "you don't use it regularly!".
It is clear Perl was seen in the wrong way, since both the language as well as regular expressions can be really short, as well as
a one liner…
No other comments required!
a one liner…
No other comments required!
venerdì 19 maggio 2017
Arabic to Roman number converter in Perl 5
Puzzled by a post on the Planet KDE about GCompris and roman numbers,
and needing an easy way to explain to my six-years old son about roman
numbers, I thought it would be an easy task to make a simple program in
Perl to convert an arabic number into its roman notation.
Not so easy, pal!
Well, it's not a problem about Perl, of course, rather I found it required a quite brainpower for me to write down rules to convert numbers, and I did not search for the web for a copy-and-paste alghoritm. Please note: if you need a rock-solid way to handle conversions, have a look at CPAN that is full of modules for this particular aim.
Here I'm going to discuss the solution I found and how I implemented it. It is not supposed to be the best one, or the faster one, it's just my solution from scratch.
that produces the following output:
Each method references
The
The following is the code for the
The first thing the method does it to create the hash
The
The
The promotion must be done from the smaller letter to the greater one, so this time the letters are walked in ascending order (i.e.,
A letter requires to be promoted if its quantity is
So for instance, the 29 hash of the previous paragraph is passed as follows:
At the end of method we know the final string will be made by three
The
The method accepts the normalized hash (i.e., groups are already
formed) and compose the final string placing letter on the left or the
right of each other depending on their quantity. The following is the
code of the method:
In order to be able to manipulate easily the final string, moving
letters from left to right and vice-versa, I decided to place each
single letter into the
Let's suppose we need just to add letters: in this case we need to write letters from the greater to the smaller from left to right, and this is the order I traverse the letters of
that inserts into
With regards to the previous example of 29 we have that:
Not so easy, pal!
Well, it's not a problem about Perl, of course, rather I found it required a quite brainpower for me to write down rules to convert numbers, and I did not search for the web for a copy-and-paste alghoritm. Please note: if you need a rock-solid way to handle conversions, have a look at CPAN that is full of modules for this particular aim.
Here I'm going to discuss the solution I found and how I implemented it. It is not supposed to be the best one, or the faster one, it's just my solution from scratch.
The program
I split the problem of converting an arabic number into a roman one into three steps, with one dedicated subroutine for each step, so that the main loop reduces to something like the following:say "$_ = " . $roman_string->( $reassemble->( $disassemble->( $_ ) ) )
for ( 1..30 );
1 = I
2 = II
3 = III
4 = IV
5 = V
6 = VI
7 = VII
8 = VIII
9 = IX
10 = X
11 = XI
12 = XII
13 = XIII
14 = XIV
15 = XV
16 = XVI
17 = XVII
18 = XVIII
19 = XIX
20 = XX
21 = XXI
22 = XXII
23 = XXIII
24 = XXIV
25 = XXV
26 = XXVI
27 = XXVII
28 = XXVIII
29 = XXIX
30 = XXX
The steps must be read from the inner subroutine to the outer, of course, and therefore we have:disassemblethat translates an arabic number into roman basis, that is computes how many units, tens, hundreds and thousands are required. In this phase there is no application of roman rules, so numbers are decomposed into a linear string of letters. As an example the number4is translated intoIIII, which is of course a non-existent roman number.reassembleapplies roman rules, in particular promoting numbers so that groups are translated, when needed, into higher order letters. For instanceIIIIis promoted into two groups:IandV.roman_stringcompose the promoted groups into the final string. The main difficulty of this part is to understand when a letter has to be placed on the right (addition) or on the left (subtraction) of another letter. For instance, having the groupsIandVthe function must understand if the output have to beVI(6) orIV(4).
my $roman = {
1 => 'I',
5 => 'V',
10 => 'X',
50 => 'L',
100 => 'C',
500 => 'D',
1000 => 'M',
};
$roman when needing to convert
from an arabic number to its roman letter. In order to allow method to
cooperate together, they accept and return an hash keyed by a roman
letter and the number of occurences such letter must appear in the final
string. The following is an example of the hash for a few numbers:# 4 (IV)
{ 'I' => 1, 'V' => 1 }
# 19 (XIX)
{ 'I' => 1, 'X' => 2 }
# 5 (V)
{ 'V' => 1 }
# 17 (XVII)
{ 'X' => 1, 'V' => 1, 'I' => 2 }
The disassemble function
The following is the code for the disassemble function, that accepts as only input the arabic number.# Accepts the arabic number and provides an hash
# keyed by each letter, with the value of how many times
# such letter should be summed in order to obtain the
# starting number.
my $disassemble = sub{
my ( $number ) = @_;
my $items = {};
# sort the keys, that are arabic thresolds, from
# the greater to the smaller one
for my $current_value ( sort { $b <=> $a } keys $roman->%* ){
my $how_many = int( $number / $current_value );
next unless ( $how_many );
my $letter = $roman->%{ $current_value };
$items->{ $letter } = $how_many;
$number -= $current_value * $how_many;
}
return $items;
};
$items that is what it will return to allow other methods to consume. Each key of the $roman hash is passed ordered by the bigger to the smaller (please note that sort has $b first!). In this way we can surely scompose the number from the thousands, hundreds, tens, and units in this exact order. The $how_many variable contains the integer part of each letter. For example the number 29 is processed as follows:29 / 10that drives$how_manyto be2and the remaining to be a9;9 / 5that makes$how_manyto be1and the remaining to be a4;4 / 1that makes$how_manyto be4and there's nothing more to do.
$how_many value is inserted into the $items has, that in the above ecample becomes:# 29 (XIX)
{ 'X' => 2,
'V' => 1,
'I' => 4
}
The reassemble method
The reassemble method takes as input the hash produced by disassemble and checks if any letter requires a promotion. Here it is the code:# Accepts an hash with keys the letters and values the number
# of times each letter should appear.
# Traverse the hash from the smaller to the greater
# in order to "promote" smaller aggregates. For instance
# 'IIII' (4) is aggregated and therefore the hash is modified
# so there's only an 'I' and another 'V', in such case
# the quantity of the promoted letter is negative to indicate
# it has been promoted.
my $reassemble = sub{
my ( $items ) = @_;
my @sorted_thresolds = sort { $a <=> $b } keys $roman->%*;
for ( my $i = 0; $i < @sorted_thresolds; $i++ ){
my $current_value = $sorted_thresolds[ $i ];
my $key = $roman->%{ $current_value };
my $how_many = $items->%{ $key };
next unless ( $how_many );
my $greater_value = ( $i + 1 > @sorted_thresolds ? 1000 : $sorted_thresolds[ $i + 1 ] );
my $greater_key = $roman->%{ $greater_value };
my $need_to_promote = $how_many == 4
|| ( $greater_value / $current_value == $how_many );
if ( $need_to_promote ){
$items->{ $greater_key }++;
$how_many = $greater_value - $how_many * $current_value;
$items->{ $key } = $how_many * -1;
}
}
return $items;
};
sort has $a first!). Since to promote a letter I need to access the following one, I need a C-style for loop.A letter requires to be promoted if its quantity is
4 or /it is 2 and the right bigger value is exactly the double of the current one~, that is while ( $greater_value / $current_value == $how_many ). This makes, for instance IIII to be promoted (the quantity is 4), and VV to be promoted into X (because the quantity is 2 and the X is exactly the double of V).
The promotion manipulates the hash increasing by one the right bigger
letter and leaving a single current letter. In order to flag the
promoted letter, I decided to use a negative quantity (where the
absolute value is the exact one).So for instance, the 29 hash of the previous paragraph is passed as follows:
# input to the method
{ 'X' => 2,
'V' => 1,
'I' => 4
}
# first for step (I)
{ 'X' => 2,
'V' => 2,
'I' => -1 # promoted, keep 1 and increase 'V'
}
# second step (V)
{ 'X' => 3,
'V' => 0, # promoted, increase X by one
'I' => -1
}
X and one I, the point now is to understand how to render them in the correct order. This is the aim of the roman_string method.
The roman_string method
The method accepts the normalized hash (i.e., groups are already
formed) and compose the final string placing letter on the left or the
right of each other depending on their quantity. The following is the
code of the method:# Do the hard work of composing
# each group of letters in order to compose the roman string.
my $roman_string = sub {
my ( $items ) = @_;
my @chars;
for my $current_value ( sort { $b <=> $a } keys $roman->%* ){
my $letter = $roman->%{ $current_value };
my $how_many = $items->%{ $letter };
next unless ( $how_many );
if ( $how_many > 0 ){
push @chars, $letter for ( 1 .. $how_many );
}
else{
# this is promoted, so it has to be inserted as last-to-last
# in the previous chain
# example: @chars( X, X ) and here I've 'I' to make XIX (19)
push @chars, ( $letter, pop @chars );
}
}
return join "", @chars;
};
@chars array, that is then join -ed into a single string.Let's suppose we need just to add letters: in this case we need to write letters from the greater to the smaller from left to right, and this is the order I traverse the letters of
$roman (again, note that sort has $b first!). If the quantity of the letter is positive the letter has not been promoted and therefore it will not be placed to the left of another letter, so just insert into @chars the $letter for the $how_many quantity. On the other hand, if $how_many
is negative, the letter has been promoted and therefore have to be
printed on the left of the last printed letter. This is as easy as
doing:push @chars, ( $letter, pop @chars );that inserts into
@chars the $letter and the previous last character that has been removed via pop.With regards to the previous example of 29 we have that:
# method input
{ 'X' => 3,
'I' => -1
}
# first step: prints X
# with quantity 3 (not promoted)
@chars = ( 'X', 'X', 'X' );
# second step: prints I
# that has been promoted
# and must be inserted ascending
# as last-to-last
@chars = ( 'X', 'X' ,
( 'I', # $letter
'X' # pop @chars
) );
Conclusions
Well, it has been much code that I expected to write. Using an object notation, instead of plain hashes, could surely make the program more robust. I'm pretty sure there's a way to shrink the code down and to avoid that ugly C-stylefor loop, as well as the promotion
part could be simplified keeping in mind that it often reduces to -1 for
the current letter and +1 for the greater one. Anyway, it does what I
need and seems correct!
venerdì 12 maggio 2017
Postfix dereference operator
Starting from Perl 5.20 it is allowed to use a postfix dereference notation, first as an explicit feature, and since Perl 5.24 it is enabled by default.
The postfix dereference notation allows you to use the arrow operator
The following is a sample program that prints out the values of an array using full access (
As you can see,
Code and subroutine references are a little more controversial, at least to my understanding of references. First of all there is only the star operator, so
If you try to pass arguments in any way to the
The only catch-all way of passing arguments, as suggested on irc.perl.org, is to use the
{
local @_ = qw( Luca );
$sub_ref->&*; # Hello sir Luca !
}
I must admit this is a little too much for my poor brain in order to efficiently use the references, so if anyone has something to comment is truly welcome!
Now, back to the main topic, it seems to me that the postfix dereference notation is a way of managing reference more like objects, at least it reminds me a kind of
The postfix dereference notation allows you to use the arrow operator
-> on a reference (as often used when combined with references) specifying the type of the deferencing you want to. Types are indicated by their well know sigils, so for instance a $ means a scalar, a @ an array, & is for a subroutine, % for an hash and * for a typeglob. The sigil on the right of the arrow operator is enhanced by a star, so it really becomes type and *, as in $*. In the special case of arrays and hashes the star can be dropped in favor of a slicing operator, e.g., the square brackets.The following is a sample program that prints out the values of an array using full access (
->@*) and slicing (->@[]):#!env perl
use v5.24;
my @array = ( 'a' .. 'z' );
my $ref = \@array;
say "Here comes the array @{ $ref }";
say "And post dereferences is $ref->@*";
say "Here comes a slice @{ $ref }[ 0 .. 5 ]";
say "And using it as post dereference is $ref->@[ 0 .. 5 ]";
$ref->@* is the equivalent of @{ $ref }, while $ref->@[] is the same as @{ $ref }[]. The same applies to hash references.Code and subroutine references are a little more controversial, at least to my understanding of references. First of all there is only the star operator, so
->&*, and the behavior is such that $ref->&* is the same as &{ $ref }. This makes me think there is no short way of passing method arguments thru a postfix deference, as the following code demonstrates:#!env perl
use v5.24;
my $sub_ref = sub { say "Hello sir @_ !" };
$sub_ref->( 'Luca' ); # Hello sir Luca !
&{ $sub_ref }( 'Luca' ); # Hello sir Luca !
$sub_ref->&* ; # Hello sir !
{ $sub_ref->&* }( 'Luca' ); # Hello sir !
&$sub_ref( 'Luca' ); # Hello sir Luca !
If you try to pass arguments in any way to the
->&* dereferencing, you got either a compile time error or a code that does not what you expect:{ $sub_ref->&>* }( 'Luca '); # Hello sir !
$sub_ref->&( 'Luca' ); # syntax error at tmp/ref.pl line 19, near "->&"
$sub_ref->&*( 'Luca' ); # syntax error at tmp/ref.pl line 20, near "&*( "
{ $sub_ref->& }( 'Luca '); # syntax error at tmp/ref.pl line 21, near "->&"
The only catch-all way of passing arguments, as suggested on irc.perl.org, is to use the
@_, so I suggest to localize it:{
local @_ = qw( Luca );
$sub_ref->&*; # Hello sir Luca !
}
I must admit this is a little too much for my poor brain in order to efficiently use the references, so if anyone has something to comment is truly welcome!
Now, back to the main topic, it seems to me that the postfix dereference notation is a way of managing reference more like objects, at least it reminds me a kind of
as_xx methods (yes, Ruby-ers, I'm looking at you). If we read the arrow operator like as and the type on sigil on the right as the type name, we have that, for instance:$ref->$*is $ref as scalar;$ref->@*is $ref as array or$ref>@[]becomes $ref as array slice
@$ref or @{ $ref }.
mercoledì 10 maggio 2017
Diamonds in Perl
A diamond ascii is a geometric structure represented as, ehm, a diamond. For example, in the case of letters it becomes something like:
How hard can it be to build a Perl program to represent a diamond like the above one?
Well, not so much hard, but we have to observe some geometric properties:
Ok, so here it comes my shorter solution:
Allow me to explain it in all its pieces.
First of all,
Finally, I print a line every time I need with
The
then I need to get the bottom, so I need to iterate over the
a
b b
c c
d d
e e
f f
e e
d d
c c
b b
a
How hard can it be to build a Perl program to represent a diamond like the above one?
Well, not so much hard, but we have to observe some geometric properties:
- the diamond is simmetric (in the sense it becomes and ends with the same letters), but the
central row is reproduced only once (that is, thefappears only on one line, not two!);
- each letter or couple of letters is vertically centered around the number of letters in the whole diamond, that is
the lettera(vertical centre) is shifted to right of 6 chars (the total number of letters is a..f = 6);
- each couple of letters has a left and right position, and both are equally distant from the vertical
centre of the diamond.
Ok, so here it comes my shorter solution:
#!env perl
use v5.20;
my @letters = qw( a b c d e f );
my %index;
@index{ @letters } = ( 0 .. $#letters );
say {*STDOUT}
" " x ( $#letters - $index{ $_ } )
, $_
, " " x ( $index{ $_ } * 2 )
,( $index{ $_ } > 0 ? $_ : '' )
for ( ( @letters, reverse @letters[ 0 .. $#letters - 1 ] ) );
Allow me to explain it in all its pieces.
First of all,
@letters contains the letters to be printed in the right order, and this of course could come from user's input, a sequence, an array slice, or whatever, it does not mind here. Since I have to place letters depending on where they are in the array of @letters, I need to have an handy way to get the index within the array for each letter, so I build up an hash where the keys are the letters themselves and the values are the positions of such letters. In other words, $index{a} = 0, $index{f] = 5 and so on.Finally, I print a line every time I need with
say. Let's dissect the say statement:- " " x ( $#letters - $index{ $_ } ) shifts to right a number of spaces required to reach the vertical centre or the right distance from it, in other words it is the left position. For example, for the letter
ait comes
down to5 - 0 = 5, while forbit comes to5 - 1 = 4and so on.
- then I print
$_that is the current char;
- then I move again to the right of " " x ( $index{ $_ } * 2 ), that is in the case of
anothing, in the case ofbby 2, and so on;
- then if required I print again the char. Here "required" means the char is not the first one (i.e., not the one at index 0), since that is the only one character printed exactly one time per line.
The
say is repeated over the whole @letters array, so this produces the first part of the diamond:a b b c c d d e e f f
then I need to get the bottom, so I need to iterate over the
reverse @letters with the exception of the last element, that is I need to iterate over a reversed slice of @letters with the missing f: reverse @letters[ 0 .. $#letters - 1 ] ). This provides me the whole bottom of the diamond.
venerdì 5 maggio 2017
perlcritic and allowing simple double sigils dereferencing
I found out, while not searching for it, an interesting policy for Perl::Critic
named Perl::Critic::Policy::References::ProhibitComplexDoubleSigils. The idea is quite simple and I find myself agreeing with it:
when dereferencing a reference you can omit braces; while this is often not a good habit (because it can become
quite difficult to read a complex reference), it can work out on simpler cases:
In the above code it is quite simple to understand that
the braces around.
I recognize the advantages of using the braces as:
Anyway simple idioms should stay simple and so should the checkers manage them.
If I run
will report
Now, using the above mentioned Perl::Critic::Policy::References::ProhibitComplexDoubleSigils the result becomes:
Ok, let's refactor the program and transform the plain hash in a multidimensional one:
The above part is the right way of dereferencing the reference to the inner hash, and it does use curly braces
and makes
If, instead, we pretend to use double sigils (that is removing the arrow operator) the code becomes:
and of course both policies complain about:
Something similar happens when you try to extract a single scalar value from the nested hash:
both the above instructions place the correct value into the
(the one with the
Summing up the idea is to allow double sigils only when you are dereferencing a single level, not for complex data structures.
named Perl::Critic::Policy::References::ProhibitComplexDoubleSigils. The idea is quite simple and I find myself agreeing with it:
when dereferencing a reference you can omit braces; while this is often not a good habit (because it can become
quite difficult to read a complex reference), it can work out on simpler cases:
#!env perl
use v5.20;
my %hash = (
key1 => "value1"
, key2 => "value2"
, key3 => "value3"
);
my $hash_ref = \%hash;
while ( my ( $k, $v ) = each %$hash_ref ){
say "$k --> $v";
}
In the above code it is quite simple to understand that
@$hash_ref refers to the whole hash without the need to usethe braces around.
I recognize the advantages of using the braces as:
- a good habit;
- a way to do a good refactoring in the case the reference points to a multidimensional structure.
Anyway simple idioms should stay simple and so should the checkers manage them.
If I run
perlcritic against the above piece of code, the Perl::Critic::Policy::References::ProhibitDoubleSigilswill report
% perlcritic --single-policy=ProhibitDoubleSigils p.pl Double-sigil dereference at line 12, column 30. See page 228 of PBP. (Severity: 2)
Now, using the above mentioned Perl::Critic::Policy::References::ProhibitComplexDoubleSigils the result becomes:
% perlcritic --single-policy=ProhibitComplexDoubleSigils p.pl p.pl source OK
Ok, let's refactor the program and transform the plain hash in a multidimensional one:
#!env perl
use v5.20;
my %hash = (
key1 => "value1"
, key2 => "value2"
, key3 => "value3"
);
my %outer_hash = ( config1 => \%hash );
my $hash_ref = \%outer_hash;
while ( my ( $k, $v ) = each %{ $hash_ref->{config1} } ){
say "$k --> $v";
}
The above part is the right way of dereferencing the reference to the inner hash, and it does use curly braces
and makes
Perl::Critic, both policies, not complaining at all.If, instead, we pretend to use double sigils (that is removing the arrow operator) the code becomes:
#!env perl
use v5.20;
my %hash = (
key1 => "value1"
, key2 => "value2"
, key3 => "value3"
);
my %outer_hash = ( config1 => \%hash );
my $hash_ref = \%outer_hash;
while ( my ( $k, $v ) = each %{ $$hash_ref{config1} } ){
say "$k --> $v";
}
and of course both policies complain about:
% perlcritic --single-policy=ProhibitDoubleSigils p.pl Double-sigil dereference at line 13, column 33. See page 228 of PBP. (Severity: 2) % perlcritic --single-policy=ProhibitComplexDoubleSigils p.pl Complex double-sigil dereferences at line 13, column 33. Found complex double-sigil dereference without curly braces. (Severity: 2)
Something similar happens when you try to extract a single scalar value from the nested hash:
...
# line 20
my $k1 = $$hash_ref{ config1 }->{ key1 };
say "key1 is $k1";
# line 23
$k1 = $hash_ref->{ config1 }->{ key1 };
say "key1 is $k1";
both the above instructions place the correct value into the
$k1 variable, and the policies both complain about the first line(the one with the
$$):% perlcritic --single-policy=ProhibitDoubleSigils p.pl
Double-sigil dereference at line 20, column 10. See page 228 of PBP. (Severity: 2)
% perlcritic --single-policy=ProhibitDoubleComplexSigils p.pl
The value for the global "single-policy" option ("ProhibitDoubleComplexSigils") did not match any policies (in combination with other policy restrictions).
Summing up the idea is to allow double sigils only when you are dereferencing a single level, not for complex data structures.
sabato 29 aprile 2017
Another baby Perl program from a backup in the attic
This is a simple script that takes all arguments on the command line and returns a list of directories for each argument.
I don't remember at all what the purpose of this was, probably something to process a set of directories via a batch starting from
a set of filenames.
By the way, let's say how baby I was at that time…
or
Let be honest here: the adoption of
such couple of instructions, and this means the code could even be simpler, or better, shorter, but let's keep some good habits!
I don't remember at all what the purpose of this was, probably something to process a set of directories via a batch starting from
a set of filenames.
By the way, let's say how baby I was at that time…
1.1 Baby Code
Here it is, please note how long the code is…
#!/usr/bin/perl
# This script manipulates all its arguments returning a list of string which
# are the directory of all files. For example if the argument is
# /home/luca/file.txt only /home/luca/ is returned (note the last backslash).
# return array
@ret;
foreach $name (@ARGV){
if( -f $name ){
# check if the name contains a /, if no the directory must be the current one (./)
if(not $name =~ /\// ){
$ret[++$#ret] = "./";
}
else{
@parts;
$dir;
# split into the section with /
@parts = split("/",$name);
if( defined(@parts) ){
for($i=0; $i < $#parts; $i++){
$dir .= $parts[ $i ]."/";
}
}
# put the result inot the array
$ret[++$#ret] = $dir;
}
}
elsif( -d $name ){
# this is a directory, simply check if ends with the slash
if( not $name =~ /\/$/ ){
$name .= "/";
}
$ret[++$#ret] = $name;
}
}
# all done, print the array
foreach $name (@ret){
print $name."\n";
}
1.2 The teen-ager code
What if I have to write a similar service today?
That is the very first code that comes into my mind:
A lot less, uh?
It could be simpler, but so far I don't know any module to return the directory part of a path when a file is provided as argument, and
this is the reason I need to distinguish between the
The adoption of the list separator
That is the very first code that comes into my mind:
#!env perl
use v5.20;
use File::Spec;
my @dirs;
for ( @ARGV ){
push @dirs, $_ if ( -d $_ );
push @dirs, ( File::Spec->splitpath( $_ ) )[ 1 ] if ( -f $_ );
}
{
local $" = "/\n";
say "@dirs";
}
A lot less, uh?
It could be simpler, but so far I don't know any module to return the directory part of a path when a file is provided as argument, and
this is the reason I need to distinguish between the
-f and -d cases.The adoption of the list separator
$" is specific to add the trailing backslash and to place every single directory on its own line. Of course this means, as $" suggests, that the array has to be printed via doubled quoted print. Here the adoption of sayprint is totally equivalent.Let be honest here: the adoption of
local and the surrounding block could be avoided, since the script exits implicitly right aftersuch couple of instructions, and this means the code could even be simpler, or better, shorter, but let's keep some good habits!
venerdì 14 aprile 2017
A baby Perl program from a backup in the attic!
…I was assigned one of my very first program to develop: a way to assure an user can run no more than a specific number of instances
of the same executable.
The real story was this: a company was using an Unix ncurses based ERP, and users were forced to connect via remote shell and
launch it automatically. The problem was that several users were opening more terminals (and therefore ERP clients) limiting
resources to other users.
I wanted to demonstrate my skills being able to implement the solution in a couple of hours, and instead of spending time
searching for a production-ready solution on the Internet, I decided to do it all on my own.
It was clear to me I was needing a kind of wrapper to control the execution of external programs. In fact, since users were
automatically switched from the remote shell into the ERP client, it did suffice to place the wrapper as the
user shell.
But how to implement it? At that time I knew Java, C++, C, Perl and some Bourne Shell. Making it in Java was too heavy, and
most notably required to install a JVM on the server (it was the time of the Red Hat 5 branch). C and C++ required too much time
to come with a working solution, and Perl was the most promising allowing me to do everything I was able to do with
other languages, overcoming the limitation of the shell (e.g., arithmetic).
But at that time I was not a fluent Perl developer.
A few days ago I found the above program out of an old backup, and so I spent five minutes to read it again. Not surprisingly, I found
it awful with respect to the code I write today, and moreover I see a lot of code uglyness due to baby steps. But hey, it was fun
to see how many things I've changed in my coding style, idioms, adoption of the language and of its operators, and most notably
about how I'm today toward compact code instead of long and blown code. At that time I was convinced that as long the code was, as much
it must be simpler to read, today I believe it is the opposite (with a very few exceptions I tend not to adopt until I
can remember very well).
In this article I will dissect a few parts of the above program to show you how I was writing code back in those days, and it was
a huge time ago (at least in computer timeline): 15+ years ago.
I was not using scoped variables, and the reasons were:
of the same executable.
The real story was this: a company was using an Unix ncurses based ERP, and users were forced to connect via remote shell and
launch it automatically. The problem was that several users were opening more terminals (and therefore ERP clients) limiting
resources to other users.
I wanted to demonstrate my skills being able to implement the solution in a couple of hours, and instead of spending time
searching for a production-ready solution on the Internet, I decided to do it all on my own.
It was clear to me I was needing a kind of wrapper to control the execution of external programs. In fact, since users were
automatically switched from the remote shell into the ERP client, it did suffice to place the wrapper as the
user shell.
But how to implement it? At that time I knew Java, C++, C, Perl and some Bourne Shell. Making it in Java was too heavy, and
most notably required to install a JVM on the server (it was the time of the Red Hat 5 branch). C and C++ required too much time
to come with a working solution, and Perl was the most promising allowing me to do everything I was able to do with
other languages, overcoming the limitation of the shell (e.g., arithmetic).
But at that time I was not a fluent Perl developer.
A few days ago I found the above program out of an old backup, and so I spent five minutes to read it again. Not surprisingly, I found
it awful with respect to the code I write today, and moreover I see a lot of code uglyness due to baby steps. But hey, it was fun
to see how many things I've changed in my coding style, idioms, adoption of the language and of its operators, and most notably
about how I'm today toward compact code instead of long and blown code. At that time I was convinced that as long the code was, as much
it must be simpler to read, today I believe it is the opposite (with a very few exceptions I tend not to adopt until I
can remember very well).
In this article I will dissect a few parts of the above program to show you how I was writing code back in those days, and it was
a huge time ago (at least in computer timeline): 15+ years ago.
2 Baby Steps
Well, as you can imagine when I started doing a real job I was nothing more than a programmer-to-be, and my knowlegde
about Perl was really tiny. I mean, I read the Camel Book (of course!), and I was experimenting with Perl as much as I could,
but I was not an avid consumer of the Perl community (as well as other communities) and so I did not have a lot of chances
to learn from other people experience and code.
More than that, I just finished my university degree, and so my mind was literally full of theories about writing
correct and beautiful code, but that were just theories without any implementation! And last but not least, I was convinced
I could do everything by my own (that is, who needs modules?).
Today I recognize the following as baby steps in the Perl world.
about Perl was really tiny. I mean, I read the Camel Book (of course!), and I was experimenting with Perl as much as I could,
but I was not an avid consumer of the Perl community (as well as other communities) and so I did not have a lot of chances
to learn from other people experience and code.
More than that, I just finished my university degree, and so my mind was literally full of theories about writing
correct and beautiful code, but that were just theories without any implementation! And last but not least, I was convinced
I could do everything by my own (that is, who needs modules?).
Today I recognize the following as baby steps in the Perl world.
2.1 Method Prototypes
Yes, I was using prototypes everywhere.
Why? I suspect they were comfortable to me, since I was used to languages where each method has a prototype (C, C++, Java), and
so I was trying to use a kind of common approach to every language, applying to Perl prototypes even when I was not needing
them at all!
Of course, by time and experience, I found that prototypes are usually not useful at all in my programs, and made refactoring
a lot harder.
Why? I suspect they were comfortable to me, since I was used to languages where each method has a prototype (C, C++, Java), and
so I was trying to use a kind of common approach to every language, applying to Perl prototypes even when I was not needing
them at all!
Of course, by time and experience, I found that prototypes are usually not useful at all in my programs, and made refactoring
a lot harder.
2.2 Method instead of Operators
Perl allows operators to be used without braces, but that was something my eyes were not able to parse!
Again, coming from languages where methods and operators both need parentheses, I tried to bend Perl to my will
and use operators the very same way.
Again, coming from languages where methods and operators both need parentheses, I tried to bend Perl to my will
and use operators the very same way.
2.3 Untrusting the Thruth
Perl has the great ability to cast a variable depending on the context, but it was something too much complex for me.
So for instances, instead of testing a scalar against a not-true value, I was using the defined operator:
Worst: I was not using the ability of an array to be scalar-contextualized in tests:
So for instances, instead of testing a scalar against a not-true value, I was using the defined operator:
# if ( $scalar ) if ( defined $scalar ){ ... }
Worst: I was not using the ability of an array to be scalar-contextualized in tests:
#if ( ! @array ) if ( not defined @array || $#array <= 0 ){ ... }
2.4 Global Variables
my what?I was not using scoped variables, and the reasons were:
- it was not clear to me the real difference between
myandlocal, and I have to confess I thoughtlocalwas what should be the
name for scoped variables (maybe because of the way some shells declarelocalvariables), but sincelocalwas usually a bad idea
I decided not to use either; - my scripts were quite small and self contained, so there was no risk at all about variable clash.
2.5 Backtick as a Rescue!
I knew pretty much well a kind of command line Unix tools (e.g.,
to do something in Perl without knowing how to do but with shell tools. So, how could I merge the both?
Easy pal: backtick the Unix tools and manage the result in Perl!
grep, awk, sed, find), and sometimes I neededto do something in Perl without knowing how to do but with shell tools. So, how could I merge the both?
Easy pal: backtick the Unix tools and manage the result in Perl!
2.6 No Modules, please
I was not using modules, both by design and by fear.
With by design I mean that I was writing scripts for machine loosely connected to the Internet (just think I was working with server behind an ISDN router!),
and therefore even dowloading a module and install it could be quite a pain.
By fear means I was quite scared about importing other people's code. I was still learning about how to use correctly the CPAN, how to read
the documentation, and so on. And I did not want to install things in the wrong way on code that must run. After all, I was half-an-hour
away from implementing some kind of module functionality by my own (ah, the ego…).
With by design I mean that I was writing scripts for machine loosely connected to the Internet (just think I was working with server behind an ISDN router!),
and therefore even dowloading a module and install it could be quite a pain.
By fear means I was quite scared about importing other people's code. I was still learning about how to use correctly the CPAN, how to read
the documentation, and so on. And I did not want to install things in the wrong way on code that must run. After all, I was half-an-hour
away from implementing some kind of module functionality by my own (ah, the ego…).
2.7 Regexp Sometimes…
I tried to use regexp, but I was too less experienced. Therefore I usually did the substitution with friendly tools, like
split and alike.
I fear regexp nomore, and even if I'm not a master at all, I find interesting placing them in programs not only because
they allow me to write clear and compact code, but also because they still are some criptic stuff other developers
have hard time reading.
split and alike.
I fear regexp nomore, and even if I'm not a master at all, I find interesting placing them in programs not only because
they allow me to write clear and compact code, but also because they still are some criptic stuff other developers
have hard time reading.
3 The Code
3.1 University Distortion
There are a couple of places where you can see evidence of the teachings at my university, most notably the
command line argument loop:
As you can see I was hardwiring the arguments directly into the program, as well as I was not using any getopt-like module.
That was by culture: university never told me there was a getopt way of getting parameters!
Please note also that I was checking the argument numbers as well as exiting from the program with a different exit code for each branch.
The style reminds pretty much the C-style I was used to work with during my exams.
command line argument loop:
sub parseCommandLine() { # The script must be at least two arguments. if ( $#ARGV < 1 or $#ARGV > 4 ) { help(); exit(0); } $POLICY_FILE = $DEFAULT_POLICY_FILE; foreach $argument (@ARGV) { if ( $argument =~ /(-program=)/ ) { $argument =~ s/(-program=)//; $PROGRAM = $argument; } elsif ( $argument =~ /(-policy=)/ ) { $argument =~ s/(-policy=)//; $POLICY_FILE = $argument; } elsif ( $argument =~ /(-username=)/ ) { $argument =~ s/(-username=)//; $USERNAME = $argument; } elsif ( $argument =~ /(-message=)/ ) { $argument =~ s/(-message=)//; $MESSAGE_FILE = $argument; } } # check main parameters if ( not defined $USERNAME or $USERNAME eq "") { warn("\nCannot find username !!\n\n"); help(); exit(1); } elsif ( not defined $PROGRAM or $PROGRAM eq "") { warn("\nCannot find the program name \n\n"); help(); exit(2); } elsif ( not defined $POLICY_FILE or $POLICY_FILE eq "") { warn("\nI need a policy file to run!\n\n"); help(); exit(3); } }
As you can see I was hardwiring the arguments directly into the program, as well as I was not using any getopt-like module.
That was by culture: university never told me there was a getopt way of getting parameters!
Please note also that I was checking the argument numbers as well as exiting from the program with a different exit code for each branch.
The style reminds pretty much the C-style I was used to work with during my exams.
3.2 Ready? Go!
How can I execute another program from within the Perl wrapper?
Well, the simplest way that I was aware of is to call
Well, the simplest way that I was aware of is to call
execute, in other words, to work as a low level C:sub launch($) { # take arguments my ($program) = @_; # execute the program sleep(2); exec($program); }
3.3 How Many Instances can you Run?
How to define how many instances an user can run?
Here I decided to take inspiration from the sudo policy file, and so I invented my own policy file with a pretty
simple syntax:
where:
And to make it looking mor eprofessional, I allowed the policy file to include a star in any field
in order to mean anything or any instance.
Of course, the above was full crap. For instance, if you were able to create a link from the
with the right name you could change you allowance. But luckily, no user was able to do that, and to some
extent even the other sysadmins!
Having defined the policy file syntax, reading the file was as simple as:
What an amazing piece of code, uh?
Instead of reading the policy file once (or seldom), I was reading it fully every time I needed to check an user; it was
a very non-optimzed code.
Moreover, I was reading and grepping it a line at time, a very keyboard effort.
Here I decided to take inspiration from the sudo policy file, and so I invented my own policy file with a pretty
simple syntax:
username@executable=instanceswhere:
usernamewas the Unix username;executablewas the name of the executable to run;instanceswas the number of the maximum allowed instances of theexecutablefor the specifiedusername.
And to make it looking mor eprofessional, I allowed the policy file to include a star in any field
in order to mean anything or any instance.
Of course, the above was full crap. For instance, if you were able to create a link from the
executable to anotherwith the right name you could change you allowance. But luckily, no user was able to do that, and to some
extent even the other sysadmins!
Having defined the policy file syntax, reading the file was as simple as:
sub getAllowedInstances($$$) { # take params my ($policy_file, $username, $program) = @_; my $instances = -1; # try to open the policy file open (POLICY_FILE_HANDLER, "<".$policy_file) || die("\nCannot parse policy file <$policy_file> !\n"); print "\nParsing configuration file $policy_file for program $program, username $username..."; $instances = 0; # by default do not allow a user to execute a program # get each line from the policy file, and then search for the username while ( $line = <POLICY_FILE_HANDLER> ) { print "\n\t Configuration line: $line "; # take only lines with the program name specified if( grep("$program", $line) ){ @lineParts = split("@",$line); $configUsername = $lineParts[0]; print "\ncontrollo se $username == $configUsername"; if ( $username eq $configUsername ) { # this is the right line # take the instances number @pieces = split("=" , $line); $instances = $pieces[1]; # remove the '\n' chomp($instances); print "\n\t\t\tUser allowance: $instances"; return $instances; } elsif ( $configUsername eq "*" ) { # a valid entry for all users # take the instances number @pieces = split("=" , $line); $instances = $pieces[1]; # remove the '\n' chomp($instances); print "\n\t\t\tGlobal allowance: $instances"; } } } # no lines found, the user has no restrictions return $instances; }
What an amazing piece of code, uh?
Instead of reading the policy file once (or seldom), I was reading it fully every time I needed to check an user; it was
a very non-optimzed code.
Moreover, I was reading and grepping it a line at time, a very keyboard effort.
3.4 How much are you Running?
How to get the number of runnable instances an user was running?
Piece of cake: let's do it in Unix, backtick in Perl and increase by one:
Please note also the adoption of literals instead of variables: for example
the latter has been already initialized to zero.
Piece of cake: let's do it in Unix, backtick in Perl and increase by one:
sub getRunningInstancesCount($$) { # get parameters my ( $program, $username ) = @_; # get all processes for this program and the username @processes = `ps -u $username | grep $program | grep -v "grep"`; # get all lines count $running_instances = 0; if ( $#processes >= 0 ) { $running_instances = $#processes + 1; } else { return 0; } return $running_instances; }
Please note also the adoption of literals instead of variables: for example
return 0; instead of return $running_instances wherethe latter has been already initialized to zero.
3.5 All Pieces Together
Now, putting the places together made the main loop as simple as:
$RUNNING_INSTANCES = getRunningInstancesCount($BASE_NAME, $USERNAME); print "\nYou're running $RUNNING_INSTANCES $BASE_NAME\n"; # if the user can, launch the program if ( $RUNNING_INSTANCES < $ALLOWED_INSTANCES ) { print "\nExecuting $PROGRAM..."; launch($PROGRAM); print "\nBye!\n"; } else { print "\nYou can't run no more instances of $PROGRAM"; print "\nBye\n"; displayMessage(); }
4 Lesson Learned
There is no lesson to learn here, but a lot of lessons learned in the between.
The only thing I could say is that you should never, never, throw away your code. Keep it, it is cheap, and someday you could
see how you progressed from a green programmer to the very guru developer you probably are today.
The only thing I could say is that you should never, never, throw away your code. Keep it, it is cheap, and someday you could
see how you progressed from a green programmer to the very guru developer you probably are today.
domenica 5 febbraio 2017
Don't write your own template engine!
We all have done it at least one time: we designed our very-own sucking not-scalable template engine!
I remember when I was a young stupid developer, during my very first job as a contractor, I had to extract some data out of a database (not relational!) and to produce a well formatted PDF letter.
At that time my knowledge was really tiny, but luckily I had in my bag of tools both Perl and LaTeX, so I decided to use both of them (and by the way it was years before OpenOffice too).
As I said I was young, and therefore as pretty much every "green" developer does, I refused to search for and reuse some production ready module or extension (Template Toolkit, just to name it), considering myself enough smarter to develop each required functionality by myself.
So I started developing a Perl engine able to read an INI-like file format: I was extracting data out of the database and placing each record as a set of sections into the file, with special sections used to control the engine itself. Having to deal with text, why not using Perl?
Having done the above, the second phase consisted of producing LaTeX compatible output and run a controlled process to compile the output and produce the result. Again, Perl could do of course the job.
And you can see a recurring error here: as I was not using an engine template on the "reading" side (parsing my very own INI-like file format), I was not using it in the "writing" side too (outputting each single LaTeX command one by one).
So far, so bad, I had a fully working system in less than two days (thank you Perl for regexp!), and my boss was happy with that, the check was in the incoming mail, and I was enough happy too.
I have to confess that the script resulted in around 500+ lines, due also to the fact I was not using "short" comparison operators as I do today (thank you '?:'), and of course maintaining the script was a really pain.
Anyway, I learnt the lesson and since those days I never started developing my very own template engine unless really forced to.
A few years after I had enough experience to recognize the very same error I did in code provided by other developers, and this let me thought that the problem was a cultural one. I cannot say if it is due to impatience or a lack in the preparation of young developers, I tend to balme the latter most since, having worked a few years in the academic field, I had seen too less time spent explaining the importance of a language ecosystem (thank you CPAN!).
domenica 20 novembre 2016
Movie-like film reader/printer based on Perl 5
Again I found myself inspired by a blogs.perl.org post that demonstrate how to let a computer print stuff as it was reasoning on what it was printing, that is a movie-like message reader. In other words, a king of char-by-char cay(1) implementation. So, how difficult could it be to do it in Perl 5?
And here it is my solution:
#!/usr/bin/perl
use v5.10;
use Time::HiRes qw( usleep );
open my $fh, $ARGV[0] || die "\nCannot open input file\n$!";
$/ = \1; # set one char at time (input record separator)
$| = 1; # force autoflush
while ( <$fh> ){
print;
usleep( ( /[a-zA-Z]/ ? 1 : ( /[.!?\n]/ ? 10 : 2 ) ) * 75000 );
}
As you can imagine it is pretty simple: it does read an input file one char at a time, placing it into the topic variable ($_) and printing it on the screen (using autoflush, of course). Then I wait for a quite random time depending on the fact the char was a letter or something else. In this way I can simulate someone is really writing down the message, stopping after a dot or anew line.
I have to use millisecs sleep in order to make it usable at all, since perl func sleep accepts only integers, and printing a message one second at time is a little dummy!
sabato 12 novembre 2016
Hangman in Perl 5: a simple example
Inspired by an article on blogs.perl.org I decided to write down a small version of the hangman game using Perl 5.
It was interesting and quite nice.
Here it is my version, with an eye on italian words (wovels marked as '+' on the guessing line), find it only on GitHub.
#!/usr/bin/env perl
use v5.10;
use Term::ReadKey;
my $word;
# search for a word
open my $word_fh, '<', '/usr/share/dict/words' || die "\nCannot read words!\n$!\n";
srand;
rand( $. ) < 1 && ( $word = lc( ( split( /[\s']/, $_ ) )[ 0 ] ) ) while( <$word_fh> );
close $word_fh;
# wovels converted to +
my ( %guess_status ) = map { $_ , ( /[aeiouèéòà ùì]/ ? '+' : '_' ) } ( split // , $word );
my $current_guessing = '';
my $max_trials = 10;
my @wrong_chars = ();
ReadMode 3; # allow for signals
# while there are undiscovered chars or other trials to do, go for it!
while( grep( /[+_]/, values %guess_status ) && $max_trials > 0 ){
# build the guessing line
$current_guessing = join ' ' , map { $guess_status{ $_ } } ( split // , $word );
say "\n\n|| $current_guessing ||\t" . join( ',', @wrong_chars );
say "guess a char: ";
my $current_char = lc ReadKey( 0 );
if ( ! $guess_status{ $current_char } ){
# not guessed
$max_trials--;
push @wrong_chars, $current_char;
say "No [$current_char] in the word, you still have $max_trials trials.";
}
else{
say "You guessed right [$current_char]!";
$guess_status{ $current_char } = $current_char;
}
}
say "You guessed [$word] !\n" if ( $max_trials > 0 );
say "Sorry, the word you were looking for was [$word]\n" if ( ! $max_trials );
ReadMode 0;
First of all, I read in a random word from a words file, using a quite well know "read-radom-line" approach (at least it is well documented in the Perl community, see ). Since the dictionary could contain multiple words per line, I cut them taking only the first one of them and excluding also shortings, and of course making the whole result lower case for ease of comparison. In other words something like "Bud's" become simply "bud", something like "Smooth words" become simply "smooth" and so on.
The selected word is split into its chars and each char is mapped either to a '+' or a '_'. The result is placed into an hash indexed by the plain char itself, so that the word 'hello' results in an hash as follows:
h => '_',
e => '+',
l => '_',
l => '_',
o => '+',
}
(of course the hash is not sorted on the keys, and that does not matter).
Now the main loop: unless no more '+' or '_' are present in the hash, meaning that the user has guessed all occuriences of all chars, the user is prompted with the guessing line and asked for a char. I use Term::ReadKey for getting a single char, that is of course lowered and compared against the hash keys. If the current char is a key for the hash, the character is discovered and the guessing line re-prompted with the right character in the right place(s), otherwise the character is appended to an array of missed chars and the loop continues.
Each time the user inputs a wrong char a counter is decreased to allow the game to stop in a fixed number of missed trials.
There is of course a lot of room for improvements: for instance the guessing line does not need to be updated each time, but only when the user guesses a char. Therefore a little different version of the main loop becomes as follows:
while( $current_guessing =~ /[+_]/ && $max_trials > 0 ){
say "\n\n|| $current_guessing ||\t" . join( ',', @wrong_chars );
say "guess a char: ";
my $current_char = lc ReadKey( 0 );
if ( ! $guess_status{ $current_char } ){
# not guessed
$max_trials--;
push @wrong_chars, $current_char;
say "No [$current_char] in the word, you still have $max_trials trials.";
}
else{
say "You guessed right [$current_char]!";
$guess_status{ $current_char } = $current_char;
# build the guessing line
$current_guessing = join ' ' , map { $guess_status{ $_ } } ( split // , $word );
}
}
where the guessing line is updated only when a good character is inserted. Having the guessing line built before the main loop allows me for searching directly for undiscovered chars in the line itself, instead of among the values of the hash (so avoiding a grep() applied to a values() ).
And in the case you are wondering why I don't compare the guessin line against the word to guess in the while condition, well, it is because I like to print the guessing line with spaces between letters to be guessed.
Hope it can be useful as simple base Perl program for someone!
venerdì 28 ottobre 2016
From File::Find to File::Find::Rule
I tend to use
File::Find the most in order to get some file searching and mangling.
Usually my scripts have the same simple structure as follows:$| = 1; # autoflush find( \&directory_scanner, ( $starting_directory ) ); $| = 0; # non autoflush # and the scanner is something like sub directory_scanner{ chomp; return if ( $_ eq $starting_directory || ! -f $_ ); return if ( $File::Find::dir !~ /$re_dir(\d{4}-\d{6})$/ ); ... }
As you can see the event handler invoked by
File::Find is used to both print some report (the $counter)
in order to tell me the script is still alive (I do pass 200+k files at once) but, most notably, applies a regexp
to the directory I'm in in order to avoid some staging/backup/etc. directory that could be likely the one I'm interested
into but I don't want the script to pass.
For a few times I've tried to convert my
Find::File based scripts to File::Find::Rule, just to get more used with such
interface, but I didn't know how to fix the application of regular expression to the traversing path. Reading a little more
deeply the documentation I found the exec subroutine that allows me to specify an handler (i.e., a subroutine) that can
return true or false depending on what I want to do on the file I'm visiting.
Therefore, converting my scripts becomes as easy as follows:
$| = 1; my $engine = File::Find::Rule->new(); my @files = $engine->file() ->exec( sub { my ( $shortname, $path, $fullname ) = @_; return $path !~ /$re_dir(\d{4}-\d{6})$/; } ) ->exec( sub{ my ( $shortname, $path, $fullname ) = @_; $counter++; return $shortname =~ /KCL/; } ) ->exec( sub{ my ( $shortname, $path, $fullname ) = @_; print "." if ( $counter % 100 == 0 ); print "$counter\n" if ( $counter % 1000 == 0 ); return 1; # do not forget ! } ) ->in( $starting_directory ); $| = 0;
I've kept three different handlers for readibility sake, but as you can
image, it is possible to shrink them down into a single one.
The funny part here is that I can check the path against a regexp again.
The drawback is that an handler used for output reporting only must
return always a true value.
In the case you are wondering, the autoflush is used simply to display the dots while the program is running.
Etichette:
perl,
planet-perl-ironman,
programmazione
giovedì 25 agosto 2016
Perl Magazine: Cultured Perl
A news from perlsphere.net: CulturedPerl community collaborative blog has been launched!
The idea is really interesting: have a nice online magazine about Perl.
I'm not a Perl expert, at least not enough to be a writer/author for such pubblication, but I will surely read on it.
sabato 23 maggio 2015
CPAN PR Challenge: May done!
In order to recover from the April failure, I decided to do my May assignment as quick as possible.
And just a few days after I was on Mouse I placed a Pull Request:
As you can see I'm still doing more a clean-up refactoring, and this allows me to improve my Perl skills and learn about the module I'm working on. By the way, I tried also to fix up an official issue.
Etichette:
cpan-pr-challenge,
perl,
planet-perl-ironman
venerdì 22 maggio 2015
CPAN PR Challenge: April skipped!
I totally missed the April assignment.
I was assigned to Net::Pcap, that was definetively too much complex for my skills.
And besides, I did not have even time to study it in deep.
Sorry guys.
Etichette:
cpan-pr-challenge,
perl,
planet-perl-ironman
martedì 24 febbraio 2015
2015 CPAN Pull Request: February pending
My February assignment was not a piece of cake: I got MyCPAN::Indexer, a module by the great brain d foy, yes the author of so many Perl Books, the launcher of the Perl Mongers, and...you know, pretty much a lot of the Perl world.
Ok, what chance could I have to comment and improve the code of brian?
It does not matter, I did my homework at my very best.
The first step was to understand what the module was doing, and I have to say that the documentation did not helped me a lot. Then I had to try the module by myself in order to see when and how to make it working. And it took me a while to understand what should I do.
Please note that the module is by itself what brian calls a modulino, so a module that can be invoked also as a standalone application.
The code layout is...well, let me call strange. It is something I will not use, and something my Emacs refuses to use quite well, so this made changes a little more difficult. However, I limited myself to change the documentation and fix a few dependencies (optionals), as well as compressing a branch. Nothing really interesting, some monkey patching, but hey, it was a little too hard for me to do in a single month!
But I'm really happy, even if at the time of writing my patch has not yet been merged, and even if it will never be. It has been a great opportunity to be forced to learn from a real Perl guru!
Iscriviti a:
Post (Atom)
