Skip to main content

perl-patterns

Modern Perl 5.36+ idioms, best practices, and conventions for building robust, maintainable Perl applications.

Datos de origen

Repositorio
Jamkris/everything-gemini-code
Última actividad en el origen
8 de abril de 2026 a las 01:05
Idioma detectado de SKILL.md
inglés
Estrellas
91
Forks
23

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
perl-patterns
description
Modern Perl 5.36+ idioms, best practices, and conventions for building robust, maintainable Perl applications.
origin
ECC
# Modern Perl Development Patterns Idiomatic Perl 5.36+ patterns and best practices for building robust, maintainable applications. ## When to Use - Writing new Perl code or modules - Reviewing Perl code for idiom compliance - Refactoring legacy Perl to modern standards - Designing Perl module architecture - Migrating pre-5.36 code to modern Perl ## How It Works Apply these patterns as a bias toward modern Perl 5.36+ defaults: signatures, explicit modules, focused error handling, and testable boundaries. The examples below are meant to be copied as starting points, then tightened for the actual app, dependency stack, and deployment model in front of you. ## Core Principles ### 1. Use `v5.36` Pragma A single `use v5.36` replaces the old boilerplate and enables strict, warnings, and subroutine signatures. ```perl # Good: Modern preamble use v5.36; sub greet($name) { say "Hello, $name!"; } # Bad: Legacy boilerplate use strict; use warnings; use feature 'say', 'signatures'; no warnings 'experimental::signatures'; sub greet { my ($name) = @_; say "Hello, $name!"; } ``` ### 2. Subroutine Signatures Use signatures for clarity and automatic arity checking. ```perl use v5.36; # Good: Signatures with defaults sub connect_db($host, $port = 5432, $timeout = 30) { # $host is required, others have defaults return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, { RaiseError => 1, PrintError => 0, }); } # Good: Slurpy parameter for variable args sub log_message($level, @details) { say "[$level] " . join(' ', @details); } # Bad: Manual argument unpacking sub connect_db { my ($host, $port, $timeout) = @_; $port //= 5432; $timeout //= 30; # ... } ``` ### 3. Context Sensitivity Understand scalar vs list context — a core Perl concept. ```perl use v5.36; my @items = (1, 2, 3, 4, 5); my @copy = @items; # List context: all elements my $count = @items; # Scalar context: count (5) say "Items: " . scalar @items; # Force scalar context ``` ### 4. Postfix Dereferencing Use postfix dereference syntax for readability with nested structures. ```perl use v5.36; my $data = { users => [ { name => 'Alice', roles => ['admin', 'user'] }, { name => 'Bob', roles => ['user'] }, ], }; # Good: Postfix dereferencing my @users = $data->{users}->@*; my @roles = $data->{users}[0]{roles}->@*; my %first = $data->{users}[0]->%*; # Bad: Circumfix dereferencing (harder to read in chains) my @users = @{ $data->{users} }; my @roles = @{ $data->{users}[0]{roles} }; ``` ### 5. The `isa` Operator (5.32+) Infix type-check — replaces `blessed($o) && $o->isa('X')`. ```perl use v5.36; if ($obj isa 'My::Class') { $obj->do_something } ``` ## Error Handling ### eval/die Pattern ```perl use v5.36; sub parse_config($path) { my $content = eval { path($path)->slurp_utf8 }; die "Config error: $@" if $@; return decode_json($content); } ``` ### Try::Tiny (Reliable Exception Handling) ```perl 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; } ``` ### Native try/catch (5.40+) ```perl use v5.40; sub divide($x, $y) { try { die "Division by zero" if $y == 0; return $x / $y; } catch ($e) { warn "Error: $e"; return; } } ``` ## Modern OO with Moo Prefer Moo for lightweight, modern OO. Use Moose only when its metaprotocol is needed. ```perl # Good: Moo class 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; # Usage my $user = User->new( name => 'Alice', email => 'alice@example.com', roles => ['admin', 'user'], ); # Bad: Blessed hashref (no validation, no accessors) package User; sub new { my ($class, %args) = @_; return bless \%args, $class; } sub name { return $_[0]->{name} } 1; ``` ### Moo Roles ```perl 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; ``` ### Native `class` Keyword (5.38+, Corinna) ```perl 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 ``` ## Regular Expressions ### Named Captures and `/x` Flag ```perl use v5.36; # Good: Named captures with /x for readability 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}"; } # Bad: Positional captures (hard to maintain) if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$/) { say "Time: $1, Level: $2"; } ``` ### Precompiled Patterns ```perl use v5.36; # Good: Compile once, use many 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; } ``` ## Data Structures ### References and Safe Deep Access ```perl use v5.36; # Hash and array references my $config = { database => { host => 'localhost', port => 5432, options => ['utf8', 'sslmode=require'], }, }; # Safe deep access (returns undef if any level missing) my $port = $config->{database}{port}; # 5432 my $missing = $config->{cache}{host}; # undef, no error # Hash slices my %subset; @subset{qw(host port)} = @{$config->{database}}{qw(host port)}; # Array slices my @first_two = $config->{database}{options}->@[0, 1]; # Multi-variable for loop (experimental in 5.36, stable in 5.40) use feature 'for_list'; no warnings 'experimental::for_list'; for my ($key, $val) (%$config) { say "$key => $val"; } ``` ## File I/O ### Three-Argument Open ```perl use v5.36; # Good: Three-arg open with autodie (core module, eliminates 'or die') use autodie; sub read_file($path) { open my $fh, '<:encoding(UTF-8)', $path; local $/; my $content = <$fh>; close $fh; return $content; } # Bad: Two-arg open (shell injection risk, see perl-security) open FH, $path; # NEVER do this open FH, "< $path"; # Still bad — user data in mode string ``` ### Path::Tiny for File Operations ```perl use v5.36; use Path::Tiny; my $file = path('config', 'app.json'); my $content = $file->slurp_utf8; $file->spew_utf8($new_content); # Iterate directory for my $child (path('src')->children(qr/\.pl$/)) { say $child->basename; } ``` ## Module Organization ### Standard Project Layout ```text MyApp/ ├── lib/ │ └── MyApp/ │ ├── App.pm # Main module │ ├── Config.pm # Configuration │ ├── DB.pm # Database layer │ └── Util.pm # Utilities ├── bin/ │ └── myapp # Entry-point script ├── t/ │ ├── 00-load.t # Compilation tests │ ├── unit/ # Unit tests │ └── integration/ # Integration tests ├── cpanfile # Dependencies ├── Makefile.PL # Build system └── .perlcriticrc # Linting config ``` ### Exporter Patterns ```perl 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; ``` ## Tooling ### perltidy Configuration (.perltidyrc) ```text -i=4 # 4-space indent -l=100 # 100-char line length -ci=4 # continuation indent -ce # cuddled else -bar # opening brace on same line -nolq # don't outdent long quoted strings ``` ### perlcritic Configuration (.perlcriticrc) ```ini severity = 3 theme = core + pbp + security [InputOutput::RequireCheckedSyscalls] functions = :builtins exclude_functions = say print
Ver en GitHub
Este SKILL.md es muy grande, por eso SkillsMP muestra aqui solo la primera seccion. Ver en GitHub