=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 pragma lets you create simple accessors at compile-time. This saves you from writing them by hand, which tends to result in I errors and a mess of duplicated code. It can also help you reduce the ammount of unwanted I that may creep into your codebase when you're feeling lazy. B was designed with laziness in mind. Method-chaining accessors are generated by default. B If you want backwards compatability use L and wait until the dust settles. See L for accessors that always return the current value if you don't like method chaining. =head1 GENERATED METHODS B 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 together. =head1 PERFORMANCE There is B when using generated accessors; in fact there is B. =over 4 =item * typically I<10-30% faster> than hard-coded accessors (like the above example). =item * typically I<1-15% slower> than I accessors (less readable). =item * typically a I 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 pragma and other accessor generators is B. =over 4 =item * interface B is as easy as it gets. =item * a pragma it fits in nicely with the B 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 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 =head1 SEE ALSO L, L Similar and related modules: L, L, L, L, L, L, L, L =cut