File Coverage

blib/lib/Elastic/Model/TypeMap/Base.pm
Criterion Covered Total %
statement 154 191 80.6
branch 52 66 78.7
condition 35 58 60.3
subroutine 35 37 94.5
pod 16 19 84.2
total 292 371 78.7


line stmt bran cond sub pod time code
1             package Elastic::Model::TypeMap::Base;
2             $Elastic::Model::TypeMap::Base::VERSION = '0.52';
3 23     23   16841 use strict;
  23         55  
  23         623  
4 23     23   124 use warnings;
  23         54  
  23         729  
5              
6 23     23   137 use Sub::Exporter qw(build_exporter);
  23         54  
  23         253  
7 23     23   6414 use Class::MOP();
  23         57  
  23         463  
8 23     23   129 use Class::Load();
  23         48  
  23         492  
9 23     23   133 use List::MoreUtils qw(uniq);
  23         46  
  23         290  
10 23     23   11357 use Moose::Util qw(does_role);
  23         52  
  23         204  
11 23     23   4994 use Scalar::Util qw(blessed);
  23         57  
  23         1373  
12 23     23   137 use Moose::Util::TypeConstraints qw(find_type_constraint);
  23         53  
  23         272  
13 23     23   9714 use namespace::autoclean;
  23         58  
  23         305  
14              
15 609     609 0 3120 sub deflate_via (&) { deflator => $_[0] }
16 609     609 0 2817 sub inflate_via (&) { inflator => $_[0] }
17 666     666 0 2252 sub map_via (&) { mapper => $_[0] }
18              
19             #===================================
20             sub import {
21             #===================================
22 149     149   530     my ( $class, @args ) = @_;
23 149         654     my $callee = caller;
24 149 50 33     4730     return if $callee->isa(__PACKAGE__) || @args == 0;
25              
26                 {
27 23     23   5296         no strict 'refs';
  23         56  
  23         60375  
  149         260  
28 149         217         unshift @{ $callee . '::ISA' }, __PACKAGE__;
  149         2068  
29                 }
30              
31                 build_exporter(
32                     { into => $callee,
33                         exports => [
34                             qw(deflate_via inflate_via map_via),
35                             has_type => sub {
36 758     758   2286                     sub { $callee->_has_type(@_) }
37 149     149   65840                 },
38 149         1620             ]
39                     }
40                 )->( $class, ':all' );
41              
42 149         40593     for (@args) {
43 252 100       5903         next if /^[:-]/;
44 126         491         Class::Load::load_class($_);
45 126         3724         $callee->import_types( $_->typemap );
46                 }
47             }
48              
49             #===================================
50             sub find_deflator {
51             #===================================
52 77     77 1 226980     my ( $map, $attr ) = @_;
53 77         284     my $deflator = $map->find_raw_deflator($attr);
54 55 100       541     return $deflator if ref $deflator;
55 48         247     Eval::Closure::eval_closure(
56                     source => [ 'sub { my $val = $_[0];', $deflator, '}' ] );
57             }
58              
59             #===================================
60             sub find_raw_deflator {
61             #===================================
62 77     77 1 153     my ( $map, $attr ) = @_;
63                 $attr->can('deflator') && $attr->deflator
64 77 100 33     4065         || eval { $map->find( 'deflator', $attr->type_constraint, $attr ) }
  77   66     2587  
65                     || die _type_error( 'deflator', $attr, $@ );
66             }
67              
68             #===================================
69             sub find_inflator {
70             #===================================
71 77     77 1 36718     my ( $map, $attr ) = @_;
72 77         267     my $inflator = $map->find_raw_inflator($attr);
73 55 100       485     return $inflator if ref $inflator;
74 48         212     Eval::Closure::eval_closure(
75                     source => [ 'sub { my $val = $_[0];', $inflator, '}' ] );
76             }
77              
78             #===================================
79             sub find_raw_inflator {
80             #===================================
81 77     77 1 126     my ( $map, $attr ) = @_;
82                 $attr->can('inflator') && $attr->inflator
83 77 100 33     4018         || eval { $map->find( 'inflator', $attr->type_constraint, $attr ) }
  77   66     2566  
84                     || die _type_error( 'inflator', $attr, $@ );
85             }
86              
87             #===================================
88             sub find_mapper {
89             #===================================
90 205     205 1 128371     my ( $map, $attr ) = @_;
91 205         276     my $mapping;
92 205 100       9088     $mapping = $attr->mapping if $attr->can('mapping');
93 205 100 66     654     return %$mapping if $mapping && %$mapping;
94              
95 204         276     my %mapping;
96 204         301     eval {
97 204         6680         my @mapping = $map->find( 'mapper', $attr->type_constraint, $attr );
98 202 100       2667         die "Expected an even number of elements "
99                         . "to be returned by the mapper.\n"
100                         if @mapping % 2;
101 201         793         %mapping = @mapping;
102                 };
103              
104 204 100       513     die _type_error( 'mapper', $_[1], $@ )
105                     unless %mapping;
106              
107 196         1100     return %mapping;
108             }
109              
110             #===================================
111             sub _type_error {
112             #===================================
113 52     52   144     my ( $type, $attr, $error ) = @_;
114 52         215     my $name = $attr->name;
115 52         296     my $class = $attr->associated_class->name;
116 52 100       786     return $error
117                     ? "Error finding $type for attribute ($name) in class $class:\n$error"
118                     : "No $type found for attribute ($name) in class $class";
119             }
120              
121             #===================================
122             sub find {
123             #===================================
124 1012     1012 1 5548     my ( $map, $type, $tc, $attr ) = @_;
125              
126 1012   66     3312     $tc ||= find_type_constraint('Any');
127              
128 1012         6283     my $types = $type . 's';
129 1012         3109     my $handlers = $map->$types;
130 1012         25844     my $name = $tc->name;
131              
132 1012 100 100     151426     if ( my $handler = $handlers->{$name} || $handlers->{ ref $tc } ) {
133 619         2256         return $handler->( $tc, $attr, $map );
134                 }
135              
136 393 100 100     13456     my $parent = $tc->can('parent') && $tc->parent or return;
137 382         5531     $map->find( $type, $parent, $attr );
138             }
139              
140             #===================================
141             sub class_deflator {
142             #===================================
143 0     0 1 0     my ( $map, $class, $attrs ) = @_;
144              
145 0   0     0     $attrs ||= $map->indexable_attrs($class);
146              
147 0         0     my %deflators = map { $_ => $map->find_raw_deflator( $attrs->{$_} ) }
  0         0  
148                     keys %$attrs;
149              
150 0         0     my @src = ( 'sub {', 'my $self = shift;', 'my (%hash,$attr,$val);',
151                     'eval {', );
152              
153 0         0     my %readers;
154 0         0     for my $name ( sort keys %deflators ) {
155 0         0         my $attr = $attrs->{$name};
156 0         0         my $deflator = $deflators{$name};
157 0 0       0         if ( ref $deflator ) {
158 0         0             $deflator = '$deflators{"' . $name . '"}->($val)';
159                     }
160 0         0         my $is_lazy = $attr->is_lazy;
161 0         0         my $get_raw = $attr->_inline_instance_get('$self');
162 0         0         my $exists = $attr->_inline_instance_has('$self');
163              
164 0         0         push @src, '$attr="' . $name . '";';
165 0 0       0         if ($is_lazy) {
166 0         0             $readers{$name} = $attr->get_read_method_ref;
167 0         0             push @src, '$readers{"' . $name . '"}->($self);';
168                     }
169                     else {
170 0         0             push @src, "if ($exists) {";
171                     }
172 0         0         push @src, '$val = ' . $get_raw . ';',
173                         '$hash{"' . $name . '"} = ' . $deflator . ';';
174 0 0       0         push @src, '}' unless $is_lazy;
175                 }
176              
177 0         0     push @src,
178                     (
179                     '1;} ',
180                     'or die "Error deflating attribute ($attr) in class ".',
181                     'Scalar::Util::blessed($self).',
182                     '":\n ".($@ || "Unknown error");',
183                     'return \%hash',
184                     '}'
185                     );
186              
187 0         0     Eval::Closure::eval_closure(
188                     source => \@src,
189                     environment => {
190                         '%deflators' => \%deflators,
191                         '%readers' => \%readers
192                     }
193                 );
194             }
195              
196             #===================================
197             sub class_inflator {
198             #===================================
199 0     0 1 0     my ( $map, $class, $attrs ) = @_;
200              
201 0   0     0     $attrs ||= $map->indexable_attrs($class);
202 0         0     my %inflators = map { $_ => $map->find_raw_inflator( $attrs->{$_} ) }
  0         0  
203                     keys %$attrs;
204              
205 0         0     my @src = (
206                     'sub {',
207                     'my ($self,$hash) = @_;',
208                     'my ($attr,$val,$res);',
209                     'eval {'
210                 );
211 0         0     for my $name ( sort keys %inflators ) {
212 0         0         my $attr = $attrs->{$name};
213 0         0         my $inflator = $inflators{$name};
214 0         0         my $set_raw = $attr->_inline_instance_set( '$self', '$res' );
215 0 0       0         if ( ref $inflator ) {
216 0         0             $inflator = '$inflators{"' . $name . '"}->($val)';
217                     }
218 0         0         push @src,
219                         (
220                         '$attr = "' . $name . '";',
221                         'if (exists $hash->{"' . $name . '"}) {',
222                         '$val = $hash->{"' . $name . '"};',
223                         '$res = ' . $inflator . ';',
224                         $set_raw . ';',
225                         $attr->_inline_weaken_value( '$self', '$res' ),
226                         '}'
227                         );
228                 }
229 0         0     push @src,
230                     (
231                     '1}',
232                     'or die "Error inflating attribute ($attr) in class ".',
233                     'Scalar::Util::blessed($self).',
234                     '":\n ".($@ || "Unknown error");',
235                     'return $self',
236                     '}'
237                     );
238              
239 0         0     Eval::Closure::eval_closure(
240                     source => \@src,
241                     environment => { '%inflators' => \%inflators, }
242                 );
243             }
244              
245             our %Allowed_Attrs = (
246                 string => {
247                     'index_name' => 1,
248                     'store' => 1,
249                     'index' => 1,
250                     'term_vector' => 1,
251                     'boost' => 1,
252                     'null_value' => 1,
253                     'analyzer' => 1,
254                     'index_analyzer' => 1,
255                     'search_analyzer' => 1,
256                     'search_quote_analyzer' => 1,
257                     'include_in_all' => 1,
258                     'multi' => 1,
259                 },
260                 integer => {
261                     'index_name' => 1,
262                     'store' => 1,
263                     'index' => 1,
264                     'precision_step' => 1,
265                     'boost' => 1,
266                     'null_value' => 1,
267                     'include_in_all' => 1,
268                     'multi' => 1,
269                 },
270                 date => {
271                     'index_name' => 1,
272                     'format' => 1,
273                     'store' => 1,
274                     'index' => 1,
275                     'precision_step' => 1,
276                     'boost' => 1,
277                     'null_value' => 1,
278                     'include_in_all' => 1,
279                     'multi' => 1,
280                 },
281                 boolean => {
282                     'index_name' => 1,
283                     'store' => 1,
284                     'index' => 1,
285                     'boost' => 1,
286                     'null_value' => 1,
287                     'include_in_all' => 1,
288                     'multi' => 1,
289                 },
290                 binary => {
291                     'index_name' => 1,
292                     'store' => 1
293                 },
294                 object => {
295                     'dynamic' => 1,
296                     'enabled' => 1,
297                     'path' => 1,
298                     'include_in_all' => 1,
299                 },
300                 nested => {
301                     'include_in_parent' => 1,
302                     'include_in_root' => 1,
303                     'include_in_all' => 1,
304                     'dynamic' => 1,
305                     'path' => 1,
306                 },
307                 ip => {
308                     'index_name' => 1,
309                     'store' => 1,
310                     'index' => 1,
311                     'precision_step' => 1,
312                     'boost' => 1,
313                     'null_value' => 1,
314                     'include_in_all' => 1,
315                     'multi' => 1,
316                 },
317                 geo_point => {
318                     'lat_lon' => 1,
319                     'geohash' => 1,
320                     'geohash_precision' => 1,
321                     'index_name' => 1,
322                     'store' => 1,
323                     'multi' => 1,
324                 },
325              
326             # TODO: attachment => {}
327             );
328              
329             our @All_Keys = uniq map { keys %$_ } values %Allowed_Attrs;
330              
331             $Allowed_Attrs{$_} = $Allowed_Attrs{integer}
332                 for qw(long float double short byte);
333              
334             #===================================
335             sub class_mapping {
336             #===================================
337 32     32 1 65     my ( $map, $class, $attrs ) = @_;
338              
339 32   66     126     $attrs ||= $map->indexable_attrs($class);
340              
341 32         103     my %props = map { $_ => $map->attribute_mapping( $attrs->{$_} ) }
  62         563  
342                     keys %$attrs;
343              
344 32 100       856     return ( type => 'object', enabled => 0 )
345                     unless %props;
346              
347                 return (
348 31         247         type => 'object',
349                     dynamic => 'strict',
350                     properties => \%props
351                 );
352             }
353              
354             #===================================
355             sub attribute_mapping {
356             #===================================
357 107     107 1 43693     my ( $map, $attr ) = @_;
358              
359 107   100     4295     my $mapping = $attr->can('mapping') && $attr->mapping
360                     || { $map->find_mapper($attr) };
361              
362 107   100     374     my $type = $mapping->{type} || '';
363 107 100       501     if ( $attr->can('type') ) {
364 89         3613         my $new_type = $attr->type;
365 89 100 66     319         if ( $new_type and $new_type ne $type ) {
366                         delete $mapping->{enabled}
367 14 100       52                 if $type eq 'object';
368 14         39             $mapping->{type} = $type = $new_type;
369                     }
370                 }
371              
372 107 50       249     die "Missing field type" unless $type;
373              
374 107 50       340     my $allowed = $Allowed_Attrs{$type} or die "Unknown field type ($type)";
375              
376 107 100       326     return $mapping unless does_role( $attr, 'Elastic::Model::Trait::Field' );
377              
378 89         21842     for my $key (@All_Keys) {
379 1855         73318         my $val = $attr->$key;
380 1855 100       4799         next unless defined $val;
381                     die "Attribute has type '$type', which doesn't "
382                         . "understand '$key'\n"
383 108 100       414             unless $allowed->{$key};
384 97         246         $mapping->{$key} = $val;
385                 }
386              
387 78         345     $mapping = $map->_fixup_mapping($mapping);
388              
389                 my $multi = delete $mapping->{multi}
390 78 100       393         or return $mapping;
391              
392 15         79     my $main = $attr->name;
393 15         78     my %new = ( type => 'multi_field', fields => { $main => $mapping } );
394 15         53     for my $name ( keys %$multi ) {
395 19 50       62         die "Multi-field name '$name' clashes with the attribute name\n"
396                         if $name eq $main;
397 19         46         my $defn = $multi->{$name};
398 19   66     119         my $multi_type = $defn->{type} ||= $type;
399              
400 19 50       70         $allowed = $Allowed_Attrs{$multi_type}
401                         or die "Uknown field type ($type)";
402              
403 19         60         for my $key ( keys %$defn ) {
404                         die "Attribute has type '$multi_type', which doesn't "
405                             . "understand '$key'\n"
406 39 100 100     288                 unless $allowed->{$key} || $key eq 'type';
407                     }
408              
409 13         57         $new{fields}{$name} = $map->_fixup_mapping($defn);
410                 }
411 9         60     return \%new;
412             }
413              
414             #===================================
415             sub _fixup_mapping {
416             #===================================
417 91     91   169     my ( $map, $defn ) = @_;
418              
419                 delete $defn->{analyzer}
420 91 100 66     295         if $defn->{index_analyzer} && $defn->{search_analyzer};
421              
422 91         205     return $defn;
423             }
424              
425             #===================================
426 373     373 1 981 sub deflators { shift->typemap->{deflator} }
427 373     373 1 990 sub inflators { shift->typemap->{inflator} }
428 376     376 1 1146 sub mappers { shift->typemap->{mapper} }
429             #===================================
430              
431             #===================================
432             sub _has_type {
433             #===================================
434 758     758   2285     my ( $class, $type, %params ) = @_;
435 758         1981     my $map = $class->typemap();
436 758         1971     for ( keys %params ) {
437 1884         6401         $map->{$_}{$type} = $params{$_};
438                 }
439             }
440              
441             #===================================
442             sub indexable_attrs {
443             #===================================
444 9     9 1 18     my $map = shift;
445 9         17     my $class = shift;
446 9   33     41     $class = $map->model->class_for($class) || $class;
447              
448 9         28     my $meta = Class::MOP::class_of($class);
449              
450                 return {
451 22         121         map { $_->name => $_ }
452 9   66     90             grep { !( $_->can('exclude') && $_->exclude ) }
  49         2674  
453                         $meta->get_all_attributes
454                 };
455             }
456              
457             #===================================
458             sub typemap {
459             #===================================
460 2132     2132 1 2997     my $class = shift;
461 2132 100       14154     $class = $class->original_class
462                     if $class->can('original_class');
463              
464             # return a reference to the storage in ourself
465                 {
466 23     23   157         no strict 'refs';
  23         75  
  23         5520  
  2132         3057  
467 2132         2505         return \%{ $class . '::__ES_TYPE_MAP' };
  2132         13152  
468                 }
469             }
470              
471             #===================================
472             sub import_types {
473             #===================================
474 126     126 1 223     my $class = shift;
475 126         213     my $import = shift;
476 126         403     my $map = $class->typemap;
477 126         310     for (qw(deflator inflator mapper)) {
478 378 50       1149         my $types = $import->{$_} or next;
479 378         1377         @{ $map->{$_} }{ keys %$types } = values %$types;
  378         3620  
480                 }
481             }
482              
483             1;
484              
485             =pod
486            
487             =encoding UTF-8
488            
489             =head1 NAME
490            
491             Elastic::Model::TypeMap::Base - A base class for all TypeMaps
492            
493             =head1 VERSION
494            
495             version 0.52
496            
497             =head1 SYNOPSIS
498            
499             =head2 Define your own type map
500            
501             package MyApp::TypeMap;
502            
503             use Elastic::Model::TypeMap::Base qw(
504             Elastic::Model::TypeMap::Default
505             );
506            
507             has_type 'MyCustomType',
508             deflate_via { sub { ... }},
509             inflate_via { sub { ... }},
510             map_via { type => 'string' };
511            
512             # Inlined in/deflation
513             has_type 'MyCustomType',
514             deflate_via { '$val * 1000'},
515             inflate_via { '$val / 1000'},
516             map_via { type => 'string' };
517            
518             =head2 Use your type map by declaring it in your Model
519            
520             package MyApp;
521            
522             use Elastic::Model;
523            
524             has_namespace 'myapp', {
525             user => 'MyApp::User',
526             post => 'MyApp::Post'
527             };
528            
529             has_typemap 'MyApp::TypeMap';
530            
531             =head1 DESCRIPTION
532            
533             Moose's L<type constraints|Moose::Util::TypeConstraints> and introspection
534             allows Elastic::Model to figure out how to map your data model to the
535             Elasticsearch backend with the minimum of effort on your part.
536            
537             What YOU need to do is: B<Be specific about the type constraint for each attribute.>
538            
539             For instance, if you have an attribute called C<count>, then specify the
540             type constraint C<< isa => 'Int' >>.
541             That way, we know how to define the field in Elasticsearch, and how to deflate
542             and inflate the value.
543            
544             Type constraints can inherit their mapping, inflator and deflator from
545             their parent type-constraints. For instance, if you were to assign
546             C<count> the type constraint C<PositiveInt>, although we don't know about that
547             constraint, we do know about its parent, C<Int>, so we could
548             still handle the field correctly.
549            
550             Type maps are used to define:
551            
552             =over
553            
554             =item *
555            
556             what mapping Elastic::Model will generate for each attribute when you
557             L<create an index|Elastic::Model::Domain::Admin/"create_index()">
558             or L<update the mapping|Elastic::Model::Domain::Admin/"update_mapping()"> of an
559             existing index.
560            
561             =item *
562            
563             how Elastic::Model will deflate and inflate each attribute when saving or
564             retrieving docs stored in Elasticsearch.
565            
566             =back
567            
568             =head1 BUILT-IN TYPE MAPS
569            
570             See L<Elastic::Model::TypeMap::Default> for the type-maps provided by
571             default in Elastic::Model.
572            
573             =head1 DEFINING YOUR OWN TYPE MAP
574            
575             If you define your own types which need custom mapping or custom deflators/inflators
576             then you can add these definitions in your own type-map, while still falling
577             back to the built-in type-maps for other types.
578            
579             First, you need to name your type map class:
580            
581             package MyApp::TypeMap;
582            
583             Then import the helper functions from L<Elastic::Model::TypeMap::Base>
584             and load any other typemaps that you want to inherit from:
585            
586             use Elastic::Model::TypeMap::Base qw(
587             Elastic::Model::TypeMap::Default
588             Useful::TypeMap::From::CPAN
589             );
590            
591             Now you can define your type maps:
592            
593             has_type 'MyCustomType',
594             deflate_via { sub { ... }},
595             inflate_via { sub { ... }},
596             map_via { type => 'string' };
597            
598             The type name passed to C<has_type> should be a string, eg C<'Str'> for the
599             core Moose string type, or the fully qualified name for the types you have
600             defined with L<MooseX::Types>, eg C<'MyApp::Types::SomeType'>.
601            
602             C<deflate_via> and C<inflate_via> each expect a coderef which, when called
603             returns a coderef:
604            
605             sub {
606             my ($type_constraint, $attr, $typemap_class) = @_;
607             return sub {
608             my ($val) = @_;
609             return do_something($val)
610             }
611             }
612            
613             Alternatively, the C<deflate_via> and C<inflate_via> coderefs can, when
614             executed, return a string of Perl code which can be inlined for more
615             efficient flation. Both the inflator and deflator are passed the value
616             that needs to be converted in C<$val>. For instance:
617            
618             has_type 'MyDateType',
619             deflate_via { '$val->to_string' },
620             inflate_via { 'My::Date::Class->new($val)' },
621             map_via { 'type' => 'date' };
622            
623             C<map_via> expects a coderef which returns the mapping for that type as a list,
624             not as a hashref:
625            
626             sub {
627             my ($type_constraint, $attr, $typemap_class) = @_;
628             return (type => 'string', ..... );
629             }
630            
631             =head2 A simple example
632            
633             Here is an example of how to define a type map for DateTime objects:
634            
635             use DateTime;
636            
637             has_type 'DateTime',
638            
639             deflate_via {
640             sub { $_[0]->set_time_zone('UTC')->iso8601 };
641             },
642            
643             inflate_via {
644             sub {
645             my %args;
646             @args{ (qw(year month day hour minute second)) } = split /\D/, shift;
647             DateTime->new(%args);
648             };
649             },
650            
651             map_via { type => 'date' };
652            
653             =head2 An inlined example:
654            
655             use DateTime;
656            
657             has_type 'DateTime',
658            
659             deflate_via { '$val->set_time_zone("UTC")->iso8601' },
660             inflate_via {
661             'do {'
662             . ' my %args;'
663             . ' @args{ (qw(year month day hour minute second)) } = split /\D/, $val;'
664             . ' DateTime->new(%args);'
665             . '}'
666             },
667            
668             map_via { type => 'date' };
669            
670             =head1 ATTRIBUTES
671            
672             It is unlikely that you will need to know about any of these attributes, but
673             they are documented here for completeness.
674            
675             =head2 deflators
676            
677             $deflators = $class->deflators
678            
679             Returns a hashref of all deflators known to C<$class>.
680            
681             =head2 inflators
682            
683             $inflators = $class->inflators
684            
685             Returns a hashref of all inflators known to C<$class>.
686            
687             =head2 mappers
688            
689             $mappers = $class->mappers
690            
691             Returns a hashref of all mappers known to C<$class>.
692            
693             =head2 typemap
694            
695             $map = $class->typemap
696            
697             Returns a hashref containing the L</"deflators">, L</"inflators"> and
698             L</"mappers"> known to C<$class>.
699            
700             =head1 METHODS
701            
702             It is unlikely that you will need to know about any of these methods, but
703             they are documented here for completeness.
704            
705             L<Elastic::Model::TypeMap::Base> only has class methods, no instance methods,
706             and no C<new()>.
707            
708             =head2 find_deflator()
709            
710             $deflator = $class->find_deflator($attr)
711            
712             Returns a coderef which knows how to deflate C<$attr>, or throws an exception.
713             Any inlined deflators are eval'ed into an anonymous sub.
714            
715             =head2 find_raw_deflator()
716            
717             $deflator = $class->find_deflator($attr)
718            
719             Returns a coderef which knows how to deflate C<$attr>, or throws an exception.
720             Any inlined deflators are returned as strings.
721            
722             =head2 find_inflator()
723            
724             $inflator = $class->find_inflator($attr)
725            
726             Returns a coderef which knows how to inflate C<$attr>, or throws an exception.
727             Any inlined inflators are eval'ed into an anonymous sub.
728            
729             =head2 find_raw_inflator()
730            
731             $inflator = $class->find_inflator($attr)
732            
733             Returns a coderef which knows how to inflate C<$attr>, or throws an exception.
734             Any inlined inflators are returned as strings.
735            
736             =head2 find_mapper()
737            
738             $mapping = $class->find_mapper($attr)
739            
740             Returns a mapping for C<$attr>, or throws an exception.
741            
742             =head2 find()
743            
744             $result = $class->find($thing, $type_constraint, $attr);
745            
746             Finds a C<$thing> (C<deflator>, C<inflator>, C<mapper>) or returns C<undef>.
747            
748             =head2 class_deflator()
749            
750             $deflator = $class->class_deflator( $class_to_deflate, $attrs );
751            
752             Returns a coderef which knows how to deflate an object of class
753             C<$class_to_deflate>, including the attributes listed in C<$attr> (or all
754             attributes if not specified).
755            
756             =head2 class_inflator()
757            
758             $inflator = $class->class_inflator( $class_to_inflate, $attrs );
759            
760             Returns a coderef which knows how to inflate deflated data for class
761             C<$class_to_inflate>, including the attributes listed in C<$attr> (or all
762             attributes if not specified).
763            
764             =head2 class_mapping()
765            
766             $mapping = $class->class_mapping( $class_to_map, $attrs );
767            
768             Returns a hashref of the mapping for class C<$class_to_map>,
769             including the attributes listed in C<$attr> (or all attributes if not specified).
770            
771             =head2 attribute_mapping()
772            
773             $mapping = $class->attribute_mapping($attr);
774            
775             Returns a hashref of the mapping for attribute C<$attr>.
776            
777             =head2 indexable_attrs()
778            
779             $attrs = $class->indexable_attrs($some_class);
780            
781             Returns an array ref all all attributes in C<$some_class> which don't
782             have C<exclude> set to true.
783            
784             =head2 import_types()
785            
786             $class->import_types($other_class);
787            
788             Imports the deflators, inflators and mappers from another typemap class into
789             the current class.
790            
791             =head1 AUTHOR
792            
793             Clinton Gormley <drtech@cpan.org>
794            
795             =head1 COPYRIGHT AND LICENSE
796            
797             This software is copyright (c) 2015 by Clinton Gormley.
798            
799             This is free software; you can redistribute it and/or modify it under
800             the same terms as the Perl 5 programming language system itself.
801            
802             =cut
803              
804             __END__
805            
806             # ABSTRACT: A base class for all TypeMaps
807            
808