File Coverage

blib/lib/Elastic/Model/Meta/Class/Model.pm
Criterion Covered Total %
statement 54 54 100.0
branch 21 26 80.7
condition 5 8 62.5
subroutine 11 11 100.0
pod 3 3 100.0
total 94 102 92.1


line stmt bran cond sub pod time code
1             package Elastic::Model::Meta::Class::Model;
2             $Elastic::Model::Meta::Class::Model::VERSION = '0.52';
3 23     23   262325 use Moose::Role;
  23         61  
  23         215  
4 23     23   124594 use List::Util ();
  23         60  
  23         591  
5 23     23   136 use MooseX::Types::Moose qw(HashRef Str);
  23         52  
  23         294  
6 23     23   122324 use Carp;
  23         54  
  23         1774  
7 23     23   20264 use Data::Dump qw(pp);
  23         138337  
  23         1716  
8 23     23   178 use namespace::autoclean;
  23         59  
  23         284  
9              
10             my %defaults = (
11                 analyzer => {},
12                 tokenizer => {},
13             );
14              
15             for my $k (qw(namespace char_filter analyzer filter tokenizer)) {
16                 my %default = %{ $defaults{$k} || {} };
17              
18             #===================================
19                 has "${k}s" => (
20             #===================================
21                     is => 'ro',
22                     traits => ['Hash'],
23                     isa => HashRef,
24                     default => sub { +{%default} },
25                     handles => {
26                         $k => 'get',
27                         "add_${k}" => 'set',
28                         "has_${k}" => 'exists',
29                         "all_${k}s" => 'keys',
30                     }
31                 );
32                 next if $k eq 'namespace';
33              
34             #===================================
35                 before "add_$k" => sub {
36             #===================================
37                     my $class = shift;
38                     my %params = ref $_[0] ? { shift() } : @_;
39                     for my $defn ( values %params ) {
40                         my $type = $defn->{type} || 'custom';
41                         return if $type eq 'custom' and $k eq 'analyzer';
42                         croak "Unknown type ($type) in $k:\n" . pp( \%params ) . "\n"
43                             unless $class->is_default( $k, $type );
44                     }
45                 };
46             }
47              
48             #===================================
49             has 'classes' => (
50             #===================================
51                 is => 'ro',
52                 isa => HashRef [Str],
53                 traits => ['Hash'],
54                 default => sub {
55                     +{ typemap => 'Elastic::Model::TypeMap::Default',
56                         domain => 'Elastic::Model::Domain',
57                         namespace => 'Elastic::Model::Namespace',
58                         store => 'Elastic::Model::Store',
59                         view => 'Elastic::Model::View',
60                         scope => 'Elastic::Model::Scope',
61                         results => 'Elastic::Model::Results',
62                         cached_results => 'Elastic::Model::Results::Cached',
63                         scrolled_results => 'Elastic::Model::Results::Scrolled',
64                         result => 'Elastic::Model::Result',
65                         bulk => 'Elastic::Model::Bulk'
66                     };
67                 },
68                 handles => {
69                     set_class => 'set',
70                     get_class => 'get',
71                 }
72             );
73              
74             #===================================
75             has 'unique_index' => (
76             #===================================
77                 is => 'rw',
78                 isa => 'Str',
79                 default => sub {'unique_key'}
80             );
81              
82 23     23   11057 no Moose;
  23         60  
  23         212  
83              
84             our %DefaultAnalysis = (
85                 char_filter => { map { $_ => 1 } qw(html_strip mapping) },
86                 filter => +{
87                     map { $_ => 1 }
88                         qw(
89             standard asciifolding length lowercase ngram edge_ngram
90             porterStem shingle stop word_delimiter snowball kstem phonetic
91             synonym dictionary_decompounder hyphenation_decompounder
92             reverse elision trim truncate unique pattern_replace
93             icu_normalizer icu_folding icu_collation
94             )
95                 },
96                 tokenizer => {
97                     map { $_ => 1 }
98                         qw(
99             edge_ngram keyword letter lowercase ngram standard
100             whitespace pattern uax_url_email path_hierarchy
101             )
102                 },
103                 analyzer => {
104                     map { $_ => 1 }
105                         qw(
106             standard simple whitespace stop keyword pattern snowball
107             arabic armenian basque brazilian bulgarian catalan chinese
108             cjk czech danish dutch english finnish french galician german
109             greek hindi hungarian indonesian italian latvian
110             norwegian persian portuguese romanian russian spanish swedish
111             turkish thai
112             )
113                 }
114             );
115              
116             #===================================
117             sub is_default {
118             #===================================
119 24     24 1 38     my $self = shift;
120 24   50     63     my $type = shift || '';
121                 croak "Unknown type ($type) passed to is_default()"
122 24 50       70         unless exists $DefaultAnalysis{$type};
123 24 50       91     my $name = shift or croak "No $type name passed to is_default";
124 24         152     return exists $DefaultAnalysis{$type}{$name};
125             }
126              
127             #===================================
128             sub analysis_for_mappings {
129             #===================================
130 5     5 1 11     my $self = shift;
131 5         7     my $mappings = shift;
132              
133 5         8     my %analyzers;
134 5         18     for my $type ( keys %$mappings ) {
135 6         19         for my $name ( _required_analyzers( $mappings->{$type} ) ) {
136                         next
137 9 100 66     46                 if exists $analyzers{$name}
138                             || $self->is_default( 'analyzer', $name );
139 6 100       324             $analyzers{$name} = $self->analyzer($name)
140                             or die "Unknown analyzer ($name) required by type ($type)";
141                     }
142                 }
143 4 100       17     return unless %analyzers;
144              
145 3         12     my %analysis = ( analyzer => \%analyzers );
146 3         8     for my $type (qw(tokenizer filter char_filter )) {
147 7         9         my %defn;
148 7         22         for my $analyzer_name ( keys %analyzers ) {
149 13 100       45             my $vals = $analyzers{$analyzer_name}{$type} or next;
150 9 100       24             for my $name ( ref $vals ? @$vals : $vals ) {
151                             next
152 11 100 66     44                     if exists $defn{$name}
153                                 || $self->is_default( $type, $name );
154 7 100       371                 $defn{$name} = $self->$type($name)
155                                 or die
156                                 "Unknown $type ($name) required by analyzer '$analyzer_name'";
157                         }
158                     }
159 6 50       25         $analysis{$type} = \%defn if %defn;
160                 }
161 2         12     return \%analysis;
162             }
163              
164             #===================================
165             sub _required_analyzers {
166             #===================================
167 24     24   37     my @analyzers;
168 24         66     while (@_) {
169 18 50       38         my $mapping = shift or next;
170                     my @sub = (
171 18 50       79             values %{ $mapping->{fields} || {} },
172 18 100       19             values %{ $mapping->{properties} || {} }
  18         74  
173                     );
174              
175                     push @analyzers, _required_analyzers(@sub),
176 18         47             map { $mapping->{$_} } grep /analyzer/, keys %$mapping;
  9         32  
177                 }
178              
179 24         200     return @analyzers;
180             }
181              
182             our $Counter = 1;
183             #===================================
184             sub wrapped_class_name {
185             #===================================
186 234     234 1 5416     return 'Elastic::Model::__WRAPPED_' . $Counter++ . '_::' . $_[1];
187             }
188              
189             1;
190              
191             =pod
192            
193             =encoding UTF-8
194            
195             =head1 NAME
196            
197             Elastic::Model::Meta::Class::Model - A meta-class for Models
198            
199             =head1 VERSION
200            
201             version 0.52
202            
203             =head1 DESCRIPTION
204            
205             Holds static information about your model: namespaces and their types,
206             and char_filters, tokenizers, filters and analyzers for analysis.
207            
208             You shouldn't need to use this class directly. Everything you need should
209             be accessible via L<Elastic::Model> or L<Elastic::Model::Role::Model>.
210            
211             =head1 METHODS
212            
213             =head2 is_default()
214            
215             $bool = $meta->is_default($type => $name);
216            
217             Returns C<true> if C<$name> is a C<$type> (analyzer, tokenizer,
218             filter, char_filter) available in Elasticsearch by default.
219            
220             =head3 Default analyzers
221            
222             L<standard|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-standard-analyzer.html>,
223             L<simple|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-simple-analyzer.html>,
224             L<whitespace|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-whitespace-analyzer.html>,
225             L<stop|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-stop-analyzer.html>,
226             L<keyword|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-keyword-analyzer.html>,
227             L<pattern|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-pattern-analyzer.html>,
228             L<snowball|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-snowball-analyzer.html>,
229             and the L<language|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-lang-analyzer.html>
230             analyzers: C<arabic>, C<armenian>, C<basque>, C<brazilian>, C<bulgarian>,
231             C<catalan>, C<chinese>, C<cjk>, C<czech>, C<danish>, C<dutch>, C<english>,
232             C<finnish>, C<french>, C<galician>, C<german>, C<greek>, C<hindi>, C<hungarian>,
233             C<indonesian>, C<italian>, C<latvian>, C<norwegian>, C<persian>,
234             C<portuguese>, C<romanian>, C<russian>, C<spanish>, C<swedish>,
235             C<thai>, C<turkish>
236            
237             =head3 Default tokenizers
238            
239             L<edge_ngram|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenizer.html>,
240             L<keyword|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-keyword-tokenizer.html>,
241             L<letter|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-letter-tokenizer.html>,
242             L<lowercase|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenizer.html>,
243             L<ngram|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html>,
244             L<path_hierarchy|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-pathhierarchy-tokenizer.html>,
245             L<pattern|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-pattern-tokenizer.html>,
246             L<standard|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-standard-tokenizer.html>,
247             L<uax_url_email|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-uaxurlemail-tokenizer.html>,
248             L<whitespace|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-whitespace-tokenizer.html>
249            
250             =head3 Default token filters
251            
252             L<asciifolding|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-asciifolding-tokenfilter.html>,
253             L<dictionary_decompounder|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-compound-word-tokenfilter.html>,
254             L<edge_ngram|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-edgengram-tokenfilter.html>,
255             L<elision|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-elision-tokenfilter.html>,
256             L<hyphenation_decompounder|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-compound-word-tokenfilter.html>,
257             L<icu_collation|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-icu-plugin.html>,
258             L<icu_folding|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-icu-plugin.html>,
259             L<icu_normalizer|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-icu-plugin.html>,
260             L<kstem|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-kstem-tokenfilter.html>,
261             L<length|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-length-tokenfilter.html>,
262             L<lowercase|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-lowercase-tokenfilter.html>,
263             L<ngram|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-ngram-tokenfilter.html>,
264             L<pattern_replace|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-pattern_replace-tokenfilter.html>,
265             L<phonetic|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-phonetic-tokenfilter.html>,
266             L<porterStem|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-porterstem-tokenfilter.html>,
267             L<reverse|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-reverse-tokenfilter.html>,
268             L<shingle|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-shingle-tokenfilter.html>,
269             L<snowball|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-snowball-tokenfilter.html>,
270             L<standard|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-standard-tokenfilter.html>,
271             L<stop|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-stop-tokenfilter.html>,
272             L<synonym|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-synonym-tokenfilter.html>,
273             L<trim|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-trim-tokenfilter.html>,
274             L<truncate|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-truncate-tokenfilter.html>,
275             L<unique|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html>,
276             L<word_delimiter|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html>
277            
278             =head3 Default character filters
279            
280             L<html_strip|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-htmlstrip-charfilter.html>,
281             L<mapping|http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-mapping-charfilter.html>
282            
283             =head2 analysis_for_mappings()
284            
285             $analysis = $meta->analysis_for_mappings($mappings)
286            
287             Used to generate the C<analysis> settings for an index, based on which
288             analyzers are used in the C<mappings> for all C<types> in the index.
289            
290             =head2 wrapped_class_name()
291            
292             $new_class = $meta->wrapped_class_name($old_class);
293            
294             Generates a semi-anonymous classname with the format
295             C<Elastic::Model::__WRAPPED_::$n>
296            
297             =head1 ATTRIBUTES
298            
299             =head2 namespaces
300            
301             \%namespaces = $meta->namespaces;
302             \%namespace = $meta->namespace($name);
303             $bool = $meta->has_namespace($name);
304             @names = $meta->all_namespaces;
305            
306             A hash ref containing all namespaces plus their configuration, eg:
307            
308             {
309             myapp => {
310             types => {
311             user => 'MyApp::User'
312             }
313             }
314             }
315            
316             =head2 unique_index
317            
318             $index = $meta->unique_index
319            
320             The name of the index where unique keys will be stored, which defaults
321             to C<unique_key>. A different value can be specified with
322             L<has_unique_index|Elastic::Model/Custom unique key index>.
323            
324             See L<Elastic::Manual::Attributes::Unique> for more.
325            
326             =head2 analyzers
327            
328             \%analyzers = $meta->analyzers;
329             \%analyzer = $meta->analyzer($name);
330             $bool = $meta->has_analyzer($name);
331             @names = $meta->all_analyzers;
332            
333             A hash ref containing all analyzers plus their configuration, eg:
334            
335             {
336             my_analyzer => {
337             type => 'custom',
338             tokenizer => 'standard',
339             filter => ['lower']
340             }
341             }
342            
343             =head2 tokenizers
344            
345             \%tokenizers = $meta->tokenizers;
346             \%tokenizer = $meta->tokenizer($name);
347             $bool = $meta->has_tokenizer($name);
348             @names = $meta->all_tokenizers;
349            
350             A hash ref containing all tokenizers plus their configuration, eg:
351            
352             {
353             my_tokenizer => {
354             type => 'pattern',
355             pattern => '\W'
356             }
357             }
358            
359             =head2 filters
360            
361             \%filters = $meta->filters;
362             \%filter = $meta->filter($name);
363             $bool = $meta->has_filter($name);
364             @names = $meta->all_filters;
365            
366             A hash ref containing all filters plus their configuration, eg:
367            
368             {
369             my_filter => {
370             type => 'edge_ngram',
371             min_gram => 1,
372             max_gram => 20
373             }
374             }
375            
376             =head2 char_filters
377            
378             \%char_filters = $meta->char_filters;
379             \%char_filter = $meta->char_filter($name);
380             $bool = $meta->has_char_filter($name);
381             @names = $meta->all_char_filters;
382            
383             A hash ref containing all char_filters plus their configuration, eg:
384            
385             {
386             my_char_filter => {
387             type => 'mapping',
388             mappings => ['ph=>f','qu=>q']
389             }
390             }
391            
392             =head1 AUTHOR
393            
394             Clinton Gormley <drtech@cpan.org>
395            
396             =head1 COPYRIGHT AND LICENSE
397            
398             This software is copyright (c) 2015 by Clinton Gormley.
399            
400             This is free software; you can redistribute it and/or modify it under
401             the same terms as the Perl 5 programming language system itself.
402            
403             =cut
404              
405             __END__
406            
407             # ABSTRACT: A meta-class for Models
408            
409