[Jifty-commit] r1045 - in jifty/branches/jifty-jsan: . lib/Jifty/Script lib/Jifty/View/Static

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Sat May 13 16:41:17 EDT 2006


Author: trs
Date: Sat May 13 16:41:14 2006
New Revision: 1045

Added:
   jifty/branches/jifty-jsan/lib/Jifty/Script/Plugin.pm
Modified:
   jifty/branches/jifty-jsan/   (props changed)
   jifty/branches/jifty-jsan/lib/Jifty/Continuation.pm
   jifty/branches/jifty-jsan/lib/Jifty/Dispatcher.pm
   jifty/branches/jifty-jsan/lib/Jifty/Plugin.pm
   jifty/branches/jifty-jsan/lib/Jifty/Request.pm
   jifty/branches/jifty-jsan/lib/Jifty/View/Static/Handler.pm
   jifty/branches/jifty-jsan/lib/Jifty/Web.pm

Log:
 r12256 at zot (orig r1038):  alexmv | 2006-05-12 16:14:54 -0400
  r12966 at zoq-fot-pik:  chmrr | 2006-05-12 16:14:48 -0400
   * Remove confusing, undocumented, and unnecessary 'next_show'
 
 r12257 at zot (orig r1039):  alexmv | 2006-05-12 17:04:13 -0400
  r12968 at zoq-fot-pik:  chmrr | 2006-05-12 17:04:05 -0400
   * Plugin rule reodering
 
 r12258 at zot (orig r1040):  alexmv | 2006-05-12 18:09:20 -0400
  r12970 at zoq-fot-pik:  chmrr | 2006-05-12 18:09:12 -0400
   * jifty plugin --name Something
 
 r12266 at zot (orig r1043):  trs | 2006-05-13 16:33:10 -0400
  r12265 at zot:  tom | 2006-05-13 16:32:56 -0400
  Allow for MIME types to be overridden.  The included override is needed because Opera chokes with ajax-fetched JS otherwise.
 
 r12268 at zot (orig r1044):  trs | 2006-05-13 16:38:58 -0400
  r12267 at zot:  tom | 2006-05-13 16:38:53 -0400
  Put a note in a code
 


Modified: jifty/branches/jifty-jsan/lib/Jifty/Continuation.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Continuation.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Continuation.pm	Sat May 13 16:41:14 2006
@@ -214,13 +214,7 @@
         # Enter the request in the continuation, and handle it
         Jifty->web->request(Clone::clone($self->request));
         Jifty->web->handle_request();
-
-        # Now we want to skip the rest of the
-        # Jifty::Web->handle_request that we were called from.  Pop up
-        # to the dispatcher
-        Jifty::Dispatcher::next_show();
     }
-
 }
 
 =head2 delete

Modified: jifty/branches/jifty-jsan/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Dispatcher.pm	Sat May 13 16:41:14 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,10 +241,9 @@
 
 Redirect to another URI.
 
+=head2 plugin
 
-=head2 next_show
-
-INTERNAL MAGIC YOU SHOULD NOT USE THAT ALEX SHOULD RENAME ;)
+See L</Plugins and rule odering>, above.
 
 =cut
 
@@ -229,6 +256,8 @@
 
     GET POST PUT HEAD DELETE OPTIONS
 
+    plugin
+
     get next_rule last_rule
 
     already_run
@@ -263,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
@@ -284,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 != @_ ) {
@@ -328,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';
@@ -501,7 +534,6 @@
 
     die "LAST RULE"; 
 }
-sub next_show { last HANDLE_WEB }
 
 =head2 _do_under
 
@@ -698,7 +730,6 @@
     request->path($path);
     $self->render_template(request->path);
 
-
     last_rule;
 }
 
@@ -814,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";
@@ -844,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
@@ -971,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);
 }
 
 
@@ -1023,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/branches/jifty-jsan/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Plugin.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Plugin.pm	Sat May 13 16:41:14 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
 

Modified: jifty/branches/jifty-jsan/lib/Jifty/Request.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Request.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Request.pm	Sat May 13 16:41:14 2006
@@ -435,7 +435,9 @@
 =head2 call_continuation
 
 Calls the L<Jifty::Continuation> associated with this request, if
-there is one.
+there is one.  Returns true if the continuation was called
+successfully -- if calling the continuation requires a redirect, this
+function will throw an exception to its enclosing dispatcher.
 
 =cut
 
@@ -446,6 +448,7 @@
     $self->log->debug("Calling continuation $cont");
     $self->continuation(Jifty->web->session->get_continuation($cont));
     $self->continuation->call;
+    return 1;
 }
 
 =head2 path

Added: jifty/branches/jifty-jsan/lib/Jifty/Script/Plugin.pm
==============================================================================
--- (empty file)
+++ jifty/branches/jifty-jsan/lib/Jifty/Script/Plugin.pm	Sat May 13 16:41:14 2006
@@ -0,0 +1,149 @@
+use warnings;
+use strict;
+
+package Jifty::Script::Plugin;
+use base qw'App::CLI::Command Class::Accessor::Fast';
+
+use File::Copy;
+use Jifty::Config;
+use Jifty::YAML;
+use File::Basename;
+
+__PACKAGE__->mk_accessors(qw/prefix dist_name mod_name lib_dir/);
+
+
+=head1 NAME
+
+Jifty::Script::Plugin - Create the skeleton of a Jifty plugin
+
+=head1 DESCRIPTION
+
+Creates a skeleton of a new L<Jifty::Plugin>.
+
+=head2 options
+
+This script only takes one option, C<--name>, which is required; it is
+the name of the plugin to create; this will be prefixed with
+C<Jifty::Plugin::> automatically.  Jifty will create a directory with
+that name, and place all of the files it creates inside that
+directory.
+
+=cut
+
+sub options {
+    (
+     'n|name=s' => 'name',
+    )
+}
+
+=head2 run
+
+Create a directory for the application, a skeleton directory
+structure, and a C<Makefile.PL> for you application.
+
+=cut
+
+sub run {
+    my $self = shift;
+
+    $self->prefix( $self->{name} ||''); 
+
+    unless ($self->prefix =~ /\w+/ ) { die "You need to give your new Jifty app a --name"."\n";}
+    $self->prefix( $self->prefix );
+
+    # Turn my-plugin-name into My::Plugin::Name.
+    $self->mod_name ("Jifty::Plugin::" . join ("::", map { ucfirst } split (/\-/, $self->prefix)));
+    $self->dist_name("Jifty-Plugin-".$self->prefix);
+    $self->lib_dir(join("/",grep{$_} split '::', $self->mod_name));
+
+    print("Creating new plugin ".$self->mod_name."\n");
+    $self->_make_directories();
+    $self->_write_makefile();
+    $self->_write_default_files();
+}
+
+sub _write_makefile {
+    my $self = shift;
+    my $prefix = $self->prefix;
+    # Write a makefile
+    open(MAKEFILE, ">$prefix/Makefile.PL") or die "Can't write Makefile.PL: $!";
+    print MAKEFILE <<"EOT";
+use inc::Module::Install;
+name('@{[$self->dist_name]}');
+version('0.01');
+requires('Jifty' => '@{[$Jifty::VERSION]}');
+
+install_share;
+
+WriteAll;
+EOT
+    close MAKEFILE;
+} 
+
+sub _write_default_files {
+    my $self = shift;
+    my $mod_name = $self->mod_name;
+    my $prefix = $self->prefix;
+    my $lib = $self->lib_dir;
+    open(PLUGIN, ">$prefix/lib/$lib.pm") or die "Can't write $prefix/$lib.pm: $!";
+    print PLUGIN <<"EOT";
+use strict;
+use warnings;
+
+package $mod_name;
+use base qw/Jifty::Plugin/;
+
+# Your plugin goes here.  If takes any configuration or arguments, you
+# probably want to override L<Jifty::Plugin/init>.
+
+1;
+EOT
+    close PLUGIN;
+
+    open(DISPATCHER, ">$prefix/lib/$lib/Dispatcher.pm") or die "Can't write $prefix/lib/$lib/Dispatcher.pm: $!";
+    print DISPATCHER <<"EOT";
+use strict;
+use warnings;
+
+package @{[$mod_name]}::Dispatcher;
+use Jifty::Dispatcher -base;
+
+# Put any plugin-specific dispatcher rules here.
+
+EOT
+}
+
+sub _make_directories {
+    my $self = shift;
+
+    mkdir($self->prefix);
+    my @dirs = qw( lib );
+    my @dir_parts = split('/',$self->lib_dir);
+    push @dirs, join('/', 'lib', @dir_parts[0..$_]) for 0.. at dir_parts-1;
+
+    @dirs = (@dirs, $self->_directories); 
+
+    foreach my $dir (@dirs) {
+        $dir =~ s/__APP__/$self->lib_dir/e;
+        print("Creating directory $dir\n");
+        mkdir( $self->prefix."/$dir") or die "Can't create ". $self->prefix."/$dir: $!";
+    }
+}
+
+sub _directories {
+    return qw(
+        doc
+        share
+        share/po
+        share/web
+        share/web/templates
+        share/web/static
+        lib/__APP__/Model
+        lib/__APP__/Action
+        t
+    );
+}
+
+
+1;
+

Modified: jifty/branches/jifty-jsan/lib/Jifty/View/Static/Handler.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/View/Static/Handler.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/View/Static/Handler.pm	Sat May 13 16:41:14 2006
@@ -135,6 +135,17 @@
     my $self       = shift;
     my $local_path = shift;
 
+    # The key is the file extension, the value is the MIME type to send.
+    my %type_override = (
+        # MIME::Types returns application/javascript for .js, but Opera
+        # chokes on ajax-fetched JS that has a type other than the one below
+        # JSAN.js fetches JS via Ajax when it loads JSAN modules
+        'js' => 'application/x-javascript',
+    );
+
+    return ($type_override{$1})
+        if $local_path =~ /\.(.+)$/ and defined $type_override{$1};
+
     my $mimeobj   = $mime->mimeTypeOf($local_path);
     my $mime_type = (
           $mimeobj

Modified: jifty/branches/jifty-jsan/lib/Jifty/Web.pm
==============================================================================
--- jifty/branches/jifty-jsan/lib/Jifty/Web.pm	(original)
+++ jifty/branches/jifty-jsan/lib/Jifty/Web.pm	Sat May 13 16:41:14 2006
@@ -281,8 +281,8 @@
     }
     $self->session->set_cookie();
 
-    $self->request->call_continuation
-        if $self->response->success;
+    # If there's a continuation call, don't do the rest of this
+    return if $self->response->success and $self->request->call_continuation;
 
     $self->redirect if $self->redirect_required;
     $self->request->do_mapping;


More information about the Jifty-commit mailing list