filenaming.xml
Delivered as text/xml
[ hide source ] | [ make this the default ]
File Contents
<?xml version='1.0' ?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" [ <!ENTITY % myvars SYSTEM "../variables.ent"> %myvars; ]> <sect1 id="eng-standards-filenaming" xreflabel="ACS File Naming and Formatting Standards"> <title>ACS File Naming and Formatting Standards</title> <authorblurb> <para>By Michael Yoon and Aurelius Prochazka</para> </authorblurb> <para> To ensure consistency (and its collateral benefit, maintainability), we define and adhere to standards in the following areas: </para> <sect2 id="eng-standards-filenaming-nomenclature"> <title>File Nomenclature</title> <para> Usually, we organize our files so that they mainly serve one of the following three purposes: </para> <itemizedlist> <listitem><para> displaying objects and their properties</para></listitem> <listitem><para> manipulating or acting on objects in some way (by creating, editing, linking, etc)</para></listitem> <listitem><para> housing procedures, packages, data models and other prerequisite code Essentially, we want our files named in a fashion that reflects their purpose.</para></listitem> </itemizedlist> <para> Under the page root: </para> <itemizedlist> <listitem><para>For naming files that enable a specific action on an object, use this format:</para> <blockquote> <para> <emphasis><computeroutput>object-verb.extension</computeroutput></emphasis> </para> </blockquote> <para> For example, the page to erase a user's portrait from the database is <computeroutput>/admin/users/portrait-erase.tcl</computeroutput>. </para> </listitem> <listitem><para>However, modules typically deal with only one primary type of object - e.g., the Bookmarks module deals mainly with bookmarks - and so action-type files in modules don't need to be specified by the object they act on. Example: the user pages for the Bookmarks module live in the <computeroutput>/bookmarks/</computeroutput> directory, and so there is no need to name the bookmark editing page with a redundant url: <computeroutput>/bookmarks/bookmark-edit.tcl</computeroutput>. Instead, we omit the object type, and use this convention: </para> <blockquote> <para> <emphasis><computeroutput>verb.extension</computeroutput></emphasis> </para> </blockquote> <para> Thus, the page to edit a bookmark is <computeroutput>/bookmarks/edit.tcl</computeroutput>. </para> </listitem> <listitem><para>For naming files that display the properties of a primary object - such as the bookmark object within the bookmark module - use this convention:</para> <blockquote> <para> <computeroutput>one.extension</computeroutput> </para> </blockquote> <para> For example, the page to view one bookmark is <computeroutput>/bookmarks/one.tcl</computeroutput>. Note that no verb is necessary for display-type files. </para> </listitem> <listitem><para>Otherwise, if the object to be displayed is not the primary feature of a module, simply omit the verb and use the object name:</para> <blockquote> <para> <emphasis><computeroutput>object.extension</computeroutput></emphasis> </para> </blockquote> <para> For example, the page to view the properties of an ecommerce product is <computeroutput>/ecommerce/product.tcl</computeroutput>. </para> </listitem> <listitem><para>For naming files in a page flow, use the convention:</para> <itemizedlist> <listitem><para><emphasis><computeroutput>foobar.extension</computeroutput></emphasis> (Step 1)</para></listitem> <listitem><para><emphasis><computeroutput>foobar-2.extension</computeroutput></emphasis> (Step 2)</para></listitem> <listitem><para>...</para></listitem> <listitem><para><emphasis><computeroutput>foobar-N.extension</computeroutput></emphasis> (Step N)</para></listitem> </itemizedlist> <para> where <emphasis><computeroutput>foobar</computeroutput></emphasis> is determined by the above rules. </para> <para> Typically, we use a three-step page flow when taking user information: </para> <orderedlist> <listitem><para>Present a form to the user</para></listitem> <listitem><para>Present a confirmation page to the user</para></listitem> <listitem><para>Perform the database transaction, then redirect</para></listitem> </orderedlist> </listitem> <listitem><para>Put data model files in <computeroutput>/www/doc/sql</computeroutput>, and name them for the modules towards which they are used: </para> <blockquote> <para> <emphasis><computeroutput>module</computeroutput></emphasis><computeroutput>.sql</computeroutput> </para> </blockquote> </listitem> </itemizedlist> <para> In the Tcl library directory: </para> <itemizedlist> <listitem><para>For files that contain module-specific procedures, use the convention:</para> <blockquote> <para> <emphasis><computeroutput>module</computeroutput></emphasis><computeroutput>-procs.tcl</computeroutput> </para> </blockquote> </listitem> <listitem><para>For files that contain procedures that are part of the core ACS, use the convention:</para> <blockquote> <para> <computeroutput>ad-</computeroutput><emphasis>description</emphasis><computeroutput>-procs.tcl</computeroutput> </para> </blockquote> </listitem> </itemizedlist> </sect2> <sect2 id="eng-standards-filenaming-urls"> <title>URLs</title> <para> File names also appear <emphasis>within</emphasis> pages, as linked URLs and form targets. When they do, always use <ulink url="rp-design">abstract URLs</ulink> (e.g., <computeroutput>user-delete</computeroutput> instead of <computeroutput>user-delete.tcl</computeroutput>), because they enhance maintainability. </para> <para> Similarly, when linking to the index page of a directory, do not explicitly name the index file (<computeroutput>index.tcl</computeroutput>, <computeroutput>index.adp</computeroutput>, <computeroutput>index.html</computeroutput>, etc.). Instead, use just the directory name, for both relative links (<computeroutput>subdir/</computeroutput>) and absolute links (<computeroutput>/top-level-dir/</computeroutput>). If linking to the directory in which the page is located, use the empty string (<computeroutput>""</computeroutput>), which browsers will resolve correctly. </para> </sect2> <sect2 id="eng-standards-filenaming-headers"> <title>File Headers and Page Input</title> <para> Include the appropriate standard header in all scripts. The first line should be a comment specifying the file path relative to the ACS root directory. e.g. </para> <blockquote><para><computeroutput> # /www/index.tcl </computeroutput></para></blockquote> <para> or </para> <blockquote><para><computeroutput> # /tcl/module-defs.tcl </computeroutput></para></blockquote> <para> For static content files (html or adp), include a CVS identification tag as a comment at the top of the file, e.g. </para> <programlisting> <!-- file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp --> </programlisting> <para> In addition, all static HTML files, documentation and other pages should have a visible CVS ID stamp, at least during development. These can be removed at release times. This should take the form of a line like this: </para> <programlisting> <p> Last Modified: file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp </p> </programlisting> <para> This can be at the top or bottom of the file. </para> <para><phrase>Using ad_page_contract</phrase></para> <para> For non-library Tcl files (those not in the private Tcl directory), use <link linkend="tcl-doc-ad-page-contract"><computeroutput>ad_page_contract</computeroutput></link> after the file path comment (this supersedes set_the_usual_form_variables and ad_return_complaint). Here is an example of using ad_page_contract, which serves both documentation and page input validation purposes: </para> <programlisting> # www/register/user-login-2.tcl ad_page_contract { Verify the user's password and issue the cookie. @param user_id The user's id in users table. @param password_from_from The password the user entered. @param return_url What url to return to after successful login. @param persistent_cookie_p Specifies whether a cookie should be set to keep the user logged in forever. @author John Doe (jdoe@example.com) @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp } { user_id:integer,notnull password_from_form:notnull {return_url {[ad_pvt_home]}} {persistent_cookie_p f} } </programlisting> <para> Salient features of <computeroutput>ad_page_contract</computeroutput>: </para> <itemizedlist> <listitem><para>A mandatory documentation string is the first argument. This has the standard form with javadoc-style @author, @cvs-id, etc, and should contain a short description of the received variables and any necessary explanations. </para></listitem> <listitem><para>The second argument specifies the page inputs. The syntax for switches/flags (e.g. multiple-list, array, etc.) uses a colon (:) followed by any number of flags separated by commas (,), e.g. <computeroutput>foo:integer,multiple,trim</computeroutput>. In particular, <computeroutput>multiple</computeroutput> and <computeroutput>array</computeroutput> are the flags that correspond to the old <computeroutput>ad_page_variables</computeroutput> flags.</para></listitem> <listitem><para>There are new flags: <computeroutput>trim</computeroutput>, <computeroutput>notnull</computeroutput> and <computeroutput>optional</computeroutput>. They do what you'd expect; values will not be trimmed, unless you mark them for it; empty strings are valid input, unless you specify notnull; and a specified variable will be considered required, unless you declare it optional.</para></listitem> <listitem><para><computeroutput>ad_page_contract</computeroutput> can do validation for you: the flags <computeroutput>integer</computeroutput> and <computeroutput>sql_identifier</computeroutput> will make sure that the values supplied are integers/sql_identifiers. The <computeroutput>integer</computeroutput> flag will also trim leading zeros. Note that unless you specify <computeroutput>notnull</computeroutput>, both will accept the empty string. </para></listitem> <listitem><para>Note that <computeroutput>ad_page_contract</computeroutput> does not generate QQvariables, which were automatically created by ad_page_variables and set_the_usual_form_variables. The use of bind variables makes such previous variable syntax obsolete. </para></listitem> </itemizedlist> <para><phrase>Using ad_library</phrase></para> <para> For shared Tcl library files, use <link linkend="tcl-doc-ad-library"><computeroutput>ad_library</computeroutput></link> after the file path comment. Its only argument is a doc_string in the standard (javadoc-style) format, like <computeroutput>ad_page_contract</computeroutput>. Don't forget to put the @cvs-id in there. Here is an example of using ad_library: </para> <programlisting> # tcl/wp-defs.tcl ad_library { Provides helper routines for the Wimpy Point module. @author John Doe (jdoe@example.com) @cvs-id file-standards.html,v 1.2 2000/09/19 07:22:45 ron Exp } </programlisting> <para><phrase>Non-Tcl Files</phrase></para> <para> For SQL and other non-Tcl source files, the following file header structure is recommended: </para> <programlisting> -- <emphasis>path relative to the ACS root directory</emphasis> -- -- <emphasis>brief description of the file's purpose</emphasis> -- -- <emphasis>author</emphasis> -- <emphasis>created</emphasis> -- -- <ulink url="http://www.loria.fr/~molli/cvs/doc/cvs_12.html#SEC93">$Id$</ulink> </programlisting> <para> Of course, replace "<computeroutput>--</computeroutput>" with the comment delimiter appropriate for the language in which you are programming. </para> </sect2> <sect2 id="eng-standards-filenaming-pages"> <title>Page Construction</title> <para> Construct the page as one Tcl variable (name it <computeroutput>page_content</computeroutput>), and then send it back to the browser with one call to <computeroutput>doc_return</computeroutput>, which will call db_release_unused_handles prior to executing ns_return, effectively combining the two operations. </para> <para> For example: </para> <programlisting> set page_content "<emphasis>Page Title</emphasis>] <h2><emphasis>Page Title</emphasis></h2> <hr> <ul> " db_foreach get_row_info { select row_information from bar } { append page_content "<li><emphasis>row_information</emphasis>\n" } append page_content "</ul> [ad_footer]" doc_return 200 text/html $page_content </programlisting> <para> The old convention was to call <computeroutput>util_return_headers</computeroutput> and then <computeroutput>ns_write</computeroutput> for each distinct chunk of the page. This approach has the disadvantage of tying up a scarce and valuable resource (namely, a database handle) for an unpredictable amount of time while sending packets back to the browser, and so it should be avoided in most cases. (On the other hand, for a page that requires an expensive database query, it's better to call <computeroutput>ad_return_top_of_page</computeroutput> first, so that the user is not left to stare at an empty page while the query is running.) </para> <para> Local procedures (i.e., procedures defined and used only within one page) should be prefixed with "<emphasis><computeroutput>module_</computeroutput></emphasis>" and should be used rarely, only when they are exceedingly useful. </para> </sect2> <sect2 id="eng-standards-filenaming-tcllib"> <title>Tcl Library Files</title> <para> Further standards for Tcl library files are under discussion; we plan to include naming conventions for procs. </para> <para><phrase role="cvstag">($Id: filenaming.xml,v 1.8.2.2 2021/09/02 16:56:02 gustafn Exp $)</phrase></para> </sect2> </sect1>