# This file documents the revision history for Perl extension Catalyst.
- - Use ~ as prefix for plugins or action classes which are located in
- MyApp::Plugin / MyApp::Action (mo)
- - Controller methods without attributes are now considered actions if
- they are specified in config->{action(s)} (mo)
+ Bug fixes:
+ - Revert change to URL encode things passed into $c->uri_for
+ Args and CaptureArgs as this causes breakage to pre-existing
+ applications.
+ - Remove use of Test::MockObject as it doesn't install from CPAN
+ in some environments.
+ - Remove use of dclone to deep copy configs and replace with
+ Catalyst::Utils::merge_hashes which has the same effect, of
+ ensuring child classes don't inherit their parent's config,
+ except works correctly with closures.
+
++ New features:
++ - Use ~ as prefix for plugins or action classes which are located in
++ MyApp::Plugin / MyApp::Action (mo)
++ - Controller methods without attributes are now considered actions if
++ they are specified in config->{action(s)} (mo)
+
5.80005 2009-06-06 14:40:00
Behaviour changes:
requires 'URI' => '1.35';
requires 'Text::Balanced'; # core in 5.8.x but mentioned for completeness
requires 'MRO::Compat';
+requires 'String::RewritePrefix' => '0.004'; # Catalyst::Utils::resolve_namespace
recommends 'B::Hooks::OP::Check::StashChange';
test_requires 'Class::Data::Inheritable';
- test_requires 'Test::MockObject' => '1.07'; # Newish (hah, 2006!) version to
- # hopefully avoid broken distro
- # packages (RT#46104)
test_requires 'Test::Exception';
# aggregate tests if AGGREGATE_TESTS is set and a recent Test::Aggregate is available
# NOTE - This is the version number of the _incompatible_ code,
# not the version number of the fixed version.
my %conflicts = (
+ 'Catalyst::Component::ACCEPT_CONTEXT' => '0.06',
'Catalyst::Plugin::ENV' => '9999', # This plugin is just stupid, full stop
# should have been a core fix.
'Catalyst::Plugin::Unicode::Encoding' => '0.2',
$c->error(0);
}
- # search components given a name and some prefixes
sub _comp_search_prefixes {
+ my $c = shift;
+ return map $c->components->{ $_ }, $c->_comp_names_search_prefixes(@_);
+ }
+
+ # search components given a name and some prefixes
+ sub _comp_names_search_prefixes {
my ( $c, $name, @prefixes ) = @_;
my $appclass = ref $c || $c;
my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
my $query = ref $name ? $name : qr/^$name$/i;
my @result = grep { $eligible{$_} =~ m{$query} } keys %eligible;
- return map { $c->components->{ $_ } } @result if @result;
+ return @result if @result;
# if we were given a regexp to search against, we're done.
return if ref $name;
# regexp fallback
$query = qr/$name/i;
- @result = map { $c->components->{ $_ } } grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
+ @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
# no results? try against full names
if( !@result ) {
- @result = map { $c->components->{ $_ } } grep { m{$query} } keys %eligible;
+ @result = grep { m{$query} } keys %eligible;
}
# don't warn if we didn't find any results, it just might not exist
my $filter = "^${appclass}::(" . join( '|', @prefixes ) . ')::';
- my @names = map { s{$filter}{}; $_; } $c->_comp_search_prefixes( undef, @prefixes );
+ my @names = map { s{$filter}{}; $_; }
+ $c->_comp_names_search_prefixes( undef, @prefixes );
+
return @names;
}
( scalar @args && ref $args[$#args] eq 'HASH' ? pop @args : {} );
carp "uri_for called with undef argument" if grep { ! defined $_ } @args;
- s/([^A-Za-z0-9\-_.!~*'()])/$URI::Escape::escapes{$1}/go for @args;
+ s/([^$URI::uric])/$URI::Escape::escapes{$1}/go for @args;
unshift(@args, $path);
$_ = "$_";
utf8::encode( $_ ) if utf8::is_utf8($_);
# using the URI::Escape pattern here so utf8 chars survive
- s/([^A-Za-z0-9\-_.!~*'()])/$URI::Escape::escapes{$1}/go;
+ s/([^A-Za-z0-9\-_.!~*'() ])/$URI::Escape::escapes{$1}/go;
s/ /+/g;
"${key}=$_"; } ( ref $val eq 'ARRAY' ? @$val : $val ));
} @keys);
$class->_plugins( {} ) unless $class->_plugins;
$plugins ||= [];
-
- my @plugins = map { s/\A\+// ? $_ : "Catalyst::Plugin::$_" } @$plugins;
+
+ my @plugins = Catalyst::Utils::resolve_namespace($class . '::Plugin', 'Catalyst::Plugin', @$plugins);
-
+
for my $plugin ( reverse @plugins ) {
Class::MOP::load_class($plugin);
my $meta = find_meta($plugin);
grep { $_ && blessed($_) && $_->isa('Moose::Meta::Role') }
map { find_meta($_) }
@plugins;
-
+
Moose::Util::apply_all_roles(
$class => @roles
) if @roles;
=head1 LICENSE
- This library is free software, you can redistribute it and/or modify it under
+ This library is free software. You can redistribute it and/or modify it under
the same terms as Perl itself.
=cut
sub get_action_methods {
my $self = shift;
my $meta = find_meta($self);
- confess("Metaclass for " . ref($meta) ." for " . $meta->name
- . " cannot support register_actions.")
- unless $meta->can('get_nearest_methods_with_attributes');
+ confess("Metaclass for "
+ . ref($meta) . " for "
+ . $meta->name
+ . " cannot support register_actions." )
+ unless $meta->can('get_nearest_methods_with_attributes');
my @methods = $meta->get_nearest_methods_with_attributes;
+
+ # actions specified via config are also action_methods
+ push(
+ @methods,
+ map {
+ $meta->get_method($_)
+ || confess( 'Action "'
+ . $_
+ . '" is not available from controller '
+ . ( ref $self ) )
+ } keys %{ $self->_controller_actions }
+ ) if ( ref $self );
return @methods;
}
+
sub register_actions {
my ( $self, $c ) = @_;
$self->register_action_methods( $c, $self->get_action_methods );
foreach my $method (@methods) {
my $name = $method->name;
my $attributes = $method->attributes;
- next unless $attributes;
my $attrs = $self->_parse_attrs( $c, $name, @{ $attributes } );
if ( $attrs->{Private} && ( keys %$attrs > 1 ) ) {
$c->log->debug( 'Bad action definition "'
sub _parse_ActionClass_attr {
my ( $self, $c, $name, $value ) = @_;
- unless ( $value =~ s/^\+// ) {
- $value = join('::', $self->_action_class, $value );
- }
+ my $appname = $self->_application;
+ $value = Catalyst::Utils::resolve_namespace($appname . '::Action', $self->_action_class, $value);
return ( 'ActionClass', $value );
}
=head1 COPYRIGHT
- This program is free software, you can redistribute it and/or modify
+ This library is free software. You can redistribute it and/or modify
it under the same terms as Perl itself.
=cut
=head1 METHODS
- =head2 new
+ =head2 new
Construct a new dispatcher.
return $self->_action_hash->{"${namespace}/${name}"};
}
- =head2 $self->get_action_by_path( $path );
+ =head2 $self->get_action_by_path( $path );
Returns the named action by its full private path.
my ( $self, @types ) = @_;
my @loaded;
-
# Preload action types
for my $type (@types) {
- my $class =
- ( $type =~ /^\+(.*)$/ ) ? $1 : "Catalyst::DispatchType::${type}";
-
+ # first param is undef because we cannot get the appclass
+ my $class = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $type);
+
eval { Class::MOP::load_class($class) };
Catalyst::Exception->throw( message => qq/Couldn't load "$class"/ )
if $@;
Get the DispatchType object of the relevant type, i.e. passing C<$type> of
C<Chained> would return a L<Catalyst::DispatchType::Chained> object (assuming
- of course it's being used.)
+ of course it's being used.)
=cut
sub dispatch_type {
my ($self, $name) = @_;
-
- unless ($name =~ s/^\+//) {
- $name = "Catalyst::DispatchType::" . $name;
- }
+
+ # first param is undef because we cannot get the appclass
+ $name = Catalyst::Utils::resolve_namespace(undef, 'Catalyst::DispatchType', $name);
for (@{ $self->_dispatch_types }) {
return $_ if ref($_) eq $name;
# See also t/lib/TestApp/Plugin/AddDispatchTypes.pm
# Alias _method_name to method_name, add a before modifier to warn..
- foreach my $public_method_name (qw/
- tree
- dispatch_types
- registered_dispatch_types
- method_action_class
- action_hash
+ foreach my $public_method_name (qw/
+ tree
+ dispatch_types
+ registered_dispatch_types
+ method_action_class
+ action_hash
container_hash
/) {
my $private_method_name = '_' . $public_method_name;
=head1 COPYRIGHT
- This program is free software, you can redistribute it and/or modify it under
+ This library is free software. You can redistribute it and/or modify it under
the same terms as Perl itself.
=cut
use Carp qw/croak/;
use Cwd;
+use String::RewritePrefix;
+
use namespace::clean;
=head1 NAME
=head1 DESCRIPTION
- Catalyst Utilities.
+ Catalyst Utilities.
=head1 METHODS
my ( $lefthash, $righthash ) = @_;
return $lefthash unless defined $righthash;
-
+
my %merged = %$lefthash;
for my $key ( keys %$righthash ) {
my $right_ref = ( ref $righthash->{ $key } || '' ) eq 'HASH';
$merged{ $key } = $righthash->{ $key };
}
}
-
+
return \%merged;
}
1) Install Term::Size::Any, or
- 2) Export $COLUMNS from your shell.
+ 2) Export $COLUMNS from your shell.
(Warning to bash users: 'echo $COLUMNS' may be showing you the bash
- variable, not $ENV{COLUMNS}. 'export COLUMNS=$COLUMNS' and you should see
+ variable, not $ENV{COLUMNS}. 'export COLUMNS=$COLUMNS' and you should see
that 'env' now lists COLUMNS.)
As last resort, default value of 80 chars will be used.
return $_term_width = $width;
}
+
+=head2 resolve_namespace
+
+Method which adds the namespace for plugins and actions.
+
+ __PACKAGE__->setup(qw(MyPlugin));
+
+ # will load Catalyst::Plugin::MyPlugin
+
+=cut
+
+
+sub resolve_namespace {
+ my $appnamespace = shift;
+ my $namespace = shift;
+ my @classes = @_;
+ return String::RewritePrefix->rewrite(
+ { '' => $namespace.'::', '+' => '', '~' => $appnamespace . '::' }, @classes,
+ );
+}
+
+
=head1 AUTHORS
Catalyst Contributors, see Catalyst.pm
=head1 COPYRIGHT
- This program is free software, you can redistribute it and/or modify it under
+ This library is free software. You can redistribute it and/or modify it under
the same terms as Perl itself.
=cut