File Coverage

blib/lib/Elastic/Model/TypeMap/Base.pm
Criterion Covered Total %
statement 154 191 80.6
branch 52 66 78.7
condition 36 58 62.0
subroutine 36 38 94.7
pod 16 19 84.2
total 294 372 79.0


line stmt bran cond sub pod time code
1             package Elastic::Model::TypeMap::Base;
2             $Elastic::Model::TypeMap::Base::VERSION = '0.51';
3 23     23   14527 use strict;
  23         48  
  23         804  
4 23     23   109 use warnings;
  23         37  
  23         617  
5              
6 23     23   112 use Sub::Exporter qw(build_exporter);
  23         37  
  23         226  
7 23     23   6687 use Class::MOP();
  23         39  
  23         323  
8 23     23   97 use Class::Load();
  23         32  
  23         436  
9 23     23   105 use List::MoreUtils qw(uniq);
  23         37  
  23         268  
10 23     23   9577 use Moose::Util qw(does_role);
  23         42  
  23         195  
11 23     23   4482 use Scalar::Util qw(blessed);
  23         42  
  23         1880  
12 23     23   136 use Moose::Util::TypeConstraints qw(find_type_constraint);
  23         45  
  23         313  
13 23     23   9556 use namespace::autoclean;
  23         43  
  23         314  
14              
15 609     609 0 2563 sub deflate_via (&) { deflator => $_[0] }
16 609     609 0 2057 sub inflate_via (&) { inflator => $_[0] }
17 666     666 0 1755 sub map_via (&) { mapper => $_[0] }
18              
19             #===================================
20             sub import {
21             #===================================
22 149     149   465     my ( $class, @args ) = @_;
23 149         736     my $callee = caller;
24 149 50 33     4452     return if $callee->isa(__PACKAGE__) || @args == 0;
25              
26                 {
27 23     23   5257         no strict 'refs';
  23         39  
  23         49702  
  149         213  
28 149         193         unshift @{ $callee . '::ISA' }, __PACKAGE__;
  149         1977  
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   1904                     sub { $callee->_has_type(@_) }
        32      
37 149     149   59753                 },
38 149         1779             ]
39                     }
40                 )->( $class, ':all' );
41              
42 149         34040     for (@args) {
43 252 100       6232         next if /^[:-]/;
44 126         489         Class::Load::load_class($_);
45 126         4049         $callee->import_types( $_->typemap );
46                 }
47             }
48              
49             #===================================
50             sub find_deflator {
51             #===================================
52 77     77 1 197536     my ( $map, $attr ) = @_;
53 77         309     my $deflator = $map->find_raw_deflator($attr);
54 55 100       620     return $deflator if ref $deflator;
55 48         259     Eval::Closure::eval_closure(
56                     source => [ 'sub { my $val = $_[0];', $deflator, '}' ] );
57             }
58              
59             #===================================
60             sub find_raw_deflator {
61             #===================================
62 77     77 1 126     my ( $map, $attr ) = @_;
63                 $attr->can('deflator') && $attr->deflator
64 77 100 33     4146         || eval { $map->find( 'deflator', $attr->type_constraint, $attr ) }
  77   66     2241  
65                     || die _type_error( 'deflator', $attr, $@ );
66             }
67              
68             #===================================
69             sub find_inflator {
70             #===================================
71 77     77 1 32266     my ( $map, $attr ) = @_;
72 77         279     my $inflator = $map->find_raw_inflator($attr);
73 55 100       417     return $inflator if ref $inflator;
74 48         209     Eval::Closure::eval_closure(
75                     source => [ 'sub { my $val = $_[0];', $inflator, '}' ] );
76             }
77              
78             #===================================
79             sub find_raw_inflator {
80             #===================================
81 77     77 1 110     my ( $map, $attr ) = @_;
82                 $attr->can('inflator') && $attr->inflator
83 77 100 33     3783         || eval { $map->find( 'inflator', $attr->type_constraint, $attr ) }
  77   66     2177  
84                     || die _type_error( 'inflator', $attr, $@ );
85             }
86              
87             #===================================
88             sub find_mapper {
89             #===================================
90 205     205 1 117580     my ( $map, $attr ) = @_;
91 205         289     my $mapping;
92 205 100       9131     $mapping = $attr->mapping if $attr->can('mapping');
93 205 100 66     664     return %$mapping if $mapping && %$mapping;
94              
95 204         264     my %mapping;
96 204         271     eval {
97 204         7585         my @mapping = $map->find( 'mapper', $attr->type_constraint, $attr );
98 202 100       2126         die "Expected an even number of elements "
99                         . "to be returned by the mapper.\n"
100                         if @mapping % 2;
101 201         875         %mapping = @mapping;
102                 };
103              
104 204 100       482     die _type_error( 'mapper', $_[1], $@ )
105                     unless %mapping;
106              
107 196         1113     return %mapping;
108             }
109              
110             #===================================
111             sub _type_error {
112             #===================================
113 52     52   109     my ( $type, $attr, $error ) = @_;
114 52         511     my $name = $attr->name;
115 52         740     my $class = $attr->associated_class->name;
116 52 100       735     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 6110     my ( $map, $type, $tc, $attr ) = @_;
125              
126 1012   66     14624     $tc ||= find_type_constraint('Any');
127              
128 1012         5720     my $types = $type . 's';
129 1012         2839     my $handlers = $map->$types;
130 1012         24072     my $name = $tc->name;
131              
132 1012 100 100     151607     if ( my $handler = $handlers->{$name} || $handlers->{ ref $tc } ) {
133 619         2318         return $handler->( $tc, $attr, $map );
134                 }
135              
136 393 100 100     12015     my $parent = $tc->can('parent') && $tc->parent or return;
137 382         4800     $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 84     my ( $map, $class, $attrs ) = @_;
338              
339 32   66     164     $attrs ||= $map->indexable_attrs($class);
340              
341 32         133     my %props = map { $_ => $map->attribute_mapping( $attrs->{$_} ) }
  62         769  
342                     keys %$attrs;
343              
344 32 100       1574     return ( type => 'object', enabled => 0 )
345                     unless %props;
346              
347                 return (
348 31         441         type => 'object',
349                     dynamic => 'strict',
350                     properties => \%props
351                 );
352             }
353              
354             #===================================
355             sub attribute_mapping {
356             #===================================
357 107     107 1 52948     my ( $map, $attr ) = @_;
358              
359 107   100     5190     my $mapping = $attr->can('mapping') && $attr->mapping
360                     || { $map->find_mapper($attr) };
361              
362 107   100     404     my $type = $mapping->{type} || '';
363 107 100       655     if ( $attr->can('type') ) {
364 89         3784         my $new_type = $attr->type;
365 89 100 66     369         if ( $new_type and $new_type ne $type ) {
366 14 100       58             delete $mapping->{enabled}
367                             if $type eq 'object';
368 14         38             $mapping->{type} = $type = $new_type;
369                     }
370                 }
371              
372 107 50       344     die "Missing field type" unless $type;
373              
374 107 50       432     my $allowed = $Allowed_Attrs{$type} or die "Unknown field type ($type)";
375              
376 107 100       486     return $mapping unless does_role( $attr, 'Elastic::Model::Trait::Field' );
377              
378 89         27664     for my $key (@All_Keys) {
379 1854         72307         my $val = $attr->$key;
380 1854 100       4106         next unless defined $val;
381 108 100       495         die "Attribute has type '$type', which doesn't "
382                         . "understand '$key'\n"
383                         unless $allowed->{$key};
384 97         224         $mapping->{$key} = $val;
385                 }
386              
387 78         557     $mapping = $map->_fixup_mapping($mapping);
388              
389 78 100       519     my $multi = delete $mapping->{multi}
390                     or return $mapping;
391              
392 15         204     my $main = $attr->name;
393 15         129     my %new = ( type => 'multi_field', fields => { $main => $mapping } );
394 15         68     for my $name ( keys %$multi ) {
395 19 50       60         die "Multi-field name '$name' clashes with the attribute name\n"
396                         if $name eq $main;
397 19         42         my $defn = $multi->{$name};
398 19   66     114         my $multi_type = $defn->{type} ||= $type;
399              
400 19 50       116         $allowed = $Allowed_Attrs{$multi_type}
401                         or die "Uknown field type ($type)";
402              
403 19         64         for my $key ( keys %$defn ) {
404 35 100 100     232             die "Attribute has type '$multi_type', which doesn't "
405                             . "understand '$key'\n"
406                             unless $allowed->{$key} || $key eq 'type';
407                     }
408              
409 13         49         $new{fields}{$name} = $map->_fixup_mapping($defn);
410                 }
411 9         42     return \%new;
412             }
413              
414             #===================================
415             sub _fixup_mapping {
416             #===================================
417 91     91   156     my ( $map, $defn ) = @_;
418              
419 91 100 100     396     delete $defn->{analyzer}
420                     if $defn->{index_analyzer} && $defn->{search_analyzer};
421              
422 91         219     return $defn;
423             }
424              
425             #===================================
426 373     373 1 813 sub deflators { shift->typemap->{deflator} }
427 373     373 1 771 sub inflators { shift->typemap->{inflator} }
428 376     376 1 1049 sub mappers { shift->typemap->{mapper} }
429             #===================================
430              
431             #===================================
432             sub _has_type {
433             #===================================
434 758     758   1572     my ( $class, $type, %params ) = @_;
435 758         1623     my $map = $class->typemap();
436 758         1453     for ( keys %params ) {
437 1884         4729         $map->{$_}{$type} = $params{$_};
438                 }
439             }
440              
441             #===================================
442             sub indexable_attrs {
443             #===================================
444 9     9 1 17     my $map = shift;
445 9         17     my $class = shift;
446 9   33     44     $class = $map->model->class_for($class) || $class;
447              
448 9         37     my $meta = Class::MOP::class_of($class);
449              
450                 return {
451 22   66     171         map { $_->name => $_ }
  49         2586  
452 9         95             grep { !( $_->can('exclude') && $_->exclude ) }
453                         $meta->get_all_attributes
454                 };
455             }
456              
457             #===================================
458             sub typemap {
459             #===================================
460 2132     2132 1 2380     my $class = shift;
461 2132 100       13421     $class = $class->original_class
462                     if $class->can('original_class');
463              
464             # return a reference to the storage in ourself
465                 {
466 23     23   198         no strict 'refs';
  23         48  
  23         4896  
  2132         2173  
467 2132         1963         return \%{ $class . '::__ES_TYPE_MAP' };
  2132         11533  
468                 }
469             }
470              
471             #===================================
472             sub import_types {
473             #===================================
474 126     126 1 207     my $class = shift;
475 126         171     my $import = shift;
476 126         360     my $map = $class->typemap;
477 126         358     for (qw(deflator inflator mapper)) {
478 378 50       893         my $types = $import->{$_} or next;
479 378         1230         @{ $map->{$_} }{ keys %$types } = values %$types;
  378         3184  
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.51
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