📦 Procedural Perl Packages Done Right: Mastering $RealBin and Export Tags

Date Created: 2025-03-30
By: 16BitMiker
[ BACK.. ]

🧩 Introduction

Perl stands out as a language that comfortably supports procedural programming, even as modern trends lean toward object-oriented paradigms. For utility scripts, quick tooling, and modular command-line programs, procedural Perl remains clean, fast, and easy to reason about.

In this post, we’ll walk through how to create and use custom procedural Perl packages in a structured project. We'll highlight a particularly useful trick: how to use FindBin’s $RealBin to reliably locate your project’s lib/ directory even when running scripts from a nested pl/ directory. We'll also explore Perl’s Exporter module and how to use tags like :all to manage what your modules expose.

📁 Directory Layout

Let’s assume this simple but common directory structure:

Your scripts live in pl/ and must load modules from the top-level lib/ directory—not from a non-existent pl/lib/.

🔍 The Problem: Finding lib/ from pl/

When a script like pl/file.pl tries to load a module from lib/, Perl needs that path added to @INC, the array of module search paths. But by default, @INC won’t include ../lib unless you explicitly push it.

This is where the FindBin module—and more specifically, $RealBin—comes to the rescue.

🔧 What Is $RealBin?

The FindBin module provides the $RealBin variable, which holds the fully resolved, symlink-free absolute path to the directory where your script is located.

If you execute:

Then $RealBin will equal something like:

If you naively write:

Perl will look for modules in:

But your actual modules live in:

✅ The Trick: Use Regex to Adjust $RealBin

Here’s a clean one-liner that fixes the path:

🔍 Breakdown:

This trick ensures both the current script directory and the top-level lib/ directory are included in @INC—without hardcoding relative paths.

📜 Creating a Procedural Package

Let’s build a simple package in lib/MikerGeneral.pm:

📝 Key Points:

▶️ Using the Module in a Script

Here’s how you’d use this module inside pl/file.pl:

📌 Notes:

🧪 Try It Out

From your project root, run:

You should see:

✅ And no errors about missing modules.

📋 Exporter Tips

Using Exporter effectively helps keep your namespace clean and your modules flexible.

ElementPurpose
@EXPORT_OKList of functions or variables that can be imported
%EXPORT_TAGSNamed groups of exports (e.g., :all, :visual)
use Module qw(:tag)Import all items under a tag defined in %EXPORT_TAGS
use Module qw(func1 func2)Import only the listed functions

Avoid using @EXPORT unless you want to import symbols by default (not recommended for procedural libraries).

🧠 Summary

Here’s what we learned:

📚 Read More

With just a few lines of thoughtful path logic and a clean module structure, you can build powerful procedural Perl systems that scale without the baggage of full-blown object-oriented design. Happy hacking! 🐪💻