File Coverage

blib/lib/accessors.pm
Criterion Covered Total %
statement 41 41 100.0
branch 12 14 85.7
condition n/a
subroutine 13 13 100.0
pod 0 6 0.0
total 66 74 89.1


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             accessors - create accessor methods in caller's package.
4              
5             =head1 SYNOPSIS
6              
7             package Foo;
8             use accessors qw( foo bar baz );
9              
10             my $obj = bless {}, 'Foo';
11              
12             # generates chaining accessors
13             # that you can set like this:
14             $obj->foo( 'hello ' )
15             ->bar( 'world' )
16             ->baz( "!\n" );
17              
18             # you get the values by passing no params:
19             print $obj->foo, $obj->bar, $obj->baz;
20              
21             =cut
22              
23             package accessors;
24              
25 7     7   21482 use 5.006;
  7         22  
  7         266  
26 7     7   38 use strict;
  7         11  
  7         222  
27 7     7   49 use warnings::register;
  7         615  
  7         1560  
28              
29             our $VERSION = '1.01';
30             our $REVISION = (split(/ /, ' $Revision: 1.22 $ '))[2];
31              
32             our $Debug = 0;
33             our $ExportLevel = 0;
34             our @InvalidNames = qw( BEGIN CHECK INIT END DESTROY AUTOLOAD );
35              
36 7     7   45 use constant style => 'chained';
  7         15  
  7         2318  
37              
38             sub import {
39 23     23   18306 my $class = shift;
40 23         76 my $callpkg = caller( $class->ExportLevel );
41              
42 23 100       146 my @properties = @_ or return;
43              
44 16         68 $class->create_accessors_for( $callpkg, @properties );
45             }
46              
47             sub create_accessors_for {
48 16     16 0 21 my $class = shift;
49 16         29 my $callpkg = shift;
50              
51 16 50       43 warn( 'creating ' . $class->style . ' accessors( ',
52             join(' ',@_)," ) in pkg '$callpkg'" ) if $class->Debug;
53              
54 16         32 foreach my $property (@_) {
55 21         44 my $accessor = "$callpkg\::$property";
56 21 100       60 die( "can't create $accessor - '$property' is not a valid name!" )
57             unless $class->isa_valid_name( $property );
58 13 50       27 warn( "creating " . $class->style . " accessor: $accessor\n" ) if
59             $class->Debug > 1;
60 13         45 $class->create_accessor( $accessor, $property );
61             }
62              
63 8         8552 return $class;
64             }
65              
66             sub create_accessor {
67 5     5 0 6 my ($class, $accessor, $property) = @_;
68 5         8 $property = "-$property";
69             # set/get is slightly faster if we eval instead of using a closure + anon
70             # sub, but the difference is marginal (~5%), and this uses less memory...
71 7     7   36 no strict 'refs';
  7         15  
  7         2068  
72 5         24 *{$accessor} = sub {
73 7 100   7   1876 (@_ > 1)
74             ? ($_[0]->{$property} = $_[1], return $_[0])
75             : $_[0]->{$property};
76 5         26 };
77             }
78              
79             sub isa_valid_name {
80 21     21 0 27 my ($class, $property) = @_;
81 21 100       118 return unless $property =~ /^(?!\d)\w+$/;
82 19 100       57 return if grep {$property eq $_} $class->InvalidNames;
  114         252  
83 13         37 return 1;
84             }
85              
86             ##
87             ## on the off-chance that someone will sub-class:
88             ##
89              
90             ## don't like studly caps for sub-names, but stick with Exporter-like style...
91 29     29 0 76 sub Debug { $Debug; }
92 23     23 0 53 sub ExportLevel { $ExportLevel }
93 19     19 0 57 sub InvalidNames { @InvalidNames }
94              
95             1;
96              
97             __END__