From: Ben Hutchings Date: Tue, 4 Nov 2008 03:28:37 +0000 (+0000) Subject: Maypole-2.13.tar.gz X-Git-Tag: 2.13 X-Git-Url: https://git.decadent.org.uk/gitweb/?a=commitdiff_plain;h=213b0e139beb727fa7ef1ba757b41a00cf8437f7;p=maypole.git Maypole-2.13.tar.gz --- diff --git a/META.yml b/META.yml index 2a9b00d..17c5cfb 100644 --- a/META.yml +++ b/META.yml @@ -1,7 +1,7 @@ # http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Maypole -version: 2.11_pre5 +version: 2.13 version_from: lib/Maypole.pm installdirs: site requires: @@ -16,19 +16,16 @@ requires: Class::DBI::Pager: 0 Class::DBI::Plugin::RetrieveAll: 0 Class::DBI::Plugin::Type: 0 - Class::DBI::SQLite: 0.08 Digest::MD5: 0 File::MMagic::XS: 0.08 - HTML::Element: 0 + HTML::Tree: 0 HTTP::Body: 0.5 - HTTP::Headers: 1.59 Template: 0 Template::Plugin::Class: 0 Test::MockModule: 0 UNIVERSAL::moniker: 0 UNIVERSAL::require: 0 URI: 0 - URI::QueryParam: 0 distribution_type: module -generated_by: ExtUtils::MakeMaker version 6.17 +generated_by: ExtUtils::MakeMaker version 6.30 diff --git a/examples/fancy_example/templates/factory/addnew b/examples/fancy_example/templates/factory/addnew deleted file mode 100644 index 2334496..0000000 --- a/examples/fancy_example/templates/factory/addnew +++ /dev/null @@ -1,41 +0,0 @@ -[%# - -=head1 addnew - -This is the interface to adding a new instance of an object. (or a new -row in the database, if you want to look at it that way) It displays a -form containing a list of HTML components for each of the columns in the -table. - -=cut - -#%] - -
-
-
-Add a new [% classmetadata.moniker %] - [% FOR col = classmetadata.columns %] - [% NEXT IF col == "id" %] - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] - - [% END; %] - - -
-
-
diff --git a/examples/fancy_example/templates/factory/edit b/examples/fancy_example/templates/factory/edit deleted file mode 100644 index cf88311..0000000 --- a/examples/fancy_example/templates/factory/edit +++ /dev/null @@ -1,70 +0,0 @@ -[%# - -=head1 edit - -This is the edit page. It edits the passed-in object, by displaying a -form similar to L but with the current values filled in. - -=cut - -#%] -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] - -[% IF request.action == 'edit' %] -[% INCLUDE navbar %] -[% END %] - -[% IF object %] -
Edit a [% classmetadata.moniker %]
-
-
-Edit [% object.name %] - [% FOR col = classmetadata.columns; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - '"; - IF errors.$col; - ''; errors.$col;''; - END; - END %] - - -
- -[% ELSE %] - -
-
-
-Add a new [% classmetadata.moniker %] - [% FOR col = classmetadata.columns %] - [% NEXT IF col == "id" %] - - [% IF errors.$col %] - [% errors.$col | html %] - [% END %] - - [% END; %] - - -
-
-
- -[% END %] -[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/footer b/examples/fancy_example/templates/factory/footer deleted file mode 100644 index 1b8ae55..0000000 --- a/examples/fancy_example/templates/factory/footer +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/examples/fancy_example/templates/factory/frontpage b/examples/fancy_example/templates/factory/frontpage deleted file mode 100644 index ac47269..0000000 --- a/examples/fancy_example/templates/factory/frontpage +++ /dev/null @@ -1,27 +0,0 @@ -[%# - -=head1 frontpage - -This is the frontpage for your Maypole application. -It shows a list of all tables it is allowed to display. - -=cut - -#%] -[% INCLUDE header %] -
- [% config.application_name || "A poorly configured Maypole application" %] -
-
- -
- -[% INCLUDE maypole %] - -[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/header b/examples/fancy_example/templates/factory/header deleted file mode 100644 index ba0b190..0000000 --- a/examples/fancy_example/templates/factory/header +++ /dev/null @@ -1,16 +0,0 @@ - - - - - [% - title || config.application_name || - "A poorly configured Maypole application" - %] - - - - - - -
diff --git a/examples/fancy_example/templates/factory/list b/examples/fancy_example/templates/factory/list deleted file mode 100644 index 9abbc01..0000000 --- a/examples/fancy_example/templates/factory/list +++ /dev/null @@ -1,63 +0,0 @@ -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] -[% IF search %] -
Search results
-[% ELSE %] -
Listing of all [% classmetadata.plural %]
-[% END %] -[% INCLUDE navbar %] -
- - - [% FOR col = classmetadata.list_columns.list; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - ""; - END %] - - - [% SET count = 0; - FOR item = objects; - SET count = count + 1; - ""; - display_line(item); - ""; - END %] -
"; - SET additional = "?order=" _ col; - SET additional = additional _ "&page=" _ pager.current_page - IF pager; - SET additional = additional _ "&o2=desc" - IF col == request.params.order and request.params.o2 != "desc"; - SET action = "list"; - FOR name = classmetadata.columns.list; - IF request.query.$name; - SET additional = - additional _ "&" _ name _ "=" _ - request.params.$name; - SET action = "search"; - END; - END; - USE model_obj = Class request.model_class; - IF model_obj.find_column(col); - link(classmetadata.table, action, additional, - classmetadata.colnames.$col); - IF col == request.params.order; - IF request.params.o2 != "desc"; - "↓"; - ELSE; - "↑"; - END; - END; - ELSE; - classmetadata.colnames.$col || col FILTER ucfirst; - END; - "Actions
- -[% INCLUDE pager %] -[% INCLUDE addnew %] -[% INCLUDE search_form %] -
-[% INCLUDE footer %] diff --git a/examples/fancy_example/templates/factory/login b/examples/fancy_example/templates/factory/login deleted file mode 100644 index af08e5b..0000000 --- a/examples/fancy_example/templates/factory/login +++ /dev/null @@ -1,27 +0,0 @@ -[% PROCESS macros %] -[% INCLUDE header %] -[% INCLUDE title %] -[% user_field = config.auth.user_field || "user" %] - -
You need to log in
- -
- [% IF login_error %] -
[% login_error | html %]
- [% END %] -
-
- Login - - - -
-
-
- diff --git a/examples/fancy_example/templates/factory/macros b/examples/fancy_example/templates/factory/macros deleted file mode 100644 index fc75d09..0000000 --- a/examples/fancy_example/templates/factory/macros +++ /dev/null @@ -1,185 +0,0 @@ -[%# - -=head1 MACROS - -These are some default macros which are used by various templates in the -system. - -=head2 link - -This creates an to a command in the Apache::MVC system by -catenating the base URL, table, command, and any arguments. - -#%] -[% -MACRO link(table, command, additional, label) BLOCK; - SET lnk = base _ "/" _ table _ "/" _ command _ "/" _ additional; - lnk = lnk | uri | html; - ''; - label | html; - ""; -END; -%] - -[%# - -=head2 maybe_link_view - -C takes something returned from the database - either -some ordinary data, or an object in a related class expanded by a -has-a relationship. If it is an object, it constructs a link to the view -command for that object. Otherwise, it just displays the data. - -#%] - -[% -MACRO maybe_link_view(object) BLOCK; - IF object.isa('Maypole::Model::Base'); - link(object.table, "view", object.id.join('/'), object); - ELSE; - object | html ; - END; -END; -%] - -[%# - -=head2 display_line - -C is used in the list template to display a row from the -database, by iterating over the columns and displaying the data for each -column. It misses out the C column by default, and magically -URLifies columns called C. This may be considered too much magic -for some. - -#%] -[% MACRO display_line(item) BLOCK; - FOR col = classmetadata.list_columns; - NEXT IF col == "id" OR col == classmetadata.table _ "_id"; - col_obj = item.find_column(col); - ""; - IF col == "url" AND item.url; - ' '; item.url; ''; - ELSIF col == classmetadata.stringify_column; - maybe_link_view(item); - ELSIF col_obj; # its a real column - accessor = item.accessor_name_for(col_obj) || - item.accessor_name(col_obj); # deprecated in cdbi - maybe_link_view(item.$accessor); - ELSE; - item.$col; - END; - - ""; - END; - ''; - button(item, "edit"); - button(item, "delete"); - ""; -END %] -[%# - -=head2 button - -This is a generic button, which performs an action on an object. - -=cut - -#%] -[% MACRO button(obj, action) BLOCK; %] -[% IF obj.is_public(action) %] -
-
-[% END %] -[% END %] -[%# - -=head2 view_related - -This takes an object, and looks up the C; this should -give a list of accessors that can be called to get a list of related -objects. It then displays a title for that accessor, (i.e. "Beers" for a -brewery) calls the accesor, and displays a list of the results. - -=cut - -#%] -[% -MACRO view_related(object) BLOCK; - FOR accessor = classmetadata.related_accessors.list; - "
"; accessor | ucfirst; "
\n"; - "
    "; - FOR thing = object.$accessor; - "
  • "; maybe_link_view(thing); "
  • \n"; - END; - "
"; - END; -END; - -MACRO test_xxxx(myblock) BLOCK; - FOR col = classmetadata.columns; - NEXT IF col == "id"; - myblock; - END; -END; -%] -[%# - -=head2 view_item - -This takes an object and and displays its properties in a table. - -=cut - -#%] -[% MACRO view_item(item) BLOCK; %] - [% SET string = classmetadata.stringify_column %] -
[% item.$string | html %]
- [% INCLUDE navbar %] - - - - - - [% FOR col = classmetadata.columns.list; - NEXT IF col == "id" OR col == string OR col == classmetadata.table _ "_id";; - NEXT UNLESS item.$col; - %] -[%# - -=for doc - -It gets the displayable form of a column's name from the hash returned -from the C method: - -#%] - - - - - [% END; %] -
[% classmetadata.colnames.$string %][% item.$string | html %]
[% classmetadata.colnames.$col || - col | ucfirst | replace('_',' '); %] - [% IF col == "url" && item.url; # Possibly too much magic. - ' '; item.url; ''; - ELSIF item.$col.size > 1; # has_many column - FOR thing IN item.$col; - maybe_link_view(thing);", "; - END; - - ELSE; - maybe_link_view(item.$col); - END; %] -[%# - -This tests whether or not the returned value is an object, and if so, -creates a link to a page viewing that object; if not, it just displays -the text as normal. The object is linked using its stringified name; -by default this calls the C method, or returns the object's ID -if there is no C method or other stringification method defined. - -=cut - -#%] -
-[% END %] diff --git a/examples/fancy_example/templates/factory/maypole b/examples/fancy_example/templates/factory/maypole deleted file mode 100644 index 7ab2744..0000000 --- a/examples/fancy_example/templates/factory/maypole +++ /dev/null @@ -1,7 +0,0 @@ - -
 
-
 
-
 
-
 
-
 
- diff --git a/examples/fancy_example/templates/factory/maypole.css b/examples/fancy_example/templates/factory/maypole.css deleted file mode 100644 index d63be55..0000000 --- a/examples/fancy_example/templates/factory/maypole.css +++ /dev/null @@ -1,381 +0,0 @@ -html { - padding-right: 0px; - padding-left: 0px; - padding-bottom: 0px; - margin: 0px; - padding-top: 0px -} -body { - font-family: sans-serif; - padding-right: 0px; - padding-left: 0px; - padding-bottom: 0px; - margin: 0px; padding-top: 0px; - background-color: #fff; -} -#frontpage_list { - position: absolute; - z-index: 5; - padding: 0px 100px 0px 0px; - margin:0 0.5%; - margin-bottom:1em; - margin-top: 1em; - background-color: #fff; -} - -#frontpage_list a:hover { - background-color: #d0d8e4; -} - -#frontpage_list ul { - list-style-type: square; -} - -.content { - padding: 12px; - margin-top: 1px; - margin-bottom:0px; - margin-left: 15px; - margin-right: 15px; - border-color: #000000; - border-top: 0px; - border-bottom: 0px; - border-left: 1px; - border-right: 1px; -} - -A { - text-decoration: none; - color:#225 -} -A:hover { - text-decoration: underline; - color:#222 -} - -#title { - z-index: 6; - width: 100%; - height: 18px; - margin-top: 10px; - font-size: 90%; - border-bottom: 1px solid #ddf; - text-align: left; -} - -#subtitle { - postion: absolute; - z-index: 6; - padding: 10px; - margin-top: 2em; - height: 18px; - text-align: left; - background-color: #fff; -} - -input[type=text] { - height: 16px; - width: 136px; - font-family: sans-serif; - font-size: 11px; - color: #2E415A; - padding: 0px; - margin-bottom: 5px; -} - -input[type=submit] { - height: 18px; - width: 60px; - font-family: sans-serif; - font-size: 11px; - border: 1px outset; - background-color: #fff; - padding: 0px 0px 2px 0px; - margin-bottom: 5px; -} - -input:hover[type=submit] { - color: #fff; - background-color: #7d95b5; -} - -textarea { - width: 136px; - font-family: sans-serif; - font-size: 11px; - color: #2E415A; - padding: 0px; - margin-bottom: 5px; -} - -select { - height: 16px; - width: 140px; - font-family: sans-serif; - font-size: 12px; - color: #202020; - padding: 0px; - margin-bottom: 5px; -} - -.deco1 { - font-size: 0px; - z-index:1; - border:0px; - border-style:solid; - border-color:#4d6d99; - background-color:#4d6d99; -} - -.deco2 { - z-index:2; - border:0px; - border-style:solid; - border-color:#627ea5; - background-color:#627ea5; -} - - -.deco3 { - z-index:3; - border:0px; - border-style:solid; - border-color:#7d95b5; - background-color:#7d95b5; -} - -.deco4 { - z-index:4; - border:0px; - border-style:solid; - border-color:#d0d8e4; - background-color:#d0d8e4; -} - - -table { - border: 0px solid; - background-color: #ffffff; -} - -#matrix { width: 100%; } - -#matrix th { - background-color: #b5cadc; - border: 1px solid #778; - font: bold 12px Verdana, sans-serif; -} - -#matrix #actionth { - width: 1px; - padding: 0em 1em 0em 1em; -} - -#matrix tr.alternate { background-color:#e3eaf0; } -#matrix tr:hover { background-color: #b5cadc; } -#matrix td { font: 12px Verdana, sans-serif; } - -#navlist { - padding: 3px 0; - margin-left: 0; - margin-top:3em; - border-bottom: 1px solid #778; - font: bold 12px Verdana, sans-serif; -} - -#navlist li { - list-style: none; - margin: 0; - display: inline; -} - -#navlist li a { - padding: 3px 0.5em; - margin-left: 3px; - border: 1px solid #778; - border-bottom: none; - background: #b5cadc; - text-decoration: none; -} - -#navlist li a:link { color: #448; } -#navlist li a:visited { color: #667; } - -#navlist li a:hover { - color: #000; - background: #eef; - border-top: 4px solid #7d95b5; - border-color: #227; -} - -#navlist #active a { - background: white; - border-bottom: 1px solid white; - border-top: 4px solid; -} - -td { font: 12px Verdana, sans-serif; } - - -fieldset { - margin-top: 1em; - padding: 1em; - background-color: #f3f6f8; - font:80%/1 sans-serif; - border:1px solid #ddd; -} - -legend { - padding: 0.2em 0.5em; - background-color: #fff; - border:1px solid #aaa; - font-size:90%; - text-align:right; -} - -label { - display:block; -} - -label.error { - border-color: red; - border-width: 1px; -} - -label .field { - float:left; - width:25%; - margin-right:0.5em; - padding-top:0.2em; - text-align:right; - font-weight:bold; -} - -#vlist { - padding: 0 1px 1px; - margin-left: 0; - font: bold 12px Verdana, sans-serif; - background: gray; - width: 13em; -} - -#vlist li { - list-style: none; - margin: 0; - border-top: 1px solid gray; - text-align: left; -} - -#vlist li a { - display: block; - padding: 0.25em 0.5em 0.25em 0.75em; - border-left: 1em solid #7d95b5; - background: #d0d8e4; - text-decoration: none; -} - -#vlist li a:hover { - border-color: #227; -} - -.view .field { - background-color: #f3f6f8; - border-left: 1px solid #7695b5; - border-top: 1px solid #7695b5; - padding: 1px 10px 0px 2px; -} - -#addnew { - width: 50%; - float: left; -} - -#search { - width: 50%; - float:right; -} - -.error { color: #d00; } - -.action { - border: 1px outset #7d95b5; - style:block; -} - -.action:hover { - color: #fff; - text-decoration: none; - background-color: #7d95b5; -} - -.actionform { - display: inline; -} - -.actionbutton { - height: 16px; - width: 40px; - font-family: sans-serif; - font-size: 10px; - border: 1px outset; - background-color: #fff; - margin-bottom: 0px; -} - -.actionbutton:hover { - color: #fff; - background-color: #7d95b5; -} - -.actions { - white-space: nowrap; -} - -.field { - display:inline; -} - -#login { width: 400px; } - -#login input[type=text] { width: 150px; } -#login input[type=password] { width: 150px; } - -.pager { - font: 11px Arial, Helvetica, sans-serif; - text-align: center; - border: solid 1px #e2e2e2; - border-left: 0; - border-right: 0; - padding-top: 10px; - padding-bottom: 10px; - margin: 0px; - background-color: #f3f6f8; -} - -.pager a { - padding: 2px 6px; - border: solid 1px #ddd; - background: #fff; - text-decoration: none; -} - -.pager a:visited { - padding: 2px 6px; - border: solid 1px #ddd; - background: #fff; - text-decoration: none; -} - -.pager .current-page { - padding: 2px 6px; - font-weight: bold; - vertical-align: top; -} - -.pager a:hover { - color: #fff; - background: #7d95b5; - border-color: #036; - text-decoration: none; -} - diff --git a/examples/fancy_example/templates/factory/navbar b/examples/fancy_example/templates/factory/navbar deleted file mode 100644 index 0c8b168..0000000 --- a/examples/fancy_example/templates/factory/navbar +++ /dev/null @@ -1,22 +0,0 @@ -[%# - -=head1 navbar - -This is a navigation bar to go across the page. (Or down the side, or -whatetver you want to do with it.) It displays all the tables which are -accessible, with a link to the list page for each one. - -#%] -[% PROCESS macros %] - diff --git a/examples/fancy_example/templates/factory/pager b/examples/fancy_example/templates/factory/pager deleted file mode 100644 index 78c89fd..0000000 --- a/examples/fancy_example/templates/factory/pager +++ /dev/null @@ -1,48 +0,0 @@ -[%# - -=head1 pager - -This controls the pager display at the bottom (by default) of the list -and search views. It expects a C template argument which responds -to the L interface. - -#%] -[% -IF pager AND pager.first_page != pager.last_page; -%] -

Pages: -[% - UNLESS pager_action; - SET pager_action = request.action; - END; - - SET begin_page = pager.current_page - 10; - IF begin_page < 1; - SET begin_page = pager.first_page; - END; - SET end_page = pager.current_page + 10; - IF pager.last_page < end_page; - SET end_page = pager.last_page; - END; - FOREACH num = [begin_page .. end_page]; - IF num == pager.current_page; - ""; num; ""; - ELSE; - SET label = num; - SET args = "?page=" _ num; - SET args = args _ "&order=" _ request.params.order - IF request.params.order; - SET args = args _ "&o2=desc" - IF request.params.o2 == "desc"; - FOR col = classmetadata.columns.list; - IF request.params.$col; - SET args = args _ "&" _ col _ "=" _ request.params.$col; - SET action = "search"; - END; - END; - link(classmetadata.table, pager_action, args, label); - END; - END; -%] -

-[% END %] diff --git a/examples/fancy_example/templates/factory/search_form b/examples/fancy_example/templates/factory/search_form deleted file mode 100644 index d10101e..0000000 --- a/examples/fancy_example/templates/factory/search_form +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/examples/fancy_example/templates/factory/search_form_recursive b/examples/fancy_example/templates/factory/search_form_recursive deleted file mode 100644 index 5d540fb..0000000 --- a/examples/fancy_example/templates/factory/search_form_recursive +++ /dev/null @@ -1,9 +0,0 @@ - diff --git a/examples/fancy_example/templates/factory/title b/examples/fancy_example/templates/factory/title deleted file mode 100644 index 401f0a3..0000000 --- a/examples/fancy_example/templates/factory/title +++ /dev/null @@ -1 +0,0 @@ - [% config.application_name %] diff --git a/examples/fancy_example/templates/factory/view b/examples/fancy_example/templates/factory/view deleted file mode 100644 index 9f06086..0000000 --- a/examples/fancy_example/templates/factory/view +++ /dev/null @@ -1,32 +0,0 @@ -[%# - -=for doc - -The C template takes some objects (usually just one) from -C and displays the object's properties in a table. - -=cut - -#%] -[% PROCESS macros %] -[% INCLUDE header %] -[% view_item(object); %] -[%# - -=for doc - -The C template also displays a list of other objects related to the first -one via C style relationships; this is done by calling the -C method - see L - to return -a list of has-many accessors. Next it calls each of those accessors, and -displays the results in a table. - -#%] -
Back to listing -[% view_related(object); %] - -[% - button(object, "edit"); - button(object, "delete"); -%] -[% INCLUDE footer %] diff --git a/lib/Apache/MVC.pm b/lib/Apache/MVC.pm index 20046a6..0dba642 100644 --- a/lib/Apache/MVC.pm +++ b/lib/Apache/MVC.pm @@ -217,7 +217,7 @@ sub redirect_request { $r->ar->status($status); $r->ar->headers_out->set('Location' => $redirect_url); - $r->output('redirecting...

redirecting..

') unless ($r->output) + $r->output('redirecting...

redirecting..

') unless ($r->output); return OK; } diff --git a/lib/Maypole/Constants.pm b/lib/Maypole/Constants.pm index cee418f..b70a06c 100644 --- a/lib/Maypole/Constants.pm +++ b/lib/Maypole/Constants.pm @@ -5,7 +5,7 @@ use constant OK => 0; use constant DECLINED => -1; use constant ERROR => 500; our @EXPORT = qw(OK DECLINED ERROR); -our $VERSION = "1." . sprintf "%04d", q$Rev$ =~ /: (\d+)/; +our $VERSION = "1." . sprintf "%04d", q$Rev: 483 $ =~ /: (\d+)/; 1; diff --git a/lib/Maypole/Headers.pm b/lib/Maypole/Headers.pm index 320cb05..28675fc 100644 --- a/lib/Maypole/Headers.pm +++ b/lib/Maypole/Headers.pm @@ -4,7 +4,7 @@ use base 'HTTP::Headers'; use strict; use warnings; -our $VERSION = "1." . sprintf "%04d", q$Rev$ =~ /: (\d+)/; +our $VERSION = "1." . sprintf "%04d", q$Rev: 376 $ =~ /: (\d+)/; sub get { shift->header(shift); diff --git a/lib/Maypole/Manual/Terminology.pod b/lib/Maypole/Manual/Terminology.pod deleted file mode 100644 index adc5dc8..0000000 --- a/lib/Maypole/Manual/Terminology.pod +++ /dev/null @@ -1,212 +0,0 @@ -=head1 NAME - -Maypole::Manual::Terminology - common terms - -=head1 VERSION - -This version written for Maypole 2.11 - -=head1 TERMINOLOGY - -For the avoidance of confusion, the following terms are defined. We'll try and -ensure the Maypole docs stick to these usages. - -=over 4 - -=item driver - -The custom package written to set up a Maypole application. This is the package -that has the C statement. If you're not using -L to set up your app (not recommended for newbies, but -common enough), the driver class will directly inherit from one of Maypole's -frontend classes. - -=item controller - -Occasionally this term is used in place of C. - -See the entry below (MVC) for the main usage of the term C within -Maypole. - -=item application - -Sometimes this is used to refer to the driver, or the driver plus configuration -data, but this term is best reserved to refer to the complete application, i.e. -driver, plugins, templates, model, config, the whole shebang. - -=item frontend - -An adapter class that allows Maypole to work in a number of different server -environments. The currently available frontends are: - - Frontend Distribution Environment - ============================================== - CGI::Maypole Maypole CGI - Apache::MVC Maypole Apache/mod_perl or Apache2/mod_perl2 - MasonX::Maypole MasonX::Maypole Apache/mod_perl with Mason - -The driver class inherits from the appropriate frontend, which inherits from -L. - -=item backend - -Confusingly, sometimes you'll see the frontend referred to as the backend. It -depends on your point of view. - -Also confusingly, the Maypole model (e.g. L) is sometimes -referred to as the backend. - -You'll just need to pay attention to context. In general, it's probably best to -avoid using this term altogether. - -=item request - -The Maypole request object. This contains all data sent in the request -(including headers, cookies, CGI parameters), and accumulates data to be sent in -the response (headers and content). It also provides access to the configuration -object, and stores the information parsed out of the URL (action, table, args -etc.). Plugins often add methods and further data members to the request object. - -=item workflow - -The sequence of events when a browser sends a request to a Maypole -application. - -You will also often see this referred to as the C (distinct from the -request object). - -=item Exported method - -A method in a Maypole model class that is labelled with the C -attribute. These methods are mapped to part of the request URI. So requesting -a path will result in a particular method being called on a particular model -class. - -=item action - -An Exported method. - -Note: this is not the action attribute of a form, although the form's action URI -will generally include a Maypole action component. For instance, a form might -submit to the following URL: C<[% $base %]/beer/drink/5>. The form action is the -URL, whereas the Maypole action is the C method on the C -object with an ID of 5. - -=item command - -In some of the standard factory templates, an C is referred to as a -C. - -=item template - -A file used to generate HTML for part or all of a web page. Maypole currently -supports Template Toolkit and Mason as templating languages, but others could -be added easily. Of course, a template doesn't have to generate only HTML. - -=back - -=head2 MVC and Maypole - -=head3 MVC - Model-View-Controller - -A pattern describing separation of concerns in a complex application. The -C represents the domain or business logic. The C represents the -user interface. The C mediates the interaction between the two. - -Opinions vary between how closely Maypole adheres to this pattern. - -Here's one opinion: - -=over 4 - -=item view - -This is represented in Maypole by the view class (L, -L, or L), and by the templates. - -=item controller - -An abstract concept in Maypole, i.e. there is no specific controller class. - -The main sequence of events that occur during the processing of a request is -controlled by methods in C. Thus, the controller logic is in the -same class as the request object. This may seem a bit strange, but in practice -it works well. - -More detailed events within the processing of a request are actually handled by -methods in the Maypole 'model'. For instance, switching from one template to -another - the "Template Switcheroo" referred to in L. - -Be aware that occasionally authors refer to the C when they are -describing the C. - -=item model - -In Maypole, the 'model' is the set of classes representing individual tables in -the database. Tables are related to each other in a more or less complex way. -Each table class inherits from a Maypole model class, such as -L or L. - -The functionality provided by the Maypole model class is more accurately -described as a Presentation Model (see below). In complex Maypole applications, -it is good practise to separate the domain model (the 'heart' of the -application) into a separate class hierarchy (see -L). - -The distinction is relatively unimportant when using Maypole in 'default' mode - -i.e. using L, and allowing Maypole to autogenerate the -'model' classes straight out of the database. - -However, in many applications, a more complex domain model is required, or may -already exist. In this case, the Maypole model is more clearly seen as a layer -that sits on top of the domain model, mediating access to it from the web UI, -via the controller. - -This conceptualisation helps developers maintain a separation between the -Maypole model classes (presentation model), and the domain model. Without this -distinction, developers may add domain-specific code to the Maypole model -classes. To a certain extent, in simple applications, this is fine. But if you -find yourself adding lots of non-Exported methods to your Maypole model classes, -and these methods are not there to directly support Exported methods, consider -whether you could separate out the domain model into a separate hierarchy of -classes - see L. - -Otherwise, the 'model' classes may develop into two quite uncoupled code bases, -but which co-exist in the same files. They will interact through a relatively -small number of methods. These methods should in fact become the public API of -the domain model, which should be moved to a separate class hierarchy. At some -point, the convenience of dropping new methods into the 'shared' classes will be -outweighed by the heuristic advantage of separating different layers into -separate class hierarchies. - -=back - -=head3 Presentation Model - -This pattern more accurately describes the role of the Maypole model. -Martin Fowler describes I in L -and L. - -The user sends an event (e.g. an HTTP request) to the Controller. The Controller -translates the request into a method call on the Presentation Model. The -Presentation Model interacts with the underlying Domain Model, and stores the -results in a bunch of variables, which I -(that's why it's a Presentation Model, not a Domain Model). The View then -queries the Presentation Model to retrieve these new values. In Maypole, this is -the role of the C method on L, which transmits the -new values to the templates. - -=head1 AUTHOR - -David Baird, C<< >> - -=head1 COPYRIGHT & LICENSE - -Copyright 2005 David Baird, All Rights Reserved. - -This text is free documentation; you can redistribute it and/or modify it -under the same terms as the Perl documentation itself. - -=cut diff --git a/t/01basics.t b/t/01basics.t index 6fa0c1e..324bb0b 100644 --- a/t/01basics.t +++ b/t/01basics.t @@ -1,5 +1,6 @@ #!/usr/bin/perl -w use Test::More; +use Data::Dumper; use lib 'examples'; # Where BeerDB should live BEGIN { $ENV{BEERDB_DEBUG} = 0; @@ -32,7 +33,12 @@ like(BeerDB->call_url("http://localhost/beerdb"), qr/frontpage/, "Got frontpage, trailing '/' on uri_base but not request"); like(BeerDB->call_url("http://localhost/beerdb/beer/list"), qr/Organic Best/, "Found a beer in the list"); -my (%classdata)=split /\n/, BeerDB->call_url("http://localhost/beerdb/beer/classdata"); + +my $classdata_page = BeerDB->call_url("http://localhost/beerdb/beer/classdata"); +my (%classdata)=split /\n+/, $classdata_page; +#warn $classdata_page; +#warn Dumper(%classdata); + is ($classdata{plural},'beers','classdata.plural'); is ($classdata{moniker},'beer','classdata.moniker'); like ($classdata{cgi},qr/^HTML::Element/,'classdata.cgi'); diff --git a/t/crud.t b/t/crud.t deleted file mode 100755 index 8afe888..0000000 --- a/t/crud.t +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/perl -w -use Test::More; -use lib 'examples'; # Where BeerDB should live -BEGIN { - $ENV{BEERDB_DEBUG} = 2; - - eval { require BeerDB }; - Test::More->import( skip_all => - "SQLite not working or BeerDB module could not be loaded: $@" - ) if $@; - - plan tests =>21; - -} -use Maypole::CLI qw(BeerDB); -use Maypole::Constants; -$ENV{MAYPOLE_TEMPLATES} = "t/templates"; - -isa_ok( (bless {},"BeerDB") , "Maypole"); - - - -# Test create missing required -like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit?name=&url=www.sammysmiths.com¬es=Healthy Brew"), qr/name' => 'This field is required/, "Required fields necessary to create "); - -# Test create with all required -like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit?name=Samuel Smiths&url=www.sammysmiths.com¬es=Healthy Brew"), qr/^# view/, "Created a brewery"); - -($brewery,@other) = BeerDB::Brewery->search(name=>'Samuel Smiths'); - - -SKIP: { - skip "Could not create and retrieve Brewery", 8 unless $brewery; - like(eval {$brewery->name}, qr/Samuel Smiths/, "Retrieved Brewery, $brewery, we just created"); - - #-------- Test updating printable fields ------------------ - - # TEST clearing out required printable column - like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit/".$brewery->id."?name="), qr/name' => 'This field is required/, "Required printable field can not be cleared on update"); - - # Test cgi update errors hanging around from last request - unlike(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit/".$brewery->id), qr/name' => 'This field is required/, "cgi_update_errors did not persist"); - - # Test update no columns - like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit/".$brewery->id), qr/^# view/, "Updated no columns"); - - # Test only updating one non required column - like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit/".$brewery->id."?notes="), qr/^# view/, "Updated a single non required column"); - - # TEST empty input for non required printable - like(BeerDB->call_url("http://localhost/beerdb/brewery/do_edit/".$brewery->id."?notes=&name=Sammy Smiths"), qr/^# view/, "Updated brewery" ); - - # TEST update actually cleared out a printable field - $val = $brewery->notes ; - if ($val eq '') { $val = undef }; - is($val, undef, "Verified non required printable field was cleared"); - - # TEST update did not change a field not in parameter list - is($brewery->url, 'www.sammysmiths.com', "A field not in parameter list is not updated."); -}; - -#----------------- Test other types of fields -------------- - -$style = BeerDB::Style->insert({name => 'Stout', notes => 'Rich, dark, creamy, mmmmmm.'}); - -# TEST create with integer, date, printable fields -like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit?name=Oatmeal Stout&brewery=".$brewery->id."&style=".$style->id."&score=5¬es=Healthy Brew&price=5.00&tasted=2000-12-01"), qr/^# view/, "Created a beer with date, integer and printable fields"); - -($beer, @other) = BeerDB::Beer->search(name=>'Oatmeal Stout'); - -SKIP: { - skip "Could not create and retrieve Beer", 7 unless $beer; - - # TEST wiping out an integer field - like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit/".$beer->id."?name=Oatmeal Stout&brewery=".$brewery->id."&style=".$style->id."&score=¬es=Healthy Brew&price=5.00"), qr/^# view/, "Updated a beer"); - - # TEST update actually cleared out a the integer field - $val = $beer->score ; - if ($val eq '') { $val = undef }; - is($val, undef, "Verified non required integer field was cleared"); - - - # TEST invalid integer field - like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit/".$beer->id."?name=Oatmeal Stout&brewery=".$brewery->id."&style=Stout&price=5.00"), qr/style' => 'Please provide a valid value/, "Integer field invalid"); - - # TEST update with empty date field - like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit/".$beer->id."?name=Oatmeal Stout&brewery=".$brewery->id."&style=".$style->id."&tasted=¬es=Healthy Brew&price=5.00"), qr/^# view/, "Updated a beer"); - - # TEST update actually cleared out a date field - $tasted = $beer->tasted ; - if ($tasted eq '') { $tasted = undef }; - is($tasted, undef, "Verified non required date field was cleared."); - - # TEST invalid date - like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit/".$beer->id."?name=Oatmeal Stout&brewery=".$brewery->id."&style=".$style->id."&tasted=baddate¬es=Healthy Brew&price=5.00"), qr/tasted' => 'Please provide a valid value/, "Date field invalid"); - - # TEST negative value allowed for required field - like(BeerDB->call_url("http://localhost/beerdb/beer/do_edit/".$beer->id."?name=Oatmeal Stout&brewery=".$brewery->id."&price=-5.00"), qr/^# view/, "Negative values allowed for required field"); - - # TEST negative value actually got stored - like($beer->price, qr/-5(\.00)?/, "Negative value for required field stored in database") -}; - -$beer_id = $beer->id; -$beer->delete; - -# TEST delete -$beer = BeerDB::Beer->retrieve($beer_id); -is($beer, undef, "Deleted Beer"); - -$brewery->delete; -$style->delete; diff --git a/t/templates/custom/classdata b/t/templates/custom/classdata index d5f60cc..788e2c7 100644 --- a/t/templates/custom/classdata +++ b/t/templates/custom/classdata @@ -1,18 +1,35 @@ name + [% classmetadata.name %] + table + [% classmetadata.table %] + columns + [% classmetadata.columns.join(' ')%] + list_columns + [% classmetadata.list_columns.join(' ') %] + colnames + [% classmetadata.colnames.abv %] + related_accessors + [% classmetadata.related_accessors.join(' ') %] + moniker + [% classmetadata.moniker %] + plural + [% classmetadata.plural %] + cgi + [% classmetadata.cgi.abv%] diff --git a/t/templates/custom/edit b/t/templates/custom/edit deleted file mode 100644 index ceee5d2..0000000 --- a/t/templates/custom/edit +++ /dev/null @@ -1,11 +0,0 @@ -# edit -[% - - USE dumper; -"# errors dump"; - dumper.dump(errors); -"# parameters dump"; - dumper.dump(request.params); -%] - -# End errors dump diff --git a/wishlist.txt b/wishlist.txt deleted file mode 100644 index 385eb99..0000000 --- a/wishlist.txt +++ /dev/null @@ -1,56 +0,0 @@ -2.12/3.0 wishlist -================= - -Not for inclusion in the MANIFEST. - -2.11 -==== -Fix factory roots, document and explain behaviour -send_output() should return a status code -Move template test out of process() and into handler_guts() - maybe -Fix bug 14570 - returning error codes breaks CGI::Maypole -Write Maypole::Manual::Exceptions -Test and refactor external_redirect() - -Fix Mp::P::USC. - -2.12 -==== -Maypole::instance() -Better plugin architecture, for models and bits of models. -Investigate problems reported with adopt() - rt 15598 -Re-implement Maypole::Cache as Maypole::Plugin::Cache, probably using - start_request_hook, and not overriding handler_guts() -Handle repeat form submissions. -Implement internal_redirect(). -Build a more sophisticated app for testing. -Move class_of() to the controller - need to do this to support multiple models - - maybe -Multiple model support - URLs like /$base/$model/$table/$action/$id. -Refactor M-P-USC and M-P-Session into M-P-User, M-P-Session, and M-P-Cookie - - -3.0 -==== -Encapsulate all request data in HTTP::Request object, and all response data -in HTTP::Response object - -Look at HTTP::Body - -Easier file uploads - look at incorporating Mp::P::Upload - -Add email handling - like Rails - via model plugins. - -An e-commerce model plugin would be nice - or proof of concept - maybe look -at Handel. - -Add validation layer(s), or just an API - -killer apps: SVN model; mitiki; Pet Shop; adventure builder - -Multiple views - HTML, text-only, PDF, SOAP, XML - use request data to switch -to an alternate view_object - switch via a factory method. - -Maybe rename the model to PModel (Presentation Model)? - -Pseudo-continuations...