Commit | Line | Data |
7adfd53f |
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 }; |
e22de101 |
33 | |
34 | $options->{clearer} ||= ($name =~ /^_/) ? "_clear${name}" : "clear_${name}" |
35 | if $build; |
7adfd53f |
36 | } |
37 | |
38 | #we are using this everywhere so might as well move it here. |
39 | $options->{predicate} ||= ($name =~ /^_/) ? "_has${name}" : "has_${name}" |
40 | if !$options->{required} || $options->{lazy}; |
41 | |
42 | |
43 | $super->($class, $name, $options); |
44 | }; |
45 | |
a5200252 |
46 | __PACKAGE__->meta->make_immutable(inline_constructor => 0); |
47 | |
7adfd53f |
48 | 1; |
49 | |
50 | __END__; |
51 | |
52 | =head1 NAME |
53 | |
54 | Reaction::Meta::Attribute |
55 | |
56 | =head1 SYNOPSIS |
57 | |
58 | has description => (is => 'rw', isa => 'Str', lazy_fail => 1); |
59 | |
60 | # OR |
61 | has description => (is => 'rw', isa => 'Str', lazy_build => 1); |
62 | sub build_description{ "My Description" } |
63 | |
64 | # OR |
65 | has _description => (is => 'rw', isa => 'Str', lazy_build => 1); |
66 | sub _build_description{ "My Description" } |
67 | |
68 | =head1 Method-naming conventions |
69 | |
70 | Reaction::Meta::Attribute will never override the values you set for method names, |
71 | but if you do not it will follow these basic rules: |
72 | |
73 | Attributes with a name that starts with an underscore will default to using |
74 | builder and predicate method names in the form of the attribute name preceeded by |
75 | either "_has" or "_build". Otherwise the method names will be in the form of the |
76 | attribute names preceeded by "has_" or "build_". e.g. |
77 | |
78 | #auto generates "_has_description" and expects "_build_description" |
79 | has _description => (is => 'rw', isa => 'Str', lazy_build => 1); |
80 | |
81 | #auto generates "has_description" and expects "build_description" |
82 | has description => (is => 'rw', isa => 'Str', lazy_build => 1); |
83 | |
84 | =head2 Predicate generation |
85 | |
86 | All non-required or lazy attributes will have a predicate automatically |
87 | generated for them if one is not already specified. |
88 | |
89 | =head2 lazy_fail |
90 | |
91 | =head2 lazy_build |
92 | |
93 | lazy_build will lazily build to the return value of a user-supplied builder sub |
94 | The builder sub will recieve C<$self> as the first argument. |
95 | |
96 | lazy_fail will simply fail if it is called without first having set the value. |
97 | |
98 | =head1 AUTHORS |
99 | |
100 | See L<Reaction::Class> for authors. |
101 | |
102 | =head1 LICENSE |
103 | |
104 | See L<Reaction::Class> for the license. |
105 | |
106 | =cut |