“There is more than one way to do it” is Perl’s famous motto. And as you start programming in Perl you begin to see both how brilliant and how dangerous that is. Luckily, there’s a tool to help you write better and safer code: perlcritic.

Perl is extremely flexible and it lets you do a lot of stuff. Also, the Perl5-Porters, the team that manages the new versions of Perl, work very hard to keep compatibility with older versions (as long as it makes sense). If you know what you’re doing, these two facts will probably fit you perfectly. However, if you’re a bit inexperienced in the type of code you are writing, or you just don’t know about some of Perl’s hidden features, or you are using old code published on the Internet, you might find yourself with some vulnerable or suboptimal code without knowing. This is especially important when coding in a team, where there are many people of different levels and knowledge contributing to the same code. In these circumstances, it’s often desirable to determine a set of rules to make sure the code is safe and coherent. Of course, Perl has just the thing for the job.

Perlcritic

If you look up perlcritic on CPAN (Perl’s modules and distributions archive on the Internet) you’ll find the following definition:

perlcritic is a Perl source code analyzer. It is the executable front-end to the Perl::Critic engine, which attempts to identify awkward, hard to read, error-prone, or unconventional constructs in your code.

So what does it mean and how can it help you? This basically states that perlcritic is a tool that uses a Perl module to analyse your code and tell you if there’s something you should be doing differently. The rules that the analyser uses are based on Damian Conway’s book Perl Best Practices, but this set of rules can be easily modified by removing or adding some of your own.

Let’s see it in action. Consider the following code:

#!/usr/bin/perl use v5.22; my $first = "42"; my $second = "314"; my $multiplication = $first * $second; say "$first times $second is $multiplication";

This code is working as expected and, if executed, prints 42 times 314 is 13188 . However, if we analyse it with perlcritic we get the following:

~$ perlcritic mult.pl [TestingAndDebugging::RequireUseWarnings] Code before warnings are enabled at mult.pl line 4, near 'my $first = "42";'

We forgot to add to the code the use warnings; pragma that enables warnings in dangerous or confusing situations in your code. This is, of course, a very simple example, but it shows how easy it is to use perlcritic by default and how it can help in finding slips and potentially problematic code.

Consider now some legacy code (or some old Internet site) that uses the unsafe two-argument open function. There’s a specific policy in perlcritic to detect this behaviour so you can change it before it bites you:

[InputOutput::ProhibitTwoArgOpen] Two-argument "open" used at read-file.pl line 8, near 'open my $fh, ">$filename"'

By using perlcritic in your team’s codebase you can detect this before it goes to production, ensuring that your code will be safer, no matter who wrote it. In other words, it helps you stablish and implement your team’s standards of quality.

Creating a profile

By default, perlcritic applies a set of valid and important rules. However, you might want to tweak that behaviour to fit your organisation better. As announced, perlcritic allows you to create a set of rules that makes sense for you and your team. To do so, you only need to create a .perlcriticrc file, set it in your home directory and perlcritic will use it. Let’s see an example:

color = 1 only = 1 verbose = [%p] %m at %f line %l, near '%r'

severity = 2 color-severity-highest = bold red color-severity-high = yellow color-severity-medium = bold blue color-severity-low = blue color-severity-lowest = magenta # ----------------- # - Core policies - # ----------------- # Always use strict [TestingAndDebugging::RequireUseStrict] severity = 5 # Some modules enable strict automatically, so no need to enforce it equivalent_modules = Moo Moose Moo::Role Moose::Role strictures common::sense # Use of 'no strict' is forbidden [TestingAndDebugging::ProhibitNoStrict] [TestingAndDebugging::RequireUseWarnings] severity = 5 # Some modules enable warnings utomatically, so no need to enforce it equivalent_modules = Moo Moose Moo::Role Moose::Role strictures # Use of 'no warnings' is forbidden [TestingAndDebugging::ProhibitNoWarnings] # No bareword filehandles [InputOutput::ProhibitBarewordFileHandles] # Always use three arg open and check the result [InputOutput::ProhibitTwoArgOpen] severity = 5 [InputOutput::RequireCheckedOpen] # --------------------------------- # - 'Avoid human errors' policies - # --------------------------------- # Don't use the comma operator as a statement separator [ValuesAndExpressions::ProhibitCommaSeparatedStatements] # Allow map and grep blocks to return lists. allow_last_statement_to_be_comma_separated_in_map_and_grep = 0 # It is unsafe to call: require "string" # It is wrong to call: eval "string" [BuiltinFunctions::ProhibitStringyEval] [BuiltinFunctions::ProhibitStringySplit] severity = 3 # To avoid confusion if labeled blocks are used [ControlStructures::ProhibitLabelsWithSpecialBlockNames] # Do not put in production testing code with 'exit' or 'die' statements in the middle [ControlStructures::ProhibitUnreachableCode]

In this example profile we have two sections:

General configuration : basically the output format.

: basically the output format. The rules: separated for easy reading and with comments. If you take the name of the rule (for example, InputOutput::ProhibitBarewordFileHandles) and look it up in CPAN you can find more documentation about what does it mean. You can also decide the level of criticity of every rule according to what matters to you the most.

Some things in the example might not make sense for your situation. For example, in an experienced team the prohibition to use no strict might be limiting. But if you don’t know the consequences, it’s a good idea to have it there.

Perl::Critic

As mentioned before, perlcritic is a command line tool that works as an interface to Perl::Critic, the module that does all the work. And, since it’s a module like any other, you can use it directly too like so:

#!/usr/bin/perl use v5.22; use strict; use warnings; use Perl::Critic; my $file = shift; my $critic = Perl::Critic->new(); my @violations = $critic->critique($file); say @violations;

If we take the previous example and pass it as a parameter to this script we get:

Two-argument "open" used at line 5, column 1. See page 207 of PBP.

With this method, it’s easy to integrate the code analysis in your test suite.

Installing perlcritic

Perlcritic comes with a package in most distributions/OS:

libperl-critic-perl in Debian and Ubuntu

in Debian and Ubuntu perl-Perl-Critic in CentOS, Fedora and RHEL

in CentOS, Fedora and RHEL PerlCritic in ActiveState

If you’d rather use the module version, then you just need to install the Perl::Critic module with your method of choice (cpan, cpanm, carton, etc).

Alternatives to perlcritic

Perlcritic is widely used among the Perl community, but it’s not the only tool available for this purpose. Two newer alternatives are Perl::Lint and B::Lint:

Perl::Lint: a source code linter for Perl that “aims to create a fast and flexible static analyser for Perl5 that has compatibility with Perl::Critic”.

B::Lint: described as an “equivalent to an extended version of the -w option of Perl” generates warnings when it detects several dangerous or ambiguous situations. It, too, can be extended with plugins.

Conclusion

As your code base and your team grow, the possibility of inadvertently generating bugs increases too. Having a basic perlcritic profile used by all the coders will help avoid future headaches and security breaches. It’s easy to set up, can be easily customised and can teach you about Perl features you were unaware of. It’s a good practice worth taking the time to set up to produce better and safer code.

CAPSiDE builds on the back of open source software, especially Perl, and have always been willing to give back to the community. We participate in Perl conferences and workshops, either presenting, sponsoring, attending, etc and contribute with the Perl SDK for AWS and Azure. If you’re interested in working with Perl, don’t forget to write Hermes!

TAGS: Perl, Perl best practices, perl source code analiser, Perlcritic