Showing posts with label plmotw. Show all posts
Showing posts with label plmotw. Show all posts

Perl Module(s) Of The Week - 2019 Week 02 - Module::CoreList

One of the issue when using Perl is the abundant list of Perl's modules. Finding the right modules can be overwhelming and sometimes frustrating. Duplicating, deprecating, or abandon modules is typical situation for a programming language which is 31 years old. Hence, which recommended Perl's module should you uses then? Start with the modules that came default with the Perl installation, the core list. How? By using the Module::CoreList module.

Installation and quick check of the module.
$ cpanm Module::CoreList
$ perl -e 'use Module::CoreList'

Now, let's write some code (`ex1.pl`) to list out all the core modules that came with Perl 5.29.6.
use strict;
use warnings;
use feature qw|say|;

use Module::CoreList;

say $_ foreach sort @{[Module::CoreList->find_modules(qr/.*/i, 5.029006)]};

Running the code and show the first ten results.
$ perl ex1.pl | head
Amiga::ARexx
Amiga::Exec
AnyDBM_File
App::Cpan
App::Prove
App::Prove::State
App::Prove::State::Result
App::Prove::State::Result::Test
Archive::Tar
Archive::Tar::Constant

So far so good. But do we need to write some code in order to make any query? No, there is a console utility, corelist that will do that. For corresponding command almost similar to our Perl's code before this.
$ corelist -v 5.29.6 | head

The following modules were in perl 5.29.6 CORE
Amiga::ARexx                                 0.04
Amiga::Exec                                  0.02
AnyDBM_File                                  1.01
App::Cpan                                    1.671
App::Prove                                   3.42
App::Prove::State                            3.42
App::Prove::State::Result                    3.42
App::Prove::State::Result::Test              3.42

Now some code reading. What interesting stuff can we learn from reading the source code of Module::CoreList?

(1) All the data, for example, Perl's version, starting from Perl 5 was hard-coded as large hash (see the `%released` hash).

(2) To prevent duplication, the changes (see `delta_from`, `changed`, and `removed` hash) of modules for each Perl version were stored as delta hash (see `%delta` hash).

(3) These use of `@_` pass through from one subroutine to another subroutine as shown below. See the `first_release_raw` subroutine.
sub a { say @_; }
sub b { &a; }
sub c { &a(); }
sub d { a(@_); }
sub e { &a(@_); }

b 1, 2, 3; # 123
c 1, 2, 3; # nothing is printed
d 1, 2, 3; # 123
e 1, 2, 3; # 123

(4) The END block is not a subroutine but a block of code that executed after all codes have been ran and before the Perl interpreter exited.

How about source code from corelist?

(1) *nix piping in Perl. See the example below.
    my @bundles =  map { $_->[0] }
                  sort { $b->[1] <=> $a->[1] }
                   map { [$_, numify_version($_)] }
                  grep { not /[^0-9.]/ }
                  keys %feature::feature_bundle;

Perl Module(s) Of The Week - 2019 Week 01 - Data::Money

Since this item was on my to-do list for quite some time and this is the first week of the new year, might as well proceed ahead and do it. Inspired by Python Module of the Week (PyMOTW), I will start a series of weekly blog posts to review and discuss any interesting Perl module(s) that caught my attention. Write up mostly will be on some code example, issue encounter, and what can we learn from the code, as in code reading.

Our Perl module of this week is Data::Money, which allows us to perform math operations on different currency in an object manner and let us understand how operator overloading works in Perl. Furthermore, this is a good example to showcase the actual implementation of PoEAA's Money class design (there are actual four Money class designs exists), which is a rather simple approach which does not allows multiple currencies operation. Nevertheless, an actual production ready implementation.

Installation and quick check of the module.
$ cpanm Data::Money

It seemed in latest Perl version (v5.28.0), the dependant modules, Locale::Currency and Locale::Codes will be removed from Perl core distribution.
$ perl -e "use Data::Money"
Locale::Currency will be removed from the Perl core distribution in the next major release. 
Please install it from CPAN. It is being used at /usr/local/lib/perl5/site_perl/5.28.0/Data/Money.pm, line 27.
Locale::Codes will be removed from the Perl core distribution in the next major release. 
Please install it from CPAN. It is being used at /usr/local/lib/perl5/5.28.0/Locale/Currency.pm, line 22.

To remove the warnings, we have to install Locale::Currency manually.
$ cpanm Locale::Currency
$ perl -e "use Data::Money"

Let write some code (save as file `ex1.pl`) that create the new Money object or data type. `MYR` is the currency code where `MY` is two digits country code for `MalaYsia` and `R` is the name of the currency, in this case, `Ringgit`.
use strict;
use warnings;
use feature 'say';

use Data::Money;

my $price = Data::Money->new(value => 1.2, code => 'MYR');
say $price->as_string;
say $price->stringify;

Running the code will give us the same result twice. `RM` is the currency symbol that replaced our previous used `$` symbol.
$ perl ex1.pl
RM1.20
RM1.20

Let's look at these two subroutines, `as_string` and `stringify`. First, `as_string` is an alias to `stringify` subroutine. To create an subroutine alias in Perl, we will need to use typeglob (hence, the asterisk notation) to manipulate the Symbol Table, which stores all the variables in a package.
*as_string = \&stringify;

Second, as the name implied, `stringify` is typical subroutine naming convention for stringification in Perl, to convert an object into string or context of string. This is done through `overload` package as shown below, where it's implemented through anonymous subroutine. The subroutine will be invoked whenever the blessed package was called in a string context. You can read this tutorial for a sample working stringification using classical OOP way.
use overload
    '""' => sub { shift->stringify };