X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=381a2506469a3907eb46090f3867dec810da13cb;hp=de2f188f2b930138b1abcfff7157d7b762f35781;hb=6323fda2e7ace0fc0aa06305c674957cedc6d025;hpb=cb69249ef4c0f2c88ec4361b46be37d473402153 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index de2f188..381a250 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -1,7 +1,9 @@ package Catalyst; -use strict; -use base 'Catalyst::Component'; +use Moose; +#use MooseX::ClassAttribute; +extends 'Catalyst::Component'; + use bytes; use Catalyst::Exception; use Catalyst::Log; @@ -30,9 +32,15 @@ use Carp qw/croak carp/; BEGIN { require 5.008001; } -__PACKAGE__->mk_accessors( - qw/counter request response state action stack namespace stats/ -); +has counter => ( is => 'rw'); +has request => ( is => 'rw'); +has response => ( is => 'rw'); +has state => ( is => 'rw'); +has action => ( is => 'rw'); +has stack => ( is => 'rw'); +has namespace => ( is => 'rw'); +has stats => ( is => 'rw'); + attributes->import( __PACKAGE__, \&namespace, 'lvalue' ); @@ -52,18 +60,33 @@ our $START = time; our $RECURSION = 1000; our $DETACH = "catalyst_detach\n"; +# class_has components => (is => 'rw'); +# class_has arguments => (is => 'rw'); +# class_has dispatcher => (is => 'rw'); +# class_has engine => (is => 'rw'); +# class_has log => (is => 'rw'); +# class_has dispatcher_class => (is => 'rw', required => 1, default => sub {'Catalyst::Dispatcher'}); +# class_has engine_class => (is => 'rw', required => 1, default => sub {'Catalyst::Engine::CGI'}); +# class_has context_class => (is => 'rw'); +# class_has request_class => (is => 'rw', required => 1, default => sub {'Catalyst::Request'}); +# class_has response_class => (is => 'rw', required => 1, default => sub {'Catalyst::Response'}); +# class_has stats_class => (is => 'rw', required => 1, default => sub {'Catalyst::Stats'}); +# class_has setup_finished => (is => 'rw'); + __PACKAGE__->mk_classdata($_) for qw/components arguments dispatcher engine log dispatcher_class - engine_class context_class request_class response_class setup_finished/; + engine_class context_class request_class response_class stats_class + setup_finished/; __PACKAGE__->dispatcher_class('Catalyst::Dispatcher'); __PACKAGE__->engine_class('Catalyst::Engine::CGI'); __PACKAGE__->request_class('Catalyst::Request'); __PACKAGE__->response_class('Catalyst::Response'); +__PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.7008'; +our $VERSION = '5.7013'; sub import { my ( $class, @arguments ) = @_; @@ -77,6 +100,9 @@ sub import { unless ( $caller->isa('Catalyst') ) { no strict 'refs'; push @{"$caller\::ISA"}, $class, 'Catalyst::Controller'; + #my $caller_meta = $caller->meta; + #my @isa = $caller_meta->superclasses; + #$caller_meta->superclasses(@isa, $class, 'Catalyst::Controller'); } $caller->arguments( [@arguments] ); @@ -110,30 +136,30 @@ documentation and tutorials. ### in lib/MyApp.pm use Catalyst qw/-Debug/; # include plugins here as well - - ### In lib/MyApp/Controller/Root.pm (autocreated) + + ### In lib/MyApp/Controller/Root.pm (autocreated) sub foo : Global { # called for /foo, /foo/1, /foo/1/2, etc. my ( $self, $c, @args ) = @_; # args are qw/1 2/ for /foo/1/2 $c->stash->{template} = 'foo.tt'; # set the template # lookup something from db -- stash vars are passed to TT - $c->stash->{data} = + $c->stash->{data} = $c->model('Database::Foo')->search( { country => $args[0] } ); if ( $c->req->params->{bar} ) { # access GET or POST parameters $c->forward( 'bar' ); # process another action - # do something else after forward returns + # do something else after forward returns } } - + # The foo.tt TT template can use the stash data from the database [% WHILE (item = data.next) %] [% item.foo %] [% END %] - + # called for /bar/of/soap, /bar/of/soap/10, etc. sub bar : Path('/bar/of/soap') { ... } # called for all actions, from the top-most controller downwards - sub auto : Private { + sub auto : Private { my ( $self, $c ) = @_; if ( !$c->user_exists ) { # Catalyst::Plugin::Authentication $c->res->redirect( '/login' ); # require login @@ -141,9 +167,9 @@ documentation and tutorials. } return 1; # success; carry on to next action } - + # called after all actions are finished - sub end : Private { + sub end : Private { my ( $self, $c ) = @_; if ( scalar @{ $c->error } ) { ... } # handle errors return if $c->res->body; # already have a response @@ -153,20 +179,20 @@ documentation and tutorials. ### in MyApp/Controller/Foo.pm # called for /foo/bar sub bar : Local { ... } - + # called for /blargle sub blargle : Global { ... } - + # an index action matches /foo, but not /foo/1, etc. sub index : Private { ... } - + ### in MyApp/Controller/Foo/Bar.pm # called for /foo/bar/baz sub baz : Local { ... } - + # first Root auto is called, then Foo auto, then this sub auto : Private { ... } - + # powerful regular expression paths are also possible sub details : Regex('^product/(\w+)/details$') { my ( $self, $c ) = @_; @@ -240,6 +266,17 @@ MYAPP_WEB_HOME. If both variables are set, the MYAPP_HOME one will be used. Specifies log level. +=head2 -Stats + +Enables statistics collection and reporting. You can also force this setting +from the system environment with CATALYST_STATS or _STATS. The +environment settings override the application, with _STATS having the +highest priority. + +e.g. + + use Catalyst qw/-Stats=1/ + =head1 METHODS =head2 INFORMATION ABOUT THE CURRENT REQUEST @@ -307,8 +344,8 @@ sub forward { my $c = shift; $c->dispatcher->forward( $c, @_ ) } =head2 $c->detach() -The same as C, but doesn't return to the previous action when -processing is finished. +The same as C, but doesn't return to the previous action when +processing is finished. When called with no arguments it escapes the processing chain entirely. @@ -335,7 +372,7 @@ Catalyst). $c->stash->{foo} = $bar; $c->stash( { moose => 'majestic', qux => 0 } ); $c->stash( bar => 1, gorch => 2 ); # equivalent to passing a hashref - + # stash is automatically passed to the view for use in a template $c->forward( 'MyApp::View::TT' ); @@ -345,7 +382,7 @@ sub stash { my $c = shift; if (@_) { my $stash = @_ > 1 ? {@_} : $_[0]; - croak('stash takes a hash or hashref') unless ref $stash; + croak('stash takes a hash or hashref') unless ref $stash; foreach my $key ( keys %$stash ) { $c->{stash}->{$key} = $stash->{$key}; } @@ -443,7 +480,7 @@ sub _comp_prefixes { return $comp; } -# Find possible names for a prefix +# Find possible names for a prefix sub _comp_names { my ( $c, @prefixes ) = @_; @@ -515,7 +552,7 @@ Gets a L instance by name. Any extra arguments are directly passed to ACCEPT_CONTEXT. -If the name is omitted, it will look for +If the name is omitted, it will look for - a model object in $c->stash{current_model_instance}, then - a model name in $c->stash->{current_model}, then - a config setting 'default_model', or @@ -529,7 +566,7 @@ sub model { @args ) if $name; if (ref $c) { - return $c->stash->{current_model_instance} + return $c->stash->{current_model_instance} if $c->stash->{current_model_instance}; return $c->model( $c->stash->{current_model} ) if $c->stash->{current_model}; @@ -560,7 +597,7 @@ Gets a L instance by name. Any extra arguments are directly passed to ACCEPT_CONTEXT. -If the name is omitted, it will look for +If the name is omitted, it will look for - a view object in $c->stash{current_view_instance}, then - a view name in $c->stash->{current_view}, then - a config setting 'default_view', or @@ -574,7 +611,7 @@ sub view { @args ) if $name; if (ref $c) { - return $c->stash->{current_view_instance} + return $c->stash->{current_view_instance} if $c->stash->{current_view_instance}; return $c->view( $c->stash->{current_view} ) if $c->stash->{current_view}; @@ -663,14 +700,15 @@ L. =cut -sub config { +around config => sub { + my $orig = shift; my $c = shift; $c->log->warn("Setting config after setup has been run is not a good idea.") if ( @_ and $c->setup_finished ); - $c->NEXT::config(@_); -} + $c->$orig(@_); +}; =head2 $c->log @@ -748,6 +786,7 @@ sub plugin { $class->_register_plugin( $plugin, 1 ); eval { $plugin->import }; + #MooseX::ClassAttribute::process_class_attribute($class, $name => (is => 'rw')); $class->mk_classdata($name); my $obj; eval { $obj = $plugin->new(@args) }; @@ -813,6 +852,7 @@ sub setup { $class->setup_plugins( delete $flags->{plugins} ); $class->setup_dispatcher( delete $flags->{dispatcher} ); $class->setup_engine( delete $flags->{engine} ); + $class->setup_stats( delete $flags->{stats} ); for my $flag ( sort keys %{$flags} ) { @@ -837,7 +877,7 @@ You are running an old script! EOF } - + if ( $class->debug ) { my @plugins = map { "$_ " . ( $_->VERSION || '' ) } $class->registered_plugins; @@ -906,6 +946,9 @@ If the last argument to C is a hash reference, it is assumed to contain GET parameter key/value pairs, which will be appended to the URI in standard fashion. +Note that uri_for is destructive to the passed hashref. Subsequent calls +with the same hashref may have unintended results. + Instead of C<$path>, you can also optionally pass a C<$action> object which will be resolved to a path using C<< $c->dispatcher->uri_for_action >>; if the first element of @@ -943,7 +986,7 @@ sub uri_for { } unshift(@args, $namespace || ''); } - + # join args with '/', or a blank string my $args = join('/', grep { defined($_) } @args); $args =~ s/\?/%3F/g; # STUPID STUPID SPECIAL CASE @@ -964,7 +1007,7 @@ sub uri_for { $val = '' unless defined $val; (map { $_ = "$_"; - utf8::encode( $_ ); + 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/ /+/g; @@ -993,8 +1036,8 @@ sub welcome_message { "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> - - + + $name on Catalyst $VERSION