Class-Monadic
view release on metacpan or search on metacpan
lib/Class/Monadic.pm view on Meta::CPAN
use strict;
use warnings;
our $VERSION = '0.04';
use Exporter qw(import);
our @EXPORT_OK = qw(monadic);
our %EXPORT_TAGS = (all => \@EXPORT_OK);
use Carp ();
use Data::Util ();
use Scalar::Util ();
use Hash::FieldHash ();
#use Class::Method::Modifiers::Fast ();
Hash::FieldHash::fieldhash my %Meta;
sub _cannot_initialize{
Carp::croak 'Cannot initialize a monadic object without object references';
}
sub monadic{
my($object) = @_;
ref($object) or _cannot_initialize();
return $Meta{$object} ||= __PACKAGE__->_new($object);
}
sub initialize{
my($class, $object) = @_;
ref($object) or _cannot_initialize();
return $Meta{$object} ||= $class->_new($object);
}
sub _new{
my($metaclass, $object) = @_;
if(Data::Util::is_glob_ref($object)){
$object = *{$object}{IO};
}
my $class = Scalar::Util::blessed($object) or _cannot_initialize();
$class =~ s/ ::0x[a-f0-9]+ \z//xms; # remove its monadic identity (in cloning)
my $meta = bless {
class => $class,
id => sprintf('0x%x', Scalar::Util::refaddr($object)),
object => $object,
isa => undef,
sclass => undef,
methods => undef,
modifiers => undef,
fields => undef,
field_map => undef,
}, $metaclass;
Scalar::Util::weaken( $meta->{object} );
&Internals::SvREADONLY($meta, 1); # lock_keys(%{$meta})
my $sclass = $class . '::' . $meta->{id};
my $sclass_isa = do{ no strict 'refs'; \@{$sclass . '::ISA'} };
$meta->{sclass} = $sclass;
$meta->{isa} = $sclass_isa;
my $base = $metaclass . '::Object';
if($class->can('clone')){
$base .= '::Clonable';
}
@{$sclass_isa} = ($base, $class);
bless $object, $sclass; # re-bless
return $meta;
}
sub name{
my($meta) = @_;
return $meta->{class};
}
sub id{
my($meta) = @_;
return $meta->{id};
}
*add_methods = \&add_method; # alias
sub add_method{
my $meta = shift;
Data::Util::install_subroutine($meta->{sclass}, @_); # dies on fail
push @{$meta->{methods} ||= []}, @_;
return;
}
*add_fields = \&add_field; # alias
sub add_field{
my $meta = shift;
my $fields_ref = Data::Util::mkopt_hash(\@_, 'add_field', [qw(Regexp ARRAY CODE)]);
my $field_map_ref = $meta->{field_map} ||= {};
my $fields = $meta->{fields} ||= [];
while(my($name, $validator) = each %{$fields_ref}){
my $slot;
my $validate_sub;
if($validator){
if(Data::Util::is_regex_ref $validator){
$validate_sub = sub{ $_[0] =~ /$validator/ };
( run in 1.900 second using v1.01-cache-2.11-cpan-39bf76dae61 )