search spec components factored out of T365
[catagits/Reaction.git] / lib / Reaction / Meta / Attribute.pm
CommitLineData
7adfd53f 1package Reaction::Meta::Attribute;
2
3use Moose;
4
5extends 'Moose::Meta::Attribute';
6
7#is => 'Bool' ? or leave it open
8has lazy_fail =>
9 (is => 'ro', reader => 'is_lazy_fail', required => 1, default => 0);
7adfd53f 10
905a0946 11around legal_options_for_inheritance => sub {
12 return (shift->(@_), qw/valid_values/);
13};
14
7adfd53f 15around _process_options => sub {
16 my $super = shift;
17 my ($class, $name, $options) = @_;
18
89939ff9 19 my $fail = $options->{lazy_fail};
7adfd53f 20
89939ff9 21 if ( $fail ) {
7adfd53f 22 confess("You may not use both lazy_build and lazy_fail for one attribute")
89939ff9 23 if $fail && $options->{lazy_build};
7adfd53f 24
25 $options->{lazy} = 1;
26 $options->{required} = 1;
89939ff9 27 $options->{default} = sub { confess "${name} must be provided before calling reader" };
7adfd53f 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
7adfd53f 34 $super->($class, $name, $options);
35};
36
4949e0ee 37foreach 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
a5200252 67__PACKAGE__->meta->make_immutable(inline_constructor => 0);
68
7adfd53f 691;
70
71__END__;
72
73=head1 NAME
74
75Reaction::Meta::Attribute
76
77=head1 SYNOPSIS
78
79 has description => (is => 'rw', isa => 'Str', lazy_fail => 1);
80
7adfd53f 81=head1 Method-naming conventions
82
83Reaction::Meta::Attribute will never override the values you set for method names,
84but if you do not it will follow these basic rules:
85
86Attributes with a name that starts with an underscore will default to using
87builder and predicate method names in the form of the attribute name preceeded by
88either "_has" or "_build". Otherwise the method names will be in the form of the
89attribute names preceeded by "has_" or "build_". e.g.
90
91 #auto generates "_has_description" and expects "_build_description"
89939ff9 92 has _description => (is => 'rw', isa => 'Str', lazy_fail => 1);
7adfd53f 93
94 #auto generates "has_description" and expects "build_description"
89939ff9 95 has description => (is => 'rw', isa => 'Str', lazy_fail => 1);
7adfd53f 96
97=head2 Predicate generation
98
99All non-required or lazy attributes will have a predicate automatically
100generated for them if one is not already specified.
101
102=head2 lazy_fail
103
89939ff9 104lazy_fail will fail if it is called without first having set the value.
7adfd53f 105
106=head1 AUTHORS
107
108See L<Reaction::Class> for authors.
109
110=head1 LICENSE
111
112See L<Reaction::Class> for the license.
113
114=cut