refactor component injection 5.90089_003
John Napiorkowski [Mon, 27 Apr 2015 20:11:56 +0000 (15:11 -0500)]
Changes
lib/Catalyst.pm
lib/Catalyst/Contributing.pod [new file with mode: 0644]
lib/Catalyst/DispatchType/Chained.pm

diff --git a/Changes b/Changes
index a9daad4..2655f99 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,8 +1,11 @@
 # This file documents the revision history for Perl extension Catalyst.
 
-5.90089_003 - TBA
+5.90089_003 - 2015-04-27
   - Fixed an issue where a delayed controller that did ACCEPT_CONTEXT would
     raise an error when registering its actions.
+  - Updated some documentation around route matching.
+  - refactored the setup of injected components to allow you to hook into
+    the injection and do custom injection types.
 
 5.90089_002 - 2015-04-17
   - Changed the way we check for presence of Type::Tiny in a test case to be
@@ -44,7 +47,7 @@
     report any stats related issues.
   - Added a developer mode warning if you call a component with arguments that does not
     expect arguments (for example calling $c->model('Foo', 1,2,3,4) where Myapp::Model::Foo
-    does not ACCEPT_CONTEXT.   Only components that ACCEPT_CONTEXT do anything with
+    does not ACCEPT_CONTEXT.  Only components that ACCEPT_CONTEXT do anything with
     passed arguments in $c->controller/view/model.
   - Change the way components are setup so that you can now rely on all components
     when setting up a component.  Previously application scoped components could not
index b0e0129..fc278fb 100644 (file)
@@ -715,20 +715,15 @@ sub _comp_names {
 
 # Filter a component before returning by calling ACCEPT_CONTEXT if available
 
-#our %tracker = ();
 sub _filter_component {
     my ( $c, $comp, @args ) = @_;
 
-    # die "Circular Dependencies Detected." if $tracker{$comp};
-    #   $tracker{$comp}++;
     if(ref $comp eq 'CODE') {
       $comp = $comp->();
     }
-    #$tracker{$comp}++;
 
     if ( eval { $comp->can('ACCEPT_CONTEXT'); } ) {
-        die "Component '${\$comp->catalyst_component_name}' does ACCEPT_CONTEXT but I am in application scope" unless blessed $c;
-        return $comp->ACCEPT_CONTEXT( $c, @args );
+      return $comp->ACCEPT_CONTEXT( $c, @args );
     }
 
     $c->log->warn("You called component '${\$comp->catalyst_component_name}' with arguments [@args], but this component does not ACCEPT_CONTEXT, so args are ignored.") if scalar(@args) && $c->debug;
@@ -2855,25 +2850,49 @@ sub setup_components {
     # of named components in the configuration that are not actually existing (not a
     # real file).
 
+    my @injected_components = $class->setup_injected_components;
+
+    # All components are registered, now we need to 'init' them.
+    foreach my $component_name (@comps, @injected_components) {
+      $class->components->{$component_name} = $class->components->{$component_name}->() if
+        (ref($class->components->{$component_name}) || '') eq 'CODE';
+    }
+}
+
+=head2 $app->setup_injected_components
+
+Called by setup_compoents to setup components that are injected.
+
+=cut
+
+sub setup_injected_components {
+    my ($class) = @_;
     my @injected_components = keys %{$class->config->{inject_components} ||+{}};
+
     foreach my $injected_comp_name(@injected_components) {
-      my $component_class = $class->config->{inject_components}->{$injected_comp_name}->{from_component} || '';
-      if($component_class) {
-        my @roles = @{$class->config->{inject_components}->{$injected_comp_name}->{roles} ||[]};
-        my %args = %{ $class->config->{$injected_comp_name} || +{} };
+        $class->setup_injected_component(
+          $injected_comp_name,
+          $class->config->{inject_components}->{$injected_comp_name});
+    }
+
+    return @injected_components;
+}
+
+=head2 $app->setup_injected_component( $injected_component_name, $config )
+
+Setup a given injected component.
+
+=cut
 
+sub setup_injected_component {
+    my ($class, $injected_comp_name, $config) = @_;
+    if(my $component_class = $config->{from_component}) {
+        my @roles = @{$config->{roles} ||[]};
         Catalyst::Utils::inject_component(
           into => $class,
           component => $component_class,
           (scalar(@roles) ? (traits => \@roles) : ()),
           as => $injected_comp_name);
-      }
-    }
-
-    # All components are registered, now we need to 'init' them.
-    foreach my $component_name (@comps, @injected_components) {
-      $class->components->{$component_name} = $class->components->{$component_name}->() if
-        (ref($class->components->{$component_name}) || '') eq 'CODE';
     }
 }
 
diff --git a/lib/Catalyst/Contributing.pod b/lib/Catalyst/Contributing.pod
new file mode 100644 (file)
index 0000000..7faa66c
--- /dev/null
@@ -0,0 +1,41 @@
+=encoding UTF-8
+
+=head1 Name
+
+Catalyst::Contributing - Contributing to Catalyst and Change managment
+
+=head1 Description
+
+How to contribute to L<Catalyst> and what are the criteria for evaluating change and
+deciding on the future direction of the project.
+
+=head2 Change Management
+
+In general there are two rules when thinking about changing Catalyst. The first is technical merit of the idea. If there is a bug, then its obvious it needs to be fixed. Less obvious is the types of refactoring that went into giving Catalyst modern features like websocket support, interoperability with event loops and to expose more and more of Catalyst's PSGI underpinnings.
+
+When an idea has strong technical merit, it recommends itself. The only thing to consider is the needs of backward compatibility, and to offer people upgrading at least some sort of path forward when features change (such as to have plugins or configuration options to replace or replicate something that is no longer available).
+
+Then there is a second and more difficult type of change consideration, which is the general will of the community. Like technical merit, this needs to balance against our commitment to not leave existing users high and dry with changes that break code and offer no path forward that does not involve significant code rewrites. Unlike technical merit, the will of the community can be hard to figure. In general we don't get a lot of bug reports or conversation around Catalyst future evolution. I wish I could find a way to get more involvement, but I also understand this is not very unusual issue for open source projects. I personally don't believe that "silence is consent" either. I think choices need to have broad acceptability or the choosers lose respect and authority. Typical that results in people just drifting away.
+
+Without direct involvement the only other way to measure the will of the community is to look at what other choices people are making and what other projects have received the acceptance of a broad number of people. Since Plack is clearly accepted and important it leads me to feel the choice to make Catalyst expose more of its Plack nature and to better play with the larger Plack ecosystem are correct ones. One can also pay attention to the kinds of problems that get reported on IRC, at conferences and the problems that I see having looked at how Catalyst has been used in the wild. For example its clear that Chaining actions could use a tweak in some way since it seems to trip up people a lot. The same goes with $c->forward and $c->go, which tend to lead to confusing code (and combined with the stash is a particularly toxic brew).
+
+Going further, if we allow ourselves to look hard at projects outside of Perl we can get lots of great ideas about what has worked for other projects in other languages. When we see certain features and approaches have excited programmers using frameworks like Ruby on Rails, Django, Scala Play, etc. then it should provide us with with help in thinking about how those features might influence the evolution of Catalyst as well.
+
+=head2 Reporting a bug
+
+Reported bugs via RT or Github Issues that come with attached test cases will be more likely addressed quickly than those that do not.  Proposing a bugfix patch is also alwaysvery welcomed, although it is recommended to stick as closely as possible to an actual bug (rather than a feature change) and to not include unneeded changes in your patch such as formatting corrections.  In any case it is recommended before spending a lot of time on a patch to discuss the issue and your proposed solution, else you risk spending a lot of time on code that may not get merged, which tends to be frustrating.
+
+For bug patches you should create a new branch from the current master.
+
+=head2 Proposing a new feature
+
+You should first ask yourself if your new idea could rationally live in the extended Catalyst ecosystem independently on CPAN.  Ideas that have demonstrated worth over time as stand alone modules are more likely to be considered for core inclusion.  Additionally, ideas that are best achieved in core rather than as standalone, are more likely considered for core inclusion than those ideas which could just as well be stand alone.  For example, the PSGI integration project happened because it was clear that building Catalyst on top of PSGI standards would lead to a better overall version than keeping it stand alone.
+
+You should propose your new idea in a github issue, on IRC and ideally on the mailing list so that other people can comment on your idea and its merits prior to you writing code.  If you write code before proposing the idea you stand a high chance of being frustrated when you idea is not accepted.
+
+=head2 AUTHOR
+
+John Napiorkowski L<jjnapiork@cpan.org|email:jjnapiork@cpan.org>
+
+=cut
+
index 2ac8c0c..b74c29d 100644 (file)
@@ -289,8 +289,6 @@ sub recurse_match {
             else {
                 {
                     local $c->req->{arguments} = [ @{$c->req->args}, @parts ];
-warn $action;
-
                     next TRY_ACTION unless $action->match($c);
                 }
                 my $args_attr = $action->attributes->{Args}->[0];