NAME

Package::Prototype - Super easily to create prototype object

SYNOPSIS

use strict;
use warnings;
use Data::Dumper;
use feature 'say';
use Package::Prototype;

my $obj = Package::Prototype->bless({
        foo => 10,
        bar => "Hello",
        baz => sub {
            my ($self, $arg) = @_;
            say "$arg, World";
        },
        # It do not create a method if key is started at '_'
        _data => "internal data"
    });

say "\$obj classname: " . ref $obj;
say Dumper $obj;
say $obj->foo;        # 10
say $obj->bar;        # "Hello"
$obj->baz($obj->bar); # "Hello, World"

my $obj2 = Package::Prototype->bless({
        hoge => [1..10],
        fuga => {abc => "def"}
    }, 'CLASS');

say "\$obj2 classname: " . ref $obj2;

# reference
my $a = $obj2->hoge;
my $h = $obj2->fuga;

# wantarray
my @a = $obj2->hoge;
my %h = $obj2->fuga;

$obj2->prototype(bow => sub { say "Bow!!" }, nyao => sub { say "Nyao!!" });
$obj2->prototype(baw => 10, nyan => "nyan");
$obj2->nyao(); # "Nyao!!"
$obj2->bow();  # "Bow!!"
say "bow: " . $obj2->baw . " nyan: " . $obj2->nyan;

DESCRIPTION

Package::Prototype can create prototype object like javascript.

This module can provide anonymous packages which are independent of the main namespace if not specified by classname. Also, available as an object instance.

METHODS

bless($ref :HashRef[, $classname :Str])

Create a new anonymous package and an instance. The optional $clasname argument sets the stash's name. $classname default is __ANON__.

That instance also provide a method that will return values corresponding to keys that do not start with '_'.

my $obj = Package::Prototype->bless({
    foo => 10,
    bar => sub { say $_[1] },

    # It do not create a method if key is started at '_'
    _data => "internal data"
});

say $obj->foo; # 10
say $obj->bar("Hello");

# $obj->_data is not provided
prototype($key :Str => $val :Any, ...)

This method can be used from the generated instance. By using this, it is possible to add new methods easily.

$obj->prototype(add => sub {
    my $self = shift;
    return $_[0] + $_[1];
});

$obj->add(3, 5); # 8

EXPLICIT PROPERTIES

create separates stored values from executable methods:

my $obj = Package::Prototype->create(
    properties => {
        count => { value => 0, writer => 'set_count' },
        callback => { value => sub { "done" } },
    },
    methods => {
        increment => sub {
            my $self = shift;
            $self->set_count($self->count + 1);
        },
    },
);
$obj->increment;
my $callback = $obj->callback;
print $callback->();

Each property requires value, which may be undef or any reference. reader defaults to the property name. Supplying writer creates an explicitly named setter; otherwise the property has no setter. Readers accept no arguments, writers accept one value and return the assigned value.

Readers and writers share one private scalar per property per object. Values are shallowly copied: referenced arrays, hashes and objects remain shared. Readers always return that value, including in list context. In contrast, legacy bless getters expand array and hash references in list context. A read-only property can still contain a mutable reference.

methods contains code references. Optional classname labels the anonymous stash as with bless. Input hashes are not modified. Duplicate method names, unknown options and the method name prototype are rejected by create. The existing bless API still allows overriding prototype.

The resulting object supports prototype for subsequent method replacement. Replacing a reader or writer replaces only that method, not its paired accessor.

MODERN PERL

On Perl 5.36 and later, methods may use subroutine signatures. The first parameter is the invocant, just as with a normal Perl method:

use v5.36;
my $obj = Package::Prototype->bless({
    add => sub ($self, $x, $y = 2) { $x + $y },
});
say $obj->add(4); # 6

Code references are installed directly. Perl handles argument validation, calling context, and exceptions. The module does not enable language features in the caller or require a newer Perl merely to use its existing API.

Perl 5.44 also supports experimental named parameters in signatures:

use v5.44;
no warnings 'experimental::signature_named_parameters';
my $obj = Package::Prototype->bless({
    greet => sub ($self, :$name, :$suffix = '!') { "$name$suffix" },
});
say $obj->greet(name => 'Perl');

This works with bless, prototype, and create methods. It requires Perl 5.44; the module does not emulate named signatures on earlier releases.

On Perl 5.36 and later, Unicode property and method names are supported, including dynamic replacement. Earlier Perls are only tested with ASCII names. Use use utf8 when writing non-ASCII names in source. On Perl 5.36 and later, getters preserve the boolean identity of builtin::true and builtin::false.

SEE ALSO

Package::Anon

Plack::Util::Prototype

LICENSE

Copyright (C) K.

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

AUTHOR

K <x00.x7f@gmail.com>