Communitygithub.com

perl-patterns

Moderne Perl 5.36+ Idiome, Best Practices und Konventionen zum Bau robuster, wartbarer Perl-Anwendungen. Verwenden Sie dies beim Schreiben oder Überprüfen modernen Perl 5.36+ Codes.

Was ist perl-patterns?

Diese Fähigkeit bietet eine umfassende Referenz zu modernen Perl-Entwicklungsmustern, die auf Version 5.36 und höher ausgerichtet sind. Sie behandelt Kernprinzipien wie das `use v5.36`-Pragma, Subroutinensignaturen, Postfix-Dereferenzierung und den `isa`-Operator. Darüber hinaus werden Fehlerbehandlung mit `eval/die`, `Try::Tiny` und nativem `try/catch`, moderne objektorientierte Programmierung mit Moo und der nativen `class`-Syntax, reguläre Ausdrücke mit benannten Captures, Datei-I/O mit drei Argumenten und `Path::Tiny` sowie Modulorganisation und Werkzeuge wie `perltidy` und `perlcritic` abgedeckt. Die Fähigkeit ist ideal, um neuen Perl-Code zu schreiben, vorhandenen Code zu überprüfen oder Legacy-Code auf moderne Standards zu migrieren. Sie basiert auf der SKILL.md-Dokumentation, die sowohl als Leitfaden als auch als Kopiervorlage dient, um konsistente, sichere und wartbare Perl-Anwendungen zu erstellen.

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

In Ihrer bevorzugten KI fragen

Öffnet einen neuen Chat, in dem dieser Agent-Skill bereits geladen ist.

Dokumentation

Moderne Perl-Entwicklungsmuster

Idiomatische Perl 5.36+ Muster und Best Practices für den Bau robuster, wartbarer Anwendungen.

Wann zu aktivieren

  • Schreiben von neuem Perl-Code oder neuen Modulen
  • Überprüfen von Perl-Code auf Einhaltung von Idiomen
  • Refaktorieren von Legacy-Perl auf moderne Standards
  • Entwerfen von Perl-Modularchitekturen
  • Migrieren von Code vor 5.36 zu modernem Perl

Wie es funktioniert

Wenden Sie diese Muster als Tendenz zu modernen Perl 5.36+ Standardeinstellungen an: Signaturen, explizite Module, fokussierte Fehlerbehandlung und testbare Grenzen. Die Beispiele unten sollen als Ausgangspunkte kopiert und dann für die tatsächliche Anwendung, den Abhängigkeits-Stack und das Bereitstellungsmodell vor Ihnen angepasst werden.

Kernprinzipien

1. Verwenden Sie das v5.36 Pragma

Ein einzelnes use v5.36 ersetzt den alten Boilerplate-Code und aktiviert strict, warnings und Subroutinensignaturen.

# Gut: Moderne Präambel
use v5.36;

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

# Schlecht: Legacy-Boilerplate
use strict;
use warnings;
use feature 'say', 'signatures';
no warnings 'experimental::signatures';

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

2. Subroutinensignaturen

Verwenden Sie Signaturen für Klarheit und automatische Überprüfung der Argumentanzahl.

use v5.36;

# Gut: Signaturen mit Standardwerten
sub connect_db($host, $port = 5432, $timeout = 30) {
    # $host ist erforderlich, andere haben Standardwerte
    return DBI->connect("dbi:Pg:host=$host;port=$port", undef, undef, {
        RaiseError => 1,
        PrintError => 0,
    });
}

# Gut: Aufnehmender Parameter für variable Argumente
sub log_message($level, @details) {
    say "[$level] " . join(' ', @details);
}

# Schlecht: Manuelles Entpacken der Argumente
sub connect_db {
    my ($host, $port, $timeout) = @_;
    $port    //= 5432;
    $timeout //= 30;
    # ...
}

3. Kontextsensitivität

Verstehen Sie skalaren vs. Listenkontext – ein zentrales Perl-Konzept.

use v5.36;

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

my @copy  = @items;            # Listenkontext: alle Elemente
my $count = @items;            # Skalarer Kontext: Anzahl (5)
say "Elemente: " . scalar @items; # Skalaren Kontext erzwingen

4. Postfix-Dereferenzierung

Verwenden Sie die Postfix-Dereferenzierungssyntax für Lesbarkeit bei verschachtelten Strukturen.

use v5.36;

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

# Gut: Postfix-Dereferenzierung
my @users = $data->{users}->@*;
my @roles = $data->{users}[0]{roles}->@*;
my %first = $data->{users}[0]->%*;

# Schlecht: Circumfix-Dereferenzierung (schwerer lesbar in Ketten)
my @users = @{ $data->{users} };
my @roles = @{ $data->{users}[0]{roles} };

5. Der isa Operator (5.32+)

Infix-Typüberprüfung – ersetzt blessed($o) && $o->isa('X').

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

Fehlerbehandlung

eval/die Muster

use v5.36;

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

Try::Tiny (Zuverlässige Ausnahmebehandlung)

use v5.36;
use Try::Tiny;

sub fetch_user($id) {
    my $user = try {
        $db->resultset('User')->find($id)
            // die "Benutzer $id nicht gefunden\n";
    }
    catch {
        warn "Fehler beim Abrufen von Benutzer $id: $_";
        undef;
    };
    return $user;
}

Nativer try/catch (5.40+)

use v5.40;

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

Modernes OO mit Moo

Bevorzugen Sie Moo für leichtgewichtiges, modernes OO. Verwenden Sie Moose nur, wenn sein Metaprotokoll benötigt wird.

# Gut: Moo-Klasse
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 "Hallo, ich bin " . $self->name;
}

1;

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

# Schlecht: Blessed Hashref (keine Validierung, keine Accessoren)
package User;
sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}
sub name { return $_[0]->{name} }
1;

Moo Rollen

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;

Nativer class Schlüsselwort (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

Reguläre Ausdrücke

Benannte Captures und /x Flag

use v5.36;

# Gut: Benannte Captures mit /x für Lesbarkeit
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 "Zeit: $+{timestamp}, Level: $+{level}";
    say "Nachricht: $+{message}";
}

# Schlecht: Positions-Captures (schwer zu warten)
if ($line =~ /^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+\[(\w+)\]\s+(.+)$/) {
    say "Zeit: $1, Level: $2";
}

Vorkompilierte Muster

use v5.36;

# Gut: Einmal kompilieren, mehrfach verwenden
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;
}

Datenstrukturen

Referenzen und sicherer tiefer Zugriff

use v5.36;

# Hash- und Array-Referenzen
my $config = {
    database => {
        host => 'localhost',
        port => 5432,
        options => ['utf8', 'sslmode=require'],
    },
};

# Sicherer tiefer Zugriff (gibt undef zurück, wenn eine Ebene fehlt)
my $port = $config->{database}{port};           # 5432
my $missing = $config->{cache}{host};           # undef, kein Fehler

# Hash-Slices
my %subset;
@subset{qw(host port)} = @{$config->{database}}{qw(host port)};

# Array-Slices
my @first_two = $config->{database}{options}->@[0, 1];

# Multi-Variablen for-Schleife (experimentell in 5.36, stabil in 5.40)
use feature 'for_list';
no warnings 'experimental::for_list';
for my ($key, $val) (%$config) {
    say "$key => $val";
}

Datei-I/O

Drei-Argumente open

use v5.36;

# Gut: Drei-Arg open mit autodie (Kernmodul, eliminiert 'or die')
use autodie;

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

# Schlecht: Zwei-Arg open (Shell-Injection-Risiko, siehe perl-security)
open FH, $path;            # NIEMALS so machen
open FH, "< $path";        # Immer noch schlecht – Benutzerdaten im Modus-String

Path::Tiny für Dateioperationen

use v5.36;
use Path::Tiny;

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

# Verzeichnis durchlaufen
for my $child (path('src')->children(qr/\.pl$/)) {
    say $child->basename;
}

Modulorganisation

Standard-Projektstruktur

MyApp/
├── lib/
│   └── MyApp/
│       ├── App.pm           # Hauptmodul
│       ├── Config.pm        # Konfiguration
│       ├── DB.pm            # Datenbankschicht
│       └── Util.pm          # Hilfsprogramme
├── bin/
│   └── myapp                # Einstiegsskript
├── t/
│   ├── 00-load.t            # Kompilierungstests
│   ├── unit/                # Unit-Tests
│   └── integration/         # Integrationstests
├── cpanfile                 # Abhängigkeiten
├── Makefile.PL              # Build-System
└── .perlcriticrc            # Lint-Konfiguration

Exporter-Muster

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;

Werkzeuge

perltidy Konfiguration (.perltidyrc)

-i=4        # 4 Leerzeichen Einzug
-l=100      # 100 Zeichen Zeilenlänge
-ci=4       # Fortsetzungseinzug
-ce         # Geschweifte Klammer bei else
-bar        # Öffnende Klammer in derselben Zeile
-nolq       # Lange quoted Strings nicht ausrücken

perlcritic Konfiguration (.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

Abhängigkeitsverwaltung (cpanfile + carton)

cpanm App::cpanminus Carton   # Werkzeuge installieren
carton install                 # Abhängigkeiten aus cpanfile installieren
carton exec -- perl bin/myapp  # Mit lokalen Abhängigkeiten ausführen
# cpanfile
requires 'Moo', '>= 2.005';
requires 'Path::Tiny';
requires 'JSON::MaybeXS';
requires 'Try::Tiny';

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

Kurzreferenz: Moderne Perl-Idiome

Legacy-MusterModerne Ersetzung
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
blessed hashrefMoo-Klasse mit Typen
$1, $2, $3$+{name} (benannte Captures)
eval { }; if ($@)Try::Tiny oder nativer try/catch (5.40+)
BEGIN { require Exporter; }use Exporter 'import';
Manuelle DateioperationenPath::Tiny
blessed($o) && $o->isa('X')$o isa 'X' (5.32+)
builtin::true / falseuse builtin 'true', 'false'; (5.36+, experimentell)

Anti-Patterns

# 1. Zwei-Argumente open (Sicherheitsrisiko)
open FH, $filename;                     # NIEMALS

# 2. Indirekte Objektsyntax (mehrdeutige Analyse)
my $obj = new Foo(bar => 1);            # Schlecht
my $obj = Foo->new(bar => 1);           # Gut

# 3. Übermäßiges Vertrauen auf $_
map { process($_) } grep { validate($_) } @items;  # Schwer zu folgen
my @valid = grep { validate($_) } @items;           # Besser: aufteilen
my @results = map { process($_) } @valid;

# 4. Deaktivieren von strict refs
no strict 'refs';                        # Fast immer falsch
${"My::Package::$var"} = $value;         # Stattdessen einen Hash verwenden

# 5. Globale Variablen als Konfiguration
our $TIMEOUT = 30;                       # Schlecht: veränderbare Globale
use constant TIMEOUT => 30;              # Besser: Konstante
# Am besten: Moo-Attribut mit Standardwert

# 6. String eval zum Laden von Modulen
eval "require $module";                  # Schlecht: Code-Injektionsrisiko
eval "use $module";                      # Schlecht
use Module::Runtime 'require_module';    # Gut: sicheres Modulladen
require_module($module);

Denken Sie daran: Modernes Perl ist sauber, lesbar und sicher. Lassen Sie use v5.36 den Boilerplate-Code übernehmen, verwenden Sie Moo für Objekte und bevorzugen Sie die kampferprobten Module von CPAN gegenüber handgestrickten Lösungen.

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.

Verwandte Skills