Categories
Mojolicious Perl Test::Most

BeastBB, my new project to build a Bulletin Board like webpage using Mojolicious.

https://gitea.sergiotarxz.freemyip.com/sergiotarxz/BeastBB

Just to improve with Mojolicious as Perl web developer I started a few weeks ago a project called BeastBB which I want to be just another Bulletin Board webpage.

In this project I am learning a lot about Mojo::Pg, for example I learned how to test it using DBD::Mock, and also learned to use SQL::Abstract::Pg which makes querying simple things or inserts/updates less overhead.

Also in the development of this project I found how to avoid a nasty error which required my Makefile.PL to run the install target two times before the templates being correctly installed.

I also achieved .config/beastbb/ config file installation which is great because mades the installation project dir agnostic, you can run cpanm . –installdeps && cpanm . -v and then delete the project dir and the webpage will work anyway. The database migrations files also get installed automatically and if new migrations are found after an upgrade they will be run without the need to do it manually.

I created an object called BeastBB::Response which is used to control controllable errors, you typically would use it like this:

my $response = FunctionThatMayFail();
return $self->reply->exception('Function failed because the data is wrong with message ' . $response->ErrorMessage)->rendered(400) if $response->IsError;
my $data = $response->Content;
doThings($data);

The BeastBB::Response code is something like this:

package BeastBB::Response;

use 5.32.1;

use strict;
use warnings;

use Carp qw/confess cluck/;

use Params::ValidationCompiler 'validation_for';
use Types::Standard qw/Bool Str Any/;

{
    my $validator = validation_for(
        params => {
            is_error      => { type => Bool, default  => 0 },
            content       => { type => Any,  optional => 1 },
            error_message => { type => Str,  optional => 1 },
        }
    );

    sub new {
        my $class    = shift;
        my %params   = $validator->(@_);
        my $is_error = $params{is_error};
        my $content;
        my $error_message;

        if ( exists $params{content} ) {
            $content = $params{content};
        }
        if ( exists $params{error_message} ) {
            $error_message = $params{error_message};
        }

        if ($is_error) {
            cluck 'Error should not have content, stripping it.'
              if defined $content;
            cluck 'You should pass a error message on error.'
              if !defined $error_message;
            return bless {
                is_error      => 1,
                error_message => $error_message // '',
            }, $class;
        }
        return bless { content => $content }, $class;
    }
}

sub IsError {
    my $self = shift;
    return $self->{is_error};
}

sub ErrorMessage {
    my $self = shift;
    if ( !$self->IsError ) {
        confess 'This is not an error.';
    }
    return $self->{error_message};
}

sub Content {
    my $self = shift;
    if ( $self->IsError ) {
        confess 'Attempt to get content from error.';
    }
    return $self->{content};
}
1;

I trying to test most I do, but the 100% coverage is still a challenge because testing controllers is hard and sometimes I am to lazy to test too trivial things:

I didn’t achieve yet to split the Mock objects from the real code, I suppose more Mock objects will be needed to avoid to do large objects constructions in most tests like the ones needed to build a User which is a object which takes many parameters.

Params::ValidationCompiler is making my live easier than it was with Params::Validate allowing me to define my own types like matrix_address or asking for a concrete class.

I made a class with a few utility types to reuse them everywhere called BeastBB::Types:

package BeastBB::Types;

use 5.30.3;

use strict;
use warnings;

use Exporter qw/import/;
use Scalar::Util qw/blessed/;
use Type::Tiny;

use Const::Fast;

our @EXPORT_OK = ( '&IsClassTypeGenerator', '$MATRIX_ADDRESS_REGEX', '$MATRIX_ADDRESS_TYPE' );

const our $MATRIX_ADDRESS_REGEX => qr/^@\w+:(\w|\.)+\.(\w+)$/;


const our $MATRIX_ADDRESS_TYPE => Type::Tiny->new(
    name => "MatrixAddressChecker",
    constraint => sub {
        my $matrix_address = shift;
        return 1 if $matrix_address =~ /$MATRIX_ADDRESS_REGEX/;
    }
);

my %generated_classes;

sub IsClassTypeGenerator {
    my $class = shift;
    if ( !exists $generated_classes{$class} ) {
        my $sanitized_class = $class =~ s/:://gr;
        $generated_classes{$class} = Type::Tiny->new(
            name => "Is$sanitized_class",
            constraint => sub {
                my $item_to_test = shift;
                return 1 if blessed $item_to_test && $item_to_test->isa($class);
                return 0;
            },
        );
    }
    return $generated_classes{$class};
}
1;

It’s being really fun to build BeastBB with Perl thanks to all the libraries I can use, in my cpanfile you can find all those:

requires 'Mojolicious';
requires 'Mojo::Pg';
requires 'ExtUtils::MakeMaker';
requires 'Crypt::URandom';
requires 'DBD::Pg';
requires 'DBD::Mock';
requires 'Const::Fast';
requires 'Params::ValidationCompiler';
requires 'Types::Standard';
requires 'Crypt::Bcrypt::Easy';
requires 'DateTime';
requires 'DateTime::Format::Pg';
requires 'Test::Most';
requires 'Test::MockModule';
requires 'Test::Warnings';

They may not seem to be too much, but they give me the capabilities of their dependencies like does Mojo::Pg with SQL::Abstract::Pg.

Using Perl to build a web is a fun exercise with Mojolicious.

Categories
notest Perl PHP

Creating reproducible tests in pull requests so reviewers can know the code is properly working when your codebase lacks unit tests.

Everyone who has worked before with unit testing will know that pull request based testing is highly inefficient on the sense tests are going to be lost once the pull request is approved. But meanwhile automated testing is implemented in a legacy project code has still to be done to implement new features or bugfixes.

That is where the guideline I am going to expose has it’s niche, trying to get the job done while preserving a sane behaviour in the code.

This guide assumes a web based project, some parts may have to be adapted on discrection for other use cases.

General Guidelines.

  • Avoid high level instructions that can be written as commands.

It is usually the best to avoid saying the reviewers to do something that they may have to investigate when you can write some fancy command that does it. Example:

Bad example:

“Block the black haired users from having a avatar.”

Good example:

“Execute the following sql query to block the black haired users from having a avatar.”

update set avatar_blocked=1 from users where hair = 'black';

Other bad example:

Remove lines from 500-550 from lib/Users/BlockAvatar.php since they attempt to connect to a external ftp and are going to generate an error and set $got_external_csv to 0.

Good example:

Remove lines from 500-550 from lib/Users/BlockAvatar.php since they attempt to connect to a external ftp and are going to generate an error with this command and set $got_external_csv to 0:

perl <( cat << 'EOF'
use 5.30.0;
my $i = 0;
while (<>) {
    $i++; 
    next if $i >= 500 && $i <= 550;
    say << 'END_OF_SAY' if $i == 551;
        # Temporal fix to avoid ftp connections in testing.
        $got_external_csv = 0;
END_OF_SAY
    print;
}
EOF
) lib/Users/BlockAvatar.php > block_avatar_tmp.php
cp block_avatar_tmp.php lib/Users/BlockAvatar.php
rm block_avatar_tmp.php
  • Avoid to write a database query as a bash command and write the query directly so everyone can use whatever database client they find more comfortable with.

Bad example:

echo 'select * from users' | mysql

Good example:

select * from users;
  • Avoid to write operations in the webpage that users are supposed to do as bash commands and instead send the reviewers to do those operations unless it is really needed.

This is mainly because two reasons, if you bindly copy as Posix Curl a Firefox request you have chances to collide against csfr tokens or leak your authentication cookies, not a good deal, also you have chances that if you broke something in frontend in your changes it gets unnoticed in the pull request.

Bad example:

“Delete the Luffy user”

curl -X DELETE www.myweb.com/api/user/luffy

Good example:

Go to https://www.myweb.com/admin/manage_user?user=luffy and press delete this user.

  • Include screenshots of GUI steps if possible indicating where should be reviewer interact with the webpage and how.

Those screenshots should not be an alternative against text description but a complement to avoid blind reviewer discrimination, it should be a help for people with visual minds, not a diversity killer.

Categories
Perl XS

More refactor to our XS module. Bringing the internals to a private C file.

In this article the code I did in the last article to allow the usage of the arguments list as a Hash is going to be moved to a C file to provide a way to reuse this code in all my subroutines of this module without exposing this API to Perl. (In Perl this job is already done.)

Let’s see how, first we are going to make the following directories into mega_openssl_helper_xs src and src/include and we are going to add to the Makefile.PL of mega_openssl_helper_xs an OBJECT and postamble directive so it gets the code into that folders.

use ExtUtils::MakeMaker;

WriteMakefile(
    NAME    => 'Peertube::DL::Mega::Helper',
    VERSION => '0.1',
    XS      => { 'mega.xs' => 'mega.o' },
    INC     => '-Isrc/include',
    OBJECT  => 'src/private.o mega.o',
    LDFLAGS => '-Wl-t',
    DIR     => ['src'],
);  
        
package MY {
            
    sub postamble {
        return . "src: src/Makefile\n" . "\tcd src && $(MAKE) $(PASSTHRU)\n";
    }       
} 

Now we are making a mega_openssl_helper_xs/src/Makefile.PL to compile the C that I am going to put into that directory:

use ExtUtils::MakeMaker;

WriteMakefile(
    NAME    => 'Peertube::DL::Mega::Helper::SRC',
    VERSION => '0.1',
    INC     => '-I./include',
    C       => [ 'private.c', ],
    OBJECT  => '${O_FILES}',
    LDFLAGS => '-Wl-t',
);

We make the src/include/private.h file to declare the subroutines for code reuse:

#include "EXTERN.h"
#include "perl.h"

HV * hash_from_list(SV **, size_t list_len);

And we move the code handling the hashes to this subroutine into src/private.c

#include "EXTERN.h"
#include "perl.h"

HV * hash_from_list(SV **list, size_t list_len) {
    HV * hash = newHV();
    bool is_key = true;
    char *key;
    STRLEN key_len;
    for ( int i = 0; i < list_len; i++ ) {
        if (is_key) {
            key = SvPV(list[i], key_len);
        } else {
            SvREFCNT_inc(list[i]);
            if ( !hv_store(hash, key, key_len, list[i], 0) ) {
                warn("Failed to write into hash.");
                SvREFCNT_dec(list[i]);
            }
        }
        is_key = !is_key;
    }
    if ( !is_key ) {
        warn("Even number of parameters in hash argument list.");
        SV *undef = sv_newmortal();
        SvREFCNT_inc(undef);
        if ( !hv_store(hash, key, key_len, sv_newmortal(), 0) ) {
            warn("Failed to write into hash.");
            SvREFCNT_dec(undef);
        }
    } 
    return hash;
}

Now our mega.xs print XSUB is more compact:

void
print(self, ...)
    Peertube_DL_Mega_Helper self 
    CODE:
        if ( items <= 1 ) {
            croak("Less parameters than expected.");
        }
        size_t list_len = items - 1;
        SV **list = malloc(sizeof (SV *) * list_len);
        for ( int i = 1; i < items; i++ ) {
            list[i-1] = ST(i);
        }

        HV *hash = hash_from_list(list, list_len);        
        free(list);
        char *key = "hello";
        SV **hello = hv_fetch(hash, key, strlen(key), 0);
        if ( hello != NULL && *hello != NULL ) {
            if ( !SvOK(*hello) ) {
                warn("hello is undef.");
            }
            printf("hello: %s\n", SvPV_nolen(*hello));
        } else {
            croak("Parameter hello required.");
        }

I hope you have enjoy this article about XS.

Erratas: sizeof was unfortunatelly not enought to get the size of the array, so I did it passing the size manually to the subroutine which sightly complicates the code.

Erratas II: I left some printf statements not needed.

Erratas III: I left a stdio.h import in the C file which was no longer needed, I used it with debugging purposes.

Categories
Perl XS

Playing more with XS: Retrieving subroutine arguments as a hash.

It’s common to use the argument list as a hash in Perl to provide a easier way for the Perl developers interface with subroutines, in this article I will explain how to do the same in XS. Note: not as easy as in Perl.

First we will change the signature like this to take variadic arguments:

void
print(self, ...)
    Peertube_DL_Mega_Helper self
CODE:

As you may now self is the caller object in Perl, not too much trouble, and … is saying basically “Pass me whatever and I will handle it.”, Peertube_DL_Mega_Helper is a custom typemap made by me in the last XS article.

Now we are going to check if users passed us more than a value, for example:

if ( item <= 1 ) {
    croak("Less parameters than expected.");
}

This is a little agresive way to handle this suppose, but this is a demo, feel free to take whatever behaviour you feel more appropiate for your case use.

Now we are going to define a hash to hold our arguments:

HV *hash = newHV();

And some variables useful in the argument processing loop:

bool is_key = true;
char *key;
STRLEN key_len;

And we define the loop to introduce those arguments into a our hash:

for ( int i = 1; i < items; i++ ) {
    if (is_key) {
        key = SvPV(ST(i), key_len);
    } else {    
        SvREFCNT_inc(ST(i));
        if ( !hv_store(hash, key, key_len, ST(i), 0) ) {
            SvREFCNT_dec(ST(i));
        }
    }
    is_key = !is_key;
}

Unfortunatelly this loop misses warning the developer if a even number of elements is passed with default to the last element without value to be undef, we are going to implement also that:

if ( !is_key ) { 
    warn("Even number of parameters in hash argument list.");
    SV *undef = sv_newmortal();
    SvREFCNT_inc(undef);
    if ( !hv_store(hash, key, key_len, sv_newmortal(), 0) ) {
        SvREFCNT_dec(undef);
    }
}

Croak is also an option, but this introduces how to add undefs and I thought would be educative to handle that case as Perl does™

Now we are going to use what we just did to search for the named parameter “hello”, let’s see how:

// Reusing the variable since the name is really convenient and descriptive.
key = "hello"; 
SV **hello = hv_fetch(hash, key, strlen(key), 0);
if ( hello != NULL && *hello != NULL ) {
    if ( !SvOK(*hello) ) {
        warn("hello is undef.");
    }
    printf("hello: %s\n", SvPV_nolen(*hello));
} else {
    croak("Parameter hello required.");
}

After compiling with cpanm . -v to catch errors we are going to run the usual oneliners to check the capabilities we added, I may do an article of testing in Perl later, now I am just learning XS.

sergio@tiki ~/Peertube-dl $ perl -MPeertube::DL::Mega::Helper -e 'Peertube::DL::Mega::Helper->new(3)->print("hello" => "world")';
hello: world
sergio@tiki ~/Peertube-dl $ perl -MPeertube::DL::Mega::Helper -e 'Peertube::DL::Mega::Helper->new(3)->print';
Less parameters than expected. at -e line 1.
sergio@tiki ~/Peertube-dl $ perl -MPeertube::DL::Mega::Helper -e 'Peertube::DL::Mega::Helper->new(3)->print("hello" => "world", "hello" => )';
Even number of parameters in hash argument list. at -e line 1.
hello is undef. at -e line 1.
hello: 

I hope you enjoyed the article.

Categories
Perl

Why Perl is my favourite programming language in 2021?

Perl started it’s development in 1987 before the born of the Linux kernel and gained popularity as a web development language for CGI scripting during the 90s since then many developers have categorized the language as a write only language, but I think this opinions are deprecated with the today features of modern Perl plus the expressiveness Perl have been given to it’s developers since it’s starting.

Perl has three important types of variables, each of one features a sigil which must be before any representation of that variable.

$ features a Scalar variable, a variable which can hold only a element.

@ features an Array variable, a variable that holds a list of elements.

% features a Hash variable, a variable that holds a map of String to Scalar without order.

This differentiation plus the usage of “use strict;’ makes the development of Perl easier since many complex data type errors can be caught on compile time.

Perl is a dynamic typed programming language as Python or Javascript, so you can assign a Scalar variable any value like a String, a Number, Undef (Perl has no null.) or a Reference to a more complex type of variable.

By default Perl interprets that if you are passing a Array or Hash to a Subroutine what you want is passing the contents of this structure as the parameters of the Subroutine which makes some constructs longer in some programming languages to be written without hastle.

Let’s put it in a example:

use strict;
use warnings;

use feature 'say';

sub ExampleSubroutine {
    my ($a, $b, $c) = @_;
    say $a;
    say $b;
    say $c;
}

my @params = ('a', 'b', 'c');
ExampleSubroutine(@params);

The lack of need to specify signatures to subroutines allows a lot of expresiveness also, althought you may use libraries like https://metacpan.org/pod/Params::ValidationCompiler in more complex programs to get a self-documenting interface to your methods and subroutines.

Testing in Perl is also great thanks to great resources from cpan like https://metacpan.org/pod/Test::MockObject, https://metacpan.org/pod/Test::MockModule and https://metacpan.org/pod/Test::Most and the flexibity of Perl on mocking subroutines that allows to test both procedural and OOP in a really easy way no matter there was not test before unlike PHP where mocking it’s limited to object methods.

Tons of the Perl cpan modules are packaged in GNU/Linux distributions so if you want to package your software to work in a GNU/Linux distribution it is not a so difficult task.

Perl also grants its developers a great UTF-8 optionally aware regex engine which helps to parse complex data in a easy manner and it’s the most common way to manipulate Strings in Perl.

The Perl object’s are just blessed references which allows your object to be a Hash (The most common since allows the common key/value internal scheme of an Object.), an Array, an Subroutine (To force encapsulation by having the real attributes in a more restricted scope.)

Perl anonymous subroutines inherit the scope allowing to do some functional programming tricks.

There are great libraries to work with files in Perl like https://metacpan.org/pod/Path::Tiny which allows a near natural language way to manipulate files without having to be so aware about file handles or directory handles as the default. (The default sometimes also plays well in scripts.)

The Perl command line debugger is simply great, allowing to discover bugs in a easy and reproducible way so you can share debugging sessions as plain text with other programmers.

The default variable $_ allows the programmer to not to be having to name a variable that is used in a very limited scope before stopping being useful.

The for syntax is really cool $object->doSomething for my $object (@objects) or it’s anonymous counterpart $_->doSomething for (@objects)

It’s not always needed to put parents on subroutine calls allowing the developer to type less when the scope is clear.

It is also great the “There is more than a way to do it” philosophy behind the language, allowing you to choose the best way to do for your problem.

When we talk about optimization we should first know for what we want to optimize like Speed, CPU, Memory Usage or code Legibility it’s not uncommon you have to trade one to have the other, for example a complex and extensive data structure can be stored in disk to save memory but accesing it will harm Speed, CPU usage and Legibility by increasing the latency because disk reads, increasing the CPU usage because the aditional cycles to retrieve the data when needed and Legibility by doing the program more complex.

It’s is great a language takes different problems have different needs and adapt itself to the multiple ways to tackle a problem a developer may have.

Categories
Perl XS

Perl niceness, building a XS module that acts like a Perl object.

I have been trying the last days to add Mega.nz support to Peertube-dl, it is not an easy task since Mega.nz implements encryption with AES in the files so the server owner is not able in theory to read the users files. (My opinion is anyway the server admins would be able to get access to those files by simply parsing the server logs.)

I have not success yet, because the lack of good Perl libraries and the bad Perl is for parsing binary data and then I thought, why not try to use XS to solve this problem as I did before with the Javascript interpreter need for Youtube?

So this I am trying, and in the process I did a little improvement in my way to write XS thanks to the learn about how to use typemaps to build more ideomatic for both Perl and C XS modules.

Let’s start the house by the roof, would not be great being able to write a XS module like this:

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include <stdio.h>

typedef struct helper {
    int value;
} * Peertube_DL_Mega_Helper;

MODULE = Peertube::DL::Mega::Helper  PACKAGE = Peertube::DL::Mega::Helper
PROTOTYPES: DISABLE

Peertube_DL_Mega_Helper
new(class, value)
    char *class
    int value
    CODE:
        RETVAL = malloc(sizeof (struct helper));
        RETVAL->value = value;
    OUTPUT:
        RETVAL

void
print(self)
    Peertube_DL_Mega_Helper self
    CODE:
        printf("%d\n", self->value);

void
DESTROY(self)
    Peertube_DL_Mega_Helper self
    CODE:
        free(self);

This code can be achieved with the help of the file typemap, with the help of https://perldoc.perl.org/perlxstypemap I discovered that, and the following typemap will look familiar to anybody which have read that document.

TYPEMAP
    Peertube_DL_Mega_Helper T_PTROBJ_SPECIAL

INPUT
T_PTROBJ_SPECIAL
    if (sv_derived_from($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\")){
        IV tmp = SvIV((SV*)SvRV($arg));
        $var = INT2PTR($type, tmp);
    } else {
        croak(\"$var is not of type ${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\");
    }

OUTPUT
T_PTROBJ_SPECIAL
    sv_setref_pv($arg, \"${(my $ntt=$ntype)=~s/_/::/g;\$ntt}\",
           (void*)$var);

Of course some more additions will be needed to make this code run, like the clasical xsloader Perl module and some lines in the Makefile.PL which is out of scope in this document.

We will be able to run this code like this and check it works:

perl -MPeertube::DL::Mega::Helper -e 'Peertube::DL::Mega::Helper->new(3)->print';

It should print 3.

It is true XS is scaring because strange subroutines and magical variable names and tons of rare sections difficult to understand on the first read of the docs, but this kind of sugar makes my day, it is a shame there aren’t much XS articles and Stackoverflow responses because makes the language slower to learn.

Categories
C Perl XS

If you program in Perl and learn XS is like you have super powers.

Perl has a big amount of modules available, but sometimes you need a library from C, in my case that library was Duktape to embed a JS interpreter in my application to be able to use a scrapped function from the Youtube video player to implement download videos with obfuscated signatures in Peertube-dl.

XS allows you to embed C libraries in Perl, this opens the door to many applications from writting programs using GTK to fast a critical in performance subroutine, tons of CPAN modules use it to extend the Perl’s capabilities.

The main resources to learn XS are: https://perldoc.perl.org/perlxs and https://perldoc.perl.org/perlguts.

This is how a very basic XS Perl module look:

#define PERL_NO_GET_CONTEXT
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#include "duktape.h"
#include "duk_config.h"
#include "javascript_builtins.h"

MODULE = Peertube::DL::Javascript  PACKAGE = Peertube::DL::Javascript
PROTOTYPES: ENABLE

SV *
_duk_create_heap_default()
    CODE:
        duk_context *context = duk_create_heap_default();
        if (context) {
            duk_push_c_function(context, js_builtin_print, 1);
            duk_put_global_string(context, "print");
            RETVAL = newSVuv((size_t)context);
        } else {
            RETVAL = &PL_sv_undef;
        }
    OUTPUT:
        RETVAL

This is how the loader Perl module would look:

package Peertube::DL::Javascript;

use strict;
use warnings;

use feature 'say';

use XSLoader;
use Data::Dumper;

XSLoader::load();

sub new {
    my $class = shift;
    my $self  = bless {}, $class;
    $self->{___ContextPrivateDONOTTOUCH} =
      Peertube::DL::Javascript::_duk_create_heap_default();
    return $self;
}

You can check for a complete example on the source of Peertube-dl: https://gitea.sergiotarxz.freemyip.com/sergiotarxz/Peertube-dl

Categories
Javascript Perl

Doing common things for Perl developers on Javascript (II)

From Perl to Javascript relearning.

Perl allows us to bless any reference into any being an object of any class, this is not a good practice always, but can become handy on corner cases, here is how is done in Perl:

sub bless_into_class {
    my $class = shift;
    bless {}, $class;
}
my $object = bless_into_class( 'MY::Class' );

And the JS equivalent:

function create_object_of_class(input_class) {
    return Object.create(input_class.prototype);
}
let new_object = create_object_of_class(my_class);

Categories
Perl

Perl Programming language and the “You are in your own” feeling.

The “You are in your own” phrase comes from the Archlinux initramfs, when you mess the booting it drops you to a rescue shell and gives you that phrase.

The feeling I describe is when you must solve something with little or none help.

When I first started programming Perl because I thought it would be the better language to make a web based mail client I did not know it would become the language which gave me my first job nor my favourite language.

But I fast knew a thing, searching fast responses on StackOverflow using DuckDuckGo or other search engine was not a trivial task.

It was not the community fault, simply there are less developers doing Perl than Javascript or other mainstream programming language.

I tried to do something to solve that situation and I joined StackOverflow to bring my questions and found answers, but that is other story…

Thanks I became used to this situation I got better reading proper documentation like Metacpan or Perldoc and the code of the involved library on my error or “don’t know how to do this”.

But I think it is a experience which can make some developer to forget trying to use Perl as the proper tool to do something if they can not longer develop as they are used to. (No more snippet copy from StackOverflow.)

I think every developer will or have got in one of those situations, but in Perl is more frecuent than in other languages.

I think as a community Perl developers as me should think what we can do today to improve the Perl learning curve.

That is all.

Categories
Javascript Perl

Doing common things for Perl developers on Javascript (I)

From Perl to Javascript relearning.

It is common in Perl using an array as the arguments of a function, this is the useful default behaviour on Perl and I found myself not being able to do it so I searched it and I found how to do it.

This is the Perl code I wanted to emulate.

use strict;
use warnings;

use feature 'say';

sub a {
    my ($arg1, $arg2) = @_;
    say "$arg1 $arg2";
}

my @a = ('arg1', 'arg2');
a(@a);

And this is the equivalent Javascript code using .apply a prototype function for implementors of Function class.

"use strict";

function a(a, b) {
    console.log(`${a} ${b}`);
}

let a_array = [ 'arg1', 'arg2' ];

// The first argument is null because it sends the value of this.
// If you are doing this to a object it probably should be different
a.apply(null, a_array);