[Jifty-commit] r2815 - in jifty/branches/template-declare: . lib lib/Jifty lib/Jifty/Action lib/Jifty/Manual lib/Jifty/Plugin/REST

jifty-commit at lists.jifty.org jifty-commit at lists.jifty.org
Thu Feb 22 05:23:14 EST 2007


Author: audreyt
Date: Thu Feb 22 05:23:13 2007
New Revision: 2815

Added:
   jifty/branches/template-declare/lib/Jifty/Manual/TutorialRest.pod
   jifty/branches/template-declare/lib/Jifty/Script/Adopt.pm
   jifty/branches/template-declare/lib/Jifty/Script/Env.pm
Modified:
   jifty/branches/template-declare/   (props changed)
   jifty/branches/template-declare/Makefile.PL
   jifty/branches/template-declare/lib/Jifty.pm
   jifty/branches/template-declare/lib/Jifty/API.pm
   jifty/branches/template-declare/lib/Jifty/Action.pm
   jifty/branches/template-declare/lib/Jifty/Action/Autocomplete.pm
   jifty/branches/template-declare/lib/Jifty/Action/Record.pm
   jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
   jifty/branches/template-declare/lib/Jifty/Logger.pm
   jifty/branches/template-declare/lib/Jifty/Manual/Cookbook.pod
   jifty/branches/template-declare/lib/Jifty/Manual/Tutorial.pod
   jifty/branches/template-declare/lib/Jifty/Plugin.pm
   jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm
   jifty/branches/template-declare/lib/Jifty/Script/Schema.pm
   jifty/branches/template-declare/lib/Jifty/Test.pm
   jifty/branches/template-declare/lib/Jifty/Web.pm

Log:
* Merge from trunk to T-D branch; no tests were affected.

Modified: jifty/branches/template-declare/Makefile.PL
==============================================================================
--- jifty/branches/template-declare/Makefile.PL	(original)
+++ jifty/branches/template-declare/Makefile.PL	Thu Feb 22 05:23:13 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/template-declare/lib/Jifty.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty.pm	Thu Feb 22 05:23:13 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.
@@ -170,6 +201,13 @@
     
 }
 
+# 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
@@ -187,6 +225,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 {
@@ -199,6 +240,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 {
@@ -382,19 +426,20 @@
 }
 
 
-=head1 LICENSE
-
-Jifty is Copyright 2005-2006 Best Practical Solutions, LLC.
-Jifty is distributed under the same terms as Perl itself.
-
 =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
 
 Jesse Vincent, Alex Vandiver and David Glasser.
 
+=head1 LICENSE
+
+Jifty is Copyright 2005-2006 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
+
+
 
 =cut
 

Modified: jifty/branches/template-declare/lib/Jifty/API.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/API.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/API.pm	Thu Feb 22 05:23:13 2007
@@ -8,6 +8,33 @@
 Jifty::API - Manages and allow reflection on the Jifty::Actions that
 make up a Jifty application's API
 
+=head1 SYNOPSIS
+
+ # Find the full name of an action
+ my $class = Jifty->api->qualify('SomeAction');
+
+ # 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 +47,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 +76,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 +251,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/template-declare/lib/Jifty/Action.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Action.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Action.pm	Thu Feb 22 05:23:13 2007
@@ -51,18 +51,20 @@
 
 =head1 COMMON METHODS
 
-These common methods are designed to 
+These common methods provide the basic guts for the action.
 
 =head2 new 
 
-Construct a new action.  Subclasses who need do custom initialization
-should start with:
+B<Do not call this directly>; always go through C<< Jifty->web->new_action >>! 
 
-    my $class = shift; my $self = $class->SUPER::new(@_)
+This method constructs a new action. Subclasses who need do custom initialization should start with:
 
-B<Do not call this yourself>; always go through C<<
-Jifty->web->new_action >>!  The arguments that this will be
-called with include:
+    my $class = shift;
+    my $self = $class->SUPER::new(@_)
+
+The arguments that this will be called with include:
+
+=head3 Arguments
 
 =over
 
@@ -1045,7 +1047,7 @@
 Used to report a warning during validation.  Inside a validator you
 should write:
 
-  return $self->validation_warning( $field => "warning");
+  return $self->validation_warning( $field => _("warning"));
 
 ..where C<$field> is the name of the argument which is at fault.
 
@@ -1085,7 +1087,7 @@
 Used to send an informational message to the user from the canonicalizer.  
 Inside a canonicalizer you can write:
 
-  $self->canonicalization_note( $field => "I changed $field for you");
+  $self->canonicalization_note( $field => _("I changed $field for you"));
 
 ..where C<$field> is the name of the argument which the canonicalizer is 
 processing
@@ -1108,8 +1110,108 @@
 Autogenerated Actions will always return true when this method is called. 
 "Regular" actions will return false.
 
+=head1 CUSTOMIZATION
+
+=head2 Canonicalization
+
+If you wish to have the data in a field normalized into a particular format (such as changing a date into YYYY-MM-DD format, adding commas to numbers, capitalizing words, or whatever you need) you can do so using a canonicalizer. 
+
+This is just a method titled C<canonicalize_FIELD> where C<FIELD> is the name of the field be normalized. Here is an example:
+
+  sub canonicalize_foo {
+      my ($self, $value) = @_;
+
+      # do something to canonicalize the value
+      my $normal_form = lc($value);
+      
+      return $normal_form;
+  }
+
+In this case, all values in the "foo" field will be changed into lower case.
+
+While doing this you might also want to call the L</canonicalization_note> to inform the client of the modification:
+
+  my $normal_form = lc($value);
+  $self->canonicalization_note( 
+      foo => _('Foo values are always in lowercase.'));
+
+If the "foo" field has "ajax canoncalizes" set in the action schema, then this process will be performed automatically as the form is being filled without reloading the page.
+
+=head2 Validation
+
+If a value must follow a certain format, you can provide a validation method for fields to make sure that no value enters the database until it is in a valid form.
+
+A validation method is one named C<validate_FIELD> where C<FIELD> is the name of the field being checked. Here is an example:
+
+  sub validate_foo {
+      my ($self, $value) = @_;
+
+      # Check for uppercase letters
+      if ($value =~ /\p{Lu}/) {
+          return $self->validation_warning(
+              foo => _("Foo cannot contain uppercase letters."));
+      }
+
+      # Check for -, *, +, and ?
+      elsif ($value =~ /[\-\*\+\?]/) {
+          return $self->validation_error(
+              foo => _("Foo cannot contain -, *, +, or ?."));
+      }
+
+      return 1;
+  }
+
+Here the "foo" field should not contain uppercase letters and must not contain the characters '-', '*', '+', or '?'. You can use L</validation_error> and L</validation_warning> to return the results of your validation to the user or simply return 1 to indicate a valid value.
+
+If you just have a list of valid values, you may want to use the C<valid_values> schema parameter to perform this task instead.
+
+=head2 Autocompletion
+
+Autocompletion provides a way of suggesting choices to the client based upon partial data entry. This doesn't necessarily force the client to use one of the choices given but gives hints in an application specific way.
+
+To create an autocompletion field, you implement a method named C<autocomplete_FIELD> where C<FIELD> is the field to autocomplete. This is generally done with fields rendered as 'Text'. Here is an example:
+
+  sub autocomplete_foo {
+      my ($self, $value) = @_;
+
+      # Be careful to validate your input! You don't want a malicious user
+      # hacking your system.
+      my ($match_value) = $value =~ /^(\w+)$/;
+
+      my $foos = MyApp::Model::FooCollection->new;
+      $foos->limit(
+          column   => 'name',
+          operator => 'LIKE',
+          value    => '%$value%',
+      );
+
+      return map { $_->name } @{ $foos->item_array_ref };
+  }
+
+In this example, the "foo" field is autocompleted from names matched from the C<MyApp::Model::Foo> table. The match, in this case, matches any substring found in the database. I could have matched any item that starts with the string, ends with the string, matches other fields than the one returned, etc. It's up to you to decide.
+
+Note also that I have untainted the value coming in to make sure a malicious user doesn't get anyway. You should always perform a check like this when data is coming in from an outside source.
+
+If you need a more complicated solution, you can return the autocompletion values as a list of hash references containing the keys C<value> and (optionally) C<label>:
+
+  return map { { value => $_->name, label => $_->label } }
+            @{ $foos->item_array_ref };
+
+In this case, the labels will be shown to the client, but the selected value would be returned to your application.
+
 =cut
 
 sub autogenerated {0}
 
+=head1 SEE ALSO
+
+L<Jifty>, L<Jifty::API>, L<Jifty::Action::Record>, L<Jifty::Result>, L<Jifty::Param::Schema>, L<Jifty::Manual::Actions>
+
+=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/template-declare/lib/Jifty/Action/Autocomplete.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Action/Autocomplete.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Action/Autocomplete.pm	Thu Feb 22 05:23:13 2007
@@ -3,7 +3,7 @@
 
 =head1 NAME
 
-Jifty::Action::Autocomplete
+Jifty::Action::Autocomplete - An action for making autocompletion suggestions
 
 =head1 DESCRIPTION
 
@@ -71,5 +71,16 @@
     return 1;
 }
 
+=head1 SEE ALSO
+
+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/template-declare/lib/Jifty/Action/Record.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Action/Record.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Action/Record.pm	Thu Feb 22 05:23:13 2007
@@ -11,8 +11,9 @@
 
 Represents a web-based action that is a create, update, or delete of a
 L<Jifty::Record> object.  This automatically populates the arguments
-method of L<Jifty::Action> so that you don't need to bother.  To
-actually use this class, you probably want to inherit from one of
+method of L<Jifty::Action> so that you don't need to bother.  
+
+To actually use this class, you probably want to inherit from one of
 L<Jifty::Action::Record::Create>, L<Jifty::Action::Record::Update>, or
 L<Jifty::Action::Record::Delete> and override the C<record_class>
 method.
@@ -392,7 +393,13 @@
 =head1 SEE ALSO
 
 L<Jifty::Action>, L<Jifty::Record>, L<Jifty::DBI::Record>,
-L<Jifty::Action::Record::Create>, L<Jifty::Action::Record::Update>
+L<Jifty::Action::Record::Create>, L<Jifty::Action::Record::Update>,
+L<Jifty::Action::Reocrd::Delete>
+
+=head1 LICENSE
+
+Jifty is Copyright 2005-2006 Best Practical Solutions, LLC.
+Jifty is distributed under the same terms as Perl itself.
 
 =cut
 

Modified: jifty/branches/template-declare/lib/Jifty/ClassLoader.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/ClassLoader.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/ClassLoader.pm	Thu Feb 22 05:23:13 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;
 }
@@ -295,6 +299,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/template-declare/lib/Jifty/Logger.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Logger.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Logger.pm	Thu Feb 22 05:23:13 2007
@@ -122,7 +122,6 @@
             # the aliasing so we can remove trailing newlines
             my @lines = map {"$_"} @_;
             $logger->warn(map {chomp; $_} @lines);
-            carp (map {chomp; $_} @lines);
         }
         elsif ($previous_warning_handler) {
             # Fallback to the old handler

Modified: jifty/branches/template-declare/lib/Jifty/Manual/Cookbook.pod
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Manual/Cookbook.pod	(original)
+++ jifty/branches/template-declare/lib/Jifty/Manual/Cookbook.pod	Thu Feb 22 05:23:13 2007
@@ -181,7 +181,7 @@
 dispatcher, to limit who is able to perform what actions -- see
 L<Jifty::API>.
 
-=head2 Run my Jifty app as fascgi in Apache/Lighttpd ?
+=head2 Run my Jifty app as fastcgi in Apache/Lighttpd ?
 
 Jifty provides a really simple way to run the application as a fastcgi
 server. The complete instructions and examples are in C<'jifty help
@@ -259,7 +259,7 @@
 
 If the form is generated by a C<Jifty::Action::Record>-based action
 (all those autogenerated CRUD actions), then this is all you need to
-do. And that is probably 90% of the case.  C<Jifty::Action::Record>
+do. And that is probably 90% of cases.  C<Jifty::Action::Record>
 would check if there is a method named like C<canonicalize_fieldname>
 when it is rendering form fields. If found, related javascript code is
 generated. You do not have to modify any code in your view. Jifty does

Modified: jifty/branches/template-declare/lib/Jifty/Manual/Tutorial.pod
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Manual/Tutorial.pod	(original)
+++ jifty/branches/template-declare/lib/Jifty/Manual/Tutorial.pod	Thu Feb 22 05:23:13 2007
@@ -30,11 +30,10 @@
 modules your system needs, and downloading and installing them all in
 one go.  Don't worry, it will ask you first before it makes any changes.
 
-On most systems you can Perl's bundled CPAN module to download
+On most systems you can use Perl's bundled CPAN module to download
 and install Jifty:
 
-  # perl -MCPAN -e'install Jifty'       # Unix-like systems
-  # perl -MCPAN -e"install Jifty"       # Win32 systems
+  # perl -MCPAN -e"install Jifty"
 
 If you've downloaded a C<.tar.gz> of Jifty, you can do a
 manual install:
@@ -55,9 +54,9 @@
 Once you have Jifty happily installed, you're ready to 
 create your first application. 
 
-Jifty is intentionally a bit minimalist. All you I<really>
-need to make an application go is a copy of the F<jifty> commandline
-tool (inside your new application's F<bin/> directory.  
+Jifty is intentionally a bit minimalist. All you I<really> need to make
+an application go is a copy of the F<jifty> commandline tool (inside
+your new application's F<bin/> directory.)
 
 Of course, it's often helpful to have a bit more structure around to
 help guide your work. Jifty comes with tools to build that structure for
@@ -240,7 +239,7 @@
 
 Ok. It's time to initialize MyWeblog's database. By default, Jifty sets up your
 application with the SQLite database engine.  If you'd rather use PostgreSQL or
-MySQL, you need to add some content to F<etc/jifty.yml>. (See C<Jifty::Config>
+MySQL, you need to add some content to F<etc/jifty.yml>. (See L<Jifty::Config>
 for a bit more information).
 
   # jifty schema --setup
@@ -488,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/template-declare/lib/Jifty/Manual/TutorialRest.pod
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/Manual/TutorialRest.pod	Thu Feb 22 05:23:13 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/template-declare/lib/Jifty/Plugin.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Plugin.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Plugin.pm	Thu Feb 22 05:23:13 2007
@@ -25,7 +25,7 @@
             the: constructor
 
 The dispatcher for a plugin should live in
-C<Jifty::Plugin::I<name>::Disptcher>; it is written like any other
+C<Jifty::Plugin::I<name>::Dispatcher>; 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.

Modified: jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Plugin/REST/Dispatcher.pm	Thu Feb 22 05:23:13 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 );
 }
 

Added: jifty/branches/template-declare/lib/Jifty/Script/Adopt.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/Script/Adopt.pm	Thu Feb 22 05:23:13 2007
@@ -0,0 +1,127 @@
+package Jifty::Script::Adopt;
+
+use warnings;
+use strict;
+
+use base qw/App::CLI::Command/;
+
+use File::Copy ();
+use File::Spec ();
+use File::Basename ();
+
+use Jifty::Util;
+
+=head1 NAME
+
+Jifty::Script::Adopt - localize a stock jifty component
+
+=head1 DESCRIPTION
+
+Creates directories and copies files for you, launching $ENV{EDITOR} if
+it is defined.
+
+=head2 options
+
+=over
+
+=item --ls PATH
+
+List the contents of the stock components path.
+
+=back
+
+=cut
+
+sub options {
+    (
+     'l|ls' => 'list',
+     't|tree' => 'tree',
+    )
+}
+
+=head2 run
+
+  jifty adopt web/templates/_elements/nav
+
+  jifty adopt --ls web/static/
+
+=cut
+
+sub run {
+    my $self = shift;
+    my (@args) = @_;
+
+    my $filename = shift(@args);
+    $filename ||= '';
+    my @parts = split(/[\/\\]/, $filename);
+
+    if($self->{list}) {
+        my $dir = File::Spec->catfile(Jifty::Util->share_root, @parts);
+        unless(-d $dir) {
+            warn "no such directory $dir";
+        }
+        opendir(my $dh, $dir) or die;
+        my @files = sort(grep(! /^\.\.?$/, readdir($dh)));
+        my @dirs;
+        # sort directories first
+        for(my $i = 0; $i < @files; $i++) { # List::MoreUtil::part ?
+            if(-d File::Spec->catfile($dir, $files[$i])) {
+                push(@dirs, splice(@files, $i, 1) . '/');
+                $i--;
+            }
+        }
+        print join("\n", @dirs, @files, '');
+
+        exit;
+    }
+    elsif($self->{tree}) {
+        # Just punting here, maybe don't need this usage except when you
+        # have no tree command?  Oh, the irony.
+        my $dir = File::Spec->catfile(Jifty::Util->share_root, @parts);
+        unless(-d $dir) {
+            warn "no such directory $dir";
+        }
+
+        system('tree', $dir) and die "oops $!";
+
+        exit;
+    }
+
+    unless($filename) {
+        die "usage: jifty adopt <filename>\n";
+    }
+
+    my $share = 'share';
+    unless(-d $share) {
+        die "must be run from your app directory\n";
+    }
+
+    my $source = File::Spec->catfile(Jifty::Util->share_root, @parts);
+    (-e $source) or die "no such source file '$source'\n";
+
+    my $dest = File::Spec->catfile($share, @parts);
+
+    unless(-d File::Basename::dirname($dest)) {
+        Jifty::Util->make_path($dest);
+    }
+
+    if(-e $dest) {
+        print "$dest exists, overwrite? [n]\n";
+        chomp(my $ans = <STDIN>); $ans ||= 'n';
+        exit 1 unless(lc($ans) eq 'y');
+    }
+    File::Copy::copy($source, $dest) or die "copy failed $!";
+    chmod(0644, $dest) or die "cannot change mode $!";
+
+    # TODO put an option on that?
+    if($ENV{EDITOR}) {
+        fork and exit;
+        exec("$ENV{EDITOR} $dest");
+    }
+
+} # end run
+
+# original author:  Eric Wilhelm
+
+1;
+# vim:ts=4:sw=4:et:sta

Added: jifty/branches/template-declare/lib/Jifty/Script/Env.pm
==============================================================================
--- (empty file)
+++ jifty/branches/template-declare/lib/Jifty/Script/Env.pm	Thu Feb 22 05:23:13 2007
@@ -0,0 +1,92 @@
+package Jifty::Script::Env;
+
+use warnings;
+use strict;
+
+use base qw/App::CLI::Command/;
+
+use Scalar::Util ();
+
+use Jifty::Config;
+use Jifty::YAML;
+
+=head1 NAME
+
+Jifty::Script::Env - access the Jifty environment
+
+=head1 DESCRIPTION
+
+Loads Jifty and your configuration, allowing you to verify and examine
+your setup.
+
+=head2 run
+
+  jifty env <Class> <method> [arguments]
+
+Loads Jifty::Class and calls method on it, providing shortcuts for
+things like:
+
+  perl -MJifty::Util -e 'print Jifty::Util->share_root, "\n";'
+
+The class and method can be combined with a '->' But, unquoted '>' is a
+redirect so simply use the '-' or '.' characters.
+
+  jifty env  Util share_root
+  jifty env 'Util->share_root'
+  jifty env  Util.share_root
+
+You may chain accessors.  A leading dot also means the class is Jifty.
+
+  jifty env Jifty.config.framework ApplicationName
+  jifty env .config.framework ApplicationName
+
+With no arguments, acts as 'C<jifty env Jifty.config.stash>'.
+
+=cut
+
+sub run {
+    my $self = shift;
+    my (@args) = @_;
+
+    Jifty->new();
+
+    unless(@args) {
+        return($self->run('Jifty.config.stash'));
+    }
+
+    my ($class, $method, @and) = split(/(?:->?|\.)/, shift(@args));
+    $class ||= 'Jifty';
+    $method ||= shift(@args);
+
+    my @ans;
+
+    # enable Jifty.config.stash usage
+    unless($class eq 'Jifty') {
+        $class = 'Jifty::' . $class;
+        eval("require $class") or die $@;
+    }
+
+    # walk down the chain of methods
+    unshift(@and, $method);
+    $method = pop(@and);
+    while(my $attrib = shift(@and)) {
+        $class = $class->$attrib;
+    }
+
+    @ans = $class->$method(@args);
+
+    # if something in the answer is a reference, just dump
+    if(grep({Scalar::Util::reftype($_)} @ans)) {
+        print Jifty::YAML::Dump(\@ans);
+    }
+    else {
+        print join("\n", @ans, '');
+    }
+
+
+} # end run
+
+# original author:  Eric Wilhelm
+
+1;
+# vim:ts=4:sw=4:et:sta

Modified: jifty/branches/template-declare/lib/Jifty/Script/Schema.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Script/Schema.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Script/Schema.pm	Thu Feb 22 05:23:13 2007
@@ -419,6 +419,7 @@
 }
 
 sub _print_upgrades {
+    my $self     = shift;
     my %UPGRADES = (@_);
     for (
         map  { @{ $UPGRADES{$_} } }

Modified: jifty/branches/template-declare/lib/Jifty/Test.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Test.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Test.pm	Thu Feb 22 05:23:13 2007
@@ -142,14 +142,11 @@
 
     Jifty->new( no_handle => 1 );
 
-    Log::Log4perl->get_logger("SchemaTool")->less_logging(3);
     my $schema = Jifty::Script::Schema->new;
     $schema->{drop_database} =
       $schema->{create_database} =
         $schema->{create_all_tables} = 1;
     $schema->run;
-    Jifty->handle(undef); # get rid of the handle the schema tool created.
-    Log::Log4perl->get_logger("SchemaTool")->more_logging(3);
 
     Jifty->new();
     $class->setup_mailbox;
@@ -192,6 +189,7 @@
             },
             Mailer => 'Jifty::Test',
             MailerArgs => [],
+            LogLevel => 'WARN'
         }
     };
 }
@@ -222,7 +220,6 @@
         unshift @Jifty::Server::ISA, 'Test::HTTP::Server::Simple';
     }
 
-    Log::Log4perl->get_logger("Jifty::Server")->less_logging(3);
     my $server = Jifty::Server->new;
 
     return $server;
@@ -403,15 +400,17 @@
         # 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->config and Jifty->bus;
+
         # Remove testing db
         if (Jifty->handle) {
             Jifty->handle->disconnect();
-            Log::Log4perl->get_logger("SchemaTool")->less_logging(3);
             my $schema = Jifty::Script::Schema->new;
             $schema->{drop_database} = 1;
             $schema->run;
-            Jifty->handle(undef); # get rid of the handle the schema tool created.
-            Log::Log4perl->get_logger("SchemaTool")->more_logging(3);
         }
 
         # Unlink test files

Modified: jifty/branches/template-declare/lib/Jifty/Web.pm
==============================================================================
--- jifty/branches/template-declare/lib/Jifty/Web.pm	(original)
+++ jifty/branches/template-declare/lib/Jifty/Web.pm	Thu Feb 22 05:23:13 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
@@ -401,25 +401,39 @@
 
 =head3 new_action class => CLASS, moniker => MONIKER, order => ORDER, arguments => PARAMHASH
 
-Creates a new action (an instance of a subclass of L<Jifty::Action>)
+Creates a new action (an instance of a subclass of L<Jifty::Action>). The named arguments passed to this method are passed on to the C<new> method of the action named in C<CLASS>.
+
+=head3 Arguments
+
+=over
+
+=item class 
 
 C<CLASS> is L<qualified|Jifty::API/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.
 
+=item moniker
+
 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
 used to tie together arguments that relate to the same action.
 
+=item order
+
 C<ORDER> defines the order in which the action is run, with lower
 numerical values running first.
 
+=item arguments
+
 C<ARGUMENTS> are passed to the L<Jifty::Action/new> method.  In
 addition, if the current request (C<< $self->request >>) contains an
 action with a matching moniker, any arguments that are in that
 requested action but not in the C<PARAMHASH> list are set.  This
 implements "sticky fields".
 
+=back
+
 As a contrast to L<Jifty::Web::Form/add_action>, this does not add the
 action to the current form -- instead, the first form field to be
 rendered will automatically register the action in the current form
@@ -1012,6 +1026,7 @@
 
         __PACKAGE__->cached_css( $css );
         __PACKAGE__->cached_css_digest( md5_hex( $css ) );
+		__PACKAGE__->cached_css_time( time );
     }
 }
 
@@ -1133,6 +1148,7 @@
 
         __PACKAGE__->cached_javascript( $js );
         __PACKAGE__->cached_javascript_digest( md5_hex( $js ) );
+        __PACKAGE__->cached_javascript_time( time );
     }
 }
 


More information about the Jifty-commit mailing list