1package Attribute::Constant; 2use 5.008001; 3use warnings; 4use strict; 5our $VERSION = sprintf "%d.%02d", q$Revision: 1.1 $ =~ /(\d+)/g; 6use Attribute::Handlers; 7use Data::Lock (); 8 9sub UNIVERSAL::Constant : ATTR { 10 my ( $pkg, $sym, $ref, $attr, $data, $phase ) = @_; 11 ( 12 ref $ref eq 'HASH' ? %$ref 13 : ref $ref eq 'ARRAY' ? @$ref 14 : ($$ref) 15 ) 16 = ref $data 17 ? ref $data eq 'ARRAY' 18 ? @$data # perl 5.10.x 19 : $data 20 : $data; # perl 5.8.x 21 Data::Lock::dlock($ref); 22} 23 241; 25__END__ 26 27=head1 NAME 28 29Attribute::Constant - Make read-only variables via attribute 30 31=head1 VERSION 32 33$Id: Constant.pm,v 1.1 2013/04/03 14:37:57 dankogai Exp $ 34 35=head1 SYNOPSIS 36 37 use Attribute::Constant; 38 my $sv : Constant( $initial_value ); 39 my @av : Constant( @values ); 40 my %hv : Constant( key => value, key => value, ...); 41 42=head1 DESCRIPTION 43 44This module uses L<Data::Lock> to make the variable read-only. Check 45the document and source of L<Data::Lock> for its mechanism. 46 47=head1 ATTRIBUTES 48 49This module adds only one attribute, C<Constant>. You give its 50initial value as shown. Unlike L<Readonly>, parantheses cannot be 51ommited but it is semantically more elegant and thanks to 52L<Data::Lock>, it imposes almost no performance penalty. 53 54=head1 CAVEAT 55 56=head2 Multi-line attributes 57 58Multi-line attributes are not allowed in Perl 5.8.x. 59 60 my $o : Constant(Foo->new(one=>1,two=>2,three=>3)); # ok 61 my $p : Constant(Bar->new( 62 one =>1, 63 two =>2, 64 three =>3 65 ) 66 ); # needs Perl 5.10 67 68In which case you can use L<Data::Lock> instead: 69 70 dlock(my $p = Bar->new( 71 one => 1, 72 two => 2, 73 three => 3 74 ) 75 ); 76 77After all, this module is a wrapper to L<Data::Lock>; 78 79=head2 Constants from Variables 80 81You may be surprised the following code B<DOES NOT> work as you expected: 82 83 #!/usr/bin/perl 84 use strict; 85 use warnings; 86 use Attribute::Constant; 87 use Data::Dumper; 88 { 89 package MyClass; 90 sub new { 91 my ( $class, %params ) = @_; 92 return bless \%params, $class; 93 } 94 } 95 my $o = MyClass->new( a => 1, b => 2 ); 96 my $x : Constant($o); 97 print Dumper( $o, $x ); 98 99Which outputs: 100 101 $VAR1 = bless( { 102 'a' => 1, 103 'b' => 2 104 }, 'MyClass' ); 105 $VAR2 = undef; 106 107Why? Because C< $x : Constant($o) > happens B<before> 108C<< $o = Myclass->new() >>. 109 110On the other hand, the following works. 111 112 my $y : Constant(MyClass->new(a => 1,b => 2)); 113 print Dumper( $o, $y ); 114 115Rule of the thumb is do not feed variables to constant because 116varialbes change after the attribute invocation. 117 118Or simply use C<Data::Lock::dlock>. 119 120 use Data::Lock qw/dlock/; 121 dlock my $z = $o; 122 print Dumper( $o, $y ); 123 124=head1 SEE ALSO 125 126L<Data::Lock>, L<constant> 127 128=head1 AUTHOR 129 130Dan Kogai, C<< <dankogai+cpan at gmail.com> >> 131 132=head1 BUGS & SUPPORT 133 134See L<Data::Lock>. 135 136=head1 ACKNOWLEDGEMENTS 137 138L<Readonly> 139 140=head1 COPYRIGHT & LICENSE 141 142Copyright 2008-2013 Dan Kogai, all rights reserved. 143 144This program is free software; you can redistribute it and/or modify it 145under the same terms as Perl itself. 146