Author: spadkins
Date: Mon Sep  4 11:25:18 2006
New Revision: 6844

Modified:
   p5ee/trunk/App-Context/CHANGES
   p5ee/trunk/App-Context/MANIFEST
   p5ee/trunk/App-Context/Makefile.PL
   p5ee/trunk/App-Context/lib/App/installguide/hosted.pod
   p5ee/trunk/App-Context/lib/App/quickstart.pod

Log:
freeze for 0.964

Modified: p5ee/trunk/App-Context/CHANGES
==============================================================================
--- p5ee/trunk/App-Context/CHANGES      (original)
+++ p5ee/trunk/App-Context/CHANGES      Mon Sep  4 11:25:18 2006
@@ -2,6 +2,11 @@
 # CHANGE LOG
 #########################################
 
+VERSION 0.964
+ x mostly documentation updates
+ x moved Apache::Framework::App to Apache::App
+ x trying to improve Makefile.PL to install things in the right place (app in 
cgi-bin)
+
 VERSION 0.963
  x App->use() now detects entries in the symbol table to inhibit an attempt to 
load the module
  x enhance App::Service::substitute() to understand default syntax (i.e. 
{username:NULL})

Modified: p5ee/trunk/App-Context/MANIFEST
==============================================================================
--- p5ee/trunk/App-Context/MANIFEST     (original)
+++ p5ee/trunk/App-Context/MANIFEST     Mon Sep  4 11:25:18 2006
@@ -6,7 +6,7 @@
 bin/app
 bin/app-apache
 bin/call
-lib/Apache/Framework/App.pm
+lib/Apache/App.pm
 lib/App.pm
 lib/App/Authentication.pm
 lib/App/Authorization.pm

Modified: p5ee/trunk/App-Context/Makefile.PL
==============================================================================
--- p5ee/trunk/App-Context/Makefile.PL  (original)
+++ p5ee/trunk/App-Context/Makefile.PL  Mon Sep  4 11:25:18 2006
@@ -16,7 +16,7 @@
 %opts = (
     'NAME'        => 'App-Context',
     'DISTNAME'    => 'App-Context',
-    'VERSION'     => '0.963',
+    'VERSION'     => '0.964',
     'EXE_FILES'   => [ @programs ],
     'PREREQ_PM'   => {
         'App::Options'             => "0.01",  # for loading a startup 
configuration file
@@ -42,7 +42,7 @@
     return <<EOF;
 
 install ::
-       @\$(MOD_INSTALL) cgi-bin "\$(PREFIX)/cgi-bin"
+       @\$(CP) "\$(PREFIX)/bin/app" "\$(PREFIX)/cgi-bin/app"
 
 EOF
 }

Modified: p5ee/trunk/App-Context/lib/App/installguide/hosted.pod
==============================================================================
--- p5ee/trunk/App-Context/lib/App/installguide/hosted.pod      (original)
+++ p5ee/trunk/App-Context/lib/App/installguide/hosted.pod      Mon Sep  4 
11:25:18 2006
@@ -99,7 +99,7 @@
 additional tests are performed that are not destructive to the data.
 
 When it passes these final tests, it ceases to be a test environment
-any long, and it becomes the latest production environment.
+any longer, and it becomes the latest production environment.
 A symbolic link is changed in order to point the "production" web
 application to the latest numbered version.
 

Modified: p5ee/trunk/App-Context/lib/App/quickstart.pod
==============================================================================
--- p5ee/trunk/App-Context/lib/App/quickstart.pod       (original)
+++ p5ee/trunk/App-Context/lib/App/quickstart.pod       Mon Sep  4 11:25:18 2006
@@ -22,7 +22,7 @@
 I got started building the App::Context framework a while ago.
 The documentation is very limited.  This is an effort to bring it all together.
 This list shows how all of the documentation fits together and in what state
-it is [???=unknown,RED=incomplete,YEL=ok,GRN=complete].
+it is.
 
 =head2 PURE DOCUMENTATION
 
@@ -86,9 +86,9 @@
 
 =item *  +-- L<App::Context::Server> - A program running in a multi-process 
server context.
 
-=item *       +-- L<App::Context::ClusterController> - Running in a multi-node 
cluster context.
+=item *  =====+-- L<App::Context::ClusterController> - Running in a multi-node 
cluster context.
 
-=item *       +-- L<App::Context::ClusterNode> - Running on a single node of a 
cluster.
+=item *  =====+-- L<App::Context::ClusterNode> - Running on a single node of a 
cluster.
 
 =item *  +-- L<App::Context::NetServer> - Another flavor of server context 
(not yet implemented).
 
@@ -112,27 +112,27 @@
 
 =item *  +-- L<App::Conf>
 
-=item *       +-- L<App::Conf::File>
+=item *  =====+-- L<App::Conf::File>
 
 =item * L<App::Service>
 
 =item *  +-- L<App::Serializer>
 
-=item *       +-- L<App::Serializer::Properties>
+=item *  =====+-- L<App::Serializer::Properties>
 
-=item *       +-- L<App::Serializer::Ini>
+=item *  =====+-- L<App::Serializer::Ini>
 
-=item *       +-- L<App::Serializer::Perl>
+=item *  =====+-- L<App::Serializer::Perl>
 
-=item *       +-- L<App::Serializer::Xml>
+=item *  =====+-- L<App::Serializer::Xml>
 
-=item *       +-- L<App::Serializer::Yaml>
+=item *  =====+-- L<App::Serializer::Yaml>
 
-=item *       +-- L<App::Serializer::OneLine>
+=item *  =====+-- L<App::Serializer::OneLine>
 
-=item *       +-- L<App::Serializer::TextArray>
+=item *  =====+-- L<App::Serializer::TextArray>
 
-=item *       +-- L<App::Serializer::Storable>
+=item *  =====+-- L<App::Serializer::Storable>
 
 =item *  +-- L<App::SessionObject>
 
@@ -148,13 +148,13 @@
 
 =item *  +-- L<App::CallDispatcher>
 
-=item *       +-- L<App::CallDispatcher::HTTPSimple>
+=item *  =====+-- L<App::CallDispatcher::HTTPSimple>
 
 =item *  +-- L<App::ResourceLocker>
 
-=item *       +-- L<App::ResourceLocker::IPCSemaphore>
+=item *  =====+-- L<App::ResourceLocker::IPCSemaphore>
 
-=item *       +-- L<App::ResourceLocker::IPCLocker>
+=item *  =====+-- L<App::ResourceLocker::IPCLocker>
 
 =item * L<Apache::Framework::App>
 
@@ -174,11 +174,12 @@
   cpan> exit
 
 If it's not this easy, I need to work on making it easier.
+Please let me know ([EMAIL PROTECTED]) and I'll fix it.
 
-=head1 QUICK START TO COMMAND LINE APPLICATIONS
+=head1 QUICK START TO COMMAND LINE DATABASE PROGRAMS
 
-At the moment, the biggest advantage of using the App::Context Framework for
-programs which are not web applications is in developing a suite of database 
programs
+One of the big advantages of using the App::Context Framework for
+command-line programs is in developing a suite of database programs
 (particularly for a MySQL database).
 
 Choose a root directory for your system, assigning it to the PREFIX variable.
@@ -202,6 +203,7 @@
       db => {
         class => "App::Repository::MySQL",
       },
+    },
   };
 
 vi $PREFIX/bin/prog
@@ -213,18 +215,19 @@
       option => {
           dbhost => {
               description => "database host",
-              default => "localhost",
+              required => 1,
           },
           dbname => {
               description => "database name",
-              default => "test",
+              required => 1,
           },
           dbuser => {
               description => "database user",
-              default => "scott",
+              required => 1,
           },
           dbpass => {
               description => "database password",
+              required => 1,
           },
       },
   );
@@ -239,5 +242,183 @@
       # my $age = $db->get("customer", { customer_id => 45 }, "age");
   }
 
+The best parts about writing database programs with App::Repository in the 
App::Context framework
+is that all of your programs get automatic SQL debugging, timing, and 
explaining.
+
+  prog --debug_sql      # show all SQL statements and their timings
+  prog --debug_sql=2    # show all SQL statements and their timings and all 
rows returned from selects
+  prog --debug_sql --explain_sql   # show SQL statements and explain them
+
+See L<App::Options>, L<App::Repository::quickstart>, and 
L<App::Repository::devguide> for more info on this.
+
+=head1 QUICK START TO OBJECT-ORIENTED COMMAND LINE PROGRAMS
+
+Another of the big advantages of using the App::Context Framework for
+command line programs is in developing programs which use and operate on 
Business Objects
+(the object-oriented analysis concept, not the commercial reporting software).
+
+Many "object-oriented" programs are written without ever using a true Business 
Object.
+The reason for this is that the issues of maintaining object state are so 
tricky that
+people rarely get around to using Business Objects in their command line 
programs.
+
+Business Objects come in two types: Business Entity Objects and Business 
Process Objects.
+Business Entity Objects represent things in the business realm: Customer, 
Store, Employee,
+Product, PurchaseOrder.  Business Process Objects are those objects that model 
business
+processes.
+
+The following abstractions exist in order to subclass for your business 
objects.
+As you get into using them, you will learn when to use which one, and you will 
find that
+there is of course more than one way to do it.
+
+=over
+
+=item * L<App::RepositoryObject> - An object whose state is shared across 
multiple sessions as a single row in a database (repository).  These are 
generally the Business Entity Objects.
+
+=item * L<App::SessionObject> - A named object whose state is maintained 
throughout the session.  These are generally the Business Process Objects.
+
+=item * L<App::SessionObject::RepositoryObjectSet> - A named object with 
session state and shared state consisting of a set of rows from a single table 
in a database (repository).
+
+=item * L<App::SessionObject::RepositoryObjectDomain> - A named object with 
session state and shared state consisting of a set of related sets of rows from 
multiple tables in a database (repository).
+
+=back
+
+The big advantage of writing object-oriented programs is for code reuse.
+Whenever someone whips up a perl script to do some processing on the system, 
that
+programming logic is unavailable for use in any other program (such as an 
interactive
+web application).
+
+One way to cure this is to have an L<App::SessionObject> where all of the logic
+for a command line program is implemented as a single method call.
+
+The choice of how many SessionObjects to use for all of the logic is a matter 
of
+preference.  You could put all this logic on one kitchen-sink-style 
SessionObject
+or you could group the functions into like types and put them on different
+SessionObjects.  You may wish to have these SessionObject take on the 
responsibilities
+of different "roles" played by members of the organization or tasks performed 
by
+different departments.  These can easily be reorganized later.  The important
+thing is to get the logic out of the command line programs and into objects
+so that the logic can be reused later.
+
+When viewed in this light, the command line program only becomes a user 
interface
+for a method call provided by a SessionObject.  The easy way to start is just 
to
+pass the %App::options hash (shown below).  However, in many cases the program
+will do a few more steps to make a more natural call to the SessionObject's 
method.
+
+=head2 EXAMPLES
+
+vi $PREFIX/etc/app.pl
+
+  $conf = {
+    Repository => {
+      default => { alias => "db", },
+      db => {
+        class => "App::Repository::MySQL",
+      },
+    },
+    SessionObject => {
+      credit_manager => {
+        class => "App::SessionObject::CreditManager",
+      },
+    },
+  };
+
+vi $PREFIX/lib/App/SessionObject/CreditManager.pm
+
+  use App;
+  use App::Repository;
+  package App::SessionObject::CreditManager;
+  $VERSION = "0.50";
+  @ISA = ("App::SessionObject");
+  use strict;
+
+  sub check_customer_credit {
+      my ($self, $options) = @_;
+      my $customer_id = $options->{customer_id} || die "No customer ID 
provided";
+      my $context = $self->{context};   # every Service has a reference to its 
Context
+      my $db = $context->repository();  # get the default repository from the 
Context
+
+      # There must be a table named customer with primary key of "customer_id" 
and
+      # at least the columns "approval_ind char(1)", "denial_msg varchar(255)",
+      # "first_name varchar(255)", and "last_name varchar(255)".
+      my $customer = $db->get_object("customer", $customer_id);  # returns an 
App::RepositoryObject
+
+      my ($approval_ind, $denial_msg);
+
+      # ... do some processing ...
+      if ($customer->{first_name} eq "Bill" && $customer->{last_name} eq 
"Gates") {
+          $approval_ind = "N";
+          $denial_msg = "Too rich";
+      }
+      else {
+          $approval_ind = "N";
+      }
+
+      if ($approval_ind eq "Y") {
+          $customer->set("approval_ind",$approval_ind);
+          print "Customer $customer_id approved.\n";
+      }
+      else {
+          
$customer->set(["approval_ind","denial_msg"],[$approval_ind,$denial_msg]);
+          print "Customer $customer_id denied: $denial_msg.\n";
+      }
+  }
+
+  1;
+
+vi $PREFIX/bin/check_customer_credit
+
+  #!/usr/bin/perl -w
+  # NOTE: All of this code is about the User Interface to the logic.
+  #       The logic itself is hidden away in 
"App::SessionObject::CreditManager".
+  use strict;
+  use App::Options (
+      options => [qw(dbhost dbname dbuser dbpass customer_id)],
+      option => {
+          dbhost => {
+              description => "database host",
+              required => 1,
+          },
+          dbname => {
+              description => "database name",
+              required => 1,
+          },
+          dbuser => {
+              description => "database user",
+              required => 1,
+          },
+          dbpass => {
+              description => "database password",
+              required => 1,
+          },
+          customer_id => {
+              description => "the ID of the customer to check",
+              required => 1,
+              type => "integer",
+          },
+      },
+  );
+  use App;
+  use App::Repository;
+  {
+      my $context = $App->context();
+      my $db = $context->repository();
+      my $credit_manager = $context->session_object("credit_manager");
+      $credit_manager->check_customer_credit(\%App::options);
+  }
+
+=head1 QUICK START TO WEB PROGRAMS
+
+A web program is simply choosing a widget to display on the browser.
+Widgets may be arbitrarily complex, containing other widgets, and so taking
+the form of an entire web application.  Since any widget can be viewed in a
+browser, additional widgets may be developed and debugged before they are
+integrated into a larger applications.
+
+Widgets (L<App::Widget>) are simply SessionObject's with an html() method
+which allows them to be viewed nicely by a web browser.  They maintain their
+state throughout the duration of the session.
+
+
+
 =cut
 

Reply via email to