File Coverage

blib/lib/MooseX/Declare/Syntax/NamespaceHandling.pm
Criterion Covered Total %
statement 62 62 100.0
branch 13 14 92.8
condition 6 6 100.0
subroutine 19 20 95.0
pod 5 10 50.0
total 105 112 93.7


line stmt bran cond sub pod time code
1             package MooseX::Declare::Syntax::NamespaceHandling;
2             # ABSTRACT: Handle namespaced blocks
3              
4             our $VERSION = '0.43';
5              
6 24     24   13742 use Moose::Role;
  24         33  
  24         161  
7 24     24   84641 use Moose::Util qw( does_role );
  24         33  
  24         151  
8 24     24   3495 use MooseX::Declare::Util qw( outer_stack_peek );
  24         31  
  24         140  
9 24     24   3262 use Carp;
  24         34  
  24         1461  
10              
11 24     24   97 use aliased 'MooseX::Declare::Context::Namespaced';
  24         31  
  24         143  
12 24     24   3298 use aliased 'MooseX::Declare::Context::WithOptions';
  24         33  
  24         72  
13 24     24   2026 use aliased 'MooseX::Declare::Context::Parameterized';
  24         33  
  24         112  
14 24     24   1937 use aliased 'MooseX::Declare::StackItem';
  24         34  
  24         106  
15              
16 24     24   2218 use namespace::autoclean;
  24         38  
  24         146  
17              
18             #pod =head1 DESCRIPTION
19             #pod
20             #pod Allows the implementation of namespaced blocks like the
21             #pod L<role|MooseX::Declare::Syntax::Keyword::Role> and
22             #pod L<class|MooseX::Declare::Syntax::Keyword::Class> keyword handlers.
23             #pod
24             #pod Namespaces are automatically nested. Meaning that, for example, a C<class Bar>
25             #pod declaration inside another C<class Foo> block gives the inner one actually the
26             #pod name C<Foo::Bar>.
27             #pod
28             #pod =head1 CONSUMES
29             #pod
30             #pod =for :list
31             #pod * L<MooseX::Declare::Syntax::KeywordHandling>
32             #pod * L<MooseX::Declare::Syntax::InnerSyntaxHandling>
33             #pod
34             #pod =cut
35              
36             with qw(
37             MooseX::Declare::Syntax::KeywordHandling
38             MooseX::Declare::Syntax::InnerSyntaxHandling
39             );
40              
41             #pod =head1 REQUIRED METHODS
42             #pod
43             #pod =head2 handle_missing_block
44             #pod
45             #pod Object->handle_missing_block (Object $context, Str $body, %args)
46             #pod
47             #pod This must be implemented to decide what to do in case the statement is
48             #pod terminated rather than followed by a block. It will receive the context
49             #pod object, the produced code that needs to be injected, and all the arguments
50             #pod that were passed to the call to L<MooseX::Declare::Context/inject_code_parts>.
51             #pod
52             #pod The return value will be ignored.
53             #pod
54             #pod =cut
55              
56             requires qw(
57             handle_missing_block
58             );
59              
60             #pod =head1 EXTENDABLE STUB METHODS
61             #pod
62             #pod =head2 add_namespace_customizations
63             #pod
64             #pod =head2 add_optional_customizations
65             #pod
66             #pod Object->add_namespace_customizations (Object $context, Str $package, HashRef $options)
67             #pod Object->add_optional_customizations (Object $context, Str $package, HashRef $options)
68             #pod
69             #pod These will be called (in this order) by the L</parse> method. They allow specific hooks
70             #pod to attach before/after/around the customizations for the namespace and the provided
71             #pod options that are not attached to the namespace directly.
72             #pod
73             #pod While this distinction might seem superficial, we advise library developers facilitating
74             #pod this role to follow the precedent. This ensures that when another component needs to
75             #pod tie between the namespace and any additional customizations everything will run in the
76             #pod correct order. An example of this separation would be
77             #pod
78             #pod class Foo is mutable ...
79             #pod
80             #pod being an option of the namespace generation, while
81             #pod
82             #pod class Foo with Bar ...
83             #pod
84             #pod is an additional optional customization.
85             #pod
86             #pod =head2 handle_post_parsing
87             #pod
88             #pod Object->handle_post_parsing (Object $context, Str $package, Str | Object $name)
89             #pod
90             #pod Allows for additional modifications to the namespace after everything else has been
91             #pod done. It will receive the context, the fully qualified package name, and either a
92             #pod string with the name that was specified (might not be fully qualified, since
93             #pod namespaces can be nested) or the anonymous metaclass instance if no name was
94             #pod specified.
95             #pod
96             #pod The return value of this method will be the value returned to the user of the
97             #pod keyword. If you always return the C<$package> argument like this:
98             #pod
99             #pod sub handle_post_parsing {
100             #pod my ($self, $context, $package, $name) = @_;
101             #pod return $package;
102             #pod }
103             #pod
104             #pod and set this up in a C<foo> keyword handler, you can use it like this:
105             #pod
106             #pod foo Cthulhu {
107             #pod
108             #pod my $fhtagn = foo Fhtagn { }
109             #pod my $anon = foo { };
110             #pod
111             #pod say $fhtagn; # Cthulhu::Fhtagn
112             #pod say $anon; # some autogenerated package name
113             #pod }
114             #pod
115             #pod =head2 make_anon_metaclass
116             #pod
117             #pod Class::MOP::Class Object->make_anon_metaclass ()
118             #pod
119             #pod This method should be overridden if you want to provide anonymous namespaces.
120             #pod
121             #pod It does not receive any arguments for customization of the metaclass, because
122             #pod the configuration and customization will be done by L<MooseX::Declare> in the
123             #pod package of the generated class in the same way as in those that have specified
124             #pod names. This way ensures that anonymous and named namespaces are always handled
125             #pod equally.
126             #pod
127             #pod If you do not extend this method (it will return nothing by default), an error
128             #pod will be thrown when a user attempts to declare an anonymous namespace.
129             #pod
130             #pod =cut
131              
132       61 1   sub add_namespace_customizations { }
133       61 1   sub add_optional_customizations { }
134       61 1   sub handle_post_parsing { }
135       0 1   sub make_anon_metaclass { }
136              
137             around context_traits => sub { super, WithOptions, Namespaced };
138              
139             sub parse_specification {
140 63     63 0 133 my ($self, $ctx) = @_;
141              
142 63         230 $self->parse_namespace_specification($ctx);
143 63         266 $self->parse_option_specification($ctx);
144              
145 62         88 return;
146             }
147              
148             sub parse_namespace_specification {
149 63     63 0 382 my ($self, $ctx) = @_;
150 63         290 return scalar $ctx->strip_namespace;
151             }
152              
153             sub parse_option_specification {
154 63     63 0 95 my ($self, $ctx) = @_;
155 63         274 return scalar $ctx->strip_options;
156             }
157              
158             sub generate_inline_stack {
159 61     61 0 104 my ($self, $ctx) = @_;
160              
161             return join ', ',
162 65         275 map { $_->serialize }
163 61         98 @{ $ctx->stack },
  61         1947  
164             $self->generate_current_stack_item($ctx);
165             }
166              
167             sub generate_current_stack_item {
168 61     61 0 108 my ($self, $ctx) = @_;
169              
170             return StackItem->new(
171             identifier => $self->identifier,
172             is_dirty => $ctx->options->{is}{dirty},
173 61   100     1903 is_parameterized => does_role($ctx, Parameterized) && $ctx->has_parameter_signature,
174             handler => ref($self),
175             namespace => $ctx->namespace,
176             );
177             }
178              
179             #pod =method parse
180             #pod
181             #pod Any Object->parse (Object $context)
182             #pod
183             #pod This is the main handling routine for namespaces. It will remove the namespace
184             #pod name and its options. If the handler was invoked without a name, options or
185             #pod a following block, it is assumed that this is an instance of an autoquoted
186             #pod bareword like C<< class => "Foo" >>.
187             #pod
188             #pod The return value of the C<parse> method is also the value that is returned
189             #pod to the user of the keyword.
190             #pod
191             #pod =cut
192              
193             sub parse {
194 63     63 1 125 my ($self, $ctx) = @_;
195              
196             # keyword comes first
197 63         426 $ctx->skip_declarator;
198              
199             # read the name and unwrap the options
200 63         2661 $self->parse_specification($ctx);
201              
202 62         1796 my $name = $ctx->namespace;
203              
204 62         92 my ($package, $anon);
205              
206             # we have a name in the declaration, which will be used as package name
207 62 100 100     187 if (defined $name) {
    100          
208 58         97 $package = $name;
209              
210             # there is an outer namespace stack item, meaning we namespace below
211             # it, if the name starts with ::
212 58 100       1717 if (my $outer = outer_stack_peek $ctx->caller_file) {
213 12 100       55 $package = $outer . $package
214             if $name =~ /^::/;
215             }
216             }
217              
218             # no name, no options, no block. Probably { class => 'foo' }
219 4         100 elsif (not(keys %{ $ctx->options }) and $ctx->peek_next_char ne '{') {
220 1         12 return;
221             }
222              
223             # we have options and/or a block, but not name
224             else {
225 3 50       21 $anon = $self->make_anon_metaclass
226             or croak sprintf 'Unable to create an anonymized %s namespace', $self->identifier;
227 3         2508 $package = $anon->name;
228             }
229              
230             # namespace and mx:d initialisations
231 61         1895 $ctx->add_preamble_code_parts(
232             "package ${package}",
233             sprintf(
234             "use %s %s => '%s', file => __FILE__, stack => [ %s ]",
235             $ctx->provided_by,
236             outer_package => $package,
237             $self->generate_inline_stack($ctx),
238             ),
239             );
240              
241             # allow consumer to provide specialisations
242 61         1707 $self->add_namespace_customizations($ctx, $package);
243              
244             # make options a separate step
245 61         742 $self->add_optional_customizations($ctx, $package);
246              
247             # finish off preamble with a namespace cleanup
248             $ctx->add_preamble_code_parts(
249             $ctx->options->{is}->{dirty}
250 61 100       1916 ? 'use namespace::clean -except => [qw( meta )]'
251             : 'use namespace::autoclean'
252             );
253              
254             # clean up our stack afterwards, if there was a name
255 61         2245 $ctx->add_cleanup_code_parts(
256             ['BEGIN',
257             'MooseX::Declare::Util::outer_stack_pop __FILE__',
258             ],
259             );
260              
261             # actual code injection
262             $ctx->inject_code_parts(
263 1     1   6 missing_block_handler => sub { $self->handle_missing_block(@_) },
264 61         497 );
265              
266             # a last chance to change things
267 61 100       492 $self->handle_post_parsing($ctx, $package, defined($name) ? $name : $anon);
268             }
269              
270             #pod =head1 SEE ALSO
271             #pod
272             #pod =for :list
273             #pod * L<MooseX::Declare>
274             #pod * L<MooseX::Declare::Syntax::MooseSetup>
275             #pod
276             #pod =cut
277              
278             1;
279              
280             __END__
281              
282             =pod
283              
284             =encoding UTF-8
285              
286             =head1 NAME
287              
288             MooseX::Declare::Syntax::NamespaceHandling - Handle namespaced blocks
289              
290             =head1 VERSION
291              
292             version 0.43
293              
294             =head1 DESCRIPTION
295              
296             Allows the implementation of namespaced blocks like the
297             L<role|MooseX::Declare::Syntax::Keyword::Role> and
298             L<class|MooseX::Declare::Syntax::Keyword::Class> keyword handlers.
299              
300             Namespaces are automatically nested. Meaning that, for example, a C<class Bar>
301             declaration inside another C<class Foo> block gives the inner one actually the
302             name C<Foo::Bar>.
303              
304             =head1 METHODS
305              
306             =head2 parse
307              
308             Any Object->parse (Object $context)
309              
310             This is the main handling routine for namespaces. It will remove the namespace
311             name and its options. If the handler was invoked without a name, options or
312             a following block, it is assumed that this is an instance of an autoquoted
313             bareword like C<< class => "Foo" >>.
314              
315             The return value of the C<parse> method is also the value that is returned
316             to the user of the keyword.
317              
318             =head1 CONSUMES
319              
320             =over 4
321              
322             =item *
323              
324             L<MooseX::Declare::Syntax::KeywordHandling>
325              
326             =item *
327              
328             L<MooseX::Declare::Syntax::InnerSyntaxHandling>
329              
330             =back
331              
332             =head1 REQUIRED METHODS
333              
334             =head2 handle_missing_block
335              
336             Object->handle_missing_block (Object $context, Str $body, %args)
337              
338             This must be implemented to decide what to do in case the statement is
339             terminated rather than followed by a block. It will receive the context
340             object, the produced code that needs to be injected, and all the arguments
341             that were passed to the call to L<MooseX::Declare::Context/inject_code_parts>.
342              
343             The return value will be ignored.
344              
345             =head1 EXTENDABLE STUB METHODS
346              
347             =head2 add_namespace_customizations
348              
349             =head2 add_optional_customizations
350              
351             Object->add_namespace_customizations (Object $context, Str $package, HashRef $options)
352             Object->add_optional_customizations (Object $context, Str $package, HashRef $options)
353              
354             These will be called (in this order) by the L</parse> method. They allow specific hooks
355             to attach before/after/around the customizations for the namespace and the provided
356             options that are not attached to the namespace directly.
357              
358             While this distinction might seem superficial, we advise library developers facilitating
359             this role to follow the precedent. This ensures that when another component needs to
360             tie between the namespace and any additional customizations everything will run in the
361             correct order. An example of this separation would be
362              
363             class Foo is mutable ...
364              
365             being an option of the namespace generation, while
366              
367             class Foo with Bar ...
368              
369             is an additional optional customization.
370              
371             =head2 handle_post_parsing
372              
373             Object->handle_post_parsing (Object $context, Str $package, Str | Object $name)
374              
375             Allows for additional modifications to the namespace after everything else has been
376             done. It will receive the context, the fully qualified package name, and either a
377             string with the name that was specified (might not be fully qualified, since
378             namespaces can be nested) or the anonymous metaclass instance if no name was
379             specified.
380              
381             The return value of this method will be the value returned to the user of the
382             keyword. If you always return the C<$package> argument like this:
383              
384             sub handle_post_parsing {
385             my ($self, $context, $package, $name) = @_;
386             return $package;
387             }
388              
389             and set this up in a C<foo> keyword handler, you can use it like this:
390              
391             foo Cthulhu {
392              
393             my $fhtagn = foo Fhtagn { }
394             my $anon = foo { };
395              
396             say $fhtagn; # Cthulhu::Fhtagn
397             say $anon; # some autogenerated package name
398             }
399              
400             =head2 make_anon_metaclass
401              
402             Class::MOP::Class Object->make_anon_metaclass ()
403              
404             This method should be overridden if you want to provide anonymous namespaces.
405              
406             It does not receive any arguments for customization of the metaclass, because
407             the configuration and customization will be done by L<MooseX::Declare> in the
408             package of the generated class in the same way as in those that have specified
409             names. This way ensures that anonymous and named namespaces are always handled
410             equally.
411              
412             If you do not extend this method (it will return nothing by default), an error
413             will be thrown when a user attempts to declare an anonymous namespace.
414              
415             =head1 SEE ALSO
416              
417             =over 4
418              
419             =item *
420              
421             L<MooseX::Declare>
422              
423             =item *
424              
425             L<MooseX::Declare::Syntax::MooseSetup>
426              
427             =back
428              
429             =head1 AUTHOR
430              
431             Florian Ragwitz <rafl@debian.org>
432              
433             =head1 COPYRIGHT AND LICENSE
434              
435             This software is copyright (c) 2008 by Florian Ragwitz.
436              
437             This is free software; you can redistribute it and/or modify it under
438             the same terms as the Perl 5 programming language system itself.
439              
440             =cut