[Jifty-commit] r1034 - in jifty/trunk: . lib lib/Jifty lib/Jifty/Action/Devel lib/Jifty/View/Mason lib/Jifty/View/Static plugins plugins/EditInPlace plugins/EditInPlace/lib plugins/EditInPlace/lib/Jifty plugins/EditInPlace/lib/Jifty/Plugin plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace plugins/EditInPlace/share plugins/EditInPlace/share/web plugins/EditInPlace/share/web/templates plugins/EditInPlace/share/web/templates/__jifty share/web/templates/__jifty share/web/templates/__jifty/error t

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Thu May 11 15:11:53 EDT 2006


Author: alexmv
Date: Thu May 11 15:11:18 2006
New Revision: 1034

Added:
   jifty/trunk/lib/Jifty/Plugin.pm
   jifty/trunk/plugins/
   jifty/trunk/plugins/EditInPlace/
   jifty/trunk/plugins/EditInPlace/META.yml
   jifty/trunk/plugins/EditInPlace/Makefile.PL
   jifty/trunk/plugins/EditInPlace/lib/
   jifty/trunk/plugins/EditInPlace/lib/Jifty/
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace.pm
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Action/
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Action/FileEditor.pm
   jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Dispatcher.pm
   jifty/trunk/plugins/EditInPlace/share/
   jifty/trunk/plugins/EditInPlace/share/web/
   jifty/trunk/plugins/EditInPlace/share/web/templates/
   jifty/trunk/plugins/EditInPlace/share/web/templates/__jifty/
   jifty/trunk/plugins/EditInPlace/share/web/templates/__jifty/edit_file
   jifty/trunk/share/web/templates/__jifty/error/autohandler
Removed:
   jifty/trunk/lib/Jifty/Action/Devel/FileEditor.pm
   jifty/trunk/share/web/templates/__jifty/edit_file
Modified:
   jifty/trunk/   (props changed)
   jifty/trunk/Changelog
   jifty/trunk/MANIFEST
   jifty/trunk/lib/Jifty.pm
   jifty/trunk/lib/Jifty/API.pm
   jifty/trunk/lib/Jifty/ClassLoader.pm
   jifty/trunk/lib/Jifty/Config.pm
   jifty/trunk/lib/Jifty/Dispatcher.pm
   jifty/trunk/lib/Jifty/Handler.pm
   jifty/trunk/lib/Jifty/LetMe.pm
   jifty/trunk/lib/Jifty/View/Mason/Handler.pm
   jifty/trunk/lib/Jifty/View/Static/Handler.pm
   jifty/trunk/lib/Jifty/Web.pm
   jifty/trunk/t/07-limit-actions.t

Log:
 r12958 at zoq-fot-pik:  chmrr | 2006-05-11 15:07:39 -0400
  * First pass at a plugin archetecture
 
  * This also include some reworking of the ClassLoader, including
    removing the ActionBaseClass and CurrentUserPath config settings,
    which breaks backwards compatibility!  If you were using these,
    please let us know your use case.
 


Modified: jifty/trunk/Changelog
==============================================================================
--- jifty/trunk/Changelog	(original)
+++ jifty/trunk/Changelog	Thu May 11 15:11:18 2006
@@ -1,20 +1,25 @@
-0.60507 (7 May 2006)
+  * Removed the ActionBasePath and CurrentUserClass configuration
+    variables.  This breaks backwards compatibility.
 
-* Pod fixes from Eric Wilhelm
-  lib/Jifty/Object.pm - removed incorrect '=for' directive
-  lib/Jifty/Web/Form/Field.pm - removed incorrect '=for' directive
-  lib/Jifty/Web/Form.pm - removed incorrect '=for' directive
-  
-
-* Better failure messages on when schema upgrades with SQLite fail from Alex Vandiver
-   * Be a little more explicit about SQLite's limitation, and a possible
-     (painful) workaround
- 
-* Update the inc tree to 0.62 for various fixes,
-   in particular improved share_dir compatibility. --Audrey Tang
+0.60507 (7 May 2006)
 
-* We were inconsistently using Jifty::Util::make_path as a subroutine. It's a class method.
-  This could break the stub generators and tutorial.  Thanks to Sean E. Millichamp
+  * Pod fixes from Eric Wilhelm
+    lib/Jifty/Object.pm - removed incorrect '=for' directive
+    lib/Jifty/Web/Form/Field.pm - removed incorrect '=for' directive
+    lib/Jifty/Web/Form.pm - removed incorrect '=for' directive
+
+  * Better failure messages on when schema upgrades with SQLite fail
+    from Alex Vandiver
+
+  * Be a little more explicit about SQLite's limitation, and a possible
+    (painful) workaround
+
+  * Update the inc tree to 0.62 for various fixes,
+    in particular improved share_dir compatibility. --Audrey Tang
+
+  * We were inconsistently using Jifty::Util::make_path as a
+    subroutine. It's a class method.  This could break the stub
+    generators and tutorial.  Thanks to Sean E. Millichamp
 
 0.60505 - Cinco de Jifty! (5 May 2006)
 

Modified: jifty/trunk/MANIFEST
==============================================================================
--- jifty/trunk/MANIFEST	(original)
+++ jifty/trunk/MANIFEST	Thu May 11 15:11:18 2006
@@ -44,7 +44,6 @@
 lib/Jifty.pm
 lib/Jifty/Action.pm
 lib/Jifty/Action/Autocomplete.pm
-lib/Jifty/Action/Devel/FileEditor.pm
 lib/Jifty/Action/Record.pm
 lib/Jifty/Action/Record/Create.pm
 lib/Jifty/Action/Record/Delete.pm
@@ -200,7 +199,6 @@
 share/web/templates/__jifty/admin/index.html
 share/web/templates/__jifty/admin/model/dhandler
 share/web/templates/__jifty/autocomplete.xml
-share/web/templates/__jifty/edit_file
 share/web/templates/__jifty/error/_elements/error_text
 share/web/templates/__jifty/error/_elements/wrapper
 share/web/templates/__jifty/error/dhandler

Modified: jifty/trunk/lib/Jifty.pm
==============================================================================
--- jifty/trunk/lib/Jifty.pm	(original)
+++ jifty/trunk/lib/Jifty.pm	Thu May 11 15:11:18 2006
@@ -62,7 +62,7 @@
 use base qw/Jifty::Object/;
 use Jifty::Everything;
 
-use vars qw/$HANDLE $CONFIG $LOGGER $HANDLER $API/;
+use vars qw/$HANDLE $CONFIG $LOGGER $HANDLER $API @PLUGINS/;
 
 =head1 METHODS
 
@@ -117,7 +117,17 @@
 
     __PACKAGE__->logger( Jifty::Logger->new( $args{'logger_component'} ) );
     # Get a classloader set up
-    Jifty::ClassLoader->new->require;
+    Jifty::ClassLoader->new(base => Jifty->config->framework('ApplicationClass'))->require;
+
+    # Set up plugins
+    my @plugins;
+    for my $plugin (@{Jifty->config->framework('Plugins')}) {
+        my $class = "Jifty::Plugin::".(keys %{$plugin})[0];
+        my %options = %{ $plugin->{(keys %{$plugin})[0]} };
+        Jifty::Util->require($class);
+        push @plugins, $class->new(%options);
+    }
+    __PACKAGE__->plugins(@plugins);
 
     __PACKAGE__->handler(Jifty::Handler->new());
     __PACKAGE__->api(Jifty::API->new());
@@ -204,6 +214,17 @@
     return $HTML::Mason::Commands::JiftyWeb;
 }
 
+=head2 plugins
+
+Returns a list of L<Jifty::Plugin> objects for this Jifty application.
+
+=cut
+
+sub plugins {
+    my $class = shift;
+    @PLUGINS = @_ if @_;
+    return @PLUGINS;
+}
 
 =head2 setup_database_connection
 

Modified: jifty/trunk/lib/Jifty/API.pm
==============================================================================
--- jifty/trunk/lib/Jifty/API.pm	(original)
+++ jifty/trunk/lib/Jifty/API.pm	Thu May 11 15:11:18 2006
@@ -33,9 +33,9 @@
 
     Module::Pluggable->import(
         search_path => [
-            Jifty->config->framework('ActionBasePath'),
             Jifty->config->framework('ApplicationClass') . "::Action",
-            "Jifty::Action"
+            "Jifty::Action",
+            map {ref($_)."::Action"} Jifty->plugins,
         ],
         sub_name => "_actions",
     );
@@ -46,9 +46,9 @@
 =head2 qualify ACTIONNAME
 
 Returns the fully qualified package name for the given provided
-action.  If the C<ACTIONNAME> starts with C<Jifty::Action> or your
-application's C<ActionBasePath>, simply returns the given name;
-otherwise, it prefixes it with the C<ActionBasePath>.
+action.  If the C<ACTIONNAME> starts with C<Jifty::> or
+C<ApplicationClass>::Action, simply returns the given name; otherwise,
+it prefixes it with the C<ApplicationClass>::Action.
 
 =cut
 
@@ -56,10 +56,10 @@
     my $self   = shift;
     my $action = shift;
 
-    my $base_path = Jifty->config->framework('ActionBasePath');
+    my $base_path = Jifty->config->framework('ApplicationClass') . "::Action";
 
     return $action
-        if $action =~ /^Jifty::Action/
+        if $action =~ /^Jifty::/
         or $action =~ /^\Q$base_path\E/;
 
     return $base_path . "::" . $action;
@@ -67,11 +67,10 @@
 
 =head2 reset
 
-Resets which actions are allowed to the defaults; that is, all actions
-from the application's C<ActionBasePath>, and
-L<Jifty::Action::Autocomplete> and L<Jifty::Action::Redirect> are
-allowed; everything else is denied.  See L</restrict> for the details
-of how limits are processed.
+Resets which actions are allowed to the defaults; that is, all of the
+application's actions, L<Jifty::Action::Autocomplete>, and
+L<Jifty::Action::Redirect> are allowed; everything else is denied.
+See L</restrict> for the details of how limits are processed.
 
 =cut
 
@@ -79,7 +78,7 @@
     my $self = shift;
 
     # Set up defaults
-    my $app_actions = Jifty->config->framework('ActionBasePath');
+    my $app_actions = Jifty->config->framework('ApplicationClass') . "::Action";
 
     $self->action_limits(
         [   { deny => 1, restriction => qr/.*/ },
@@ -176,10 +175,9 @@
 
 =head2 is_allowed CLASS
 
-Returns false if the I<CLASS> name (which is fully qualified with the
-application's ActionBasePath if it is not already) is allowed to be
-executed.  See L</restrict> above for the rules that the class
-name must pass.
+Returns false if the I<CLASS> name (which is fully qualified if it is
+not already) is allowed to be executed.  See L</restrict> above for
+the rules that the class name must pass.
 
 =cut
 
@@ -215,8 +213,7 @@
 
 Lists the class names of all of the allowed actions for this Jifty
 application; this may include actions under the C<Jifty::Action::>
-namespace, in addition to actions under your application's
-C<ActionBasePath>.
+namespace, in addition to your application's actions.
 
 =cut
 

Modified: jifty/trunk/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/trunk/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/trunk/lib/Jifty/ClassLoader.pm	Thu May 11 15:11:18 2006
@@ -19,11 +19,15 @@
 C<@INC> that allows L<Jifty::ClassLoader> to dynamically create needed
 classes if they do not exist already.
 
+Takes one mandatory argument, C<base>, which should be the the
+application's base path; all of the classes under this will be
+automatically loaded.
+
 =cut
 
 sub new {
     my $class = shift;
-    my $self = bless {}, $class;
+    my $self = bless {@_}, $class;
 
     push @INC, $self;
     return $self;
@@ -50,11 +54,11 @@
 
 An empty class that descends from L<Jifty::Collection> is created.
 
-=item I<ApplicationClass::Notification>.
+=item I<Application>::Notification
 
 An empty class that descends from L<Jifty::Notification>.
 
-=item I<ApplicationClass::Dispatcher>.
+=item I<Application>::Dispatcher
 
 An empty class that descends from L<Jifty::Dispatcher>.
 
@@ -62,11 +66,9 @@
 
 An empty class that descends from L<Jifty::Bootstrap>.
 
-=item I<CurrentUserClass> (generally I<Application>::CurrentUser)
+=item I<Application>::CurrentUser
 
-...where I<CurrentUserClass> is defined by the C<CurrentUserClass>
-from the L<configuration file|Jifty::Config>.  This defaults to an
-empty class which is a subclass of L<Jifty::CurrentUser>.
+An empty class that descends from L<Jifty::CurrentUser>.
 
 =item I<Application>::Model::I<Anything>Collection
 
@@ -88,61 +90,54 @@
 # This subroutine's name is fully qualified, as perl will ignore a 'sub INC'
 sub Jifty::ClassLoader::INC {
     my ( $self, $module ) = @_;
-    my $ApplicationClassPrefix = Jifty->config->framework('ApplicationClass');
-    my $ActionBasePath   = Jifty->config->framework('ActionBasePath');
-    my $CurrentUserClass = Jifty->config->framework('CurrentUserClass');
-    my $CurrentUserClassPath =Jifty->config->framework('CurrentUserClass') .".pm";
-    $CurrentUserClassPath =~ s!::!/!g;
-    return undef unless ( $module and $ApplicationClassPrefix );
 
+    my $base = $self->{base};
+    return undef unless ( $module and $base );
 
     # Canonicalize $module to :: style rather than / and .pm style;
-    
     $module =~ s/.pm$//;
     $module =~ s{/}{::}g;
 
-    if ( $module =~ m!^($ApplicationClassPrefix)$! ) {
-        return $self->return_class( "use warnings; use strict; package " . $ApplicationClassPrefix . ";\n"." 1;" );
-    } 
-#    elsif ( $module =~ m!^($ActionBasePath)$! ) {
-#        return $self->return_class( "use warnings; use strict; package " . $ActionBasePath . ";\n".
-#            "use base qw/Jifty::Action/; sub _autogenerated { 1 };\n"."1;" );
-#    } 
-    elsif ( $module =~ m!^(?:$ApplicationClassPrefix)::(Record|Collection|Notification|Dispatcher|Bootstrap)$! ) {
-        return $self->return_class( "use warnings; use strict; package " . $ApplicationClassPrefix . "::". $1.";\n".
-            "use base qw/Jifty::$1/; sub _autogenerated { 1 };\n"."1;" );
-    } 
-
-    elsif ( $module =~ m!^$CurrentUserClass$! or $module =~ m!^$CurrentUserClassPath$!) {
-      return $self->return_class( "package " . $CurrentUserClass . ";\n" . "use base 'Jifty::CurrentUser';\n" . " 1;" );
-      }
-    elsif ( $module
-        =~ m!^($ApplicationClassPrefix)::Model::(\w+)Collection$!
-        )
-    {
-
-        # Auto-create Collection classes
-        my $record_class = $ApplicationClassPrefix . "::Model::" . $2;
-        return $self->return_class( "package " . $ApplicationClassPrefix . "::Model::" . $2 . "Collection;\n"."use base qw/@{[$ApplicationClassPrefix]}::Collection/;\n sub record_class { '@{[$ApplicationClassPrefix]}::Model::$2' }\n"." 1;"
-        );
-
-    } elsif ( $module
-        =~ m!^($ApplicationClassPrefix)::Action::(Create|Update|Delete)([^\.]+)$!
-        )
-    {
-         
-        # Auto-create CRUD classes - this applies to model subclasses too
-        my $modelclass = $ApplicationClassPrefix . "::Model::" . $3;
+    # The quick check
+    return undef unless $module =~ m!^$base!;
+
+    if ( $module =~ m!^(?:$base)$! ) {
+        return $self->return_class(
+            "use warnings; use strict; package " . $base . ";\n" . " 1;" );
+    }
+#    elsif ( $module =~ m!^(?:$base)::Action$! ) {
+#        return $self->return_class(
+#                  "use warnings; use strict; package $module;\n"
+#                . "use base qw/Jifty::Action/; sub _autogenerated { 1 };\n"
+#                . "1;" );
+#    }
+    elsif ( $module =~ m!^(?:$base)::(Record|Collection|Notification|Dispatcher|Bootstrap)$! ) {
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/Jifty::$1/; sub _autogenerated { 1 };\n"
+                . "1;" );
+    } elsif ( $module =~ m!^(?:$base)::CurrentUser$! ) {
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/Jifty::CurrentUser/; sub _autogenerated { 1 };\n"
+                . "1;" );
+    } elsif ( $module =~ m!^(?:$base)::Model::(\w+)Collection$! ) {
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/@{[$base]}::Collection/;\n"
+                . "sub record_class { '@{[$base]}::Model::$1' }\n"
+                . "1;" );
+    } elsif ( $module =~ m!^(?:$base)::Action::(Create|Update|Delete)([^\.]+)$! ) {
+        my $modelclass = $base . "::Model::" . $2;
         Jifty::Util->require($modelclass);
 
-        return undef unless eval {$modelclass->table}; #self->{models}{$modelclass};
+        return undef unless eval { $modelclass->table };
 
-        my $class = $ActionBasePath ."::".$2.$3;
-        return $self->return_class( "package $class;\n"
-                . "use base qw/Jifty::Action::Record::$2/;\n"
-                . "sub record_class {'$modelclass'};\n"
+        return $self->return_class(
+                  "use warnings; use strict; package $module;\n"
+                . "use base qw/Jifty::Action::Record::$1/;\n"
+                . "sub record_class { '$modelclass' };\n"
                 . "1;" );
-
     }
     return undef;
 }
@@ -154,7 +149,6 @@
 
 =cut
 
-
 sub return_class {
     my $self = shift;
     my $content = shift;
@@ -175,28 +169,25 @@
 sub require {
     my $self = shift;
     
-    my $ApplicationClassPrefix = Jifty->config->framework('ApplicationClass');
+    my $base = $self->{base};
     # if we don't even have an application class, this trick will not work
-    return unless  ($ApplicationClassPrefix); 
-    Jifty::Util->require($ApplicationClassPrefix);
-    Jifty::Util->require(Jifty->config->framework('CurrentUserClass'));
-
-    my $ActionBasePath = Jifty->config->framework('ActionBasePath');
+    return unless ($base); 
+    Jifty::Util->require($base);
+    Jifty::Util->require($base."::CurrentUser");
 
     Module::Pluggable->import(
         search_path =>
-          [ $ActionBasePath, map { $ApplicationClassPrefix . "::" . $_ } 'Model', 'Action', 'Notification' ],
+          [ map { $base . "::" . $_ } 'Model', 'Action', 'Notification' ],
         require => 1,
         inner => 0
     );
-    $self->{models} = {map {($_ => 1)} grep {/^($ApplicationClassPrefix)::Model::(.*)$/ and not /Collection$/} $self->plugins};
+    $self->{models}{$_} = 1 for grep {/^($base)::Model::(.*)$/ and not /Collection$/} $self->plugins;
     for my $full (keys %{$self->{models}}) {
         my($short) = $full =~ /::Model::(.*)/;
         Jifty::Util->require($full . "Collection");
-        Jifty::Util->require($ActionBasePath . "::" . $_ . $short)
+        Jifty::Util->require($base . "::Action::" . $_ . $short)
             for qw/Create Update Delete/;
     }
-
 }
 
 1;

Modified: jifty/trunk/lib/Jifty/Config.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Config.pm	(original)
+++ jifty/trunk/lib/Jifty/Config.pm	Thu May 11 15:11:18 2006
@@ -213,9 +213,7 @@
         framework => {
             AdminMode        => 1,
             DevelMode        => 1,
-            ActionBasePath   => $app_class . "::Action",
             ApplicationClass => $app_class,
-            CurrentUserClass => $app_class . "::CurrentUser",
             ApplicationName  => $app_name,
             LogLevel         => 'INFO',
             Database         => {
@@ -232,6 +230,7 @@
             L10N       => {
                 PoDir => "%share/po%",
             },
+            Plugins    => [],
             Web        => {
                 Port => '8888',
                 BaseURL => 'http://localhost',

Modified: jifty/trunk/lib/Jifty/Dispatcher.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Dispatcher.pm	(original)
+++ jifty/trunk/lib/Jifty/Dispatcher.pm	Thu May 11 15:11:18 2006
@@ -1015,4 +1015,22 @@
 }
 
 
+=head2 import_plugins
+
+Imports rules from L<Jifty/plugins> into the main dispatcher's space.
+
+=cut
+
+sub import_plugins {
+    my $self = shift;
+    for my $stage (qw/SETUP RUN CLEANUP/) {
+        my @rules;
+        push @rules, $_->dispatcher->rules($stage) for Jifty->plugins;
+        push @rules, $self->rules($stage);
+
+        no strict 'refs';
+        @{ $self . "::RULES_$stage" } = @rules;
+    }
+}
+
 1;

Modified: jifty/trunk/lib/Jifty/Handler.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Handler.pm	(original)
+++ jifty/trunk/lib/Jifty/Handler.pm	Thu May 11 15:11:18 2006
@@ -52,6 +52,8 @@
     $self->dispatcher(
         Jifty->config->framework('ApplicationClass') . "::Dispatcher" );
     Jifty::Util->require( $self->dispatcher );
+    $self->dispatcher->import_plugins;
+
     $self->mason( Jifty::View::Mason::Handler->new( $self->mason_config ) );
 
     $self->static_handler(Jifty::View::Static::Handler->new());
@@ -108,14 +110,17 @@
         %{ Jifty->config->framework('Web')->{'MasonConfig'} },
     );
 
+    for my $plugin (Jifty->plugins) {
+        my $comp_root = $plugin->template_root;
+        next unless $comp_root;
+        push @{ $config{comp_root} }, [ ref($plugin)."-".Jifty->web->serial => $comp_root ];
+    }
+
     # In developer mode, we want halos, refreshing and all that other good stuff. 
     if (Jifty->config->framework('DevelMode') ) {
         push @{$config{'plugins'}}, 'Jifty::Mason::Halo';
-            $config{static_source}        = 0;
-            $config{use_object_files}        = 0;
-            
-            
-
+        $config{static_source}    = 0;
+        $config{use_object_files} = 0;
     }
     return (%config);
         
@@ -167,6 +172,7 @@
     Jifty->web->setup_session;
     Jifty->web->session->set_cookie;
     Jifty->api->reset;
+    $_->new_request for Jifty->plugins;
 
     Jifty->log->debug( "Received request for " . Jifty->web->request->path );
 

Modified: jifty/trunk/lib/Jifty/LetMe.pm
==============================================================================
--- jifty/trunk/lib/Jifty/LetMe.pm	(original)
+++ jifty/trunk/lib/Jifty/LetMe.pm	Thu May 11 15:11:18 2006
@@ -72,7 +72,7 @@
 sub _user_from_email {
     my $self = shift;
     my $email = shift;
-    my $currentuser_object_class = Jifty->config->framework('CurrentUserClass');
+    my $currentuser_object_class = Jifty->config->framework('ApplicationClass')."::CurrentUser";
     return $currentuser_object_class->new( email => $email );
 }
 

Added: jifty/trunk/lib/Jifty/Plugin.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/lib/Jifty/Plugin.pm	Thu May 11 15:11:18 2006
@@ -0,0 +1,110 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin;
+
+=head1 NAME
+
+Jifty::Plugin - Describes a plugin to the Jifty framework
+
+=head1 DESCRIPTION
+
+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.  
+
+=cut
+
+use File::ShareDir;
+
+=head2 new
+
+Sets up a new instance of this plugin.  This is called by L<Jifty>
+after reading the configuration file, and is supplied whatever
+plugin-specific settings were in the config file.  Note that because
+plugins affect Mason's component roots, adding plugins during runtime
+is not supported.
+
+=cut
+
+sub new {
+    my $class = shift;
+    
+    # Get a classloader set up
+    Jifty::ClassLoader->new(base => $class)->require;
+    Jifty::Util->require($class->dispatcher);
+
+    # XXX TODO: Add .po path
+
+    my $self = bless {} => $class;
+    $self->init(@_);
+    return $self;
+}
+
+
+=head2 init [ARGS]
+
+Called by L</new>, this does any custom configuration that the plugin
+might need.  It is passed the same parameters as L</new>, gleaned from
+the configuration file.
+
+=cut
+
+sub init {
+    1;
+}
+
+=head2 new_request
+
+Called right before every request.  By default, this adds the plugin's
+actions to the list of allowed actions, using L<Jifty::API/allow>.
+
+=cut
+
+sub new_request {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    Jifty->api->allow(qr/^\Q$class\E::Action/);
+}
+
+=head2 template_root
+
+Returns the root of the template directory for this plugin
+
+=cut
+
+sub template_root {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    my $share = File::ShareDir::module_dir($class);
+    return unless $share;
+    return "$share/web/templates";
+}
+
+=head2 static_root
+
+Returns the root of the static directory for this plugin
+
+=cut
+
+sub static_root {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    my $share = File::ShareDir::module_dir($class);
+    return unless $share;
+    return "$share/web/static";
+}
+
+=head2 dispatcher
+
+Returns the classname of the dispatcher class for this plugin
+
+=cut
+
+sub dispatcher {
+    my $self = shift;
+    my $class = ref($self) || $self;
+    return $class."::Dispatcher";
+}
+
+1;

Modified: jifty/trunk/lib/Jifty/View/Mason/Handler.pm
==============================================================================
--- jifty/trunk/lib/Jifty/View/Mason/Handler.pm	(original)
+++ jifty/trunk/lib/Jifty/View/Mason/Handler.pm	Thu May 11 15:11:18 2006
@@ -45,7 +45,7 @@
 
 Takes a number of key-value parameters; see L<HTML::Mason::Params>.
 Defaults the C<out_method> to L</out_method>, and the C<request_class>
-to L<HTML::MAson::request::Jifty> (below).  Finally, adds C<h> and
+to L<HTML::Mason::Request::Jifty> (below).  Finally, adds C<h> and
 C<u> escapes, which map to L</escape_uri> and L<escape_utf8>
 respectively.
 

Modified: jifty/trunk/lib/Jifty/View/Static/Handler.pm
==============================================================================
--- jifty/trunk/lib/Jifty/View/Static/Handler.pm	(original)
+++ jifty/trunk/lib/Jifty/View/Static/Handler.pm	Thu May 11 15:11:18 2006
@@ -110,18 +110,15 @@
 sub file_path {
     my $self    = shift;
     my $file    = shift;
-    my @options = (qw(StaticRoot DefaultStaticRoot));
+    my @options = map {Jifty->config->framework('Web')->{$_}} (qw(StaticRoot DefaultStaticRoot));
+    push @options, grep {$_} map {$_->static_root} Jifty->plugins;
 
     # Chomp a leading "/static" - should this be configurable?
     $file =~ s/^\/*?static//; 
 
     foreach my $path (@options) {
-
-        my $abspath = Jifty::Util->absolute_path(
-            Jifty->config->framework('Web')->{$path} . "/" . $file );
-
+        my $abspath = Jifty::Util->absolute_path( $path . "/" . $file );
         return $abspath if ( -f $abspath && -r $abspath );
-
     }
     return undef;
 

Modified: jifty/trunk/lib/Jifty/Web.pm
==============================================================================
--- jifty/trunk/lib/Jifty/Web.pm	(original)
+++ jifty/trunk/lib/Jifty/Web.pm	Thu May 11 15:11:18 2006
@@ -146,11 +146,9 @@
 If a temporary_current_user has been set, will return that instead.
 
 If the current application has no loaded current user, we get an empty
-app-specific C<CurrentUser> object. (This is determined by
-theC<framework> configuration varialbe C<CurrentUserClass> and
-defaults to $AppNameC<::CurrentUser>, a subclass of
-L<Jifty::CurrentUser>.  $AppNameC<::CurrentUser> is autogenerated if
-it doesn't exist.
+app-specific C<CurrentUser> object. (This
+C<ApplicationClass>::CurrentUser class, a subclass of
+L<Jifty::CurrentUser>, is autogenerated if it doesn't exist).
 
 =cut
 
@@ -166,7 +164,7 @@
         return $self->session->get('user');
     }
     else {
-        my $object = Jifty->config->framework('CurrentUserClass')->new();
+        my $object = (Jifty->config->framework('ApplicationClass')."::CurrentUser")->new();
         $object->is_superuser(1) if Jifty->config->framework('AdminMode');
         return ($object);
     }
@@ -319,10 +317,9 @@
 
 Creates a new action (an instance of a subclass of L<Jifty::Action>)
 
-C<CLASS> is appended to the C<ActionBasePath> found in the
-configuration file, and an instance of that class is created, passing
-the C<Jifty::Web> object, the C<MONIKER>, and any other arguments that
-C<new_action> was supplied.
+C<CLASS> is L<qualified|Jifty::Util/qualify>, and an instance of that
+class is created, passing the C<Jifty::Web> object, the C<MONIKER>,
+and any other arguments that C<new_action> was supplied.
 
 C<MONIKER> is a unique designator of an action on a page.  The moniker
 is content-free and non-fattening, and may be auto-generated.  It is

Added: jifty/trunk/plugins/EditInPlace/META.yml
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/META.yml	Thu May 11 15:11:18 2006
@@ -0,0 +1,10 @@
+distribution_type: module
+generated_by: Module::Install version 0.610
+license: unknown
+name: Jifty-Plugin-EditInPlace
+no_index: 
+  directory: 
+    - inc
+    - t
+requires: 
+  Jifty: 0.60510

Added: jifty/trunk/plugins/EditInPlace/Makefile.PL
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/Makefile.PL	Thu May 11 15:11:18 2006
@@ -0,0 +1,9 @@
+use inc::Module::Install 0.46;
+name('Jifty-Plugin-EditInPlace');
+requires('Jifty' => '0.60510' );
+&auto_install();
+
+install_share;
+
+WriteAll;
+

Added: jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace.pm	Thu May 11 15:11:18 2006
@@ -0,0 +1,9 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::EditInPlace;
+use base qw/Jifty::Plugin/;
+
+
+
+1;

Added: jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Action/FileEditor.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Action/FileEditor.pm	Thu May 11 15:11:18 2006
@@ -0,0 +1,179 @@
+package Jifty::Plugin::EditInPlace::Action::FileEditor;
+
+use base qw/Jifty::Action/;
+use File::Spec;
+use File::Basename ();
+
+
+=head1 NAME
+
+Jifty::Plugin::EditInPlace::Action::FileEditor
+
+=head1 DESCRIPTION
+
+This action allows you to edit mason components (and eventually libraries)
+using Jifty's I<Action> system.  It should only be enabled when you're
+running Jifty in C<DevelMode>. 
+
+=head1 WARNING
+
+B<THIS ACTION LETS YOU REMOTELY EDIT EXECUTABLE CODE>.
+
+B<THIS IS DANGEROUS>
+
+=cut
+
+=head2 new
+
+Create a new C<FileEditor> action.
+
+=cut
+
+sub new {
+    my $class = shift; 
+    my $self = $class->SUPER::new(@_);
+    $self->sticky_on_success(1);
+    $self->get_default_content; 
+    return($self);
+
+}
+
+=head2 arguments
+
+Sets up this action's arguments.
+
+=over
+
+=item path
+
+Where to save the file
+
+=item file_type
+
+(One of mason_component or library)
+
+=item source_path
+
+Where to read the file from.
+
+=item destination_path
+
+Where to write the file to. If the current user can't write to 
+the source_path, defaults to something inside the app's directory.
+
+=item content
+
+The actual content of the file we're editing.
+
+=back
+
+=cut
+
+
+sub arguments {
+    my $self = shift;
+
+    {   file_type => {
+            default      => 'mason_component',
+            render_as    => 'Select',
+            valid_values => [qw/mason_component library/],
+            constructor  => 1
+        },
+        source_path      => { type => 'text', constructor => 1 },
+        destination_path => { type => 'text', ajax_validates=> 1, label => 'Save as' },
+        content => { render_as => 'Textarea', cols => 80, rows => 25 },
+
+    }
+
+}
+
+
+=head2 get_default_content
+
+Finds the version of the C<source_path> (of type C<file_type>) and
+loads it into C<content>.
+
+=cut
+
+sub get_default_content {
+    my $self = shift;
+
+    # Don't override content we already have
+    return if ($self->argument_value('content'));
+    my $path = $self->argument_value('source_path');
+    my $type = $self->argument_value('file_type');
+    my $out = '';
+    my %cfg = Jifty->handler->mason_config;
+    
+    my($local_template_base, $qualified_path);
+    if ($type eq "mason_component") {
+        foreach my $item (@{$cfg{comp_root}}) {
+            $local_template_base = $item->[1] if $item->[0] eq 'application';
+            $qualified_path = File::Spec->catfile($item->[1],$path);
+            # We want the first match
+            last if -f $qualified_path and -r $qualified_path;
+            undef $qualified_path;
+        }
+        $self->argument_value(destination_path => File::Spec->catfile($local_template_base, $path));
+    } else {
+        $qualified_path = "/$path" if -f "/$path" and -r "/$path";
+        $self->argument_value(destination_path => $qualified_path);
+    }
+
+    if ($qualified_path) {
+        local $/;
+        my $filehandle;
+        open ($filehandle, "<$qualified_path")||die "Couldn't read $qualified_path: $!";
+        $self->argument_value(content => <$filehandle>);
+        close($filehandle);
+    }
+}
+
+=head2 validate_destination_path PATH
+
+Returns true if the user can write to the directory C<PATH>. False
+otherwise. Should be refactored to a C<path_writable> routine and a
+trivial validator.
+
+=cut
+
+sub validate_destination_path {
+    my $self = shift;
+    my $value = shift;
+    $self->{'write_to'} = $value;
+    unless ($self->{'write_to'}) {
+        return  $self->validation_error( destination_path => "No destination path set. Where should I write this file?");
+    }
+    if (-f $self->{'write_to'} and not -w $self->{'write_to'}) {
+        return  $self->validation_error( destination_path => "Can't save the file to ".$self->{'write_to'});
+    }
+    return $self->validation_ok( 'write_to' );
+}
+
+
+=head2 take_action
+
+Writes the C<content> out to the C<destination_path>.
+
+=cut
+
+sub take_action {
+    my $self = shift;
+    my $dest  = $self->{'write_to'};
+
+    # discard filename. we only want to make the directory ;)
+    Jifty::Util->make_path( File::Basename::dirname( $dest ) );
+    my $writehandle = IO::File->new();
+
+    my $content = $self->argument_value('content');
+    $content =~ s/\r\n/\n/g;
+
+    $writehandle->open(">$dest") || die "Couldn't open $dest for writing: ".$!;
+    $writehandle->print( $content ) || die " Couldn't write to $dest: ".$!;
+    $writehandle->close() || die "Couldn't close filehandle $dest ".$!;
+    $self->result->message("Updated $dest");
+}
+
+
+
+1;

Added: jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Dispatcher.pm
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/lib/Jifty/Plugin/EditInPlace/Dispatcher.pm	Thu May 11 15:11:18 2006
@@ -0,0 +1,22 @@
+use strict;
+use warnings;
+
+package Jifty::Plugin::EditInPlace::Dispatcher;
+use Jifty::Dispatcher -base;
+
+on qr'^/__jifty/edit/(.*?)/(.*)$', run {
+    my $editor = Jifty->web->new_action(
+        class     => 'Jifty::Plugin::EditInPlace::Action::FileEditor',
+        moniker   => 'editpage',
+        arguments => {
+            source_path => $2,
+            file_type   => $1,
+        }
+    );
+
+    set editor => $editor;
+    show '/__jifty/edit_file';
+};
+
+
+1;

Added: jifty/trunk/plugins/EditInPlace/share/web/templates/__jifty/edit_file
==============================================================================
--- (empty file)
+++ jifty/trunk/plugins/EditInPlace/share/web/templates/__jifty/edit_file	Thu May 11 15:11:18 2006
@@ -0,0 +1,14 @@
+<%args>
+$path=> undef
+$editor => undef
+</%args>
+<%init>
+my $title = _("Editing file %1",$editor->argument_value('source_path'));
+</%init>
+<&|/_elements/wrapper, title => $title &>
+<% Jifty->web->form->start %>
+<%$editor->form_field('destination_path')%>
+<%$editor->form_field('content')%>
+<% Jifty->web->return(label => 'Save and return', submit => $editor )%>
+<% Jifty->web->form->end %>
+</&>

Added: jifty/trunk/share/web/templates/__jifty/error/autohandler
==============================================================================
--- (empty file)
+++ jifty/trunk/share/web/templates/__jifty/error/autohandler	Thu May 11 15:11:18 2006
@@ -0,0 +1,4 @@
+<%flags>
+inherit => undef
+</%flags>
+% $m->call_next
\ No newline at end of file

Modified: jifty/trunk/t/07-limit-actions.t
==============================================================================
--- jifty/trunk/t/07-limit-actions.t	(original)
+++ jifty/trunk/t/07-limit-actions.t	Thu May 11 15:11:18 2006
@@ -10,14 +10,12 @@
 
 =cut
 
-use Jifty::Test tests => 22;
+use Jifty::Test tests => 21;
 
 use_ok('Jifty::API');
 
 my $api = Jifty::API->new();
 
-is(Jifty->config->framework("ActionBasePath"), "JiftyApp::Action", "Action base path is as expected");
-
 ok($api->is_allowed("Jifty::Action::Autocomplete"), "Some Jifty actions are allowed");
 ok(!$api->is_allowed("Jifty::Action::Record::Update"), "Most are not");
 ok($api->is_allowed("Foo"), "Unqualified tasks default to positive limit");


More information about the Jifty-commit mailing list