[Jifty-commit] r2805 - in jifty: . branches/virtual-models branches/virtual-models/lib branches/virtual-models/lib/Jifty branches/virtual-models/lib/Jifty/Manual branches/virtual-models/lib/Jifty/Script branches/virtual-models/share/web/templates/__jifty/css branches/virtual-models/share/web/templates/__jifty/js

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Tue Feb 20 06:51:59 EST 2007


Author: sterling
Date: Tue Feb 20 06:51:56 2007
New Revision: 2805

Added:
   jifty/branches/virtual-models/lib/Jifty/Manual/TutorialRest.pod
Modified:
   jifty/   (props changed)
   jifty/branches/virtual-models/   (props changed)
   jifty/branches/virtual-models/Makefile.PL
   jifty/branches/virtual-models/lib/Jifty.pm
   jifty/branches/virtual-models/lib/Jifty/API.pm
   jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm
   jifty/branches/virtual-models/lib/Jifty/Manual/Tutorial.pod
   jifty/branches/virtual-models/lib/Jifty/Plugin/REST/Dispatcher.pm
   jifty/branches/virtual-models/lib/Jifty/Script/Schema.pm
   jifty/branches/virtual-models/lib/Jifty/Test.pm
   jifty/branches/virtual-models/lib/Jifty/Web.pm
   jifty/branches/virtual-models/share/web/templates/__jifty/css/dhandler
   jifty/branches/virtual-models/share/web/templates/__jifty/js/dhandler

Log:
Merging latest trunk into virtual-models

Modified: jifty/branches/virtual-models/Makefile.PL
==============================================================================
--- jifty/branches/virtual-models/Makefile.PL	(original)
+++ jifty/branches/virtual-models/Makefile.PL	Tue Feb 20 06:51:56 2007
@@ -41,7 +41,7 @@
 requires('HTTP::Server::Simple::Recorder');
 requires('Hash::Merge');
 requires('Hook::LexWrap');
-requires('IPC::PubSub' => '0.22' );
+requires('IPC::PubSub' => '0.23' );
 requires('Jifty::DBI' => '0.31' );            # Jifty::DBI::Collection Jifty::DBI::Handle Jifty::DBI::Record::Cachable Jifty::DBI::SchemaGenerator
 requires('Locale::Maketext::Extract' => '0.20');
 requires('Locale::Maketext::Lexicon' => '0.60');

Modified: jifty/branches/virtual-models/lib/Jifty.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty.pm	Tue Feb 20 06:51:56 2007
@@ -13,6 +13,37 @@
 
 Jifty - an application framework
 
+=head1 SYNOPSIS
+
+ # Object containing lots of web related goodies...
+ my $web      = Jifty->web;
+ my $request  = Jifty->web->request;
+ my $response = Jifty->web->response;
+ my $link     = Jifty->web->link( label => _('W00t'), url => '/whatsit' );
+
+ # Retrieve information from your application's etc/config.yml file.
+ my $config   = Jifty->config;
+
+ # Retrieve the Jifty::DBI handle
+ my $handle   = Jifty->handle;
+
+ # Load an application class, very handy in plugins
+ my $class    = Jifty->app_class('Model', 'Foo');
+ my $foo      = $class->new;
+ $foo->create( frobnicate => 42 );
+
+ # Configure information related to your application's actions
+ my $api      = Jifty->api;
+
+ # Make parts of your page "subscribe" to information in a fragment
+ my $subs     = Jifty->subs;
+
+ # Share information via IPC::PubSub in your application
+ my $bus      = Jifty->bus;
+
+ # Retrieve general information about Mason
+ my $handler  = Jifty->handler;
+
 =head1 DESCRIPTION
 
 Yet another web framework.
@@ -160,6 +191,13 @@
     $app->start() if $app->can('start');
 }
 
+# Explicitly destroy the classloader; if this happens during global
+# destruction, there's a period of time where there's a bogus entry in
+# @INC
+END {
+    Jifty->class_loader->DESTROY if Jifty->class_loader;
+}
+
 =head2 config
 
 An accessor for the L<Jifty::Config> object that stores the
@@ -177,6 +215,9 @@
 
 An accessor for our L<Jifty::Logger> object for the application.
 
+You probably aren't interested in this. See L</log> for information on how to
+make log messages.
+
 =cut
 
 sub logger {
@@ -189,6 +230,9 @@
 
 An accessor for our L<Jifty::Handler> object.
 
+This is another method that you usually don't want to mess with too much.
+Most of the interesting web bits are handled by L</web>.
+
 =cut
 
 sub handler {
@@ -392,7 +436,7 @@
 
 =head1 SEE ALSO
 
-L<http://jifty.org>
+L<http://jifty.org>, L<Jifty::Manual::Tutorial>, L<Jifty::Everything>, L<Jifty::Config>, L<Jifty::Handle>, L<Jifty::Logger>, L<Jifty::Handler>, L<Jifty::Web>, L<Jifty::API>, L<Jifty::Subs>, L<IPC::PubSub>, L<Jifty::Plugin>, L<Jifty::ClassLoader>
 
 =head1 AUTHORS
 

Modified: jifty/branches/virtual-models/lib/Jifty/API.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/API.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/API.pm	Tue Feb 20 06:51:56 2007
@@ -8,6 +8,42 @@
 Jifty::API - Manages and allow reflection on the Jifty::Actions that
 make up a Jifty application's API
 
+=head1 SYNOPSIS
+
+ # A nice way to run actions in your application
+ my $class = Jifty->api->qualify('SomeAction');
+ $class->require;
+ $action = $class->new(
+     moniker  => 'my_action',
+     argument => {
+         foo => 1,
+         bar => 'baz',
+     },
+ );
+ $action->run;
+
+ # Logged users with an ID greater than 10 have restrictions
+ if (Jifty->web->current_user->id > 10) {
+     Jifty->api->deny('Foo');
+     Jifty->api->allow('FooBar');
+     Jifty->api->deny('FooBarDeleteTheWorld');
+ }
+
+ # Fetch the class names of all the allowed actions
+ my @actions = Jifty->api->actions;
+
+ # Check to see if an action is allowed
+ if (Jifty->api->is_allow('TrueFooBar')) {
+     # do something...
+ }
+
+ # Undo all allow/deny/restrict calls
+ Jifty->api->reset;
+
+=head1 DESCRIPTION
+
+You can fetch an instance of this class by calling L<Jifty/api> in your application. This object can be used to examine the actions available within your application and manage access to those actions.
+
 =cut
 
 
@@ -20,7 +56,9 @@
 
 =head2 new
 
-Creates a new C<Jifty::API> object
+Creates a new C<Jifty::API> object.
+
+Don't use this, see L<Jifty/api> to access a reference to C<Jifty::API> in your application.
 
 =cut
 
@@ -47,8 +85,8 @@
 
 Returns the fully qualified package name for the given provided
 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.
+C<ApplicationClass::Action>, simply returns the given name; otherwise,
+it prefixes it with the C<ApplicationClass::Action>.
 
 =cut
 
@@ -222,4 +260,15 @@
     return sort grep { $self->is_allowed($_) } $self->_actions;
 }
 
+=head1 SEE ALSO
+
+L<Jifty>, L<Jifty::Web>, L<Jifty::Action>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2006 Best Practical Solutions, LLC. 
+Jifty is distributed under the same terms as Perl itself.
+
+=cut
+
 1;

Modified: jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/ClassLoader.pm	Tue Feb 20 06:51:56 2007
@@ -30,8 +30,12 @@
 
 sub new {
     my $class = shift;
-    my $self = bless {@_}, $class;
+    my %args = @_;
 
+    my @exist = grep {ref $_ eq $class and $_->{base} eq $args{base}} @INC;
+    return $exist[0] if @exist;
+
+    my $self = bless {%args}, $class;
     push @INC, $self;
     return $self;
 }
@@ -285,6 +289,30 @@
     wantarray ? @{ $self->{models} } : $self->{models};
 }
 
+=head2 DESTROY
+
+When the ClassLoader gets garbage-collected, its entry in @INC needs
+to be removed.
+
+=cut
+
+# The entries in @INC end up having SvTYPE == SVt_RV, but SvRV(sv) ==
+# 0x0 and !SvROK(sv) (!?)  This may be something that perl should cope
+# with more cleanly.
+#
+# We call this explictly in an END block in Jifty.pm, because
+# otherwise the DESTROY block gets called *after* there's already a
+# bogus entry in @INC
+
+# This bug manifests itself as warnings that look like this:
+
+# Use of uninitialized value in require at /tmp/7730 line 9 during global destruction.
+
+
+sub DESTROY {
+    my $self = shift;
+    @INC = grep {defined $_ and $_ ne $self} @INC;
+}
 
 =head1 Writing your own classes
 

Modified: jifty/branches/virtual-models/lib/Jifty/Manual/Tutorial.pod
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Manual/Tutorial.pod	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Manual/Tutorial.pod	Tue Feb 20 06:51:56 2007
@@ -487,6 +487,8 @@
 
 =item * Web Services
 
+See L<Jifty::Manual::TutorialRest> for a quick overview.
+
 =item * Continuations in depth
 
 =item * Customized view (user-defined wrappers and css)

Added: jifty/branches/virtual-models/lib/Jifty/Manual/TutorialRest.pod
==============================================================================
--- (empty file)
+++ jifty/branches/virtual-models/lib/Jifty/Manual/TutorialRest.pod	Tue Feb 20 06:51:56 2007
@@ -0,0 +1,124 @@
+=head1 NAME
+
+Jifty::Manual::TutorialRest - Web Services
+
+=head1 DESCRIPTION
+
+This builds on L<Jifty::Manual::Tutorial>, so make sure you have a
+running jifty that roughly resembles the step-by-step from there.
+
+=head1 SETUP
+
+You must add this to your site_config.yml
+
+  framework:
+    Plugins:
+      - REST: {}
+
+See L<Jifty::Plugin::REST>.
+
+The commands assume that you have LWP installed with the GET alias.  If
+not, you'll need to use the longhand lwp-request -m GET, or curl, or
+your browser.
+
+=head1 help
+
+Make sure it is working:
+
+  $ GET http://localhost:8888/=/help
+
+  Accessing resources:
+  ...
+
+You should see some text describing the services, not html (that's
+longhand for 404.)  Check the config and restart the server.
+
+=head1 GET
+
+Just list the models.
+
+  $ GET http://localhost:8888/=/model.yml
+  ---
+  - MyWeblog.Model.Post
+
+List the Post schema.
+
+  $ GET http://localhost:8888/=/model/Post.yml
+  ---
+  body:
+    label: Content
+    name: body
+    readable: 1
+    sort_order: 1
+    type: text
+    writable: 1
+  id:
+    mandatory: 1
+    name: id
+    readable: 1
+    type: serial
+    writable: 0
+  title:
+    default: Untitled post
+    label: Title
+    name: title
+    readable: 1
+    sort_order: 0
+    type: text
+    writable: 1
+
+You did make some posts, right?
+
+  $ GET http://localhost:8888/=/model/Post/id.yml
+  ---
+  - 1
+  - 2
+
+Dump the data:
+
+  $ GET http://localhost:8888/=/model/Post/id/1.yml
+  ---
+  body: 'This is my post, the content of which is this, which is mine.'
+  id: 1
+  title: my first post
+
+  $ GET http://localhost:8888/=/model/Post/id/2.yml
+  ---
+  body: "Content of another post.  Got to go, the cat's on fire."
+  id: 2
+  title: post deux
+
+=head1 POST
+
+TODO not working
+
+Actually, it looks like it is not supposed to work this way.  Why not?
+
+  $ echo '---
+  body: "A post via web services"
+  id: 3
+  title: "posting from the command-line"
+  ' | lwp-request -m POST http://localhost:8888/=/model/Post.yml
+  POST http://localhost:8888/=/model/Post/id/3.yml --> 404 Not Found
+
+=head1 PUT
+
+TODO not working
+
+  $ echo '---
+  title: "posting from the cli"
+  ' | lwp-request -m PUT http://localhost:8888/=/model/Post/3.yml
+  500 Can't read entity body: Connection reset by peer
+
+=head1 DELETE
+
+  $  lwp-request -m DELETE http://localhost:8888/=/model/Post/id/3.yml
+  ---
+  content: {}
+  error: ~
+  field_errors: {}
+  field_warnings: {}
+  message: Deleted
+  success: 1
+
+=cut

Modified: jifty/branches/virtual-models/lib/Jifty/Plugin/REST/Dispatcher.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Plugin/REST/Dispatcher.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Plugin/REST/Dispatcher.pm	Tue Feb 20 06:51:56 2007
@@ -28,6 +28,7 @@
 on GET    '/=/model/*'          => \&list_model_columns;
 on GET    '/=/model'            => \&list_models;
 
+on POST   '/=/model/*'          => \&create_item;
 on PUT    '/=/model/*/*/*'      => \&replace_item;
 on DELETE '/=/model/*/*/*'      => \&delete_item;
 
@@ -58,7 +59,8 @@
 on GET    /=/model/<model>/<column>/<key>           show item
 on GET    /=/model/<model>/<column>/<key>/<field>   show item field
 
-on PUT    /=/model/<model>/<column>/<key>           replace item
+on POST   /=/model/<model>                          create item
+on PUT    /=/model/<model>/<column>/<key>           update item
 on DELETE /=/model/<model>/<column>/<key>           delete item
 
 on GET    /=/action                                 list actions
@@ -467,10 +469,17 @@
     outs( ['model', $model, $column, $key],  { map {$_ => stringify($rec->$_())} map {$_->name} $rec->columns});
 }
 
+=head2 create_item
+
+Implemented by redispatching to a CreateModel action.
+
+=cut
+
+sub create_item { _dispatch_to_action('Create') }
 
 =head2 replace_item
 
-Implemented by redispatching to a CreateModel or UpdateModel action
+Implemented by redispatching to a CreateModel or UpdateModel action.
 
 =cut
 
@@ -488,7 +497,8 @@
     my $prefix = shift;
     my ($model, $class, $column, $key) = (model($1), $1, $2, $3);
     my $rec = $model->new;
-    $rec->load_by_cols( $column => $key );
+    $rec->load_by_cols( $column => $key )
+        if defined $column and defined $key;
 
     if ( not $rec->id ) {
         abort(404)         if $prefix eq 'Delete';
@@ -497,16 +507,18 @@
 
     $class =~ s/^[\w\.]+\.//;
 
-    $ENV{REQUEST_METHOD} = 'POST';
-    Jifty->web->request->argument( $column => $key );
-    Jifty->web->request->argument( 'id' => $rec->id )
-        if defined $rec->id;
+    if ( defined $column and defined $key ) {
+        Jifty->web->request->argument( $column => $key );
+        Jifty->web->request->argument( 'id' => $rec->id )
+            if defined $rec->id;
+    }
     
     # CGI.pm doesn't handle form encoded data in PUT requests (in fact,
     # it doesn't really handle PUT requests properly at all), so we have
     # to read the request body ourselves and have CGI.pm parse it
-    if (    $ENV{'CONTENT_TYPE'} =~ m|^application/x-www-form-urlencoded$|
-         or $ENV{'CONTENT_TYPE'} =~ m|^multipart/form-data$| )
+    if (    $ENV{'REQUEST_METHOD'} eq 'PUT'
+        and (   $ENV{'CONTENT_TYPE'} =~ m|^application/x-www-form-urlencoded$|
+              or $ENV{'CONTENT_TYPE'} =~ m|^multipart/form-data$| ) )
     {
         my $cgi    = Jifty->handler->cgi;
         my $length = defined $ENV{'CONTENT_LENGTH'} ? $ENV{'CONTENT_LENGTH'} : 0;
@@ -529,6 +541,7 @@
         }
     }
 
+    $ENV{REQUEST_METHOD} = 'POST';
     dispatch '/=/action/' . action( $prefix . $class );
 }
 

Modified: jifty/branches/virtual-models/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Script/Schema.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Script/Schema.pm	Tue Feb 20 06:51:56 2007
@@ -422,6 +422,7 @@
 }
 
 sub _print_upgrades {
+    my $self     = shift;
     my %UPGRADES = (@_);
     for (
         map  { @{ $UPGRADES{$_} } }

Modified: jifty/branches/virtual-models/lib/Jifty/Test.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Test.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Test.pm	Tue Feb 20 06:51:56 2007
@@ -141,11 +141,13 @@
     rmtree([ File::Spec->canonpath("$root/var/mason") ], 0, 1);
 
     Jifty->new( no_handle => 1 );
+
     my $schema = Jifty::Script::Schema->new;
     $schema->{drop_database} =
       $schema->{create_database} =
         $schema->{create_all_tables} = 1;
     $schema->run;
+
     Jifty->new();
     $class->setup_mailbox;
 }
@@ -398,6 +400,11 @@
         # Clean up mailbox
         Jifty::Test->teardown_mailbox;
 
+        # Disconnect the PubSub bus, if need be; otherwise we may not
+        # be able to drop the testing database
+        Jifty->bus->disconnect
+          if Jifty->bus;
+
         # Remove testing db
         if (Jifty->handle) {
             Jifty->handle->disconnect();

Modified: jifty/branches/virtual-models/lib/Jifty/Web.pm
==============================================================================
--- jifty/branches/virtual-models/lib/Jifty/Web.pm	(original)
+++ jifty/branches/virtual-models/lib/Jifty/Web.pm	Tue Feb 20 06:51:56 2007
@@ -26,8 +26,8 @@
 );
 
 __PACKAGE__->mk_classdata($_)
-    for qw(cached_css        cached_css_digest
-           cached_javascript cached_javascript_digest javascript_libs);
+    for qw(cached_css        cached_css_digest        cached_css_time
+           cached_javascript cached_javascript_digest cached_javascript_time javascript_libs);
 
 __PACKAGE__->javascript_libs([qw(
     jsan/JSAN.js
@@ -1011,6 +1011,7 @@
 
         __PACKAGE__->cached_css( $css );
         __PACKAGE__->cached_css_digest( md5_hex( $css ) );
+		__PACKAGE__->cached_css_time( time );
     }
 }
 
@@ -1132,6 +1133,7 @@
 
         __PACKAGE__->cached_javascript( $js );
         __PACKAGE__->cached_javascript_digest( md5_hex( $js ) );
+        __PACKAGE__->cached_javascript_time( time );
     }
 }
 

Modified: jifty/branches/virtual-models/share/web/templates/__jifty/css/dhandler
==============================================================================
--- jifty/branches/virtual-models/share/web/templates/__jifty/css/dhandler	(original)
+++ jifty/branches/virtual-models/share/web/templates/__jifty/css/dhandler	Tue Feb 20 06:51:56 2007
@@ -9,7 +9,7 @@
 
 use HTTP::Date ();
 
-if ( Jifty->handler->cgi->http('If-Modified-Since')
+if ( ( Jifty->handler->cgi->http('If-Modified-Since') or Jifty->handler->cgi->http('If-None-Match') )
         and $m->dhandler_arg eq Jifty->web->cached_css_digest . '.css' )
 {
     Jifty->log->debug("Returning 304 for cached css");
@@ -19,6 +19,9 @@
 
 $r->content_type("text/css");
 $r->header_out( 'Expires' => HTTP::Date::time2str(time + 31536000) );
+$r->header_out( 'Last-Modified' => HTTP::Date::time2str( Jifty->web->cached_css_time ) );
+$r->header_out( 'Age' => time - Jifty->web->cached_css_time );
+$r->header_out( 'Etag' => Jifty->web->cached_css_digest );
 
 # XXX TODO: If we start caching the squished CSS in a file somewhere, we
 # can have the static handler serve it, which would take care of gzipping

Modified: jifty/branches/virtual-models/share/web/templates/__jifty/js/dhandler
==============================================================================
--- jifty/branches/virtual-models/share/web/templates/__jifty/js/dhandler	(original)
+++ jifty/branches/virtual-models/share/web/templates/__jifty/js/dhandler	Tue Feb 20 06:51:56 2007
@@ -9,7 +9,7 @@
 
 use HTTP::Date ();
 
-if ( Jifty->handler->cgi->http('If-Modified-Since')
+if ( ( Jifty->handler->cgi->http('If-Modified-Since') or Jifty->handler->cgi->http('If-None-Match') )
         and $m->dhandler_arg eq Jifty->web->cached_javascript_digest . '.js' )
 {
     Jifty->log->debug("Returning 304 for cached javascript");
@@ -19,6 +19,9 @@
 
 $r->content_type("application/x-javascript");
 $r->header_out( 'Expires' => HTTP::Date::time2str(time + 31536000) );
+$r->header_out( 'Last-Modified' => HTTP::Date::time2str( Jifty->web->cached_javascript_time ) );
+$r->header_out( 'Age' => time - Jifty->web->cached_javascript_time );
+$r->header_out( 'Etag' => Jifty->web->cached_javascript_digest );
 
 # XXX TODO: If we start caching the squished JS in a file somewhere, we
 # can have the static handler serve it, which would take care of gzipping


More information about the Jifty-commit mailing list