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