File Coverage

blib/lib/Fey/Meta/Role/Relationship/HasOne.pm
Criterion Covered Total %
statement 41 41 100.0
branch 12 14 85.7
condition n/a
subroutine 11 11 100.0
pod 2 2 100.0
total 66 68 97.0


line stmt bran cond sub pod time code
1             package Fey::Meta::Role::Relationship::HasOne;
2              
3 10     10   6862 use strict;
  10         17  
  10         369  
4 10     10   49 use warnings;
  10         19  
  10         300  
5 10     10   46 use namespace::autoclean;
  10         14  
  10         66  
6              
7             our $VERSION = '0.47';
8              
9 10     10   837 use Fey::Exceptions qw( param_error );
  10         17  
  10         631  
10 10     10   46 use Fey::ORM::Types qw( Bool Item Maybe );
  10         18  
  10         94  
11              
12 10     10   50432 use Moose::Role;
  10         23  
  10         107  
13              
14             with 'Fey::Meta::Role::Relationship';
15              
16             has associated_attribute => (
17             is => 'rw',
18             isa => Maybe ['Moose::Meta::Attribute'],
19             init_arg => undef,
20             lazy => 1,
21             builder => '_build_associated_attribute',
22             );
23              
24             has associated_method => (
25             is => 'rw',
26             isa => Maybe ['Moose::Meta::Method'],
27             init_arg => undef,
28             lazy => 1,
29             builder => '_build_associated_method',
30             );
31              
32             has allows_undef => (
33             is => 'ro',
34             isa => Bool,
35             lazy => 1,
36             builder => '_build_allows_undef',
37             );
38              
39             has handles => (
40             is => 'ro',
41              
42             # just gets passed on for attribute creation
43             isa => Item,
44             );
45              
46             sub _build_associated_attribute {
47 9     9   16 my $self = shift;
48              
49 9 50       226 return unless $self->is_cached();
50              
51             # It'd be nice to set isa to the actual foreign class, but we may
52             # not be able to map a table to a class yet, since that depends on
53             # the related class being loaded. It doesn't really matter, since
54             # this accessor is read-only, so there's really no typing issue to
55             # deal with.
56 9         25 my $type = 'Fey::Object::Table';
57 9 100       256 $type = "Maybe[$type]" if $self->allows_undef();
58              
59 7         48 my %attr_p = (
60             is => 'rw',
61             isa => $type,
62             lazy => 1,
63             default => $self->_make_subref(),
64             writer => q{_set_} . $self->name(),
65             predicate => q{_has_} . $self->name(),
66             clearer => q{_clear_} . $self->name(),
67             );
68              
69 7 100       219 $attr_p{handles} = $self->handles()
70             if $self->handles();
71              
72 7         212 return $self->associated_class()->attribute_metaclass()->new(
73             $self->name(),
74             %attr_p,
75             );
76             }
77              
78 8     8   211 sub _build_is_cached {1}
79              
80             sub _build_associated_method {
81 3     3   8 my $self = shift;
82              
83 3 100       134 return if $self->is_cached();
84              
85 2         79 return $self->associated_class()->method_metaclass()->wrap(
86             name => $self->name(),
87             package_name => $self->associated_class()->name(),
88             body => $self->_make_subref(),
89             );
90             }
91              
92             sub attach_to_class {
93 11     11 1 19 my $self = shift;
94 11         20 my $class = shift;
95              
96 11         410 $self->_set_associated_class($class);
97              
98 11 100       323 if ( $self->is_cached() ) {
99 9         275 $class->add_attribute( $self->associated_attribute() );
100             }
101             else {
102 2         74 $class->add_method( $self->name() => $self->associated_method() );
103             }
104             }
105              
106             sub detach_from_class {
107 8     8 1 13 my $self = shift;
108              
109 8 50       265 return unless $self->associated_class();
110              
111 8 100       268 if ( $self->is_cached() ) {
112 7         205 $self->associated_class->remove_attribute( $self->name() );
113             }
114             else {
115 1         26 $self->associated_class->remove_method( $self->name() );
116             }
117              
118 8         2818 $self->_clear_associated_class();
119             }
120              
121             1;
122              
123             # ABSTRACT: A role for has-one metaclasses
124              
125             __END__
126              
127             =pod
128              
129             =head1 NAME
130              
131             Fey::Meta::Role::Relationship::HasOne - A role for has-one metaclasses
132              
133             =head1 VERSION
134              
135             version 0.47
136              
137             =head1 DESCRIPTION
138              
139             This role provides functionality for the two has-one metaclasses,
140             L<Fey::Meta::HasOne::ViaFK> and L<Fey::Meta::HasOne::ViaSelect>.
141              
142             =head1 CONSTRUCTOR OPTIONS
143              
144             This role adds the following constructor options:
145              
146             =over 4
147              
148             =item * handles
149              
150             This will simply be passed on when an attribute for this has-one relationship
151             is created. Note that this is ignored if C<is_cached> is false.
152              
153             =item * allows_undef
154              
155             A boolean indicating whether or not the relationship's value can be
156             C<undef>.
157              
158             =item * is_cached
159              
160             Defaults to true for this class.
161              
162             =back
163              
164             =head1 METHODS
165              
166             This role provides the following methods:
167              
168             =head2 $ho->name()
169              
170             Corresponds to the value passed to the constructor.
171              
172             =head2 $ho->table()
173              
174             Corresponds to the value passed to the constructor.
175              
176             =head2 $ho->foreign_table()
177              
178             Corresponds to the value passed to the constructor.
179              
180             =head2 $ho->is_cached()
181              
182             Corresponds to the value passed to the constructor, or the calculated
183             default.
184              
185             =head2 $ho->allows_undef()
186              
187             Corresponds to the value passed to the constructor.
188              
189             =head2 $ho->handles()
190              
191             Corresponds to the value passed to the constructor.
192              
193             =head2 $ho->attach_to_class($class)
194              
195             This method takes a F<Fey::Meta::Class::Table> object and attaches the
196             relationship to the associated class. If this relationship is cached,
197             it creates a new attribute, otherwise it creates a new method.
198              
199             The method/attribute returns an object belonging to the class
200             associated with the foreign table. It can return C<undef> if
201             C<allows_undef> is true.
202              
203             =head2 $ho->associated_class()
204              
205             The class associated with this object. This is undefined until C<<
206             $ho->attach_to_class() >> is called.
207              
208             =head2 $ho->associated_attribute()
209              
210             Returns the attribute associated with this object, if any.
211              
212             =head2 $ho->associated_method()
213              
214             Returns the method associated with this object, if any.
215              
216             =head2 $ho->detach_from_class()
217              
218             If this object was attached to a class, it removes any attribute or
219             method it made, and unsets the C<associated_class>.
220              
221             =head1 AUTHOR
222              
223             Dave Rolsky <autarch@urth.org>
224              
225             =head1 COPYRIGHT AND LICENSE
226              
227             This software is copyright (c) 2011 - 2015 by Dave Rolsky.
228              
229             This is free software; you can redistribute it and/or modify it under
230             the same terms as the Perl 5 programming language system itself.
231              
232             =cut