AutoCode

 view release on metacpan or  search on metacpan

lib/AutoCode/AccessorMaker.pm  view on Meta::CPAN

our $VERSION='0.01';
use AutoCode::Root0;
our @ISA=qw(AutoCode::Root0);
# use AutoCode::Initializer;
use AutoCode::SymbolTableUtils;
our %AUTO_ACCESSORS;

our $VALID_ACCESSOR_NAME='[_a-z][_a-z0-9]+';
$VALID_ACCESSOR_NAME='[_a-zA-Z][_a-zA-Z0-9]+';

sub import {
    my ($class, @args)=@_;
    my $self = $class->new;
    my $caller = ref(caller) || caller;
    my %args=@args;
    
    if(exists $args{'$'}){
        foreach ($class->_scalar_to_array($args{'$'})){
            $self->make_scalar_accessor($_, $caller);
        }
    }

    if(exists $args{'@'}){
        foreach($class->_scalar_to_array($args{'@'})){
            $self->make_array_accessor($_, $caller);
        }
    }

    if(exists $args{'%'}){
        foreach($class->_scalar_to_array($args{'%'})){
            $self->make_hash_accessor($_, $caller);
        }
    }

    if(exists $args{_initialize} or exists $args{_digest_args}){
        my $initializer=$self;
    
        if(exists $args{_initialize}){
            $initializer->_make_initialize_by_hash(\%args, $caller);
        }
        if(exists $args{_digest_args}){
            $initializer->_make_digest_args_by_hash(\%args, $caller);
        }
    }
}

sub _scalar_to_array {
    my ($class, $scalar)=@_;
    my $ref=ref($scalar);
    if($ref eq'ARRAY'){
        return @$scalar;
    }elsif($ref eq ''){
        return ($scalar);
    }else{
        $class->throw("ref [$ref] is neither nothing nor ARRAY");
    }
}

# This method is only invoked by make_scalar_accessor and make_array_accessor
# While subroutine defined the argument of those two method abovementioned.
# This most hacky part is caller(2); that mean the first immedicate package
# after this Module.
sub __accessor_to_glob {
    my ($self, $accessor, $pkg)=@_;
    defined $accessor or $self->throw("method_name needed as 2nd arg");
    my $singular = (ref($accessor) eq 'ARRAY')? $accessor->[0]: $accessor;
    # According to the specification of AutoCode, upper letter are not allowed
    # in the names of methods which are automatically generated by this system.
    $self->throw("'$singular' method name must match /^$VALID_ACCESSOR_NAME\$/")
        unless $singular =~ /^$VALID_ACCESSOR_NAME$/;
    if(0){ # For debug
        print "$_\t". (caller($_))[0]."\n" foreach(0..3);
        $self->throw("");
    }
    $pkg ||= (caller(2))[0];   # This line will definitely assign a value.

    # This typeglob is meaningful for both scalar and array accessors.
    # For scalar, it means the same as the real typeglob;
    # for array, there is no such method with exact method, but a symbol for
    # these three methods.
    my $typeglob="$pkg\::$singular";
    unless(grep {$_ eq $typeglob} keys %AUTO_ACCESSORS){
        # push @{$self->{AUTO_ACCESSORS_SLOT}}, $typeglob;
        $AUTO_ACCESSORS{$typeglob}=1;
    }
    my $slot="$pkg\::_auto_accessors::$singular";
    return ($accessor, $pkg, $typeglob, $slot);
    
}

sub make_scalar_accessor {
    my $self=shift;
    my ($accessor, $pkg, $typeglob, $slot) = $self->__accessor_to_glob(@_);
    
    $typeglob="$pkg\::$accessor";
    $slot="$pkg\::$accessor\_\$";
    $self->debug("making a scalar accessor [$typeglob]");

    return if(AutoCode::SymbolTableUtils::CODE_exists_in_ST($typeglob));
    no strict 'refs';
    return if defined &$typeglob;
    *$typeglob =sub{
        my $self=shift;
        $self->{$slot}=shift if @_;
        return $self->{$slot};
    };
}

sub _deref_plural {
    my ($self, $accessor)=@_;
    (ref($accessor) eq 'ARRAY')? @$accessor: ($accessor, "${accessor}s");
}

sub make_array_accessor {
    my $self=shift;
    my ($accessor, $pkg, $typeglob, $slot)=$self->__accessor_to_glob(@_);
    my ($singular, $plural) = $self->_deref_plural($accessor);
    # $typeglob is useless here. So the 3 new method globs are composed here
    my $add_method="$pkg\::add_$singular";
    my $get_method="$pkg\::get_$plural";
    my $remove_method="$pkg\::remove_$plural";
    foreach $typeglob($add_method, $get_method, $remove_method){
        return if(AutoCode::SymbolTableUtils::CODE_exists_in_ST($typeglob));
    }
    $slot="$pkg\::$singular\_\%";
    $self->_make_array_add($add_method, $slot);
    $self->_make_array_get($get_method, $slot);
    $self->_make_array_remove($remove_method, $slot, $get_method);
}

sub _make_array_add {
    my ($self, $glob, $slot)=@_;
    no strict 'refs';
    *$glob=sub{
        my $self=shift; return unless @_;



( run in 0.808 second using v1.01-cache-2.11-cpan-39bf76dae61 )