File Coverage

blib/lib/KiokuDB/TypeMap/Composite.pm
Criterion Covered Total %
statement 55 57 96.4
branch 8 12 66.6
condition 3 6 50.0
subroutine 14 14 100.0
pod n/a
total 80 89 89.8


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2              
3             package KiokuDB::TypeMap::Composite;
4 23     23   11828 use Moose::Role;
  23         40  
  23         134  
5              
6 23     23   86407 use KiokuDB::TypeMap;
  23         44  
  23         657  
7              
8 23     23   94 use namespace::clean -except => 'meta';
  23         37  
  23         151  
9              
10             {
11             package KiokuDB::TypeMap::Composite::TypeMapAttr;
12 23     23   4912 use Moose::Role;
  23         39  
  23         93  
13              
14 23     23   86466 use namespace::clean -except => 'meta';
  23         44  
  23         115  
15              
16 23     23   21252 sub Moose::Meta::Attribute::Custom::Trait::KiokuDB::TypeMap::register_implementation { __PACKAGE__ }
17             }
18              
19             has override => (
20             isa => "HashRef[HashRef]",
21             is => "ro",
22             default => sub { +{} },
23             );
24              
25             has exclude => (
26             isa => "ArrayRef[Str]",
27             is => "ro",
28             default => sub { [] },
29             );
30              
31             has _exclude => (
32             is => "ro",
33             lazy_build => 1,
34             );
35              
36             sub _build__exclude {
37 79     79   149 my $self = shift;
38 79         111 return { map { $_ => undef } @{ $self->exclude } };
  0         0  
  79         2404  
39             }
40              
41             sub _build_includes {
42 79     79   136 my $self = shift;
43              
44 79         424 my @attrs = $self->meta->get_all_attributes;
45              
46 79         7207 my $exclude = $self->_exclude;
47              
48 1221         133110 my @typemap_attrs = grep {
49 79         189 ( my $short_name = $_->name ) =~ s/_typemap$//;
50              
51 1221 100 33     3028 $_->does("KiokuDB::TypeMap::Composite::TypeMapAttr")
      66        
52             and
53             ( !$short_name or !exists($exclude->{$short_name}) )
54             and
55             !exists($exclude->{$_->name})
56             } @attrs;
57              
58 79         8258 return [ map { $_->get_value($self) } @typemap_attrs ];
  446         149609  
59             }
60              
61             sub _construct_entry {
62 1022     1022   2258 my ( $self, @args ) = @_;
63              
64 1022         1895 my $args = $self->_entry_options(@args);
65              
66 1022         2402 my $type = delete $args->{type};
67 1022         2856 Class::MOP::load_class($type);
68              
69 1022         95887 $type->new($args);
70             }
71              
72             sub _entry_options {
73 1022     1022   2599 my ( $self, %args ) = @_;
74              
75 1022         1719 my $class = delete $args{class};
76              
77 1022 50       1471 return { %args, %{ $self->override->{$class} || {} }, };
  1022         29579  
78             }
79              
80             sub _create_entry {
81 1022     1022   1234 my ( $self, $class, $entry ) = @_;
82              
83 1022 50       31546 return if exists $self->_exclude->{$class};
84              
85 1022 50       3317 if ( blessed $entry ) {
    100          
86 0         0 return ( $class => $entry );
87             } elsif ( ref $entry ) {
88 638         2005 return ( $class => $self->_construct_entry( %$entry, class => $class ) );
89             } else {
90 384         860 return ( $class => $self->_construct_entry( type => $entry, class => $class ) );
91             }
92             }
93              
94             sub _create_entries {
95 638     638   698 my ( $self, $entries ) = @_;
96              
97 638         548 my $excl;
98              
99             return {
100 1022         1084 map {
101 638         1513 my $class = $_;
102 1022         1624 my $entry = $entries->{$class};
103              
104 1022         1827 $self->_create_entry($class, $entry);
105             } keys %$entries
106             };
107             }
108              
109             sub _create_typemap {
110 446     446   1104 my ( $self, %args ) = @_;
111              
112 446         722 foreach my $entries ( @args{grep { exists $args{$_} } qw(entries isa_entries does_entries)} ) {
  1338         2422  
113 638 50       1291 next unless $entries;
114 638         1304 $entries = $self->_create_entries($entries);
115             }
116              
117 446         13487 KiokuDB::TypeMap->new(%args);
118             }
119              
120             sub _naive_isa_typemap {
121 30     30   48 my ( $self, $class, @args ) = @_;
122              
123 30         148 $self->_create_typemap(
124             isa_entries => {
125             $class => {
126             type => "KiokuDB::TypeMap::Entry::Naive",
127             @args,
128             },
129             },
130             );
131             }
132              
133             __PACKAGE__
134              
135             __END__
136              
137             =pod
138              
139             =head1 NAME
140              
141             KiokuDB::TypeMap::Composite - A role for L<KiokuDB::TypeMaps> created out of
142             many smaller typemaps
143              
144             =head1 SYNOPSIS
145              
146             package MyTypeMap;
147             use Moose;
148              
149             extends qw(KiokuDB::TypeMap);
150              
151             with qw(KiokuDB::TypeMap::Composite);
152              
153              
154             # declare typemaps to inherit from using the KiokuDB::TypeMap trait
155             # the 'includes' attribute will be built by collecting these attrs:
156              
157             has foo_typemap => (
158             traits => [qw(KiokuDB::TypeMap)], # register for inclusion
159             does => "KiokUDB::Role::TypeMap",
160             is => "ro",
161             lazy_build => 1,
162             );
163              
164              
165             # this role also provides convenience methods for creating typemap objects
166             # easily:
167             sub _build_foo_typemap {
168             my $self = shift;
169              
170             $self->_create_typemap(
171             isa_entries => {
172             $class => {
173             type => 'KiokuDB::TypeMap::Entry::Callback',
174             intrinsic => 1,
175             collapse => "collapse",
176             expand => "new",
177             },
178             },
179             );
180             }
181              
182             sub _build_bar_typemap {
183             my $self = shift;
184              
185             # create a typemap with one naive isa entry
186             $self->_naive_isa_typemap("Class::Foo", @entry_args);
187             }
188              
189              
190              
191              
192              
193             # you also get some construction time customization:
194              
195             MyTypeMap->new(
196             exclude => [qw(Class::Blort foo)],
197             override => {
198             "Class::Blah", => $alternate_entry,
199             },
200             );
201              
202             =head1 DESCRIPTION
203              
204             This role provides a declarative, customizable way to set values for
205             L<KiokuDB::TypeMap>'s C<includes> attribute.
206              
207             Any class consuming this role can declare attributes with the trait
208             C<KiokuDB::TypeMap>.
209              
210             The result is a typemap instance that inherits from the specified typemap in a
211             way that is composable for the author and flexible for the user.
212              
213             L<KiokuDB::TypeMap::Default> is created using this role.
214              
215             =head1 ATTRIBUTES
216              
217             =over 4
218              
219             =item exclude
220              
221             An array reference containing typemap attribute names (e.g. C<path_class> in
222             the default typemap) or class name to exclude.
223              
224             Class exclusions are handled by C<_create_typemap> and do not apply to already
225             constructed typemaps.
226              
227             =item override
228              
229             A hash reference of classes to L<KiokuDB::TypeMap::Entry> objects.
230              
231             Class overrides are handled by C<_create_typemap> and do not apply to already
232             constructed typemaps.
233              
234             Classes which don't have a definition will not be merged into the resulting
235             typemap, simply create a typemap of your own and inherit if that's what you
236             want.
237              
238             =back
239              
240             =head1 METHODS
241              
242             =over 4
243              
244             =item _create_typemap %args
245              
246             Creates a new typemap.
247              
248             The entry arguments are converted before passing to L<KiokuDB::TypeMap/new>:
249              
250             $self->_create_typemap(
251             entries => {
252             Foo => {
253             type => "KiokuDB::TypeMap::Entry::Naive",
254             intrinsic => 1,
255             },
256             },
257             );
258              
259             The nested hashref will be used as arguments to
260             L<KiokuDB::TypeMap::Entry::Naive/new> in this example.
261              
262             C<exclude> and C<override> are taken into account by the hashref conversion
263             code.
264              
265             =item _naive_isa_typemap $class, %entry_args
266              
267             A convenience method to create a one entry typemap with a single inherited
268             entry for C<$class> of the type L<KiokuDB::TypeMap::Entry::Naive>.
269              
270             This is useful for when you have a base class that you'd like KiokuDB to
271             persist automatically:
272              
273             sub _build_my_class_typemap {
274             shift->_naive_isa_typemap( "My::Class::Base" );
275             }
276              
277             =back
278              
279             =cut
280