38035d56635d537c531fa05f4fcbf8e8c472cb3a
[catagits/Reaction.git] / lib / Reaction / Meta / Attribute.pm
1 package Reaction::Meta::Attribute;
2
3 use Moose;
4
5 extends 'Moose::Meta::Attribute';
6
7 #is => 'Bool' ? or leave it open
8 has lazy_fail  =>
9     (is => 'ro', reader => 'is_lazy_fail',  required => 1, default => 0);
10 has lazy_build =>
11     (is => 'ro', reader => 'is_lazy_build', required => 1, default => 0);
12
13 around _process_options => sub {
14     my $super = shift;
15     my ($class, $name, $options) = @_;
16
17     my $fail  = $options->{lazy_fail}; #will this autovivify?
18     my $build = $options->{lazy_build};
19
20     if ( $fail || $build) {
21       confess("You may not use both lazy_build and lazy_fail for one attribute")
22         if $fail && $build;
23       confess("You may not supply a default value when using lazy_build or lazy_fail")
24         if exists $options->{default};
25
26       $options->{lazy} = 1;
27       $options->{required} = 1;
28
29       my $builder = ($name =~ /^_/) ? "_build${name}" : "build_${name}";
30       $options->{default} =  $fail ?
31         sub { confess "${name} must be provided before calling reader" } :
32           sub{ shift->$builder };
33     }
34
35     #we are using this everywhere so might as well move it here.
36     $options->{predicate} ||= ($name =~ /^_/) ? "_has${name}" : "has_${name}"
37       if !$options->{required} || $options->{lazy};
38
39
40     $super->($class, $name, $options);
41 };
42
43 1;
44
45 __END__;
46
47 =head1 NAME
48
49 Reaction::Meta::Attribute
50
51 =head1 SYNOPSIS
52
53     has description => (is => 'rw', isa => 'Str', lazy_fail => 1);
54
55     # OR
56     has description => (is => 'rw', isa => 'Str', lazy_build => 1);
57     sub build_description{ "My Description" }
58
59     # OR
60     has _description => (is => 'rw', isa => 'Str', lazy_build => 1);
61     sub _build_description{ "My Description" }
62
63 =head1 Method-naming conventions
64
65 Reaction::Meta::Attribute will never override the values you set for method names,
66 but if you do not it will follow these basic rules:
67
68 Attributes with a name that starts with an underscore will default to using
69 builder and predicate method names in the form of the attribute name preceeded by
70 either "_has" or "_build". Otherwise the method names will be in the form of the
71 attribute names preceeded by "has_" or "build_". e.g.
72
73    #auto generates "_has_description" and expects "_build_description"
74    has _description => (is => 'rw', isa => 'Str', lazy_build => 1);
75
76    #auto generates "has_description" and expects "build_description"
77    has description => (is => 'rw', isa => 'Str', lazy_build => 1);
78
79 =head2 Predicate generation
80
81 All non-required or lazy attributes will have a predicate automatically
82 generated for them if one is not already specified.
83
84 =head2 lazy_fail
85
86 =head2 lazy_build
87
88 lazy_build will lazily build to the return value of a user-supplied builder sub
89  The builder sub will recieve C<$self> as the first argument.
90
91 lazy_fail will simply fail if it is called without first having set the value.
92
93 =head1 AUTHORS
94
95 See L<Reaction::Class> for authors.
96
97 =head1 LICENSE
98
99 See L<Reaction::Class> for the license.
100
101 =cut