Communitygithub.com

padrões-perl

Padrões modernos, boas práticas e convenções do Perl 5.36+ para construir aplicações robustas e de fácil manutenção. Use ao escrever ou revisar código Perl 5.36+ moderno.

O que é padrões-perl?

Esta habilidade fornece um guia abrangente de padrões e práticas recomendadas para desenvolvimento moderno em Perl 5.36+. Ela cobre desde a configuração inicial com o pragma `use v5.36`, que substitui boilerplate legado, até o uso de assinaturas de sub-rotina, desreferenciação pós-fixa, operador `isa`, tratamento de erros com `eval/die` e módulos como Try::Tiny, e orientação a objetos moderna com Moo e a palavra-chave nativa `class`. A habilidade também aborda expressões regulares com capturas nomeadas, estruturas de dados e slices, E/S de arquivo segura com Path::Tiny, organização de módulos e ferramentas como perltidy, perlcritic e gerenciamento de dependências com cpanfile e Carton. É especialmente útil para desenvolvedores que estão escrevendo novo código Perl, revisando código existente para conformidade com idiomas modernos, refatorando código legado ou projetando a arquitetura de módulos Perl. A habilidade enfatiza a clareza, legibilidade e segurança, desencorajando anti-padrões como open de dois argumentos, sintaxe de objeto indireta e uso de `eval` em strings.

Funciona com~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/perl-patterns

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Padrões Modernos de Desenvolvimento Perl

Padrões idiomáticos do Perl 5.36+ e melhores práticas para construir aplicações robustas e de fácil manutenção.

Quando Ativar

  • Escrevendo novo código ou módulos Perl
  • Revisando código Perl para conformidade com idiomas
  • Refatorando código Perl legado para padrões modernos
  • Projetando arquitetura de módulos Perl
  • Migrando código pré-5.36 para Perl moderno

Como Funciona

Aplique estes padrões como uma preferência para os padrões modernos do Perl 5.36+: assinaturas, módulos explícitos, tratamento de erros focado e limites testáveis. Os exemplos abaixo devem ser copiados como pontos de partida e, em seguida, ajustados para o aplicativo real, a pilha de dependências e o modelo de implantação à sua frente.

Princípios Fundamentais

1. Use o Pragma v5.36

Um único use v5.36 substitui o antigo boilerplate e ativa strict, warnings e assinaturas de sub-rotinas.

# Bom: Preâmbulo moderno
use v5.36;

sub greet($name) {
    say "Hello, $name!";
}

# Ruim: Boilerplate legado
use strict;
use warnings;
use feature 'say', 'signatures';
no warnings 'experimental::signatures';

sub greet {
    my ($name) = @_;
    say "Hello, $name!";
}

2. Assinaturas de Sub-rotinas

Use assinaturas para clareza e verificação automática de aridade.

use v5.36;

# Bom: Assinaturas com valores padrão
sub connect_db($host, $port = 5432, $timeout = 30) {
    # $host é obrigatório, outros têm padrões
    return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, {
        RaiseError => 1,
        PrintError => 0,
    });
}

# Bom: Parâmetro "slurpy" para argumentos variáveis
sub log_message($level, @details) {
    say "[$level] " . join(' ', @details);
}

# Ruim: Desempacotamento manual de argumentos
sub connect_db {
    my ($host, $port, $timeout) = @_;
    $port    //= 5432;
    $timeout //= 30;
    # ...
}

3. Sensibilidade a Contexto

Entenda o contexto escalar vs. lista — um conceito central do Perl.

use v5.36;

my @items = (1, 2, 3, 4, 5);

my @copy  = @items;            # Contexto de lista: todos os elementos
my $count = @items;            # Contexto escalar: contagem (5)
say "Items: " . scalar @items; # Força contexto escalar

4. Desreferenciação Pós-fixa

Use a sintaxe de desreferenciação pós-fixa para legibilidade com estruturas aninhadas.

use v5.36;

my $data = {
    users => [
        { name => 'Alice', roles => ['admin', 'user'] },
        { name => 'Bob',   roles => ['user'] },
    ],
};

# Bom: Desreferenciação pós-fixa
my @users = $data->{users}->@*;
my @roles = $data->{users}[0]{roles}->@*;
my %first = $data->{users}[0]->%*;

# Ruim: Desreferenciação circunflexa (mais difícil de ler em cadeias)
my @users = @{ $data->{users} };
my @roles = @{ $data->{users}[0]{roles} };

5. O Operador isa (5.32+)

Verificação de tipo infixa — substitui blessed($o) && $o->isa('X').

use v5.36;
if ($obj isa 'My::Class') { $obj->do_something }

Tratamento de Erros

Padrão eval/die

use v5.36;

sub parse_config($path) {
    my $content = eval { path($path)->slurp_utf8 };
    die "Config error: $@" if $@;
    return decode_json($content);
}

Try::Tiny (Tratamento de Exceções Confiável)

use v5.36;
use Try::Tiny;

sub fetch_user($id) {
    my $user = try {
        $db->resultset('User')->find($id)
            // die "User $id not found\n";
    }
    catch {
        warn "Failed to fetch user $id: $_";
        undef;
    };
    return $user;
}

try/catch Nativo (5.40+)

use v5.40;

sub divide($x, $y) {
    try {
        die "Division by zero" if $y == 0;
        return $x / $y;
    }
    catch ($e) {
        warn "Error: $e";
        return;
    }
}

OO Moderno com Moo

Prefira Moo para OO moderno e leve. Use Moose apenas quando seu metaprotocolo for necessário.

# Bom: Classe Moo
package User;
use Moo;
use Types::Standard qw(Str Int ArrayRef);
use namespace::autoclean;

has name  => (is => 'ro', isa => Str, required => 1);
has email => (is => 'ro', isa => Str, required => 1);
has age   => (is => 'ro', isa => Int, default  => sub { 0 });
has roles => (is => 'ro', isa => ArrayRef[Str], default => sub { [] });

sub is_admin($self) {
    return grep { $_ eq 'admin' } $self->roles->@*;
}

sub greet($self) {
    return "Hello, I'm " . $self->name;
}

1;

# Uso
my $user = User->new(
    name  => 'Alice',
    email => '[email protected]',
    roles => ['admin', 'user'],
);

# Ruim: Hashref abençoado (sem validação, sem accessors)
package User;
sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}
sub name { return $_[0]->{name} }
1;

Roles com Moo

package Role::Serializable;
use Moo::Role;
use JSON::MaybeXS qw(encode_json);
requires 'TO_HASH';
sub to_json($self) { encode_json($self->TO_HASH) }
1;

package User;
use Moo;
with 'Role::Serializable';
has name  => (is => 'ro', required => 1);
has email => (is => 'ro', required => 1);
sub TO_HASH($self) { { name => $self->name, email => $self->email } }
1;

Palavra-chave Nativa class (5.38+, Corinna)

use v5.38;
use feature 'class';
no warnings 'experimental::class';

class Point {
    field $x :param;
    field $y :param;
    method magnitude() { sqrt($x**2 + $y**2) }
}

my $p = Point->new(x => 3, y => 4);
say $p->magnitude;  # 5

Expressões Regulares

Capturas Nomeadas e Flag /x

use v5.36;

# Bom: Capturas nomeadas com /x para legibilidade
my $log_re = qr{
    ^ (?<timestamp> \d{4}-\d{2}-\d{2} \s \d{2}:\d{2}:\d{2} )
    \s+ \[ (?<level> \w+ ) \]
    \s+ (?<message> .+ ) $
}x;

if ($line =~ $log_re) {
    say "Time: $+{timestamp}, Level: $+{level}";
    say "Message: $+{message}";
}

# Ruim: Capturas posicionais (difícil de manter)
if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$/) {
    say "Time: $1, Level: $2";
}

Padrões Pré-compilados

use v5.36;

# Bom: Compila uma vez, usa várias vezes
my $email_re = qr/^[A-Za-z0-9._%+-]+\@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/;

sub validate_emails(@emails) {
    return grep { $_ =~ $email_re } @emails;
}

Estruturas de Dados

Referências e Acesso Profundo Seguro

use v5.36;

# Referências de hash e array
my $config = {
    database => {
        host => 'localhost',
        port => 5432,
        options => ['utf8', 'sslmode=require'],
    },
};

# Acesso profundo seguro (retorna undef se qualquer nível faltar)
my $port = $config->{database}{port};           # 5432
my $missing = $config->{cache}{host};           # undef, sem erro

# Fatiamento de hash
my %subset;
@subset{qw(host port)} = @{$config->{database}}{qw(host port)};

# Fatiamento de array
my @first_two = $config->{database}{options}->@[0, 1];

# Loop for com múltiplas variáveis (experimental em 5.36, estável em 5.40)
use feature 'for_list';
no warnings 'experimental::for_list';
for my ($key, $val) (%$config) {
    say "$key => $val";
}

E/S de Arquivo

Open de Três Argumentos

use v5.36;

# Bom: Open de três argumentos com autodie (módulo central, elimina 'or die')
use autodie;

sub read_file($path) {
    open my $fh, '<:encoding(UTF-8)', $path;
    local $/;
    my $content = <$fh>;
    close $fh;
    return $content;
}

# Ruim: Open de dois argumentos (risco de injeção de shell, veja perl-security)
open FH, $path;            # NUNCA faça isso
open FH, "< $path";        # Ainda ruim — dados do usuário na string de modo

Path::Tiny para Operações com Arquivos

use v5.36;
use Path::Tiny;

my $file = path('config', 'app.json');
my $content = $file->slurp_utf8;
$file->spew_utf8($new_content);

# Iterar diretório
for my $child (path('src')->children(qr/\.pl$/)) {
    say $child->basename;
}

Organização de Módulos

Layout Padrão de Projeto

MyApp/
├── lib/
│   └── MyApp/
│       ├── App.pm           # Módulo principal
│       ├── Config.pm        # Configuração
│       ├── DB.pm            # Camada de banco de dados
│       └── Util.pm          # Utilitários
├── bin/
│   └── myapp                # Script de entrada
├── t/
│   ├── 00-load.t            # Testes de compilação
│   ├── unit/                # Testes unitários
│   └── integration/         # Testes de integração
├── cpanfile                 # Dependências
├── Makefile.PL              # Sistema de construção
└── .perlcriticrc            # Configuração de linting

Padrões de Exportação

package MyApp::Util;
use v5.36;
use Exporter 'import';

our @EXPORT_OK   = qw(trim);
our %EXPORT_TAGS = (all => \@EXPORT_OK);

sub trim($str) { $str =~ s/^\s+|\s+$//gr }

1;

Ferramentas

Configuração do perltidy (.perltidyrc)

-i=4        # Indentação de 4 espaços
-l=100      # Comprimento de linha de 100 caracteres
-ci=4       # Indentação de continuação
-ce         # "cuddled else"
-bar        # Chave de abertura na mesma linha
-nolq       # Não recuar strings longas entre aspas

Configuração do perlcritic (.perlcriticrc)

severity = 3
theme = core + pbp + security

[InputOutput::RequireCheckedSyscalls]
functions = :builtins
exclude_functions = say print

[Subroutines::ProhibitExplicitReturnUndef]
severity = 4

[ValuesAndExpressions::ProhibitMagicNumbers]
allowed_values = 0 1 2 -1

Gerenciamento de Dependências (cpanfile + Carton)

cpanm App::cpanminus Carton   # Instalar ferramentas
carton install                 # Instalar deps do cpanfile
carton exec -- perl bin/myapp  # Executar com deps locais
# cpanfile
requires 'Moo', '>= 2.005';
requires 'Path::Tiny';
requires 'JSON::MaybeXS';
requires 'Try::Tiny';

on test => sub {
    requires 'Test2::V0';
    requires 'Test::MockModule';
};

Referência Rápida: Idiomas Modernos do Perl

Padrão LegadoSubstituição Moderna
use strict; use warnings;use v5.36;
my ($x, $y) = @_;sub foo($x, $y) { ... }
@{ $ref }$ref->@*
%{ $ref }$ref->%*
open FH, "< $file"open my $fh, '<:encoding(UTF-8)', $file
hashref abençoadoClasse Moo com tipos
$1, $2, $3$+{name} (capturas nomeadas)
eval { }; if ($@)Try::Tiny ou try/catch nativo (5.40+)
BEGIN { require Exporter; }use Exporter 'import';
Operações manuais de arquivoPath::Tiny
blessed($o) && $o->isa('X')$o isa 'X' (5.32+)
builtin::true / falseuse builtin 'true', 'false'; (5.36+, experimental)

Anti-padrões

# 1. Open de dois argumentos (risco de segurança)
open FH, $filename;                     # NUNCA

# 2. Sintaxe de objeto indireto (análise ambígua)
my $obj = new Foo(bar => 1);            # Ruim
my $obj = Foo->new(bar => 1);           # Bom

# 3. Dependência excessiva em $_
map { process($_) } grep { validate($_) } @items;  # Difícil de acompanhar
my @valid = grep { validate($_) } @items;           # Melhor: quebrar em etapas
my @results = map { process($_) } @valid;

# 4. Desabilitar strict refs
no strict 'refs';                        # Quase sempre errado
${"My::Package::$var"} = $value;         # Use um hash em vez disso

# 5. Variáveis globais como configuração
our $TIMEOUT = 30;                       # Ruim: global mutável
use constant TIMEOUT => 30;              # Melhor: constante
# Melhor: atributo Moo com valor padrão

# 6. String eval para carregamento de módulos
eval "require $module";                  # Ruim: risco de injeção de código
eval "use $module";                      # Ruim
use Module::Runtime 'require_module';    # Bom: carregamento seguro de módulos
require_module($module);

Lembre-se: Perl moderno é limpo, legível e seguro. Deixe use v5.36 cuidar do boilerplate, use Moo para objetos e prefira os módulos testados pela batalha do CPAN em vez de soluções artesanais.

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

Habilidades Relacionadas