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
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.