Initial Commit
This commit is contained in:
440
database/perl/vendor/lib/MooseX/Declare/Syntax/NamespaceHandling.pm
vendored
Normal file
440
database/perl/vendor/lib/MooseX/Declare/Syntax/NamespaceHandling.pm
vendored
Normal file
@@ -0,0 +1,440 @@
|
||||
package MooseX::Declare::Syntax::NamespaceHandling;
|
||||
# ABSTRACT: Handle namespaced blocks
|
||||
|
||||
our $VERSION = '0.43';
|
||||
|
||||
use Moose::Role;
|
||||
use Moose::Util qw( does_role );
|
||||
use MooseX::Declare::Util qw( outer_stack_peek );
|
||||
use Carp;
|
||||
|
||||
use aliased 'MooseX::Declare::Context::Namespaced';
|
||||
use aliased 'MooseX::Declare::Context::WithOptions';
|
||||
use aliased 'MooseX::Declare::Context::Parameterized';
|
||||
use aliased 'MooseX::Declare::StackItem';
|
||||
|
||||
use namespace::autoclean;
|
||||
|
||||
#pod =head1 DESCRIPTION
|
||||
#pod
|
||||
#pod Allows the implementation of namespaced blocks like the
|
||||
#pod L<role|MooseX::Declare::Syntax::Keyword::Role> and
|
||||
#pod L<class|MooseX::Declare::Syntax::Keyword::Class> keyword handlers.
|
||||
#pod
|
||||
#pod Namespaces are automatically nested. Meaning that, for example, a C<class Bar>
|
||||
#pod declaration inside another C<class Foo> block gives the inner one actually the
|
||||
#pod name C<Foo::Bar>.
|
||||
#pod
|
||||
#pod =head1 CONSUMES
|
||||
#pod
|
||||
#pod =for :list
|
||||
#pod * L<MooseX::Declare::Syntax::KeywordHandling>
|
||||
#pod * L<MooseX::Declare::Syntax::InnerSyntaxHandling>
|
||||
#pod
|
||||
#pod =cut
|
||||
|
||||
with qw(
|
||||
MooseX::Declare::Syntax::KeywordHandling
|
||||
MooseX::Declare::Syntax::InnerSyntaxHandling
|
||||
);
|
||||
|
||||
#pod =head1 REQUIRED METHODS
|
||||
#pod
|
||||
#pod =head2 handle_missing_block
|
||||
#pod
|
||||
#pod Object->handle_missing_block (Object $context, Str $body, %args)
|
||||
#pod
|
||||
#pod This must be implemented to decide what to do in case the statement is
|
||||
#pod terminated rather than followed by a block. It will receive the context
|
||||
#pod object, the produced code that needs to be injected, and all the arguments
|
||||
#pod that were passed to the call to L<MooseX::Declare::Context/inject_code_parts>.
|
||||
#pod
|
||||
#pod The return value will be ignored.
|
||||
#pod
|
||||
#pod =cut
|
||||
|
||||
requires qw(
|
||||
handle_missing_block
|
||||
);
|
||||
|
||||
#pod =head1 EXTENDABLE STUB METHODS
|
||||
#pod
|
||||
#pod =head2 add_namespace_customizations
|
||||
#pod
|
||||
#pod =head2 add_optional_customizations
|
||||
#pod
|
||||
#pod Object->add_namespace_customizations (Object $context, Str $package, HashRef $options)
|
||||
#pod Object->add_optional_customizations (Object $context, Str $package, HashRef $options)
|
||||
#pod
|
||||
#pod These will be called (in this order) by the L</parse> method. They allow specific hooks
|
||||
#pod to attach before/after/around the customizations for the namespace and the provided
|
||||
#pod options that are not attached to the namespace directly.
|
||||
#pod
|
||||
#pod While this distinction might seem superficial, we advise library developers facilitating
|
||||
#pod this role to follow the precedent. This ensures that when another component needs to
|
||||
#pod tie between the namespace and any additional customizations everything will run in the
|
||||
#pod correct order. An example of this separation would be
|
||||
#pod
|
||||
#pod class Foo is mutable ...
|
||||
#pod
|
||||
#pod being an option of the namespace generation, while
|
||||
#pod
|
||||
#pod class Foo with Bar ...
|
||||
#pod
|
||||
#pod is an additional optional customization.
|
||||
#pod
|
||||
#pod =head2 handle_post_parsing
|
||||
#pod
|
||||
#pod Object->handle_post_parsing (Object $context, Str $package, Str | Object $name)
|
||||
#pod
|
||||
#pod Allows for additional modifications to the namespace after everything else has been
|
||||
#pod done. It will receive the context, the fully qualified package name, and either a
|
||||
#pod string with the name that was specified (might not be fully qualified, since
|
||||
#pod namespaces can be nested) or the anonymous metaclass instance if no name was
|
||||
#pod specified.
|
||||
#pod
|
||||
#pod The return value of this method will be the value returned to the user of the
|
||||
#pod keyword. If you always return the C<$package> argument like this:
|
||||
#pod
|
||||
#pod sub handle_post_parsing {
|
||||
#pod my ($self, $context, $package, $name) = @_;
|
||||
#pod return $package;
|
||||
#pod }
|
||||
#pod
|
||||
#pod and set this up in a C<foo> keyword handler, you can use it like this:
|
||||
#pod
|
||||
#pod foo Cthulhu {
|
||||
#pod
|
||||
#pod my $fhtagn = foo Fhtagn { }
|
||||
#pod my $anon = foo { };
|
||||
#pod
|
||||
#pod say $fhtagn; # Cthulhu::Fhtagn
|
||||
#pod say $anon; # some autogenerated package name
|
||||
#pod }
|
||||
#pod
|
||||
#pod =head2 make_anon_metaclass
|
||||
#pod
|
||||
#pod Class::MOP::Class Object->make_anon_metaclass ()
|
||||
#pod
|
||||
#pod This method should be overridden if you want to provide anonymous namespaces.
|
||||
#pod
|
||||
#pod It does not receive any arguments for customization of the metaclass, because
|
||||
#pod the configuration and customization will be done by L<MooseX::Declare> in the
|
||||
#pod package of the generated class in the same way as in those that have specified
|
||||
#pod names. This way ensures that anonymous and named namespaces are always handled
|
||||
#pod equally.
|
||||
#pod
|
||||
#pod If you do not extend this method (it will return nothing by default), an error
|
||||
#pod will be thrown when a user attempts to declare an anonymous namespace.
|
||||
#pod
|
||||
#pod =cut
|
||||
|
||||
sub add_namespace_customizations { }
|
||||
sub add_optional_customizations { }
|
||||
sub handle_post_parsing { }
|
||||
sub make_anon_metaclass { }
|
||||
|
||||
around context_traits => sub { super, WithOptions, Namespaced };
|
||||
|
||||
sub parse_specification {
|
||||
my ($self, $ctx) = @_;
|
||||
|
||||
$self->parse_namespace_specification($ctx);
|
||||
$self->parse_option_specification($ctx);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sub parse_namespace_specification {
|
||||
my ($self, $ctx) = @_;
|
||||
return scalar $ctx->strip_namespace;
|
||||
}
|
||||
|
||||
sub parse_option_specification {
|
||||
my ($self, $ctx) = @_;
|
||||
return scalar $ctx->strip_options;
|
||||
}
|
||||
|
||||
sub generate_inline_stack {
|
||||
my ($self, $ctx) = @_;
|
||||
|
||||
return join ', ',
|
||||
map { $_->serialize }
|
||||
@{ $ctx->stack },
|
||||
$self->generate_current_stack_item($ctx);
|
||||
}
|
||||
|
||||
sub generate_current_stack_item {
|
||||
my ($self, $ctx) = @_;
|
||||
|
||||
return StackItem->new(
|
||||
identifier => $self->identifier,
|
||||
is_dirty => $ctx->options->{is}{dirty},
|
||||
is_parameterized => does_role($ctx, Parameterized) && $ctx->has_parameter_signature,
|
||||
handler => ref($self),
|
||||
namespace => $ctx->namespace,
|
||||
);
|
||||
}
|
||||
|
||||
#pod =method parse
|
||||
#pod
|
||||
#pod Any Object->parse (Object $context)
|
||||
#pod
|
||||
#pod This is the main handling routine for namespaces. It will remove the namespace
|
||||
#pod name and its options. If the handler was invoked without a name, options or
|
||||
#pod a following block, it is assumed that this is an instance of an autoquoted
|
||||
#pod bareword like C<< class => "Foo" >>.
|
||||
#pod
|
||||
#pod The return value of the C<parse> method is also the value that is returned
|
||||
#pod to the user of the keyword.
|
||||
#pod
|
||||
#pod =cut
|
||||
|
||||
sub parse {
|
||||
my ($self, $ctx) = @_;
|
||||
|
||||
# keyword comes first
|
||||
$ctx->skip_declarator;
|
||||
|
||||
# read the name and unwrap the options
|
||||
$self->parse_specification($ctx);
|
||||
|
||||
my $name = $ctx->namespace;
|
||||
|
||||
my ($package, $anon);
|
||||
|
||||
# we have a name in the declaration, which will be used as package name
|
||||
if (defined $name) {
|
||||
$package = $name;
|
||||
|
||||
# there is an outer namespace stack item, meaning we namespace below
|
||||
# it, if the name starts with ::
|
||||
if (my $outer = outer_stack_peek $ctx->caller_file) {
|
||||
$package = $outer . $package
|
||||
if $name =~ /^::/;
|
||||
}
|
||||
}
|
||||
|
||||
# no name, no options, no block. Probably { class => 'foo' }
|
||||
elsif (not(keys %{ $ctx->options }) and $ctx->peek_next_char ne '{') {
|
||||
return;
|
||||
}
|
||||
|
||||
# we have options and/or a block, but not name
|
||||
else {
|
||||
$anon = $self->make_anon_metaclass
|
||||
or croak sprintf 'Unable to create an anonymized %s namespace', $self->identifier;
|
||||
$package = $anon->name;
|
||||
}
|
||||
|
||||
# namespace and mx:d initialisations
|
||||
$ctx->add_preamble_code_parts(
|
||||
"package ${package}",
|
||||
sprintf(
|
||||
"use %s %s => '%s', file => __FILE__, stack => [ %s ]",
|
||||
$ctx->provided_by,
|
||||
outer_package => $package,
|
||||
$self->generate_inline_stack($ctx),
|
||||
),
|
||||
);
|
||||
|
||||
# allow consumer to provide specialisations
|
||||
$self->add_namespace_customizations($ctx, $package);
|
||||
|
||||
# make options a separate step
|
||||
$self->add_optional_customizations($ctx, $package);
|
||||
|
||||
# finish off preamble with a namespace cleanup
|
||||
$ctx->add_preamble_code_parts(
|
||||
$ctx->options->{is}->{dirty}
|
||||
? 'use namespace::clean -except => [qw( meta )]'
|
||||
: 'use namespace::autoclean'
|
||||
);
|
||||
|
||||
# clean up our stack afterwards, if there was a name
|
||||
$ctx->add_cleanup_code_parts(
|
||||
['BEGIN',
|
||||
'MooseX::Declare::Util::outer_stack_pop __FILE__',
|
||||
],
|
||||
);
|
||||
|
||||
# actual code injection
|
||||
$ctx->inject_code_parts(
|
||||
missing_block_handler => sub { $self->handle_missing_block(@_) },
|
||||
);
|
||||
|
||||
# a last chance to change things
|
||||
$self->handle_post_parsing($ctx, $package, defined($name) ? $name : $anon);
|
||||
}
|
||||
|
||||
#pod =head1 SEE ALSO
|
||||
#pod
|
||||
#pod =for :list
|
||||
#pod * L<MooseX::Declare>
|
||||
#pod * L<MooseX::Declare::Syntax::MooseSetup>
|
||||
#pod
|
||||
#pod =cut
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=encoding UTF-8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
MooseX::Declare::Syntax::NamespaceHandling - Handle namespaced blocks
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
version 0.43
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Allows the implementation of namespaced blocks like the
|
||||
L<role|MooseX::Declare::Syntax::Keyword::Role> and
|
||||
L<class|MooseX::Declare::Syntax::Keyword::Class> keyword handlers.
|
||||
|
||||
Namespaces are automatically nested. Meaning that, for example, a C<class Bar>
|
||||
declaration inside another C<class Foo> block gives the inner one actually the
|
||||
name C<Foo::Bar>.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 parse
|
||||
|
||||
Any Object->parse (Object $context)
|
||||
|
||||
This is the main handling routine for namespaces. It will remove the namespace
|
||||
name and its options. If the handler was invoked without a name, options or
|
||||
a following block, it is assumed that this is an instance of an autoquoted
|
||||
bareword like C<< class => "Foo" >>.
|
||||
|
||||
The return value of the C<parse> method is also the value that is returned
|
||||
to the user of the keyword.
|
||||
|
||||
=head1 CONSUMES
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
L<MooseX::Declare::Syntax::KeywordHandling>
|
||||
|
||||
=item *
|
||||
|
||||
L<MooseX::Declare::Syntax::InnerSyntaxHandling>
|
||||
|
||||
=back
|
||||
|
||||
=head1 REQUIRED METHODS
|
||||
|
||||
=head2 handle_missing_block
|
||||
|
||||
Object->handle_missing_block (Object $context, Str $body, %args)
|
||||
|
||||
This must be implemented to decide what to do in case the statement is
|
||||
terminated rather than followed by a block. It will receive the context
|
||||
object, the produced code that needs to be injected, and all the arguments
|
||||
that were passed to the call to L<MooseX::Declare::Context/inject_code_parts>.
|
||||
|
||||
The return value will be ignored.
|
||||
|
||||
=head1 EXTENDABLE STUB METHODS
|
||||
|
||||
=head2 add_namespace_customizations
|
||||
|
||||
=head2 add_optional_customizations
|
||||
|
||||
Object->add_namespace_customizations (Object $context, Str $package, HashRef $options)
|
||||
Object->add_optional_customizations (Object $context, Str $package, HashRef $options)
|
||||
|
||||
These will be called (in this order) by the L</parse> method. They allow specific hooks
|
||||
to attach before/after/around the customizations for the namespace and the provided
|
||||
options that are not attached to the namespace directly.
|
||||
|
||||
While this distinction might seem superficial, we advise library developers facilitating
|
||||
this role to follow the precedent. This ensures that when another component needs to
|
||||
tie between the namespace and any additional customizations everything will run in the
|
||||
correct order. An example of this separation would be
|
||||
|
||||
class Foo is mutable ...
|
||||
|
||||
being an option of the namespace generation, while
|
||||
|
||||
class Foo with Bar ...
|
||||
|
||||
is an additional optional customization.
|
||||
|
||||
=head2 handle_post_parsing
|
||||
|
||||
Object->handle_post_parsing (Object $context, Str $package, Str | Object $name)
|
||||
|
||||
Allows for additional modifications to the namespace after everything else has been
|
||||
done. It will receive the context, the fully qualified package name, and either a
|
||||
string with the name that was specified (might not be fully qualified, since
|
||||
namespaces can be nested) or the anonymous metaclass instance if no name was
|
||||
specified.
|
||||
|
||||
The return value of this method will be the value returned to the user of the
|
||||
keyword. If you always return the C<$package> argument like this:
|
||||
|
||||
sub handle_post_parsing {
|
||||
my ($self, $context, $package, $name) = @_;
|
||||
return $package;
|
||||
}
|
||||
|
||||
and set this up in a C<foo> keyword handler, you can use it like this:
|
||||
|
||||
foo Cthulhu {
|
||||
|
||||
my $fhtagn = foo Fhtagn { }
|
||||
my $anon = foo { };
|
||||
|
||||
say $fhtagn; # Cthulhu::Fhtagn
|
||||
say $anon; # some autogenerated package name
|
||||
}
|
||||
|
||||
=head2 make_anon_metaclass
|
||||
|
||||
Class::MOP::Class Object->make_anon_metaclass ()
|
||||
|
||||
This method should be overridden if you want to provide anonymous namespaces.
|
||||
|
||||
It does not receive any arguments for customization of the metaclass, because
|
||||
the configuration and customization will be done by L<MooseX::Declare> in the
|
||||
package of the generated class in the same way as in those that have specified
|
||||
names. This way ensures that anonymous and named namespaces are always handled
|
||||
equally.
|
||||
|
||||
If you do not extend this method (it will return nothing by default), an error
|
||||
will be thrown when a user attempts to declare an anonymous namespace.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
L<MooseX::Declare>
|
||||
|
||||
=item *
|
||||
|
||||
L<MooseX::Declare::Syntax::MooseSetup>
|
||||
|
||||
=back
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Florian Ragwitz <rafl@debian.org>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
This software is copyright (c) 2008 by Florian Ragwitz.
|
||||
|
||||
This is free software; you can redistribute it and/or modify it under
|
||||
the same terms as the Perl 5 programming language system itself.
|
||||
|
||||
=cut
|
||||
Reference in New Issue
Block a user