[Jifty-commit] r1039 - in jifty/trunk: lib/Jifty

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Fri May 12 17:04:15 EDT 2006


Author: alexmv
Date: Fri May 12 17:04:13 2006
New Revision: 1039

Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/lib/Jifty/Dispatcher.pm
   jifty/trunk/lib/Jifty/Plugin.pm

Log:
 r12968 at zoq-fot-pik:  chmrr | 2006-05-12 17:04:05 -0400
  * Plugin rule reodering


Modified: jifty/trunk/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/trunk/lib/Jifty/Dispatcher.pm	Fri May 12 17:04:13 2006
@@ -104,6 +104,34 @@
 
 =cut
 
+=head1 Plugins and rule ordering
+
+By default, L<Jifty::Plugin> dispatcher rules are added in the order
+they are specified in the application's configuration file; that is,
+after all the plugin dispatchers have run in order, then tha
+application's dispatcher runs.  It is possible to specify rules which
+should be reordered with respect to this rule, however.  This us done
+by using a variant on the C<before> and C<after> syntax:
+
+    before plugin NAME =>
+        RULE(S);
+    
+    after plugin NAME =>
+        RULE(S);
+
+C<NAME> may either be a string, which must match the plugin name
+exactly, or a regular expression, which is matched against the plugin
+name.  The rule will be placed at the first boundry that it matches --
+that is, given a C<before plugin qr/^Jifty::Plugin::Auth::/> and both
+a C<Jifty::Plugin::Auth::Basic> and a C<Jifty::Plugin::Auth::Complex>,
+the rules will be placed before the first.
+
+C<RULES> may wither be a single C<before>, C<on>, C<under>, or
+C<after> rule to change the ordering of, or an array reference of
+rules to reorder.
+
+=cut
+
 =head1 Data your dispatch routines has access to
 
 =head2 request
@@ -213,6 +241,10 @@
 
 Redirect to another URI.
 
+=head2 plugin
+
+See L</Plugins and rule odering>, above.
+
 =cut
 
 our @EXPORT = qw<
@@ -224,6 +256,8 @@
 
     GET POST PUT HEAD DELETE OPTIONS
 
+    plugin
+
     get next_rule last_rule
 
     already_run
@@ -258,6 +292,8 @@
 sub DELETE ($)  { _qualify method => @_ }
 sub OPTIONS ($) { _qualify method => @_ }
 
+sub plugin ($) { return { plugin => @_ } }
+
 =head2 import
 
 Jifty::Dispatcher is an L<Exporter>, that is, part of its role is to
@@ -279,7 +315,7 @@
 
     no strict 'refs';
     no warnings 'once';
-    for (qw(RULES_RUN RULES_SETUP RULES_CLEANUP)) {
+    for (qw(RULES_RUN RULES_SETUP RULES_CLEANUP RULES_DEFERRED)) {
         @{ $pkg . '::' . $_ } = ();
     }
     if ( @args != @_ ) {
@@ -323,7 +359,9 @@
     my($pkg, $rule) = @_;
     my $op = $rule->[0];
     my $ruleset;
-    if ( $op eq 'before' ) {
+    if ( ($op eq "before" or $op eq "after") and ref $rule->[1] and $rule->[1]{plugin} ) {
+        $ruleset = 'RULES_DEFERRED';
+    } elsif ( $op eq 'before' ) {
         $ruleset = 'RULES_SETUP';
     } elsif ( $op eq 'after' ) {
         $ruleset = 'RULES_CLEANUP';
@@ -807,7 +845,10 @@
             }
 
             # All precondition passed, get original condition literal
-            return $self->_match( $cond->{''} );
+            return $self->_match( $cond->{''} ) if $cond->{''};
+
+            # Or, if we don't have a literal, we win.
+            return 1;
         };
         if ( my $err = $@ ) {
             warn "$self _match failed: $err";
@@ -837,6 +878,12 @@
     lc( $self->{cgi}->method ) eq lc($method);
 }
 
+sub _match_plugin {
+    my ( $self, $plugin ) = @_;
+    warn "Deferred check shouldn't happen";
+    return 0;
+}
+
 =head2 _compile_condition CONDITION
 
 Takes a condition defined as a simple string ad return it as a regex
@@ -964,8 +1011,7 @@
     my $self = shift;
     my $template = shift;
 
-      return  Jifty->handler->mason->interp->comp_exists( $template);
-
+    return  Jifty->handler->mason->interp->comp_exists( $template);
 }
 
 
@@ -1016,14 +1062,78 @@
 
 sub import_plugins {
     my $self = shift;
+
+    # Find the deferred rules
+    my @deferred;
+    push @deferred, $_->dispatcher->rules('DEFERRED') for Jifty->plugins;
+    push @deferred, $self->rules('DEFERRED');
+
+    # XXX TODO: Examine @deferred and find rles that cannot fire
+    # because they match no plugins; they should become un-deferred in
+    # the appropriate group.  This is so 'before plugin qr/Auth/' runs
+    # even if we have no auth plugin
+
     for my $stage (qw/SETUP RUN CLEANUP/) {
+        my @groups;
+        push @groups, {name => ref $_,  rules => [$_->dispatcher->rules($stage)]} for Jifty->plugins;
+        push @groups, {name => 'Jifty', rules => [$self->rules($stage)]};
+
+        my @left;
         my @rules;
-        push @rules, $_->dispatcher->rules($stage) for Jifty->plugins;
-        push @rules, $self->rules($stage);
+        for (@groups) {
+            my $name        = $_->{name};
+            my @group_rules = @{$_->{rules}};
+
+            # XXX TODO: 'after' rules should possibly be placed after
+            # the *last* thing they could match
+            push @rules, $self->_match_deferred(\@deferred, before => $name, $stage);
+            push @rules, @group_rules;
+            push @rules, $self->_match_deferred(\@deferred, after => $name, $stage);
+        }
 
         no strict 'refs';
         @{ $self . "::RULES_$stage" } = @rules;
     }
+    if (@deferred) {
+        warn "Leftover unmatched deferred rules: ".YAML::Dump(\@deferred);
+    }
+}
+
+sub _match_deferred {
+    my $self = shift;
+    my ($deferred, $time, $name, $stage) = @_;
+    my %stages = (SETUP => "before", RUN => "on", CLEANUP => "after");
+    $stage = $stages{$stage};
+
+    my @matches;
+    for my $op (@{$deferred}) {
+        # Only care if we're on the correct side of the correct plugin
+        next unless $op->[0] eq $time;
+
+        # Regex or string match, appropriately
+        next unless (
+            ref $op->[1]{plugin}
+            ? ( $name =~ $op->[1]{plugin} )
+            : ( $op->[1]{plugin} eq $name ) );
+
+        # Find the list of subrules
+        my @subrules = ref $op->[2] eq "ARRAY" ? @{$op->[2]} : ($op->[2]);
+
+        # Only toplevel rules make sense (before, after, on)
+        warn "Invalid subrule ".$_->[0] for grep {$_->[0] !~ /^(before|on|after)$/} @subrules;
+        @subrules = grep {$_->[0] =~ /^(before|on|after)$/} @subrules;
+
+        # Only match if the stage matches
+        push @matches, grep {$_->[0] eq $stage} @subrules;
+        @subrules = grep {$_->[0] ne $stage} @subrules;
+
+        $op->[2] = [@subrules];
+    }
+
+    # Clean out any completely matched rules
+    @$deferred = grep {@{$_->[2]}} @$deferred;
+
+    return @matches;
 }
 
 1;

Modified: jifty/trunk/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Plugin.pm	(original)
+++ jifty/trunk/lib/Jifty/Plugin.pm	Fri May 12 17:04:13 2006
@@ -11,7 +11,25 @@
 
 Plugins are like mini-apps.  They come in packages with share
 directories which provide static and template files; they provide
-actions; they have dispatcher rules.  
+actions; they have dispatcher rules.
+
+To use a plugin in your Jifty application, find the C<Plugins:> line
+in the C<config.yml> file:
+
+      Plugins:
+        - SpiffyThing: {}
+        - SomePlugin:
+            arguments: to
+            the: constructor
+
+The dispatcher for a plugin should live in
+C<Jifty::Plugin::I<name>::Disptcher>; it is written like any other
+L<Jifty::Dispatcher>.  Plugin dispatcher rules are checked before the
+application's rules; however, see L<Jifty::Dispatcher/Plugins and rule
+ordering> for how to manually specify exceptions to this.
+
+Actions and models under a plugin's namespace are automatically
+discovered and made available to applications.
 
 =cut
 


More information about the Jifty-commit mailing list