NAME

Extender - Dynamically enhance Perl objects with additional methods from other modules or custom subroutines

SYNOPSIS

use Extender;

# Example: Extend an object with methods from a module
my $object = MyClass->new();
Extend($object, 'Some::Class');
$object->method_from_some_class();

# Example: Extend an object with custom methods
Extends($object,
    greet => sub { my ($self, $name) = @_; print "Hello, $name!\n"; },
    custom_method => sub { return "Custom method executed"; },
);
$object->greet('Alice');
$object->custom_method();

DESCRIPTION

Extender is a Perl module that facilitates the dynamic extension of objects with methods from other modules or custom-defined subroutines. It allows you to enhance Perl objects - whether hash references, array references, or scalar references - with additional functionalities without altering their original definitions.

EXPORTED FUNCTIONS

Extend($object, $module, @methods)

Extends an object with methods from a specified module.

Arguments:

  • $object - The object reference to which methods will be added.

  • $module - The name of the module from which methods will be imported.

  • @methods - Optional list of method names to import. If none are provided, all exported functions from $module will be imported.

Description:

This function extends the specified $object by importing methods from the module $module. It dynamically loads the module if it's not already loaded, retrieves the list of exported functions, and adds each specified function as a method to the object.

Example:

use Extender;

# Create an object
my $object = {};

# Extend $object with methods from 'List::Util'
Extend($object, 'Hash::Util', 'keys', 'values');

# Now $object has 'keys' and 'values' methods from 'Hash::Util'

Extends($object, %extend)

Extends an object with custom methods.

Arguments:

  • $object - The object reference to which methods will be added.

  • %extend - A hash where keys are method names and values are references to subroutines (CODE references). Alternatively, values can be references to scalars containing CODE references.

Description:

This function extends the specified $object by adding custom methods defined in %extend. Each key-value pair in %extend corresponds to a method name and its associated subroutine reference. If the method name already exists in $object, it will override it.

Example:

use Extender;

# Create an object
my $object = {};

# Define custom methods to extend $object
Extends($object,
    custom_method => sub { return "Custom method" },
    dynamic_method => \"sub { return 'Dynamic method' }",
);

# Now $object has 'custom_method' and 'dynamic_method'

Override($object, $method_name, $new_method)

Overrides an existing method in the object with a new implementation.

Arguments:

  • $object - The object reference in which the method will be overridden.

  • $method_name - The name of the method to override.

  • $new_method - Reference to the new method implementation (CODE reference).

Description:

This function overrides an existing method in the object with a new implementation provided as $new_method. It allows for dynamic replacement of method behavior in Perl objects.

Example:

use Extender;

my $object = Extends({}, original_method => sub {
    return "Original method";
});

# Override the 'original_method' in $object
Override($object, 'original_method', sub { return "New method"; });

# Using the overridden method
print $object->original_method(), "\n";  # Outputs: New method

Alias($object, $existing_method, $new_name)

Creates an alias for an existing method in the object with a new name.

Arguments:

  • $object - The object reference in which the alias will be created.

  • $existing_method - The name of the existing method to alias.

  • $new_name - The new name for the alias.

Description:

This function creates an alias for an existing method in the object with a new name. It allows referencing the same method implementation using different names within the same object.

Example:

use Extender;

my $object = Extends({}, original_method => sub {
    return "Original method";
});

# Create an alias 'new_alias' for 'original_method' in $object
Alias($object, 'original_method', 'new_alias');

# Using the alias
print $object->new_alias(), "\n";  # Outputs: Original method

Unload($object, @methods)

Removes specified methods from the object's namespace.

Arguments:

  • $object - The object reference from which methods will be removed.

  • @methods - List of method names to be removed from the object.

Description:

This function removes specified methods from the object's namespace. It effectively unloads or deletes methods that were previously added or defined within the object.

Example:

use Extender;

my $object = Extends({}, example_method => sub {
    return "Example method";
});

# Unload the method from $object
Unload($object, 'example_method');

# Attempting to use the unloaded method will fail
eval {
    $object->example_method();  # This will throw an error
};
if ($@) {
    print "Error: $@\n";
}

AddMethod($object, $method_name, $code_ref)

Adds a new method to the object.

Arguments:

  • $object - The object reference to which the method will be added.

  • $method_name - Name of the method to add. Must be a valid Perl subroutine name (word characters only).

  • $code_ref - Reference to the subroutine (code reference) that defines the method.

Description:

This function adds a new method to the object's namespace. It validates the method name and code reference before adding it to the object.

Example:

use Extender;

my $object = Extends({}, custom_method => sub {
    my ($self, $arg1, $arg2) = @_;
    return "Custom method called with args: $arg1, $arg2";
})->AddMethod(custom_method2 => sub {
    my ($self, $arg1, $arg2) = @_;
    return "Custom method2 called with args: $arg1, $arg2";
});

# Using the added method
my $result = $object->custom_method2('foo', 'bar');
print "$result\n";  # Outputs: Custom method2 called with args: foo, bar

Decorate($object, $method_name, $decorator)

Decorates an existing method of an object with a custom decorator.

Arguments:

  • $object - The object reference whose method is to be decorated.

  • $method_name - The name of the method to decorate.

  • $decorator - A coderef representing the decorator function.

Description:

This function allows decorating an existing method of an object with a custom decorator function. The original method is replaced with a new subroutine that invokes the decorator function before and/or after invoking the original method.

Example:

use Extender;

# Define a decorator function
sub timing_decorator {
    my ($self, $orig_method, @args) = @_;
    my $start_time = time();
    my $result = $orig_method->($self, @args);
    my $end_time = time();
    my $execution_time = $end_time - $start_time;
    print "Execution time: $execution_time seconds\n";
    return $result;
}

my $object = AddMethod({counter => 0}, increment => sub { my ($object)=@_; $object->{counter}++ });

# Decorate the 'increment' method with timing_decorator
Decorate($object, 'increment', \&timing_decorator);

# Invoke the decorated method
$object->increment();

# Output the counter value
print "Counter: ", $object->{counter}, "\n";

ApplyRole($object, $role_class)

Applies a role (mixin) to an object, importing and applying its methods.

Arguments:

  • $object - The object reference to which the role will be applied.

  • $role_class - The name of the role class to be applied.

Description:

This function loads a role class using require, imports its methods into the current package, and applies them to the object using apply.

Example:

# Define a role (mixin)
package MyRole;
sub foo { print "foo\n" }
sub bar { print "bar\n" }

package main;
use Extender;

# Apply the role to an object
my $object = ApplyRole({}, 'MyRole');

# Call the role methods
$object->foo();  # Outputs: foo
$object->bar();  # Outputs: bar

InitHook($object, $hook_name, $hook_code)

Adds initialization or destruction hooks to an object.

Arguments:

  • $object - The object reference to which the hook will be added.

  • $hook_name - The type of hook to add. Valid values are 'INIT' for initialization and 'DESTRUCT' for destruction.

  • $hook_code - A code reference to the hook function to be executed.

Description:

This function adds a code reference to the specified hook array (`_init_hooks` or `_destruct_hooks`) in the object. Hooks can be executed during object initialization or destruction phases.

Example:

package MyClass;

sub new {
    my ($class)=@_;
    my $self={};

    # Add initialization hook
    InitHook($self, 'INIT', sub {
        print "Object initialized\n";
    });

    # Add destruction hook
    InitHook($self, 'DESTRUCT', sub {
        print "Object destroyed\n";
    });

    return bless $self, $class
}

use Extender;

# Create an object
my $object = MyClass->new();

# Destroy an object
undef $object;

GenerateMethod($object, $method_name, $generator_code)

Generates a method on an object using a generator code reference.

Arguments:

  • $object - The object reference to which the method will be added.

  • $method_name - The name of the method to generate.

  • $generator_code - A code reference that generates the method's functionality.

Description:

This function dynamically generates a new method on the specified object using the provided generator code reference (`$generator_code`). The generator code receives the object reference (`$self`) as the first argument, followed by any additional arguments passed to the method.

Example:

use Extender;

# Create an object
my $object = {};

# Define a generator code reference
my $generator = sub {
    my ($self, $arg1, $arg2) = @_;
    return $arg1 + $arg2;
};

# Generate a new method 'add' on the object using the generator code
GenerateMethod($object, 'add', $generator);

# Call the generated method
my $result = $object->add(3, 4);  # $result will be 7

MooseCompat($object, $role_name)

Applies a Moose role to an object using MooseX::Role::Parameterized::Extender::$role_name.

Arguments:

  • $object - The object reference to which the role will be applied.

  • $role_name - The name of the Moose role to apply.

Description:

This function attempts to apply a Moose role specified by $role_name to the given object $object. It dynamically loads the Moose role module using require, applies it to the object, and handles any errors that occur during this process.

Example:

use Extender;

# Create an object
my $object = {};

# Apply a Moose role 'Logger' to the object
MooseCompat($object, 'Logger');

# Now $object has the capabilities provided by the 'Logger' role

USAGE

Extend an Object with Methods from a Module

use Extender;

# Extend an object with methods from a module
my $object = Extend(MyClass->new(), 'Some::Class');

# Now $object can use any method from Some::Class
$object->method1(1, 2, 3, 4);

Extend an Object with Custom Methods

use Extender;

# Extend an object with custom methods
my $object = Extends(
    MyClass->new(),
    greet => sub { my ($self, $name) = @_; print "Hello, $name!\n"; },
    custom_method => \&some_function,
);

# Using the added methods
$object->greet('Alice');               # Output: Hello, Alice!
$object->custom_method('Hello');       # Assuming some_function prints something

Adding Methods to Raw Reference Variables

package HashMethods;

use strict;
use warnings;
use Exporter 'import';
our @EXPORT = qw(set get);

sub set {
    my ($self, $key, $value) = @_;
    $self->{$key} = $value;
}

sub get {
    my ($self, $key) = @_;
    return $self->{$key};
}

1;

package ArrayMethods;

use strict;
use warnings;
use Exporter 'import';
our @EXPORT = qw(add get);

sub add {
    my ($self, $item) = @_;
    push @$self, $item;
}

sub get {
    my ($self, $index) = @_;
    return $self->[$index];
}

1;

package ScalarMethods;

use strict;
use warnings;
use Exporter 'import';
our @EXPORT = qw(set get substr length);

sub set {
    my ($self, $value) = @_;
    $$self = $value;
}

sub get {
    my ($self) = @_;
    return $$self;
}

sub substr {
    my $self = shift;
    return substr($$self, @_);
}

sub length {
    my ($self) = @_;
    return length $$self;
}

1;

# MAIN 

package main;

use strict;
use warnings;
use Extender;
use HashMethods;
use ArrayMethods;
use ScalarMethods;

my $hash_object = {};
my $array_object = [];
my $scalar_object = \"";

# Extend $hash_object with methods from HashMethods
Extend($hash_object, 'HashMethods', 'set', 'get');

# Extend $array_object with methods from ArrayMethods
Extend($array_object, 'ArrayMethods', 'add', 'get');

# Extend $scalar_object with methods from ScalarMethods
Extend($scalar_object, 'ScalarMethods', 'set', 'get', 'substr', 'length');

# Using extended methods for hash object
$hash_object->set('key', 'value');
print $hash_object->get('key'), "\n";  # Outputs: value

# Using extended methods for array object
$array_object->add('item1');
$array_object->add('item2');
print $array_object->get(0), "\n";  # Outputs: item1

# Using extended methods for scalar object
$scalar_object->set('John');
print $scalar_object->get(), "\n";  # Outputs: John
print $scalar_object->length(), "\n";  # Outputs: 4
print $scalar_object->substr(1, 2), "\n";  # Outputs: oh
$scalar_object->substr(1, 2, "ane");
print $scalar_object->get(), "\n";  # Outputs: Jane

1;

Adding methods using anonymous subroutines and existing functions

package MyClass;
sub new {
    my $class = shift;
    return bless {}, $class;
}

package main;
use Extender;

my $object = MyClass->new();

Extends($object,
    greet => sub { my ($self, $name) = @_; print "Hello, $name!\n"; },
    custom_method => \&some_function,
);

# Using the added methods
$object->greet('Alice'); # Output: Hello, Alice!
$object->custom_method('Hello'); # Assuming some_function prints something

Using Shared Object for Shared Variable functionality

package main;

use strict;
use warnings;
use threads;
use threads::shared;
use Extender;

# Example methods to manipulate shared data

# Method to set data in a shared hash
sub set_hash_data {
    my ($self, $key, $value) = @_;
    lock(%{$self});
    $self->{$key} = $value;
}

# Method to get data from a shared hash
sub get_hash_data {
    my ($self, $key) = @_;
    lock(%{$self});
    return $self->{$key};
}

# Method to add item to a shared array
sub add_array_item {
    my ($self, $item) = @_;
    lock(@{$self});
    push @{$self}, $item;
}

# Method to get item from a shared array
sub get_array_item {
    my ($self, $index) = @_;
    lock(@{$self});
    return $self->[$index];
}

# Method to set data in a shared scalar
sub set_scalar_data {
    my ($self, $value) = @_;
    lock(${$self});
    ${$self} = $value;
}

# Method to get data from a shared scalar
sub get_scalar_data {
    my ($self) = @_;
    lock(${$self});
    return ${$self};
}

# Create shared data structures
my %shared_hash :shared;
my @shared_array :shared;
my $shared_scalar :shared;

# Create shared objects
my $shared_hash_object = \%shared_hash;
my $shared_array_object = \@shared_array;
my $shared_scalar_object = \$shared_scalar;

# Extend the shared hash object with custom methods
Extends($shared_hash_object,
    set_hash_data => \&set_hash_data,
    get_hash_data => \&get_hash_data,
);

# Extend the shared array object with custom methods
Extends($shared_array_object,
    add_array_item => \&add_array_item,
    get_array_item => \&get_array_item,
);

# Extend the shared scalar object with custom methods
Extends($shared_scalar_object,
    set_scalar_data => \&set_scalar_data,
    get_scalar_data => \&get_scalar_data,
);

# Create threads to manipulate shared objects concurrently

# Thread for shared hash object
my $hash_thread = threads->create(sub {
    $shared_hash_object->set_hash_data('key1', 'value1');
    print "Hash thread: key1 = " . $shared_hash_object->get_hash_data('key1') . "\n";
});

# Thread for shared array object
my $array_thread = threads->create(sub {
    $shared_array_object->add_array_item('item1');
    print "Array thread: item at index 0 = " . $shared_array_object->get_array_item(0) . "\n";
});

# Thread for shared scalar object
my $scalar_thread = threads->create(sub {
    $shared_scalar_object->set_scalar_data('shared_value');
    print "Scalar thread: value = " . $shared_scalar_object->get_scalar_data() . "\n";
});

# Wait for all threads to finish
$hash_thread->join();
$array_thread->join();
$scalar_thread->join();

1;

Updating existing methods on an object class

package MyClass;

sub new {
    my $class = shift;
    my $self = bless {}, $class;
    return $self;
}

sub original_method {
    return "Original method";
}

package main;
use Extender;

my $object = MyClass->new();

# Define a method with the same name as an existing method
Extends($object,
    original_method => sub { return "New method"; },
);

# Using the extended method
print $object->original_method(), "\n";  # Outputs: New method

1;

Creating Extender Class objects from any (even shared) reference typed variable

package main;

use Extender;

my $object = Extend({},'Extender');

# Define a method with the same name as an existing method
$object->Extends(
    method => sub { return "method"; },
);

# Using the method
print $object->method(), "\n";  # Outputs: method

my $array = Extend([],'Extender');

# Define a method with the same name as an existing method
$array->Extends(
    method => sub { return "method"; },
);

# Using the method
print $array->method(), "\n";  # Outputs: method

my $scalar = Extend(\"",'Extender');

# Define a method with the same name as an existing method
$scalar->Extends(
    method => sub { return "method"; },
);

# Using the method
print $scalar->method(), "\n";  # Outputs: method

1;

AUTHOR

OnEhIppY @ Domero Software <domerosoftware@gmail.com>

LICENSE

This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See perlartistic and perlgpl.

SEE ALSO

Exporter, perlfunc, perlref, perlsub