=head1 NAME

accessors - create accessor methods in caller's package.

=head1 SYNOPSIS

  package Foo;
  use accessors qw( foo bar baz );

  my $obj = bless {}, 'Foo';

  # generates chaining accessors:
  $obj->foo( 'hello ' )
      ->bar( 'world' )
      ->baz( "!\n" );

  print $obj->foo, $obj->bar, $obj->baz;

=cut

package accessors;

use 5.006;
use strict;
use warnings::register;

our $VERSION  = '0.02';
our $REVISION = (split(/ /, ' $Revision: 1.18 $ '))[2];

our $Debug        = 0;
our $ExportLevel  = 0;
our @InvalidNames = qw( DESTROY AUTOLOAD );

use constant style => 'chained';

sub import {
    my $class   = shift;
    my $callpkg = caller( $class->ExportLevel );

    my @properties = @_ or return;

    $class->create_accessors_for( $callpkg, @properties );
}

sub create_accessors_for {
    my $class   = shift;
    my $callpkg = shift;

    warn( 'creating ' . $class->style . ' accessors( ',
	  join(' ',@_)," ) in pkg '$callpkg'" ) if $class->Debug;

    foreach my $property (@_) {
	my $accessor = "$callpkg\::$property";
	die( "can't create $accessor - '$property' is not a valid name!" )
	  unless $class->isa_valid_name( $property );
	warn( "creating " . $class->style . " accessor: $accessor\n" ) if
	  $class->Debug > 1;
	$class->create_accessor( $accessor, $property );
    }

    return $class;
}

sub create_accessor {
    my ($class, $accessor, $property) = @_;
    $property = "-$property";
    # set/get is slightly faster if we eval instead of using a closure + anon
    # sub, but the difference is marginal (~5%), and this uses less memory...
    no strict 'refs';
    *{$accessor} = sub {
	(@_ > 1)
	  ? ($_[0]->{$property} = $_[1], return $_[0])
	  : $_[0]->{$property};
    };
}

sub isa_valid_name {
    my ($class, $property) = @_;
    return unless $property =~ /^(?!\d)\w+$/;
    return if grep {$property eq $_} $class->InvalidNames;
    return 1;
}

##
## on the off-chance that someone will sub-class:
##

## don't like studly caps, but stick with Exporter-like style...
sub Debug        { $Debug; }
sub ExportLevel  { $ExportLevel }
sub InvalidNames { @InvalidNames }

1;

__END__

=head1 DESCRIPTION

The B<accessors> pragma lets you create simple accessors at compile-time.

This saves you from writing them by hand, which tends to result in
I<cut-n-paste> errors and a mess of duplicated code.  It can also help you
reduce the ammount of unwanted I<direct-variable access> that may creep into
your codebase when you're feeling lazy.  B<accessors> was designed with
laziness in mind.

Method-chaining accessors are generated by default.  B<This may be changed in
future versions!>  If you want backwards compatability use
L<accessors::chained> and wait until the dust settles.

See L<accessors::classic> for accessors that always return the current value if
you don't like method chaining.

=head1 GENERATED METHODS

B<accessors> will generate methods that return the current object on set:

  sub foo {
      my $self = shift;
      if (@_) { $self->{-foo} = shift; return $self; }
      else    { return $self->{-foo}; }
  }

This way they can be I<chained> together.

=head1 PERFORMANCE

There is B<little-to-no performace hit> when using generated accessors; in
fact there is B<usually a performance gain>.

=over 4

=item *

typically I<10-30% faster> than hard-coded accessors (like the above example).

=item *

typically I<1-15% slower> than I<optimized> accessors (less readable).

=item *

typically a I<small> performance hit at startup (accessors are created at
compile-time).

=item *

uses the same anonymous sub to reduce memory consumption (sometimes by 80%).

=back

See the benchmark tests included with this distribution for more details.

=head1 MOTIVATION

The main difference between the B<accessors> pragma and other accessor
generators is B<simplicity>.

=over 4

=item * interface

B<use accessors qw( ... )> is as easy as it gets.

=item * a pragma

it fits in nicely with the B<base> pragma:

  use base      qw( Some::Class );
  use accessors qw( foo bar baz );

and accessors get created at compile-time.

=item * no bells and whistles

The module is extensible instead.

=back

=head1 SUB-CLASSING

If you prefer a different style of accessor or you need to do something more
complicated, there's nothing to stop you from sub-classing.  Look through
L<accessors::classic> to start.

=head1 CAVEATS

Classes using blessed scalars or arrays are not supported.

=head1 THANKS

Thanks to Michael G. Schwern for indirectly inspiring this module, and for his
feedback & suggestions.

Also to Paul Makepeace and David Wright for showing me faster accessors, and to
James Duncan and people on London.pm for their feedback.

=head1 AUTHOR

Steve Purkis <spurkis@epn.nu>

=head1 SEE ALSO

L<accessors::classic>, L<accessors::chained>

Similar and related modules:

L<base>,
L<fields>,
L<Class::Accessor>,
L<Class::Struct>,
L<Class::Methodmaker>,
L<Class::Generate>,
L<Class::Class>,
L<Class::Tangram>

=cut
