Attribute-Tie

 view release on metacpan or  search on metacpan

lib/Attribute/Tie.pm  view on Meta::CPAN

package Attribute::Tie;
#
# $Id: Tie.pm,v 0.2 2009/02/08 09:00:12 dankogai Exp $
#
use 5.008001;
use strict;
use warnings;
use Attribute::Handlers;
our $VERSION = sprintf "%d.%02d", q$Revision: 0.2 $ =~ /(\d+)/g;

our %MOD2TIE;
our %SIGIL = qw/HASH % ARRAY @ SCALAR $/;
our $ERROR = \&error;

sub seterror {
    my $pkg = shift;
    $ERROR =
        ref $_[0] eq 'CODE' ? $_[0]
      : $_[0] ? \&error
      : sub { }
}

sub load {
    my ($mod2tie, $ref) = @_;
    return $MOD2TIE{$mod2tie} if $MOD2TIE{$mod2tie};
    {   # Maybe you don't need to load at all
	no strict 'refs';
	my $type =  ref $ref;
	return $MOD2TIE{$mod2tie} = $mod2tie 
	    if defined &{$mod2tie . "::TIE$type" };
	return $MOD2TIE{$mod2tie} = 'Tie::'.$mod2tie
	    if defined &{'Tie::'. $mod2tie . "::TIE$type"};
    }
    # DB_File, et al.
    eval qq{ require $mod2tie };
    return $MOD2TIE{$mod2tie} = $mod2tie unless $@;

    # Anything else
    eval qq{ require Tie::$mod2tie };
    return $MOD2TIE{$mod2tie} = 'Tie::'.$mod2tie unless $@;

    # Report Failure and die
    my ( $pkg, $file, $line ) = caller(4);
    die "Neither $mod2tie nor Tie::$mod2tie is available",
      " at $file line $line\n";
}

sub error {
    my ( $ref, $mod2tie, @tiearg ) = @_;
    my ( $pkg, $file,    $line )   = caller(4);
    my $s = $SIGIL{ ref $ref };
    die "tie(", join( ", ", $s . ref $ref, qq('$mod2tie'), @tiearg ),
      ") failed : $! at $file line $line\n";
}

sub UNIVERSAL::Tie : ATTR {
    my ( $pkg, $sym, $ref, $attr, $data, $phase ) = @_;
    my @tiearg = ref $data ? @$data : ($data);
    my $mod2tie = Attribute::Tie::load(shift @tiearg, $ref);
    my $obj =
        ref $ref eq 'HASH'   ? tie %$ref, $mod2tie, @tiearg
      : ref $ref eq 'ARRAY'  ? tie @$ref, $mod2tie, @tiearg
      : ref $ref eq 'SCALAR' ? tie $$ref, $mod2tie, @tiearg
      :   die "cannot tie to data type: ", ref $ref;
    $Attribute::Tie::ERROR->( $ref, $mod2tie, @tiearg ) if !$obj;
}

1;
__END__
# Below is stub documentation for your module. You'd better edit it!

=head1 NAME

Attribute::Tie - Tie via Attribute

=head1 SYNOPSIS

  use Attribute::Tie;
  my %hash   : Tie('Hash::Yours', args ...);
  my @array  : Tie('Array::Yours', args ...);
  my $scalar : Tie('Scalar::Yours', args ...);

=head1 DESCRIPTION

Attribute::Tie allows you to tie variables via attribute.  This is
more intuitive than

  tie my %hash, "Tie::Hash::Yours", args ... or die "$!";

The first argument to C<Tie()> is the name of the module to which you
want to tie the variable.  You can omit 'Tie' therein.

  my %db  : Tie('DB_File', ....); # ties to DB_File;
  my @fie : Tie('File', ...);     # ties to Tie::File;

You do not have to C<use Tie::Whatever>; Attribute::Tie does it for you.

=head2 Attribute::Tie vs Attribute::Handlers' autotie

I wrote this module for two reasons:

=over 2

=item semantics

L<Attribute::Handlers> offers an alternate approach via autotie.  That
looks like this.

  use Attribute::Handlers autotie => { File => 'Tie::File' };
  my @array : File('array.txt');



( run in 1.148 second using v1.01-cache-2.11-cpan-364913b4093 )