NAME

Role - A simple role system for Perl

VERSION

Version v0.1.1

SYNOPSIS

Creating Roles

package Role::Printable;
use Role;

requires 'to_string';  # Classes must implement this

sub print {
    my $self = shift;
    print $self->to_string . "\n";
}

1;

package Role::Serialisable;
use Role;

requires 'serialize', 'deserialize';

sub to_json {
    my $self = shift;
    # ... implementation
}

1;

Using Roles in Classes

package My::Class;
use Class;
with qw/Role::Printable Role::Serialisable/;

sub to_string {
    my $self = shift;
    return "My::Class instance";
}

sub serialize   { ... }
sub deserialize { ... }

1;

Applying Roles at Runtime

package My::Class;
use Class;

# Later, apply roles dynamically
Role::apply_role(__PACKAGE__, 'Role::Printable');

1;

Role Aliasing

package My::Class;
use Class;
use Role::Printable => {
    role  => 'Role::Printable',
    alias => { print => 'display' }
};

# Now use $obj->display() instead of $obj->print()

Role Composition with Exclusions

package Role::A;
use Role;
excludes 'Role::B';  # Cannot be used with Role::B

package Role::B;
use Role;

package My::Class;
use Class;
use Role::A;    # OK
# use Role::B;  # This would die

DESCRIPTION

Role provides a simple, efficient role system for Perl. Roles are reusable units of behavior that can be composed into classes. They support requirements, method conflicts detection, aliasing, and runtime application.

This module is designed to work with any class system but integrates particularly well with Class::More.

FEATURES

Core Features

  • Method Requirements: Roles can declare methods that consuming classes must implement

  • Conflict Detection: Automatic detection of method conflicts between roles

  • Method Aliasing: Rename methods when applying roles to avoid conflicts

  • Role Exclusion: Roles can declare incompatible roles

  • Runtime Application: Apply roles to classes at runtime

  • Basic Attribute Support: Simple attribute storage with accessors

  • Performance Optimized: Method and role caching for better performance

  • Class Method Priority: Class methods silently override role methods

Advanced Features

  • Batch Conflict Detection: Detects conflicts between multiple roles before application

  • Sequential Application: Supports applying roles one at a time with proper conflict checking

  • Inheritance Awareness: Understands method inheritance chains

  • Role Composition Tracking: Tracks which roles are applied to each class

METHODS

Role Definition Methods

These methods are available in packages that use Role.

requires

requires 'method1', 'method2';

Declares that consuming classes must implement the specified methods.

excludes

excludes 'Role::Incompatible', 'Role::Conflicting';

Declares that this role cannot be composed with the specified roles.

has

has 'attribute_name';
has 'attribute_name' => ( default => 'value' );

Defines a simple attribute in the role. Creates a basic accessor method. The attribute specification can include:

  • default - Default value for the attribute

Note: This provides basic attribute storage. For advanced attribute features like type constraints, coercion, or lazy building, use a full-featured class system.

Role Application Methods

with

package My::Class;
use Class;

with 'Role::A', 'Role::B';

# With aliasing
with
    { role => 'Role::A', alias => { method_a => 'new_name' } },
    'Role::B';

Composes roles into a class. Can be called as a class method.

apply_role

Role::apply_role('My::Class', 'Role::Printable');
Role::apply_role($object, 'Role::Serialisable');

Applies a role to a class or object at runtime. Returns true on success.

Query Methods

does

if ($object->does('Role::Printable')) {
    $object->print;
}

Checks if a class or object consumes a specific role.

get_applied_roles

my @roles = Role::get_applied_roles('My::Class');
my @roles = Role::get_applied_roles($object);

Returns the list of roles applied to a class.

is_role

if (Role::is_role('Role::Printable')) {
    # It's a role
}

Checks if a package is a role.

EXAMPLES

Basic Role with Requirements

package Role::Validator;
use Role;

requires 'validate', 'get_errors';

sub is_valid {
    my $self = shift;
    return $self->validate && !@{$self->get_errors};
}

1;

Role with Simple Attributes

package Role::Timestamped;
use Role;

has 'created_at' => ( default => sub { time } );
has 'updated_at' => ( default => sub { time } );

sub update_timestamp {
    my $self = shift;
    $self->updated_at(time);
}

1;

# Usage in class:
package My::Class;
use Class;
with qw/Role::Timestamped/;

sub new {
    my ($class, %args) = @_;
    my $self = bless \%args, $class;
    $self->created_at(time) unless $self->created_at;
    return $self;
}

1;

Role with Aliasing

package My::Class;
use Class;

# Avoid conflict by aliasing
with
    { role => 'Role::Logger', alias => { log => 'file_log' } },
    { role => 'Role::Debug', alias => { log => 'debug_log' } };

sub log {
    my ($self, $message) = @_;
    $self->file_log($message);
    $self->debug_log($message);
}

1;

Runtime Role Application

package PluginSystem;
use Role;

sub load_plugin {
    my ($self, $plugin_role) = @_;

    unless (Role::is_role($plugin_role)) {
        die "$plugin_role is not a role";
    }

    # Apply the plugin role to this instance's class
    Role::apply_role($self, $plugin_role);

    return $self;
}

1;

ATTRIBUTE SUPPORT

The has method in roles provides basic attribute functionality:

  • Creates a simple accessor method

  • Supports default values

  • Stores data in the object hash

However, this is basic attribute support. For advanced attribute features like:

  • Read-only/read-write access control

  • Type constraints

  • Lazy evaluation

  • Triggers and coercion

  • Initialisation hooks

You should use a full-featured class system like Moose, Moo, or Object::Pad and apply roles from those systems instead.

PERFORMANCE

The module includes several performance optimisations:

  • Method origin caching to avoid repeated lookups

  • Role loading caching to prevent redundant requires

  • Precomputed role method lists

  • Skip patterns for common non-method symbols

For best performance, apply roles at compile time when possible.

LIMITATIONS

Known Limitations

  • Basic Attribute Support:

    Only simple attributes with default values are supported. No advanced features like read-only, type constraints, or lazy building.
  • Inheritance Complexity:

    Deep inheritance hierarchies may have unexpected method resolution behavior.
  • Sequential Application:

    Applying roles sequentially vs. batched can produce different conflict detection results.
  • Method Modification:

    Does not support method modifiers (before, after, around) like Moose roles.
  • Role Parameters:

    Roles cannot take parameters at composition time.
  • Diamond Problem:

    Limited handling of diamond inheritance patterns in role composition.
  • Meta Information:

    No rich meta-object protocol for introspection.

Attribute Limitations

The attribute system is intentionally minimal:

# Supported:
has 'name';
has 'count' => ( default => 0 );
has 'items' => ( default => sub { [] } );

# NOT supported:
has 'name' => ( is => 'ro' );       # No access control
has 'count' => ( isa => 'Int' );    # No type constraints
has 'items' => ( lazy => 1 );       # No lazy building
has 'score' => ( trigger => \&_validate_score );  # No triggers

Conflict Resolution Limitations

  • Class methods always silently win over role methods

  • No built-in way to explicitly override role methods

  • No method selection or combination features

  • Aliasing is the primary conflict resolution mechanism

Compatibility Limitations

  • Designed to work with simple class systems and Class::More

  • May have issues with some class builders that don't follow standard Perl OO

  • No Moose/Mouse compatibility layer

  • Limited support for role versioning

DIAGNOSTICS

Common Errors

  • "Failed to load role 'Role::Name': ..."

    The specified role could not be loaded. Make sure the role package exists and uses use Role;.

  • "Conflict: method 'method_name' provided by both 'Role::A' and 'Role::B'..."

    Method conflict detected. Use aliasing or role exclusion to resolve.

  • "Role 'Role::Name' requires method(s) that are missing..."

    The class doesn't implement all required methods specified by the role.

  • "Role 'Role::A' cannot be composed with role(s): Role::B"

    Role exclusion violation.

  • "ROLE WARNING: Role 'Role::Name' has attributes that will be ignored"

    Role defines attributes but the class doesn't support attribute handling.

SEE ALSO

AUTHOR

Mohammad Sajid Anwar, <mohammad.anwar at yahoo.com>

REPOSITORY

https://github.com/manwar/Class-Mite

BUGS

Please report any bugs or feature requests through the web interface at https://github.com/manwar/Class-Mite/issues. I will be notified and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

You can find documentation for this module with the perldoc command.

perldoc Role

You can also look for information at:

LICENSE AND COPYRIGHT

Copyright (C) 2025 Mohammad Sajid Anwar.

This program is free software; you can redistribute it and / or modify it under the terms of the the Artistic License (2.0). You may obtain a copy of the full license at:

http://www.perlfoundation.org/artistic_license_2_0

Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license.

If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license.

This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder.

This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed.

Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.