From aaf39b90364caecf3a6da182aed5a9a8ae9cf351 Mon Sep 17 00:00:00 2001 From: BJ Dierkes Date: Mon, 22 Aug 2011 17:52:50 -0500 Subject: [PATCH] fresh doc --- README | 6 +- doc/Makefile | 89 ------ doc/source/api.rst | 11 - doc/source/api/core.rst | 78 ------ doc/source/api/source.rst | 29 -- doc/source/api/versions.rst | 57 ---- doc/source/conf.py | 67 +++-- doc/source/dev.rst | 24 -- doc/source/dev/cli_api.rst | 127 --------- doc/source/dev/features.rst | 214 -------------- doc/source/dev/handlers.rst | 153 ---------- doc/source/dev/hooks.rst | 206 -------------- doc/source/dev/logging.rst | 81 ------ doc/source/dev/mvc.rst | 179 ------------ doc/source/dev/namespaces.rst | 130 --------- doc/source/dev/options_and_arguments.rst | 203 -------------- doc/source/dev/plugin_support.rst | 128 --------- doc/source/dev/quickstart.rst | 265 ------------------ doc/source/dev/templates.rst | 226 --------------- doc/source/dev/testing.rst | 95 ------- .../dev/understanding_your_application.rst | 129 --------- doc/source/index.rst | 43 +-- 22 files changed, 57 insertions(+), 2483 deletions(-) delete mode 100644 doc/Makefile delete mode 100644 doc/source/api.rst delete mode 100644 doc/source/api/core.rst delete mode 100644 doc/source/api/source.rst delete mode 100644 doc/source/api/versions.rst delete mode 100644 doc/source/dev.rst delete mode 100644 doc/source/dev/cli_api.rst delete mode 100644 doc/source/dev/features.rst delete mode 100644 doc/source/dev/handlers.rst delete mode 100644 doc/source/dev/hooks.rst delete mode 100644 doc/source/dev/logging.rst delete mode 100644 doc/source/dev/mvc.rst delete mode 100644 doc/source/dev/namespaces.rst delete mode 100644 doc/source/dev/options_and_arguments.rst delete mode 100644 doc/source/dev/plugin_support.rst delete mode 100644 doc/source/dev/quickstart.rst delete mode 100644 doc/source/dev/templates.rst delete mode 100644 doc/source/dev/testing.rst delete mode 100644 doc/source/dev/understanding_your_application.rst diff --git a/README b/README index 095a1a8a..b4dcb3c7 100644 --- a/README +++ b/README @@ -10,7 +10,7 @@ rewrite of Cement version 0.x/1.x. Its goal is to introduce a standard, and feature-full platform for both simple and complex command line applications as well as support rapid development needs without sacrificing quality. -Cement2 Core features include (but not limited to): +Cement2 Core features include (but are not limited to): * Core pieces of the framework are customizable via handlers/interfaces * Extension handler interface to easily extend framework functionality @@ -23,6 +23,7 @@ Cement2 Core features include (but not limited to): * Output handler interface renders return dictionaries to console * Core library and extensions have zero external dependencies * Extensions with external dependencies packaged separately + * Controller handler supports sub-commands, and nested controllers * Significant Nose test coverage * Extensive Sphinx documentation, complete with examples * Supported on Python 2.6+ and 3! @@ -45,4 +46,5 @@ All documentation is available from the official website: LICENSE: The Cement CLI Application Framework is Open Source and is distributed under -the MIT License. Please see the LICENSE file included with this software. +the BSD License (three clause). Please see the LICENSE file included with +this software. diff --git a/doc/Makefile b/doc/Makefile deleted file mode 100644 index 443f5cfd..00000000 --- a/doc/Makefile +++ /dev/null @@ -1,89 +0,0 @@ -# Makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -PAPER = -BUILDDIR = build - -# Internal variables. -PAPEROPT_a4 = -D latex_paper_size=a4 -PAPEROPT_letter = -D latex_paper_size=letter -ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source - -.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest - -help: - @echo "Please use \`make ' where is one of" - @echo " html to make standalone HTML files" - @echo " dirhtml to make HTML files named index.html in directories" - @echo " pickle to make pickle files" - @echo " json to make JSON files" - @echo " htmlhelp to make HTML files and a HTML help project" - @echo " qthelp to make HTML files and a qthelp project" - @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" - @echo " changes to make an overview of all changed/added/deprecated items" - @echo " linkcheck to check all external links for integrity" - @echo " doctest to run all doctests embedded in the documentation (if enabled)" - -clean: - -rm -rf $(BUILDDIR)/* - -html: - $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." - -dirhtml: - $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml - @echo - @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." - -pickle: - $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle - @echo - @echo "Build finished; now you can process the pickle files." - -json: - $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json - @echo - @echo "Build finished; now you can process the JSON files." - -htmlhelp: - $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp - @echo - @echo "Build finished; now you can run HTML Help Workshop with the" \ - ".hhp project file in $(BUILDDIR)/htmlhelp." - -qthelp: - $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp - @echo - @echo "Build finished; now you can run "qcollectiongenerator" with the" \ - ".qhcp project file in $(BUILDDIR)/qthelp, like this:" - @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/TheCementCLIApplicationFramework.qhcp" - @echo "To view the help file:" - @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/TheCementCLIApplicationFramework.qhc" - -latex: - $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex - @echo - @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." - @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ - "run these through (pdf)latex." - -changes: - $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes - @echo - @echo "The overview file is in $(BUILDDIR)/changes." - -linkcheck: - $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck - @echo - @echo "Link check complete; look for any errors in the above output " \ - "or in $(BUILDDIR)/linkcheck/output.txt." - -doctest: - $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest - @echo "Testing of doctests in the sources finished, look at the " \ - "results in $(BUILDDIR)/doctest/output.txt." diff --git a/doc/source/api.rst b/doc/source/api.rst deleted file mode 100644 index ef682c99..00000000 --- a/doc/source/api.rst +++ /dev/null @@ -1,11 +0,0 @@ -Cement API Documentation -======================== - -This page contains the internal API documentation for the Cement Framework. - -.. toctree:: - :maxdepth: 20 - - api/source - api/core - api/versions diff --git a/doc/source/api/core.rst b/doc/source/api/core.rst deleted file mode 100644 index 8716cb6e..00000000 --- a/doc/source/api/core.rst +++ /dev/null @@ -1,78 +0,0 @@ -Cement Core API Documentation -============================= - -:mod:`cement.core.app_setup` --------------------------------- - -.. automodule:: cement.core.app_setup - :members: - - -:mod:`cement.core.command` ------------------------------- - -.. automodule:: cement.core.command - :members: - - -:mod:`cement.core.configuration` ------------------------------------- - -.. automodule:: cement.core.configuration - :members: - - -:mod:`cement.core.controller` ---------------------------------- - -.. automodule:: cement.core.controller - :members: - - -:mod:`cement.core.exc` --------------------------- - -.. automodule:: cement.core.exc - :members: - - -:mod:`cement.core.hook` ---------------------------- - -.. automodule:: cement.core.hook - :members: - - -:mod:`cement.core.log` --------------------------- - -.. automodule:: cement.core.log - :members: - - -:mod:`cement.core.namespace` --------------------------------- - -.. automodule:: cement.core.namespace - :members: - - -:mod:`cement.core.opt` --------------------------- - -.. automodule:: cement.core.opt - :members: - - -:mod:`cement.core.plugin` ------------------------------ - -.. automodule:: cement.core.plugin - :members: - - -:mod:`cement.core.view` ---------------------------- - -.. automodule:: cement.core.view - :members: \ No newline at end of file diff --git a/doc/source/api/source.rst b/doc/source/api/source.rst deleted file mode 100644 index d08d9a5b..00000000 --- a/doc/source/api/source.rst +++ /dev/null @@ -1,29 +0,0 @@ -A Look at The Source Code -========================= - -All source 'packages' are available under the './src' directory. There are -the following python packages: - - ./src/cement/ - This package provides the core framework required to run an - application built on top of Cement. - - ./src/cement.devtools/ - This package provides development tools for creating and developing - applications built on Cement. - - ./src/cement.test/ - This package provides an external application, built on top of - Cement, that also provides the nose tests to run and test the - framework. Testing requires a 'running' application to really cover - all bits of the framework code, and this is that 'running' - application. - - -Additional directories include: - - ./doc/ - Sphinx documentation (what you're reading now). - - ./util/ - Utilities/scripts/etc that help with development of Cement. diff --git a/doc/source/api/versions.rst b/doc/source/api/versions.rst deleted file mode 100644 index fd074f65..00000000 --- a/doc/source/api/versions.rst +++ /dev/null @@ -1,57 +0,0 @@ -Versioning and Compatibility ----------------------------- - -This outline uses fictitious version numbers to avoid confusion between -actual releases and this doc. Cement is versioned as follows, using the -version 0.2.4 as the example: - - * 0 = Code Base - * 2 = Major Release Version - * 4 = Minor Release Version - -That said, the Major Release Version and the Minor Release Version both -honor the following scheme: - - * Even = Stable - * Odd = Development - -Therefore, if 0.2.4 (even, even) is the current stable release of the '0' -branch, then 0.2.5 (even, odd) is the 'in progress' version in the Git -'master' branch. Once 0.2.5 reaches releasability it would be released as -0.4.6 stable (even, even). - -Development versions also follow the same scheme. The next major release -that breaks API compatibility would be versioned as 0.3.1 (odd, odd). Once a -'stable enough' version of the development branch reaches releasability, it -will be released as 0.3.2 (odd, even) meaning the branch is development, but -it is a semi-stable release. - -Any time API compatibility changes we will up the Major Release Version. We -handle this in setup.py of Cement applications by doing something like: - -.. code-block:: python - - install_requires=[ - "cement.core >=0.2.4, <0.3" - ] - -This means, if you write an application on top of cement == 0.2.4 then your -application should be compatible with all versions of 0.2.x, however would not -be compatible with anything >=0.3 because 0.3 is the next development version -where API compatibility changes. For that reason the next major development -branch is 0.3 (odd) currently, and the next major stable branch of cement will -be 0.4 (even). Both 0.3 (development) and 0.4 (stable) break compatibility -with previous versions of Cement < 0.3. - -The 'Code Base' version more or less designates a 'full rewrite'. Meaning -that within the same code base (i.e. '0') even in the next major version that -break compatibility, you should be able to make your application work with -only a few changes. Where as, in the next code base (i.e. 1) it is likely -that you will need to make significant changes, or possibly rewrite your -application to work on the newer code base. - -To keep API compatible, and non compatible development separate we work out of -two Git repos. - - * master: development that is API compatible with current stable. - * portland: development that is API incompatible with current stable. diff --git a/doc/source/conf.py b/doc/source/conf.py index 90cc5c9e..786df73d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # -# The Cement CLI Application Framework documentation build configuration file, created by -# sphinx-quickstart on Thu Jan 28 02:44:35 2010. +# Cement documentation build configuration file, created by +# sphinx-quickstart on Mon Aug 22 17:52:04 2011. # # This file is execfile()d with the current directory set to its containing dir. # @@ -12,19 +12,17 @@ # serve to show the default. import sys, os -from pkg_resources import get_distribution - -VERSION = '0.8' -RELEASE = '0.8.16' # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.append(os.path.abspath('../../src/cement/')) -sys.path.append(os.path.abspath('../../src/cement.devtools/')) +#sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] @@ -36,23 +34,23 @@ templates_path = ['_templates'] source_suffix = '.rst' # The encoding of source files. -#source_encoding = 'utf-8' +#source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'Cement' -copyright = u'2010, BJ Dierkes' +copyright = u'2011, BJ Dierkes' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. -version = VERSION +version = '1.9.1' # The full version, including alpha/beta/rc tags. -release = RELEASE +release = '1.9.1' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -64,12 +62,9 @@ release = RELEASE # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' -# List of documents that shouldn't be included in the build. -#unused_docs = [] - -# List of directories, relative to source directory, that shouldn't be searched -# for source files. -exclude_trees = [] +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = [] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None @@ -94,8 +89,8 @@ pygments_style = 'sphinx' # -- Options for HTML output --------------------------------------------------- -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme @@ -143,7 +138,7 @@ html_static_path = ['_static'] #html_additional_pages = {} # If false, no module index is generated. -#html_use_modindex = True +#html_domain_indices = True # If false, no index is generated. #html_use_index = True @@ -154,13 +149,19 @@ html_static_path = ['_static'] # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' -# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = '' +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'Cementdoc' @@ -172,7 +173,7 @@ htmlhelp_basename = 'Cementdoc' #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). -latex_font_size = '10pt' +#latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). @@ -189,6 +190,12 @@ latex_documents = [ # not chapters. #latex_use_parts = False +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + # Additional stuff for the LaTeX preamble. #latex_preamble = '' @@ -196,4 +203,14 @@ latex_documents = [ #latex_appendices = [] # If false, no module index is generated. -#latex_use_modindex = True +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'cement', u'Cement Documentation', + [u'BJ Dierkes'], 1) +] diff --git a/doc/source/dev.rst b/doc/source/dev.rst deleted file mode 100644 index a8c7ea77..00000000 --- a/doc/source/dev.rst +++ /dev/null @@ -1,24 +0,0 @@ -Developer Documentation -======================= - -This page contains documentation for developers building their application -on Cement. It outlines the features of the Cement Framework and how to use -them in your applications. - -.. toctree:: - :maxdepth: 20 - - dev/features - dev/quickstart - dev/understanding_your_application - dev/namespaces - dev/hooks - dev/handlers - dev/mvc - dev/options_and_arguments - dev/logging - dev/plugin_support - dev/templates - dev/cli_api - dev/testing - \ No newline at end of file diff --git a/doc/source/dev/cli_api.rst b/doc/source/dev/cli_api.rst deleted file mode 100644 index ad57cbcb..00000000 --- a/doc/source/dev/cli_api.rst +++ /dev/null @@ -1,127 +0,0 @@ -Cement CLI-API (Rendered JSON Output) -===================================== - -Every Cement Application has a built in CLI-API that allows other programs, -regardless of their language, to access your command line interface and get -back Json output. This is extremely powerful in mixed environments where you -might not have control over legacy applications, or other departments code. -If the language can speak Json, they can make a system call to your program -and not have to parse through unreliable STDOUT to get the information they -need. - -The the following for example: - -**./helloworld/controllers/example.py**: - -.. code-block:: python - - @expose('helloworld.templates.example.ex2', namespace='root') - @register_hook() - def ex2(self, cli_opts, cli_args): - example = ExampleModel() - example.label = 'This is my Example Model' - - if cli_opts.my_option: - print '%s passed by --my-option' % cli_opts.my_option - - return dict(foo=True, example=example, items=['one', 'two', 'three']) - - -The following would be run by: - -.. code-block:: text - - $ helloworld ex2 --my-option - loading example plugin - loading clibasic plugin - True passed by --my-option - - There are a number of things you can do such as conditional statements: - - Label: This is my Example Model - - Or a for loop: - - * one - * two - * three - - And functions: - - Hello, World! - Hello, Edward! - -You can see that, we passed the '--my-option' that triggerd a print statement. -Then our return dictionary was rendered via Genshi. Now lets see what that -looks like with our Json engine: - -.. code-block:: text - - $ helloworld ex2 --my-option --json - {"items": ["one", "two", "three"], "foo": true, "example": {"label": "This is my Example Model"}, "stderr": "", "stdout": "True passed by --my-option\n"} - -The return data is rendered as Json, as well as STDOUT and STDERR. All other -output is suppressed, meaning the application calling this will get back just -the Json, a standard format from which they can use the data more reliably and -much more easily. - - -Pretty Printing JSON --------------------- - -A very handy tool that comes with Python 2.6+ is json.tool. This allows you -to "pretty print" JSON output at the console. - -.. code-block:: text - - $ helloworld get-started --json | python -mjson.tool - { - "config": { - "app_egg_name": "helloworld", - "app_module": "helloworld", - "app_name": "helloworld", - "config_files": [ - "/etc/helloworld/helloworld.conf", - "~/.helloworld/etc/helloworld.conf", - "~/.helloworld.conf" - ], - "config_source": [ - "defaults" - ], - "datadir": "~/.helloworld/data", - "debug": false, - "enabled_plugins": [ - "helloworld.plugin.example" - ], - "example": { - "config_source": [ - "defaults" - ], - "enable_plugin": true, - "foo": "bar", - "merge_root_options": true - }, - "log_file": "~/log/helloworld.log", - "log_level": "warn", - "log_to_console": true, - "merge_root_options": true, - "output_engine": "json", - "plugin_config_dir": "~/.helloworld/etc/plugins.d", - "show_plugin_load": false, - "tmpdir": "~/.helloworld/tmp" - }, - "features": [ - "Multiple Configuration file parsing (default: /etc, ~/)", - "Command line argument and option parsing", - "Dual Console/File Logging Support", - "Full Internal and External (3rd Party) Plugin support", - "Basic \"hook\" support", - "Full MVC support for advanced application design", - "Text output rendering with Genshi templates", - "Json output rendering allows other programs to access your CLI-API" - ], - "genshi_link": "http://genshi.edgewall.org/wiki/Documentation/text-templates.html", - "stderr": "", - "stdout": "" - } - \ No newline at end of file diff --git a/doc/source/dev/features.rst b/doc/source/dev/features.rst deleted file mode 100644 index 2a01e792..00000000 --- a/doc/source/dev/features.rst +++ /dev/null @@ -1,214 +0,0 @@ -An Overview of Features -======================= - -The Cement CLI Application Framework provides the following features for -every application (out of the box): - - * Multiple Configuration file parsing (default: /etc, ~/) - * Command line argument and option parsing - * Dual Console/File Logging Support - * Internal and External (3rd Party) Plugin support - * Basic "hook" support - * MVC support for advanced application design - * Text output rendering with Genshi templates - * Json output rendering - The Cement CLI-API - - -Config File Parsing -------------------- - -Config file parsing is provided by the standard ConfigObj. The configuration -object is stored in the root namespaces config member and can be accessed as: - -.. code-block:: python - - from cement.core.namespace import get_config - config = get_config() - - -The global config dictionary is generated [and overridden] in the following -order: - - * defaults (set in ./yourapp/core/config.py) - * /etc/yourapp/yourapp.conf - * %(prefix)/etc/yourapp.conf - * ~/.yourapp.conf - - -In the above, '%(prefix)' is a hard coded setting which points to -'~/.yourapp/' by default (sane for development/no config situation). Some -applications need a set location that all files belong in such as -/var/lib/yourapp in which case the hard coded prefix can be changed. - - -Command Line Argument and Option Parsing ----------------------------------------- - -Command line arguments and options are parsed via OptParse for each namespace. -The base application owns the 'root' namespace, where as additional namespaces -branch off of that as illustrated below. - -.. code-block:: text - - # options and commands for root namespace - $ helloworld --help - - # options and subcommands for 'example' namespace - $ helloworld example --help - - -Namespaces have an option to 'merge_root_options' where their OptParse object -will merge in all of the options from the root namespace. For example, the -options --debug, --quiet, --json are all root namespace options that are -merged into the 'example' namespace by default. - -Options parsed from the command line will overwrite config options if the -name of the option matches the config option. For example, when passing the -'--debug' option at command line, the root_config['debug'] setting is set to -True. - - -Logging -------- - -Logging is provided by the standard 'logging' facility. By default Cement -configures both a console log, as well as a file log. This is fully -configurable however in your applications configuration. If no log_file is -specified, none will be created. If 'log_to_console' is false, nothing will -be logged to console. - -The log level is determined by 'log_level' in your configuration, and is one -of the following: - - * info - * warn - * error - * fatal - * debug - -Note that there are built in command line options that over ride these as well. -The --quiet option forces no console output at all (including print -statements) and the --debug option forces console output, and full logging -at every level. Debug should only be enabled for troubleshooting. - -The logger can be accessed anywhere in your application by the following: - -.. code-block:: python - - from cement.core.log import get_logger - - log = get_logger(__name__) - log.info("This is an info message") - log.error("This is an error message") - log.debug("KAPLA!") - - -Plugin Support --------------- - -Cement provides support for both internal and external (third party) plugins. -Internal plugins are those build as part of your base application, meaning -they will ship with your application and exist under ./yourapp/ source tree. -External plugins exist outside of your application and allow third parties to -build plugins that tie into your application. - -External applications can be generated for your application via the paster -utility: - -.. code-block:: text - - $ paster cement-plugin yourapp myplugin - - $ cd yourapp-plugin-myplugin - - $ python setup.py develop - - -Plugins provide additional controllers, models, helpers, and templates to -your application and function as if they were built into it directly. The -plugin system is also designed to allow and encourage portability. A plugin -can be imported into any other application built on cement. Additionally, -The Rosendale Project was created to specifically build shared plugins for -applications built on Cement. - - -Hook Support ------------- - -Cement provides hook support for both the Cement framework, as well as your -applications and plugins. Hooks are easily defined, registered, and run: - -.. code-block:: python - - from cement.core.hook import define_hook, register_hook, run_hooks - - define_hook('myhook_hook') - - @register_hook(weight=10) - def myhook_hook(*args, **kwargs): - # do something - return True - - @register_hook(weight=-99) - def myhook_hook(*args, **kwargs): - # do something else, but do it first, because I need to run before - # everyone else... my weight is -99. - return True - - for res in run_hooks('myhook_hook'): - # do something with res - pass - - -This is a simple example, but the idea is... hooks can be defined either in -your application, or in plugins. You can then register a function into that -hook meaning when the hook is called, that function will be executed in the -order of 'weight'. Finally, to run all functions that have been defined for -that hook, we use the run_hooks() method. - -*Note: run_hooks() yields its results, therefore you must iterate over it.* - - -Model, View, Controller Design ------------------------------- - -Cement encourages good programmatic design and habits by organizing your -application into separate model, view, controller pieces. - - model - The model can be any arbitrary object class, or can be something like - an SQLAlchemy declarative base. - - view - The view is generated by the Genshi Text Template engine, allowing - you to keep your controller clean and free of unnecessary print - statements. - - controller - The controller provides an outlet to expose commands to the - application. - - -Json Output Rendering - The Cement CLI-API ------------------------------------------- - -Now, sit back down and let me explain before you ask "Why in the world would -you output Json from a command line application?". It might not make sense -at first, but it does to me. As a Linux Engineer bringing a number of -utilities together to generate the output you want is always a fun task. Be -it using sed, awk, grep, etc... we're always having to mangle STDOUT and -format it for our needs at that time. - -That said, parsing output is not only unpredictable, it doesn't scale. Now -imagine a world where every command line application [optionally] spit out -Json? There is so much more you can do with a standard format such as Json, -Than parsing random output which differs from application to application. - -All reasoning aside, Cement builds in an optional engine that renders command -output as Json to the console. This is triggered by the '--json' command -line option, and is what we like to call the Cement CLI-API. Regardless of -the language, be it PERL, Ruby, Etc... if they can speak Json then they can -access your application directly via a system call and get back data that they -can use without having to tie into your python libraries. - - diff --git a/doc/source/dev/handlers.rst b/doc/source/dev/handlers.rst deleted file mode 100644 index 2e8279bd..00000000 --- a/doc/source/dev/handlers.rst +++ /dev/null @@ -1,153 +0,0 @@ -Handlers -======== - -Cement sets up and provides a handlers object that is used to make pieces -of the framework (and your application) both pluggable, and customizable. -Currently this is a new feature, and only 'output' handling has been ported -to the handler system. That said, it is a perfect example of how it is used. -At application bootstrap, Cement defines the 'output' handler type, and then -registers the default output handlers to that type (genshi, and json). As you -can see, this is useful in that functions will return data to a genshi -template, but if the '--json' option is passed it is rendered as Json. -Developers can add additional handlers via plugins such as the -Rosendale YAML Plugin which adds an output handler called 'yaml', and is called -when the user passes '--yaml'. - -Generally, a handler is a Class or Function of some kind, and provides some -functionality in more or less a 'standardized' way. Meaning, all handlers -of type 'output' should function the same way. It is a very loose, but -versatile method of configuring and using handlers. How a handler functions -is up to the developer, and should be documented well. It is recommended that -a base 'Handler' class be constructed, and documented so that other developers -know what is expected of that Handler (and so they can sub-class from it). - - -Defining a Handler ------------------- - -By default, as of 0.8.9, the only default handler type is called 'output' -and can be accessed as the following (from within a loaded cement app): - -.. code-block:: python - - from cement import handlers - handlers['output'] - - -Handlers should be defined within your bootstrap process, generally in the -root bootstrap. To define a handler type, add something similar to the -following: - -**helloworld/bootstrap/root.py** - -.. code-block:: python - - from cement.core.handler import define_handler - define_handler('my_handler') - - -Registering a Handler ---------------------- - -Handlers should also be registered during the bootstrap process. The -following is an example from rosendale.yaml and shows how to register -an output handler (keep in mind this is only a snippit of the code in that -file): - -**rosendale.bootstrap.yaml_output** - -.. code-block:: python - - from rosendale.lib.yaml_output import YamlOutputHandler - register_handler('output', 'yaml', YamlOutputHandler) - - -In this example, the first argument (output) is the handler type, the second -(yaml) is the label/name of the output handler you are registering, and finally -the last argument is the function or class object to store as the handler. - -**Note**: The handler can be store as an instantiated function/class or not. -This all depends on how the handler is to be used. For example, you might want -to use handlers to create a stateful object (instantiated once) or not -(instantiated every time it is called). The 'output' handler is an example -of a handler that is not instantiated, because it is only a function that -relies on different arguments everytime it is called. However, a database -handler might only be instantiated once (same database, same info, same args) - -Example Usage -------------- - -How a handler is accessed depends on how the handler is defined. Does it -expect arguments? Does it return data? This is all for the developer of the -application to determine, and document. As an example, lets say we have a -database handler. We want to use handlers to setup and provide access to -two different databases. One for read operations, and one for write -operations. Please note, this is a psuedo example and will not have any real -database interaction. - -helloworld/core/database.py - -.. code-block:: python - - class Database(object): - def __init__(self, uri): - self.uri = uri - - def connect(self): - # do something and establish a connection - raise NotImplementedError, "Database.connect() must be subclassed." - - def query(self, query_string): - # do something and return query_results - raise NotImplementedError, "Database.query() must be subclassed." - - -helloworld/lib/database/mysql.py - -.. code-block:: python - - from helloworld.core.database import Database - - class MySQLDatabase(Database) - def connect(self): - # do something to connect to self.uri - pass - - def query(self, query_string): - # do something with query_string - return query_results - - -helloworld/bootstrap/root.py - -.. code-block:: python - - from cement.core.handler import define_handler - from helloworld.lib.database.mysql import MySQLDatabase - - define_handler('database') - - # setup a persistant database object, one for read one for write - read_db = MySQLDatabase('some_db_uri') - write_db = MySQLDatabase('some_other_db_uri') - register_handler('database', 'read_db', read_db) - register_handler('database', 'write_db', write_db) - - -helloworld/controller/root.py - -.. code-block:: python - - from cement.core.handler import get_handler - - class RootController(CementController): - def query_database(self) - # read from the readonly database server - db = get_handler('database', 'read_db') - res = db.query('some SQL query') - # do something with res - - def update_something(self): - # do some operation on the write database server - db = get_handler('database', 'write_db') - db.query('some query to update something') diff --git a/doc/source/dev/hooks.rst b/doc/source/dev/hooks.rst deleted file mode 100644 index e3fbb327..00000000 --- a/doc/source/dev/hooks.rst +++ /dev/null @@ -1,206 +0,0 @@ -Hooks -===== - -Hooks allow the developers to tie into different pieces of the application. -A hook can be defined anywhere, be it internally in the application, or in a -plugin. Once a hook is defined, functions can be registered to that hook so -that when the hook is called, all functions registered to that hook will be -run. By defining a hook, you are saying that you are going to honor that hook -somewhere in your application. Using descriptive hook names are good for -clarity. For example, 'pre_database_connect_hook' is obviously a hook that -will be run before a database connection is attempted. - -Cement has a number of hooks that tie into the Cement Framework: - -Hook definitions: - - options_hook - Used to add options to a namespaces options object - - post_options_hook - Run after all options have been setup and merged - - post_bootstrap_hook - Run just after the root bootstrap is loaded. Note that Plugins can - not use this hook because it runs before plugins are loaded. Use - post_plugins_hook instead. - - validate_config_hook - Run after config options are setup - - pre_plugins_hook - Run just before all plugins are loaded (run once) - - post_plugins_hook - Run just after all plugins are loaded (run once) - - -Defining a Hook ---------------- - -A hook can be defined as follows: - -.. code-block:: python - - from cement.core.hook import define_hook - - define_hook('my_example_hook') - - -Hooks are defined during the bootstrap process, and should be added to the -bootstrap file for the namespace they relate to. - -**./helloworld/bootstrap/example.py**: - -.. code-block:: python - - from cement.core.hook import define_hook - from cement.core.plugin import CementPlugin, register_plugin - - define_hook('my_example_hook') - ... - - -Registering Functions to a Hook -------------------------------- - -A hook is just an identifier, but the functions registered to that hook are -what get run when the hook is called. Registering a hook should also be done -during the bootstrap process The following is how to register a hook from a -controller file: - -**./helloworld/bootstrap/someothernamespace.py**: - -.. code-block:: python - - from cement.core.hook import register_hook - - @register_hook() - def my_example_hook(*args, **kwargs): - # do something - something = "The result of my hook." - return something - - @register_hook(name='some_other_hook_name') - def my_function(*args, **kw): - # do something - ... - - -The @register_hook() decorator uses the name of the function you are -decorating to determine the hook you are registering for, or you can pass the -name parameter. Note that if combining with other decorators you must pass -the name parameter. It should also be noted, you probably don't want to -decorate a command function [one that is @expose()'d] as a hook. - -What you return depends on what the developer defining the hook is expecting. -Each hook is different, and the nature of the hook determines whether you need -to return anything or not. That is up to the developer. Also, the args and -kwargs coming in depend on the developer. You have to be familiar with -the purpose of the defined hook in order to know whether you are receiving any -args or kwargs, but either way you ant to accept them. - -Registering a hook just puts the function into the hook list. This will be an -unbound function, so if you register a function that is a class method keep in -mind that 'self' doesn't exist in the context of when the hook is run. For the -most part, standard unbound functions are best for hooks rather than controller -or other class methods. - - -Running a hook --------------- - -Now that a hook is defined, and functions have been registered to that hook -all that is left is to run it. Keep in mind, you don't want to run a hook -until after the application load process... meaning, after all plugins and -controllers are loaded. For the most part, you don't have much control over -this as that is all handled by Cement, however if you get an error that the -hook doesn't exist then you are probably running it too early. - -.. code-block:: python - - from cement.core.hook import run_hooks - - for res in run_hooks('my_example_hook'): - # do something with res - pass - -As you can see we iterate over the hook, rather than just calling -'run_hooks()'. This is necessary because run_hooks() yields the results from -each hook. Hooks can be run anywhere *after* the hook is defined, and hooks -are registered to that hook. - - -Controlling Hook Run Order --------------------------- - -Sometimes you might have a very specific purpose in mind for a hook, and need -it to run before or after other functions in the same hook. For that reason -there is an optional 'weight' option that can be passed when registering a -hook function. - -First I'm going to define the hook, and also create an example command here -that will run the hook. - -**./helloworld/controllers/root.py**: - -.. code-block:: python - - from cement.core.hook import define_hook, run_hooks - from cement.core.controller import CementController, expose - - define_hook('my_example_hook') - - class RootController(CementController): - @expose() - def hook_example(self): - for res in run_hooks('my_example_hook'): - pass - - -Then, we need to register functions into that hook, which we will do from -another controller: - -**./helloworld/controllers/example.py**: - -.. code-block:: python - - from cement.core.hook import register_hook - - @register_hook(weight=99) - def my_example_hook(*args, **kwargs): - print "In example_hook number 1, weight = 99" - - @register_hook(weight=-1000) - def my_example_hook(*args, **kwargs): - print "In example_hook number 2, weight = -1000" - - @register_hook() - def my_example_hook(*args, **kwargs): - print "In example_hook number 3, weight = 0 (defaullt)" - - # snipped the rest of the file - - -We probably wouldn’t register the same hook from the same place, but I wanted -to in order to show how hooks are ordered by weight. - -Note, you must iterate over run_hooks as it yields the results of the -function. And the result? - -.. code-block:: text - - $ helloworld hook-example - loading example plugin - loading clibasic plugin - In example_hook number 2, weight = -1000 - In example_hook number 3, weight = 0 (defaullt) - In example_hook number 1, weight = 99 - - -As you can see, it doesn’t matter what order we register the hook, the -weight runs then in order from lowest to highest. Hooks are awesome and -provide a little bit of magic to your application. Be sure to properly -document any hooks you define, what their purpose is and where they will -be run. - diff --git a/doc/source/dev/logging.rst b/doc/source/dev/logging.rst deleted file mode 100644 index c5d117fc..00000000 --- a/doc/source/dev/logging.rst +++ /dev/null @@ -1,81 +0,0 @@ -Logging -======= - -Cement applications are setup with the standard logging facility for both -file and console logging. - -Configuration Settings ----------------------- - -The following configuration options under your applications [root] namespace -are honored: - - log_file - A path to a log file (if none is set, file logging is disabled) - - log_level - Log level (info, warn, error, fatal, debug) - - log_to_console - Whether or not to log to console. - - logging_config_file - A logging configuration file that allows you to override the default - logging configuration. File format and usage can be found here: - http://docs.python.org/library/logging.html#logging.fileConfig - - log_max_bytes - Maximum number of bytes to keep in a log file (default: no limit). - - log_max_files - Maximum number of log files to keep in rotation (default: no rotation) - - -Using the Logger ----------------- - -.. code-block:: python - - from cement.core.log import get_logger - - log = get_logger(__name__) - log.info('this is an info message') - log.warn('this is a warning') - log.error('this is an error') - log.fatal('this is a critical error') - log.debug('KAPLA!!!!!!') - - -Configuring Logging via a Config File -------------------------------------- - -An example logging configuration file might look like: - -*/etc/yourapp/yourapp-logging.conf* - -.. code-block:: text - - [loggers] - keys = root - - [handlers] - keys = hand01 - - [formatters] - keys = form01 - - [logger_root] - level=DEBUG - handlers=hand01 - - [handler_hand01] - class=StreamHandler - level=NOTSET - formatter=form01 - args=(sys.stdout,) - - [formatter_form01] - format=F1 %(asctime)s %(levelname)s %(message)s - datefmt= - class=logging.Formatter - \ No newline at end of file diff --git a/doc/source/dev/mvc.rst b/doc/source/dev/mvc.rst deleted file mode 100644 index 305ef954..00000000 --- a/doc/source/dev/mvc.rst +++ /dev/null @@ -1,179 +0,0 @@ -Model, View, Controller Overview -================================ - -The Cement Framework creates applications that encourage the Model, View, -Controller design. Each piece of your application should be separated this -way. For example, if you add a plugin called 'myplugin' you should work out -of the following files: - - * helloworld/bootstrap/myplugin.py - * helloworld/model/myplugin.py - * helloworld/controllers/myplugin.py - * helloworld/templates/myplugin/ - - -As always, review the 'example' plugin included with your application to see -how this all works. Additionally, a great explanation of a typical MVC design -can be found on `Wikipedia `_. - - -The Model -^^^^^^^^^ - -The Model represents the data that you are working with. This might be a -User class, or a Product, etc. The class might be an SQLAlchemy class tied -to a database, or can just simply be an object allowing you to organize data. - -**helloworld/model/user.py** - -.. code-block:: python - - class User(object): - def __init__(self, first, last, **kwargs): - self.first_name = first - self.last_name = last - self.address = kwargs.get('address', None) - - @property - def display_name(self): - return "%s %s" % (self.first_name, self.last_name) - - -The model should always be associated with 'data' and should rarely perform -operations or tasks outside of creating/editing/saving/deleting/etc the -data associated with that model. - -A recommended way of accessing your model throughout your application is to -import all model classes into the 'root' model file like so: - -**helloworld/model/root.py** - -.. code-block:: python - - from helloworld.model.example import Example - from helloworld.model.user import User - from helloworld.model.product import Product - - -Then, throughout your application you can access all of you module objects -like this: - -.. code-block:: python - - from helloworld.model import root as model - - user = model.User() - product = model.Product() - - -The Controller -^^^^^^^^^^^^^^ - -The controller is primarily used to expose commands to your application. Note -that you can expose a command function to any namespace that has been defined. -By default all commands are exposed to the 'root' namespace and will display -when you execute: - -.. code-block:: text - - $ helloworld --help - -When you expose to another namespace, like say 'greeting' then your command -will show up under: - -.. code-block:: text - - $ helloworld greeting --help - - -A typical example of this would be - -**helloworld/controllers/greeting.py** - -.. code-block:: python - - from cement.core.controller import CementController, expose - from helloworld.model import root as model - - class GreetingController(CementController): - @expose('helloworld.templates.greetings.sayhi', namespace='root') - def sayhi(self): - user = model.User(first=self.cli_opts.first_name, - last=self.cli_opts.last_name) - return dict(user=user) - - -The method 'GreetingController.sayhi' is exposed to the 'root' namespace, and -will be called when the following command is run: - -.. code-block:: text - - $ helloworld sayhi --firstname="John" --lastname="Doe" - - -The user object is then returned in a dictionary and rendered by Genshi with -the template 'helloworld.templates.greetings.sayhi' or what equates to -'helloworld/templates/greetings/sayhi.txt' on the filesystem (as an example). -The return dictionary can contain strings, lists, tuples, dicts, class objects -and similar data. It should never return functions or other non-serializable -objects. - -*Note: You can also tell Cement to write output to a file rather than STDOUT -by passing "output_file='/path/to/file'" in your return dict().* - -Controllers are very flexible. Some people won't want to use Genshi -templating, which is perfectly fine. The following exposes a command without -template rendering: - -**helloworld/controllers/greeting.py** - -.. code-block:: python - - from cement.core.controller import CementController, expose - from helloworld.model import root as model - - class GreetingController(CementController): - @expose() - def sayhi(self): - user = model.User(first=self.cli_opts.first_name, - last=self.cli_opts.last_name) - print 'Hello %s!' % user.display_name - return dict(user=user) - -Notice how we don't need to specify a template path, though the command is -still exposed. That said, you should always return any relevant data even -if not rendering a template. This is because every command automatically -has a Json output engine. By adding '--json' to the end of your command, all -output is suppressed and only the return data is rendered via Json. In -addition stdout, and stderr are also added to the Json output. - - -The View -^^^^^^^^ - -Note that the templates directory *must* have a directory for each namespace -that contains your template file (more on templating later). Templating is not -necessary if you prefer to simply use the print statement, that said for -larger applications that provide a lot of console output learning the Genshi -Text Template syntax will significantly clean up your controllers and provide -more robust output to the user. - -Our 'sayhi' template would look like: - -**helloworld/templates/greetings/sayhi.txt** - -.. code-block:: text - - {# This is an example Genshi Text Template. Documentation is at: #}\ - {# #}\ - {# http://genshi.edgewall.org/wiki/Documentation/text-templates.html #}\ - {# #}\ - \ - \ - {# --------------------- 78 character baseline --------------------------- #}\ - - Hello ${user.display_name} - - -Using the '78 character baseline' comment in your templates is useful so that -you ensure your output remains within that limit when possible. \ No newline at end of file diff --git a/doc/source/dev/namespaces.rst b/doc/source/dev/namespaces.rst deleted file mode 100644 index 9d960911..00000000 --- a/doc/source/dev/namespaces.rst +++ /dev/null @@ -1,130 +0,0 @@ - -Namespaces -========== - -The Cement Framework establishes a global 'namespaces' dictionary that stores -information for each namespace (and/or plugin). A Cement namespace should -not be confused with a Python namespace. We use namespaces in reference to -where commands, configurations, command line options/arguments, etc are -accessible from. - -All namespaces have the following members, that are available under the -global *namespaces['namespace']* dictionary: - - config - A ConfigObj object, also accessible as a dict. For the 'root' namespace - which is the base application itself, this holds all the critical - configurations for your application. The 'root' namespace config - is generated from a default set, and then overridden by config files - in either /etc/yourapp/yourapp.conf (global) or ~/.yourapp.conf (per - user). For namespace specific configs, the configuration is generated - from a default set and then overridden by the plugin config file at - /etc/yourapp/plugins.d/yourplugin.conf or from a [namespace] block - from the main applications configuration file. - - label - The name of the namespace (single word). For complex namespaces, or - those that are better fit for two words, you must use an underscore - '_'. All python modules/files, config files, and config blocks - '[you_namespace]' must also use underscores. That said, Cement will - display this namespaces *with* dashes in the --help output and will - be called as 'your-namespace' which is more proper for command line - access. - - version - The version of the applicaton ('root') or of the plugin. If not - specified this version will be inherited from the root namespace. - - description - A brief summary of the plugin or namespace. - - commands - A dictionary of commands exposed into this namespace. This is - different than commands exposed by the namespaces controller. - Controllers from any namespace can expose commands into other - namespaces, which will be added to the commands dictionary of the - destination namespace (yes, it's confusing). - - controller - The CementController object for the namespace. Set as a string - when initializing a namespace, but is instantiated as the object - when the namespace is registered. - - options - An OptParse object used to set options that are local to this - namespace only. For example, for a subcommand 'cmd2' of the 'example' - namespace, the option '--my-opt' would only appear under - 'myapp example cmd2 --my-opt' but would not be available under - 'myapp cmd1 --my-opt'. - - is_hidden - Boolean, determines whether or not to display the namespace in the - output of 'myapp --help'. By default, if the namespace does not - have any visible/exposed commands, the namespace will not display. - - -Namespaces are generally used to breakup your applicaton into smaller parts. -For example, if you have 50 commands under the root namespace and all show -up under 'myapp --help' you're users are going to hate you. Namespaces allow -you to breaking up commands into smaller, related sections. - -**./helloworld/bootstap/example.py**: - -.. code-block:: python - - from cement.core.hook import define_hook - from cement.core.namespace import CementNamespace, register_namespace - - define_hook('my_example_hook') - - # Setup the 'example' namespace object - example = CementNamespace('example', controller='ExampleController') - - # Example namespace default configurations, overwritten by the [example] - # section of the applications config file(s). Once registered, this dict is - # accessible as: - # - # from cement.core.namespace import get_config - # example_config = get_config('example') - # - # Or simply as: - # - # root_config = get_config() - # root_config['example'] - # - example.config['foo'] = 'bar' - - # Example namespace options. These options show up under: - # - # $ {{package}} example --help - # - example.options.add_option('-F', '--foo', action='store', - dest='foo', default=None, help='Example Foo Option' - ) - - # Officialize and register the namespace - register_namespace(example) - - -Namespaces are always defined and registered in an associated bootstrap file, -as in the above example we registered the 'example' namespace from the file -'helloworld/bootstrap/example.py'. - - -Accessing Namespaces -^^^^^^^^^^^^^^^^^^^^ - -Accessing the namespaces dictionary directly is not recommended from outside -the Cement Framework code. That said, there might be a sitation you would -want to and well, we can't stop you can we? - -.. code-block:: python - - from cement import namespaces - - my_namespace = namespaces['my_namespace'] - my_namespace.config - my_namespace.commands - my_namespace.version - - diff --git a/doc/source/dev/options_and_arguments.rst b/doc/source/dev/options_and_arguments.rst deleted file mode 100644 index 43982beb..00000000 --- a/doc/source/dev/options_and_arguments.rst +++ /dev/null @@ -1,203 +0,0 @@ -Command Line Options and Arguments -================================== - -Cement fully configures command line option and argument parsing via the -`OptionParser `_ library. The following outlines how to create options, and -access the options and arguments passed to your application. - -Adding Options To a Namespace -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Typically, options are added directly to a namespace when that namespace is -registered. The following comes from the example plugin: - -**helloworld/bootstrap/example.py** - -.. code-block:: python - - from cement.core.namespace import CementNamespace, register_namespace - - example = CementNamespace( - label='example', - controller='ExampleController', - description='Example Plugin for helloworld', - provider='helloworld' - ) - - example.config['foo'] = 'bar' - - example.options.add_option('-F', '--foo', action='store', - dest='foo', default=None, help='Example Foo Option' - ) - - register_namespace(example) - - -The option added above shows up under the example namespace like so: - -.. code-block:: text - - $ helloworld example --help - Usage: helloworld example [ARGS] --(OPTIONS) - - Sub-Commands: - ex2, ex1 - - Help? try '[SUBCOMMAND]-help' - - Options: - --version show program's version number and exit - -h, --help show this help message and exit - -F FOO, --foo=FOO Example Foo Option - -R, --root-option Example root option - --json render output as json (CLI-API) - --debug toggle debug output - --quiet disable console logging - --yaml render output as yaml - - -The '-F/--foo' option does *not* show up under the root namespace -(helloworld --help). In most cases, an option also aligns with a config -option as you can see in the example above. When the '--foo' option is passed, -if the config['foo'] option exists, it will override the value with that of -the value passed at the command line. - -You will also notice in the above that all of our root options also show up -under our 'example' namespace. This is configurable by the -'merge_root_options' plugin configuration option. Take the following example: - -.. code-block:: python - - from cement.core.namespace import CementNamespace, register_namespace - - example = CementNamespace( - label='example', - controller='ExampleController', - description='Example Plugin for helloworld', - provider='helloworld' - ) - - example.config['foo'] = 'bar' - example.config['merge_root_options'] = False - - example.options.add_option('-F', '--foo', action='store', - dest='foo', default=None, help='Example Foo Option' - ) - - register_namespace(example) - - -And the output: - -.. code-block:: text - - $ helloworld example --help - Usage: helloworld example [ARGS] --(OPTIONS) - - Sub-Commands: - ex2, ex1 - - Help? try '[SUBCOMMAND]-help' - - Options: - --version show program's version number and exit - -h, --help show this help message and exit - -F FOO, --foo=FOO Example Foo Option - -If 'merge_root_options' is set to False, only the options added to this -namespace directly will be configured. - - -Adding Options To Another Namespace -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Options can be added *to* any namespace *from* any namespace bootstrap by way -of the built in 'options_hook'. For example, you will see something like the -following in your applications root bootstrap: - -**helloworld/bootstrap/root.py** - -.. code-block:: python - - from cement.core.opt import init_parser - from cement.core.hook import register_hook - - # Register root options - @register_hook() - def options_hook(*args, **kwargs): - # This hook allows us to append options to the root namespace - root_options = init_parser() - root_options.add_option('-R', '--root-option', action ='store_true', - dest='root_option', default=None, help='Example root option') - root_options.add_option('--json', action='store_true', - dest='enable_json', default=None, - help='render output as json (CLI-API)') - root_options.add_option('--debug', action='store_true', - dest='debug', default=None, help='toggle debug output') - root_options.add_option('--quiet', action='store_true', - dest='quiet', default=None, help='disable console logging') - return ('root', root_options) - - -The 'options_hook' expects a tuple in return when it runs that hook, and the -tuple is made up of (namespace_name, optparse_object). Code similar to the -above can also be used to inject options into any other namespace allowing -plugins to build off of, and add functionality to other plugins or other -built in namespaces in your application. - - -Accessing Options and Arguments -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -All options and arguments passed at command line are accessible via the -attributes 'self.cli_opts' and 'self.cli_args' from within every -CementController. For example: - -**helloworld/controllers/example.py** - -.. code-block:: python - - class ExampleController(CementController): - @expose(namespace='root') - def cmd2(self): - print "args[1] => ", self.cli_args[1] - print "root_option => ", self.cli_opts.root_option - return dict() - -The output is: - -.. code-block:: text - - $ helloworld cmd2 --root-option arg1 arg2 - args[1] => bar - root_option => True - - -Alternate Option Examples -^^^^^^^^^^^^^^^^^^^^^^^^^ - -All options are standard OptParse options, however the following are some -examples. - -.. code-block:: python - - example.options.add_option('--prompt', action='store_true', dest='prompt', - help='toggle prompting') - -The above sets namespaces['example'].config['prompt'] to True, as well as -self.cli_opts.prompt. The action is can be either 'store' or 'store_true' -which means store the value passed with the option, or just store the option -as True. dest is the variable name that the option value is stored as. help -is what is displayed in --help. - - -.. code-block:: python - - example.options.add_option('-F', '--foo', action='store', dest='foo', - help='pass value to foo', metavar='STR') - -The above sets namespaces['example'].config['foo'] to the value passed at -command line (helloworld --foo=bar), and also sets self.cli_opts.foo the same. -metavar is an extra option that alters the display in --help (-F STR, --foo=STR). - - diff --git a/doc/source/dev/plugin_support.rst b/doc/source/dev/plugin_support.rst deleted file mode 100644 index 47bff31d..00000000 --- a/doc/source/dev/plugin_support.rst +++ /dev/null @@ -1,128 +0,0 @@ -Plugin Support -============== - -Plugins are made possible by namespaces, therefore you should read and -be familiar with the Namespaces section of the documentation. There -is no difference between internal controller/model/bootstrap/etc code and -plugin code. The difference is that plugins are optional and only loaded if -'enable_plugin=true' in the plugins configuration. Internal code is -bootstrapped and imported directly by 'helloworld/bootstrap/root.py' so that -it is always loaded by your application. - -The Cement Framework automatically builds plugin support into your application. -Plugins can be either internal, or external. Internal plugins are shipped -with your application and are more or less a convenient way of maintaining -optional code within your application. External plugins are either for -third parties to build new features into your application, or perhaps for you -yourself to build extended support maybe under a different license, or in -order to not interfere with your stable application. - -Because users can override the default application configuration in their -home dir ~/.yourapp.conf, they can optionally enable/disable plugins catered -to their actual needs of the application. Plugins are a great way for them -to add functionality that the system administrator might not want to enable -globally. - - -A Look at an Internal Plugin ----------------------------- - -An internal plugin would consist of the following files: - - * ./yourapp/bootstrap/your_plugin.py - * ./yourapp/controllers/your_plugin.py - * ./yourapp/model/your_plugin.py - * ./yourapp/templates/your_plugin/ - * ./yourapp/etc/yourapp/plugins.d/your_plugin.conf - -As you can see, plugins have the same layout as the standard application which -utilizes a Model, View, Controller design as well as a bootstrap file. For -that reason we aren't going to cover much in this section because the plugin -code is exactly the same as your application. The only difference is that -you do not import the plugin's 'bootstrap' file into the root bootstrap like -you do with the rest of your application, but rather enable the plugin in the -your-plugin.conf within plugins.d. - - -Important Note on Naming Conventions ------------------------------------- - -In general, single word namespace and plugin names are preferred. That said -sometimes separating the words is necessary. Meaning, "yourplugin" versus -"your_plugin". In this case, only underscores '_' are allowed, not dashes. - - -External Plugins ----------------- - -External plugins are the same as internal plugins, however they are created -outside of the main applications source tree. To make this process as easy as -possible, we created a Paster plugin allowing you to create plugins for -applications built on cement. Therefore, if your applications name is -helloworld, the following creates an external plugin for helloworld: - -.. code-block:: python - - $ paster cement-plugin helloworld myplugin - - $ cd helloworld-plugins-myplugin - - $ python setup.py develop - - -Once the plugin is installed you simply need to enable it. An external plugin -functions by way of pkg_resources and shared library paths. Meaning, even -though the code is outside the main applications source tree the code is still -installed under the applications library path in site-packages. Take a look -at the files created by Paster and you will see that the tree is almost -the exact same as the main applications source tree. - - -Enabling Internal/External Plugins ----------------------------------- - -Plugins are enabled by first installing them, and then creating a plugin.conf -within your applications plugins.d directory (set by plugin_config_dir). -Plugin code is only loaded when 'enable_plugin=yes'. - -**/etc/yourapp/plugins.d/your-plugin.conf** - -.. code-block:: text - - [your-plugin] - enable_plugin = true - some_option = some value - foo = bar - - - -Shared Plugin Support ---------------------- - -Another form of plugin, is a shared plugin from another application. For -example, you can have a parent (company wide) application that has shared -functionality and re-usable code. Those plugins, from and for a completely -different application, can be loaded into your application to extend -functionality. - -A perfect example of using shared plugins is via The Rosendale Project. This -project is specifically geared toward building shared plugins for applications -that are built on the Cement Framework. Where internal, and external plugins -are built specifically for your application, shared plugins are loaded from -another application. - -Using the 'clibasic' plugin from The Rosendale Project as an example, the -following outlines how to load it as part of your application. - -**/etc/yourapp/plugins.d/clibasic.conf** - -.. code-block:: text - - [clibasic] - enable_plugin = true - provider = rosendale - - -The plugin will be loaded from the rosendale namespace, but will function as -if it were built specifically for your application. Yes, we know... this is -pretty awesome... you're right. diff --git a/doc/source/dev/quickstart.rst b/doc/source/dev/quickstart.rst deleted file mode 100644 index 13343c9f..00000000 --- a/doc/source/dev/quickstart.rst +++ /dev/null @@ -1,265 +0,0 @@ -Quick Starting a New CLI Application -==================================== - -The following outlines how to create a new application built on The Cement -CLI Application Framework. Throughout this documentation we reference an -application called 'helloworld'. For almost all cases, you can replace -helloworld with the package name of your application. - - -Raw Commands For The Impatient ------------------------------- - -This is for development. Please note that in production you will likely be -installing system wide (with root access), and that you only need 'cement' in -production (not cement.devtools). - -.. code-block:: text - - ### install - - $ virtualenv --no-site-packages ~/env/helloworld - - $ source ~/env/helloworld/bin/activate - - $ easy_install cement.devtools - - - ### create app - - $ paster cement-app helloworld - - $ cd helloworld - - $ python setup.py develop - - - ### setup local (user) config - - $ cp -a ./etc/helloworld.conf-dev ~/.helloworld.conf - - $ vi ~/.helloworld.conf - - $ helloworld --help - - - ### create an external plugin - - $ mkdir plugins - - $ cd plugins - - $ paster cement-plugin helloworld myplugin - - $ cd helloworld.myplugin - - $ python setup.py develop - - $ cp -a ./etc/plugins.d/myplugin.conf ~/path/to/plugin_config_dir - - $ helloworld --help - - -Installing Cement ------------------ - -This section outlines how to install Cement. By preference, we do so by way -of installing to a virtualenv. This is not necessary if you have root access -on your system and want to install system wide. That said, for development -purposes (i.e. building your application) you should be working out of a -virtualenv. - -Before installing Cement, setup your virtual environment: - -.. code-block:: text - - $ virtualenv --no-site-packages ~/devel/env/helloworld - - $ source ~/devel/env/helloworld/bin/activate - - (helloworld) $ - - -Your virtual environment is now active. Anything you install will be -installed to this location and not system wide. To leave the environment, run -the following: - -.. code-block:: text - - (helloworld) $ deactivate - - $ - - -Stable -^^^^^^ - -Stable versions of Cement can be installed from the CheezeShop via -easy_install (devtools installs cement as a dependency): - -.. code-block:: text - - $ easy_install cement.devtools - - -Development -^^^^^^^^^^^ - -Development versions of Cement can be cloned from GitHub: - -.. code-block:: text - - $ git clone git://github.com/derks/cement.git - - # install cement core framework - $ cd cement/src/cement - $ python setup.py install - - # install devtools - $ cd ../cement.devtools - $ python setup.py install - - - -The 'master' branch tracks development that is compatible with the stable -API. However, development on the next major version which will break API -compatibility is tracked in the 'portland' branch. The portland branch -can be checkout by: - -.. code-block:: text - - $ git checkout --track -b portland origin/portland - - -Creating The HelloWorld Application ------------------------------------ - -Now that the Cement Framework is installed, we can create our application -from templates via PasteScript (which is installed as a dependency when you -install Cement). The following creates and installs a new CLI Application -called HelloWorld, and copies a 'development' config file to your home -directory path. Note that the -dev config is geared towards 'local' file -paths for your user where as the other config is geared towards a system wide -production install: - -.. code-block:: text - - $ paster cement-app helloworld - - $ cd helloworld - - $ python setup.py develop - - $ cp -a etc/helloworld.conf-dev ~/.helloworld.conf - - -**Note:** You need to look at ~/.helloworld.conf and edit any settings. For -most cases, the only thing you might want to edit is the 'plugin_config_dir' -path to point it to '/path/to/helloworld/etc/plugins.d'. Your application by -default searches for configs in the following order: - - * /etc/helloworld/helloworld.conf - * ~/.helloworld/etc/helloworld.conf - * ~/.helloworld.conf - -The second is a hard set location based on the 'prefix' in your applications -'helloworld/core/config.py' and is not often relied on. Now that helloworld -is installed, lets see what it looks like: - -.. code-block:: text - - $ helloworld --help - loading example plugin - Usage: helloworld [COMMAND] --(OPTIONS) - - Commands: - get-started, cmd1, cmd2, example* - - - Help? try [COMMAND]-help - - Options: - --version show program's version number and exit - -h, --help show this help message and exit - -R, --root-option Example root option - --json render output as json (Cement CLI-API) - --debug toggle debug output - --quiet disable console logging - - -Go ahead and run the get-started command: - -.. code-block:: text - - $ helloworld get-started - - -It is more or less the same information you are reading here, however it is -also a functional command that is rendered by Genshi and a template. We've -put it there to show how commands are created and rendered. Go ahead and -take a look at the following files to see where and how that command is setup: - - * helloworld/controllers/root.py - * helloworld/templates/root/get-started.txt - - -You will also notice that your app is already loading an 'example' plugin. -Plugins are enabled under their [plugin] config either in your main -application configuration file, or in the plugins.d/.conf file for -that plugin. An example plugin config looks like: - -.. code-block:: text - - [example] - enable_plugin = true - provider = helloworld - - -The 'provider' is the package that provides it and can be omitted for plugins -that are a part of your application. However, you can load plugins from any -other application that is built on Cement by adding them as the provider. -The plugin has to be written in a 'generic' fashion of course. For more -information on shared plugins check our The Rosendale Project which provides -plugins explicitly for re-usability in other applications built on Cement. - -The included example plugin is a great starting point to learn how to build an -application on top of the Cement Framework. The following files and -directories should be explored: - - * ./helloworld/bootstrap/example.py - * ./helloworld/controllers/example.py - * ./helloworld/model/example.py - * ./helloworld/templates/example/ - -It should be noted that the only difference between a plugin, and a built in -part of your application is that a plugin is optional, and only loaded if -enabled via the configuration. You can make the example plugin part of your -application by adding the following to 'helloworld/bootstrap/root.py' - -.. code-block:: python - - from helloworld.bootstrap import example - - -All modules imported into the root bootstrap become a part of the application -permanently (meaning its not loaded as an optional plugin). You then want to -move the plugins configuration from a separate plugin config to your primary -applications configuration and remove 'enable_plugin' setting. - -Once you're ready to start coding, you can disable the 'example' plugin by -setting 'enable_plugin=false' in plugins.d/example.conf. That said, it is -recommended to keep the example plugin included with our application, as this -also provides a starting point for developers wanting to build external plugins -for your application (explained later on). - -By default, the base application has a command named 'cmd1' created in the -controller and the options -R/--root-option, --debug, --quiet, --json which -are created in the bootstrap file. You can remove these from the bootstrap -file so that they don't show up under '--help', however please note that ---debug, --quiet, and --json are hard coded in the Cement framework and will -still function if the user passes them at command line. - -The example plugin provides the 'example*' namespace, which has two commands -under it called 'ex1', and 'ex2' created in the controller, as well as the -'-F/--foo' option created in the bootstrap file. The controller also exposes -a root command called 'cmd2'. diff --git a/doc/source/dev/templates.rst b/doc/source/dev/templates.rst deleted file mode 100644 index 0747d09b..00000000 --- a/doc/source/dev/templates.rst +++ /dev/null @@ -1,226 +0,0 @@ -Genshi Templating Engine -======================== - -Cement applications use a Model, View, Controller design. By separating the -view, or in this case what is printed to STDOUT, you can significantly clean -up your controller code. Cement configures new applications to use the -Genshi text templating language by default. This is configured in your -applications 'core.config' module via the setting 'output_handler'. Note -that for developers not interested in having output rendered from template -or any other kind of output rendering... this setting can be set to None. - -A sample controller that exports its data to a Genshi template: - -**./helloworld/controllers/example.py**: - -.. code-block:: python - - from helloworld.model.example import ExampleModel - - @expose('helloworld.templates.example.ex2', namespace='root') - def ex2(self, cli_opts, cli_args): - example = ExampleModel() - example.label = 'This is my Example Model' - - if cli_opts.my_option: - print '%s passed by --my-option' % cli_opts.root_option - - return dict(foo=True, example=example, items=['one', 'two', 'three']) - -It should be noted that the output_handler is implied in the above code, and -tells Cement to use the default that is configured in your apps core.config -module under 'output_handler'. To specify an alternate handler, you can do -the following: - -.. code-block:: python - - @expose('jinja2:helloworld.templates.example.ex2', namespace='root') - ... - -Where 'jinja2' is the alternate output_handler to use for that command only, -assuming that a plugin is installed that provides an output_handler called -'jinja2'. - -The template looks like: - -**./helloworld/templates/example/ex2.txt**: - -.. code-block:: text - - {# This is an example Genshi Text Template. Documentation is available #}\ - {# at: #}\ - {# #}\ - {# http://genshi.edgewall.org/wiki/Documentation/text-templates.html #}\ - {# #}\ - \ - \ - {# --------------------- 78 character baseline --------------------------- #}\ - - There are a number of things you can do such as conditional statements: - - {% if foo %}\ - Label: ${example.label} - {% end %}\ - - Or a for loop: - - {% for item in items %}\ - * ${item} - {% end %}\ - - - And functions: - - {% def greeting(name) %}\ - Hello, ${name}! - {% end %}\ - ${greeting('World')}\ - ${greeting('Edward')} - - -Admittedly, the syntax is a bit cumbersome. But once you get the hang of it -there is a lot you can do with it, and your controller code looks so much -better. When rendered, this looks like: - -.. code-block:: text - - $ helloworld ex2 - loading example plugin - loading clibasic plugin - - There are a number of things you can do such as conditional statements: - - Label: This is my Example Model - - Or a for loop: - - * one - * two - * three - - And functions: - - Hello, World! - Hello, Edward! - - -For simple methods that don't print much data or maybe don't print at all, you -can simply skip the templating engine. The same method without rendering would -be: - -.. code-block:: python - - from helloworld.model.example import ExampleModel - - @expose(namespace='root') - def ex2(self, cli_opts, cli_args): - example = ExampleModel() - example.label = 'This is my Example Model' - - if cli_opts.my_option: - print '%s passed by --my-option' % cli_opts.root_option - - return dict(foo=True, example=example, items=['one', 'two', 'three']) - -Now, nothing is rendered by Genshi and no output will be printed to the -console unless you print it out yourself. That said, because we are still -returning our dictionary, we can still use our '--json' and output Json via -the CLI-API. - -Genshi Syntax Basics --------------------- - -As noted in the example template, documentation on Genshi Text Templating can -be found at: - - http://genshi.edgewall.org/wiki/Documentation/text-templates.html - -**Printing Variables** - -.. code-block:: text - - Hello ${user_name} - -Where 'user_name' is a variable returned from the controller. Will display: - -.. code-block:: text - - Hello Johnny - - -**if statements** - -.. code-block:: text - - {% if foo %}\ - Label: ${example.label} - {% end %}\ - -Will only output 'Label: