Add built local::lib
[catagits/Gitalist.git] / local-lib5 / lib / perl5 / MooseX / Declare / Syntax / NamespaceHandling.pm
1 package MooseX::Declare::Syntax::NamespaceHandling;
2
3 use Moose::Role;
4 use Moose::Util qw( does_role );
5 use MooseX::Declare::Util qw( outer_stack_peek );
6 use Carp;
7
8 use aliased 'MooseX::Declare::Context::Namespaced';
9 use aliased 'MooseX::Declare::Context::WithOptions';
10 use aliased 'MooseX::Declare::Context::Parameterized';
11 use aliased 'MooseX::Declare::StackItem';
12
13 use namespace::clean -except => 'meta';
14
15 with qw(
16     MooseX::Declare::Syntax::KeywordHandling
17     MooseX::Declare::Syntax::InnerSyntaxHandling
18 );
19
20 requires qw(
21     handle_missing_block
22 );
23
24 sub add_namespace_customizations { }
25 sub add_optional_customizations  { }
26 sub handle_post_parsing          { }
27 sub make_anon_metaclass          { }
28
29 around context_traits => sub { super, WithOptions, Namespaced };
30
31 sub parse_specification {
32     my ($self, $ctx) = @_;
33
34     $self->parse_namespace_specification($ctx);
35     $self->parse_option_specification($ctx);
36
37     return;
38 }
39
40 sub parse_namespace_specification {
41     my ($self, $ctx) = @_;
42     return scalar $ctx->strip_namespace;
43 }
44
45 sub parse_option_specification {
46     my ($self, $ctx) = @_;
47     return scalar $ctx->strip_options;
48 }
49
50 sub generate_inline_stack {
51     my ($self, $ctx) = @_;
52
53     return join ', ',
54         map { $_->serialize }
55             @{ $ctx->stack },
56             $self->generate_current_stack_item($ctx);
57 }
58
59 sub generate_current_stack_item {
60     my ($self, $ctx) = @_;
61
62     return StackItem->new(
63         identifier       => $self->identifier,
64         is_dirty         => $ctx->options->{is}{dirty},
65         is_parameterized => does_role($ctx, Parameterized) && $ctx->has_parameter_signature,
66         handler          => ref($self),
67         namespace        => $ctx->namespace,
68     );
69 }
70
71 sub parse {
72     my ($self, $ctx) = @_;
73
74     # keyword comes first
75     $ctx->skip_declarator;
76
77     # read the name and unwrap the options
78     $self->parse_specification($ctx);
79
80     my $name = $ctx->namespace;
81
82     my ($package, $anon);
83
84     # we have a name in the declaration, which will be used as package name
85     if (defined $name) {
86         $package = $name;
87
88         # there is an outer namespace stack item, meaning we namespace below
89         # it, if the name starts with ::
90         if (my $outer = outer_stack_peek $ctx->caller_file) {
91             $package = $outer . $package
92                 if $name =~ /^::/;
93         }
94     }
95
96     # no name, no options, no block. Probably { class => 'foo' }
97     elsif (not(keys %{ $ctx->options }) and $ctx->peek_next_char ne '{') {
98         return;
99     }
100
101     # we have options and/or a block, but not name
102     else {
103         $anon = $self->make_anon_metaclass
104             or croak sprintf 'Unable to create an anonymized %s namespace', $self->identifier;
105         $package = $anon->name;
106     }
107
108     # namespace and mx:d initialisations
109     $ctx->add_preamble_code_parts(
110         "package ${package}",
111         sprintf(
112             "use %s %s => '%s', file => __FILE__, stack => [ %s ]",
113             $ctx->provided_by,
114             outer_package => $package,
115             $self->generate_inline_stack($ctx),
116         ),
117     );
118
119     # allow consumer to provide specialisations
120     $self->add_namespace_customizations($ctx, $package);
121
122     # make options a separate step
123     $self->add_optional_customizations($ctx, $package);
124
125     # finish off preamble with a namespace cleanup
126     $ctx->add_preamble_code_parts(
127         $ctx->options->{is}->{dirty}
128             ? 'use namespace::clean -except => [qw( meta )]'
129             : 'use namespace::autoclean'
130     );
131
132     # clean up our stack afterwards, if there was a name
133     $ctx->add_cleanup_code_parts(
134         ['BEGIN',
135             'MooseX::Declare::Util::outer_stack_pop __FILE__',
136         ],
137     );
138
139     # actual code injection
140     $ctx->inject_code_parts(
141         missing_block_handler => sub { $self->handle_missing_block(@_) },
142     );
143
144     # a last chance to change things
145     $self->handle_post_parsing($ctx, $package, defined($name) ? $name : $anon);
146 }
147
148 1;
149
150 __END__
151
152 =head1 NAME
153
154 MooseX::Declare::Syntax::NamespaceHandling - Handle namespaced blocks
155
156 =head1 DESCRIPTION
157
158 Allows the implementation of namespaced blocks like the
159 L<role|MooseX::Declare::Syntax::Keyword::Role> and
160 L<class|MooseX::Declare::Syntax::Keyword::Class> keyword handlers.
161
162 Namespaces are automatically nested. Meaning that, for example, a C<class Bar>
163 declaration inside another C<class Foo> block gives the inner one actually the
164 name C<Foo::Bar>.
165
166 =head1 CONSUMES
167
168 =over
169
170 =item * L<MooseX::Declare::Syntax::KeywordHandling>
171
172 =item * L<MooseX::Declare::Syntax::InnerSyntaxHandling>
173
174 =back
175
176 =head1 REQUIRED METHODS
177
178 =head2 handle_missing_block
179
180   Object->handle_missing_block (Object $context, Str $body, %args)
181
182 This must be implemented to decide what to do in case the statement is
183 terminated rather than followed by a block. It will receive the context
184 object, the produced code that needs to be injected, and all the arguments
185 that were passed to the call to L<MooseX::Declare::Context/inject_code_parts>.
186
187 The return value will be ignored.
188
189 =head1 EXTENDABLE STUB METHODS
190
191 =head2 add_namespace_customizations
192
193 =head2 add_optional_customizations
194
195   Object->add_namespace_customizations (Object $context, Str $package, HashRef $options)
196   Object->add_optional_customizations  (Object $context, Str $package, HashRef $options)
197
198 These will be called (in this order) by the L</parse> method. They allow specific hooks
199 to attach before/after/around the customizations for the namespace and the provided
200 options that are not attached to the namespace directly.
201
202 While this distinction might seem superficial, we advise library developers faciliating
203 this role to follow the precendent. This ensures that when another component needs to
204 tie between the namspace and any additional customizations everythign will run in the
205 correct order. An example of this separation would be
206
207   class Foo is mutable ...
208
209 being an option of the namespace generation, while
210
211   class Foo with Bar ...
212
213 is an additional optional customization.
214
215 =head2 handle_post_parsing
216
217   Object->handle_post_parsing (Object $context, Str $package, Str | Object $name)
218
219 Allows for additional modifications to te namespace after everything else has been
220 done. It will receive the context, the fully qualified package name, and either a
221 string with the name that was specified (might not be fully qualified, since
222 namespaces can be nested) or the anonymous metaclass instance if no name was
223 specified.
224
225 The return value of this method will be the value returned to the user of the
226 keyword. If you always return the C<$package> argument like this:
227
228   sub handle_post_parsing {
229       my ($self, $context, $package, $name) = @_;
230       return $package;
231   }
232
233 and set this up in a C<foo> keyword handler, you can use it like this:
234
235   foo Cthulhu {
236
237       my $fhtagn = foo Fhtagn { }
238       my $anon   = foo { };
239
240       say $fhtagn;  # Cthulhu::Fhtagn
241       say $anon;    # some autogenerated package name
242   }
243
244 =head2 make_anon_metaclass
245
246   Class::MOP::Class Object->make_anon_metaclass ()
247
248 This method should be overridden if you want to provide anonymous namespaces.
249
250 It does not receive any arguments for customization of the metaclass, because
251 the configuration and customization will be done by L<MooseX::Declare> in the
252 package of the generated class in the same way as in those that have specified
253 names. This way ensures that anonymous and named namespaces are always handled
254 equally.
255
256 If you do not extend this method (it will return nothing by default), an error
257 will be thrown when a user attempts to declare an anonymous namespace.
258
259 =head1 METHODS
260
261 =head2 parse
262
263   Any Object->parse (Object $context)
264
265 This is the main handling routine for namespaces. It will remove the namespace
266 name and its options. If the handler was invoked without a name, options or
267 a following block, it is assumed that this is an instance of an autoquoted
268 bareword like C<class => "Foo">.
269
270 The return value of the C<parse> method is also the value that is returned
271 to the user of the keyword.
272
273 =head1 SEE ALSO
274
275 =over
276
277 =item * L<MooseX::Declare>
278
279 =item * L<MooseX::Declare::Syntax::MooseSetup>
280
281 =back
282
283 =head1 AUTHOR, COPYRIGHT & LICENSE
284
285 See L<MooseX::Declare>
286
287 =cut