File Coverage

blib/lib/MooseX/Declare/Syntax/NamespaceHandling.pm
Criterion Covered Total %
statement 65 66 98.4
branch 13 14 92.8
condition 6 6 100.0
subroutine 19 20 95.0
pod 5 10 50.0
total 108 116 93.1


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