Commit | Line | Data |
7f43bb45 |
1 | package Reaction::Role::Meta::Attribute; |
2 | |
3 | use Moose::Role; |
4 | |
5 | #is => 'Bool' ? or leave it open |
6 | has lazy_fail => |
7 | (is => 'ro', reader => 'is_lazy_fail', required => 1, default => 0); |
8 | |
79d94ae5 |
9 | if ( $Moose::VERSION < 1.09 ) { |
10 | around legal_options_for_inheritance => sub { |
11 | return (shift->(@_), qw/valid_values/); |
12 | }; |
13 | } |
7f43bb45 |
14 | |
15 | around _process_options => sub { |
16 | my $super = shift; |
17 | my ($class, $name, $options) = @_; |
18 | |
19 | my $fail = $options->{lazy_fail}; |
20 | |
21 | if ( $fail ) { |
22 | confess("You may not use both lazy_build and lazy_fail for one attribute") |
23 | if $fail && $options->{lazy_build}; |
24 | |
25 | $options->{lazy} = 1; |
26 | $options->{required} = 1; |
27 | $options->{default} = sub { confess "${name} must be provided before calling reader" }; |
28 | } |
29 | |
30 | #we are using this everywhere so might as well move it here. |
31 | $options->{predicate} ||= ($name =~ /^_/) ? "_has${name}" : "has_${name}" |
32 | if !$options->{required} || $options->{lazy}; |
33 | |
34 | $super->($class, $name, $options); |
35 | }; |
36 | |
37 | foreach my $type (qw(clearer predicate)) { |
38 | |
39 | my $value_meth = do { |
40 | if ($type eq 'clearer') { |
41 | 'clear_value' |
42 | } elsif ($type eq 'predicate') { |
43 | 'has_value' |
44 | } else { |
45 | confess "NOTREACHED"; |
46 | } |
47 | }; |
48 | |
49 | __PACKAGE__->meta->add_method("get_${type}_method" => sub { |
50 | my $self = shift; |
51 | my $info = $self->$type; |
52 | return $info unless ref $info; |
53 | my ($name) = %$info; |
54 | return $name; |
55 | }); |
56 | |
57 | __PACKAGE__->meta->add_method("get_${type}_method_ref" => sub { |
58 | my $self = shift; |
59 | if ((my $name = $self->${\"get_${type}_method"}) && $self->associated_class) { |
60 | return $self->associated_class->get_method($name); |
61 | } else { |
62 | return sub { $self->$value_meth(@_); } |
63 | } |
64 | }); |
65 | } |
66 | |
67 | 1; |
68 | |
69 | __END__; |
70 | |
71 | =head1 NAME |
72 | |
73 | Reaction::Meta::Attribute |
74 | |
75 | =head1 SYNOPSIS |
76 | |
77 | has description => (is => 'rw', isa => 'Str', lazy_fail => 1); |
78 | |
79 | =head1 Method-naming conventions |
80 | |
81 | Reaction::Meta::Attribute will never override the values you set for method names, |
82 | but if you do not it will follow these basic rules: |
83 | |
84 | Attributes with a name that starts with an underscore will default to using |
85 | builder and predicate method names in the form of the attribute name preceeded by |
86 | either "_has" or "_build". Otherwise the method names will be in the form of the |
87 | attribute names preceeded by "has_" or "build_". e.g. |
88 | |
89 | #auto generates "_has_description" and expects "_build_description" |
90 | has _description => (is => 'rw', isa => 'Str', lazy_fail => 1); |
91 | |
92 | #auto generates "has_description" and expects "build_description" |
93 | has description => (is => 'rw', isa => 'Str', lazy_fail => 1); |
94 | |
95 | =head2 Predicate generation |
96 | |
97 | All non-required or lazy attributes will have a predicate automatically |
98 | generated for them if one is not already specified. |
99 | |
100 | =head2 lazy_fail |
101 | |
102 | lazy_fail will fail if it is called without first having set the value. |
103 | |
104 | =head1 AUTHORS |
105 | |
106 | See L<Reaction::Class> for authors. |
107 | |
108 | =head1 LICENSE |
109 | |
110 | See L<Reaction::Class> for the license. |
111 | |
112 | =cut |