hey guys,

I just wrote a patch that allows the separation of package specific cli
options from the core of PhD. It's just a first idea so let me know what you
think.

Motivation:
Some options in PhD are specific for rendering the PHP Manual (--notoc,
--lang). These options make no effect if used with the other packages, so
would be interesting extract them from the core of PhD and implement these
options within the PHP package.

Syntax:
$ phd --<package>-<option> <value>

Examples:
$ phd -d path/to/.manual.xml -P PHP -f php --php-toc=true
$ phd --generic-version
$ phd --ide-help

Limitations:
  - Only long options available
  - getopt() based: so you have to use "--" before the options


Implementation Details:

I divided the BuildOptionsParser class in two other classes OptionsParser
and OptionsHandler. The OptionsHandler class will list the options and the
functions to handle those options. The OptionsParser loads all options (core
and per package) and parse them with getopt().

To add options in a package you have to implement a class (that implements
IOptionsHandler) and register in the factory

class Package_Generic_OptionsHandler implements IOptionsHandler {

    public function optionList() {
        return array(
            'foo:',
            'bar::',
        );
    }

    public function option_foo($k, $v) {
        //do something
    }
...

And then use: phd --generic-foo value --generic-bar=false



--Moacir de Oliveira
Index: render.php
===================================================================
--- render.php  (revisão 301979)
+++ render.php  (cópia de trabalho)
@@ -23,7 +23,7 @@
     Config::init(array());
 }
 
-BuildOptionsParser::getopt();
+OptionsParser::getopt();
 
 /* If no docbook file was passed, die */
 if (!is_dir(Config::xml_root()) || !is_file(Config::xml_file())) {
Index: phpdotnet/phd/OptionsHandler.php
===================================================================
--- phpdotnet/phd/OptionsHandler.php    (revisão 301979)
+++ phpdotnet/phd/OptionsHandler.php    (cópia de trabalho)
@@ -2,7 +2,7 @@
 namespace phpdotnet\phd;
 /* $Id$ */
 
-class BuildOptionsParser
+class OptionsHandler implements IOptionsHandler
 {
     public function __construct()
     {
@@ -14,7 +14,7 @@
         }
     }
 
-    public function getOptionList()
+    public function optionList()
     {
         return array(
             'format:'      => 'f:',        // The format to render (xhtml, 
pdf...)
@@ -393,35 +393,6 @@
         exit(0);
     }
 
-    public function handlerForOption($opt)
-    {
-        if (method_exists($this, "option_{$opt}")) {
-            return array($this, "option_{$opt}");
-        } else {
-            return NULL;
-        }
-    }
-
-    public static function getopt()
-    {
-        $bop = new self;
-        $opts = $bop->getOptionList();
-        $args = getopt(implode('', array_values($opts)), array_keys($opts));
-        if ($args === false) {
-            trigger_error("Something happend with getopt(), please report a 
bug", E_USER_ERROR);
-        }
-
-        foreach ($args as $k => $v) {
-            $handler = $bop->handlerForOption($k);
-            if (is_callable($handler)) {
-                call_user_func($handler, $k, $v);
-            } else {
-                var_dump($k, $v);
-                trigger_error("Hmh, something weird has happend, I don't know 
this option", E_USER_ERROR);
-            }
-        }
-    }
-
     /**
      * Makes a string into a boolean (i.e. on/off, yes/no, ..)
      *
Index: phpdotnet/phd/Format/Factory.php
===================================================================
--- phpdotnet/phd/Format/Factory.php    (revisão 301979)
+++ phpdotnet/phd/Format/Factory.php    (cópia de trabalho)
@@ -5,6 +5,7 @@
 abstract class Format_Factory {
     private $formats     = array();
     private $packageName = "";
+    private $optionsHandler = null;
 
     public final function getOutputFormats() {
         return array_keys($this->formats);
@@ -14,6 +15,14 @@
         $this->formats = $formats;
     }
 
+    public final function getOptionsHandler() {
+        return $this->optionsHandler;
+    }
+
+    public final function registerOptionsHandler(IOptionsHandler 
$optionsHandler) {
+        $this->optionsHandler = $optionsHandler;
+    }
+
     protected final function setPackageName($name) {
         if (!is_string($name)) {
             throw new \Exception("Package names must be strings..");
Index: phpdotnet/phd/IOptionsHandler.php
===================================================================
--- phpdotnet/phd/IOptionsHandler.php   (revisão 0)
+++ phpdotnet/phd/IOptionsHandler.php   (revisão 0)
@@ -0,0 +1,14 @@
+<?php
+namespace phpdotnet\phd;
+/* $Id$ */
+
+interface IOptionsHandler {
+
+    function optionList();
+
+}
+
+/*
+ * vim600: sw=4 ts=4 syntax=php et
+ * vim<600: sw=4 ts=4
+ */
Index: phpdotnet/phd/Package/Generic/OptionsHandler.php
===================================================================
--- phpdotnet/phd/Package/Generic/OptionsHandler.php    (revisão 0)
+++ phpdotnet/phd/Package/Generic/OptionsHandler.php    (revisão 0)
@@ -0,0 +1,40 @@
+<?php
+namespace phpdotnet\phd;
+/* $Id$ */
+
+class Package_Generic_OptionsHandler implements IOptionsHandler {
+
+    public function optionList() {
+        return array(
+            'version',
+            'help',
+        );
+    }
+
+    public function option_version($k, $v) {
+        $color  = Config::phd_info_color();
+        $output = Config::phd_info_output();
+        fprintf($output, "%s\n", term_color('PhD Generic Package Version: 
1.0.1', $color));
+        fprintf($output, "%s\n", term_color('PhD Version: ' . Config::VERSION, 
$color));
+        fprintf($output, "%s\n", term_color('PHP Version: ' . phpversion(), 
$color));
+        fprintf($output, "%s\n", term_color('Copyright(c) 2007-2010 The PHP 
Documentation Group', $color));
+        exit(0);
+    }
+
+    public function option_help($k, $v) {
+        echo "PhD Generic Package: 1.0.1";
+        echo "\nCopyright (c) 2007-2010 The PHP Documentation Group\n
+  --generic-version             Print the version information
+  --generic-help                Print this help
+
+Most options can be passed multiple times for greater effect.
+";
+        exit(0);
+    }
+
+}
+
+/*
+ * vim600: sw=4 ts=4 syntax=php et
+ * vim<600: sw=4 ts=4
+ */
Index: phpdotnet/phd/Package/Generic/Factory.php
===================================================================
--- phpdotnet/phd/Package/Generic/Factory.php   (revisão 301979)
+++ phpdotnet/phd/Package/Generic/Factory.php   (cópia de trabalho)
@@ -19,6 +19,7 @@
     {
         parent::setPackageName('Generic');
         parent::registerOutputFormats($this->formats);
+        parent::registerOptionsHandler(new Package_Generic_OptionsHandler());
     }
 }
 
Index: phpdotnet/phd/OptionsParser.php
===================================================================
--- phpdotnet/phd/OptionsParser.php     (revisão 0)
+++ phpdotnet/phd/OptionsParser.php     (revisão 0)
@@ -0,0 +1,91 @@
+<?php
+namespace phpdotnet\phd;
+/* $Id$ */
+
+class OptionsParser
+{
+
+    private $defaultHandler;
+    private $packageHandlers = array();
+
+    private function __construct() {
+        $this->defaultHandler = new OptionsHandler();
+        $this->packageHandlers = $this->loadPackageHandlers();
+    }
+
+    public static function instance() {
+        static $instance = null;
+        if ($instance == null) {
+            $instance = new OptionsParser();
+        }
+        return $instance;
+    }
+
+    private function loadPackageHandlers() {
+        $packageList = Config::getSupportedPackages();
+        $list = array();
+        foreach ($packageList as $package) {
+            if ($handler = 
Format_Factory::createFactory($package)->getOptionsHandler()) {
+                $list[strtolower($package)] = $handler;
+            }
+        }
+        return $list;
+    }
+
+    public function handlerForOption($option) {
+        if (method_exists($this->defaultHandler, "option_{$option}")) {
+            return array($this->defaultHandler, "option_{$option}");
+        }
+
+        $opt = explode('-', $option);
+        $package = strtolower($opt[0]);
+
+        if (isset($this->packageHandlers[$package])) {
+            if (method_exists($this->packageHandlers[$package], 
"option_{$opt[1]}")) {
+                return array($this->packageHandlers[$package], 
"option_{$opt[1]}");
+            }
+        }
+        return NULL;
+    }
+
+    public function getLongOptions() {
+        $defaultOptions = array_keys($this->defaultHandler->optionList());
+        $packageOptions = array();
+        foreach ($this->packageHandlers as $package => $handler) {
+            foreach ($handler->optionList() as $opt) {
+                $packageOptions[] = $package . '-' . $opt;
+            }
+        }
+        return array_merge($defaultOptions, $packageOptions);
+    }
+
+    public function getShortOptions() {
+        return implode('', array_values($this->defaultHandler->optionList()));
+    }
+
+    public static function getopt() {
+        $self = self::instance();
+
+        $args = getopt($self->getShortOptions(), $self->getLongOptions());
+        if ($args === false) {
+            trigger_error("Something happend with getopt(), please report a 
bug", E_USER_ERROR);
+        }
+
+        foreach ($args as $k => $v) {
+            $handler = $self->handlerForOption($k);
+            if (is_callable($handler)) {
+                call_user_func($handler, $k, $v);
+            } else {
+                var_dump($k, $v);
+                trigger_error("Hmh, something weird has happend, I don't know 
this option", E_USER_ERROR);
+            }
+        }
+    }
+
+}
+
+/*
+* vim600: sw=4 ts=4 syntax=php et
+* vim<600: sw=4 ts=4
+*/
+
Index: phpdotnet/phd/BuildOptionsParser.php
===================================================================
--- phpdotnet/phd/BuildOptionsParser.php        (revisão 301979)
+++ phpdotnet/phd/BuildOptionsParser.php        (cópia de trabalho)
@@ -1,463 +0,0 @@
-<?php
-namespace phpdotnet\phd;
-/* $Id$ */
-
-class BuildOptionsParser
-{
-    public function __construct()
-    {
-        // By default, Windows does not support colors on the console.
-        // ANSICON by Jason Hood can be used to provide colors at the console.
-        // Color output can still be set via the command line parameters.
-        if('WIN' === strtoupper(substr(PHP_OS, 0, 3))) {
-               $this->option_color('color', 'off');
-        }
-    }
-
-    public function getOptionList()
-    {
-        return array(
-            'format:'      => 'f:',        // The format to render (xhtml, 
pdf...)
-            'noindex'      => 'I',         // Do not re-index
-            'forceindex'   => 'r',         // Force re-indexing under all 
circumstances
-            'notoc'        => 't',         // Do not re-create TOC
-            'docbook:'     => 'd:',        // The Docbook XML file to render 
from (.manual.xml)
-            'output:'      => 'o:',        // The output directory
-            'partial:'     => 'p:',        // The ID to render (optionally 
ignoring its children)
-            'skip:'        => 's:',        // The ID to skip (optionally 
skipping its children too)
-            'verbose:'     => 'v::',        // Adjust the verbosity level
-            'list'         => 'l',         // List supported packages/formats
-            'lang::'       => 'L:',        // Language hint (used by the CHM)
-            'color:'       => 'c:',        // Use color output if possible
-            'highlighter:' => 'g:',        // Class used as source code 
highlighter
-            'version'      => 'V',         // Print out version information
-            'help'         => 'h',         // Print out help
-            'package:'     => 'P:',        // The package of formats           
 
-            'css:'         => 'C:',        // External CSS 
-            'xinclude'     => 'x',         // Automatically process xinclude 
directives
-            'ext:'         => 'e:',        // The file-format extension to 
use, including the dot
-            'saveconfig::' => 'S::',       // Save the generated config ?
-        );
-    }
-
-    public function option_f($k, $v)
-    {
-        $this->option_format($k, $v);
-    }
-    public function option_format($k, $v)
-    {
-        $formats = array();
-        foreach((array)$v as $i => $val) {
-            if (!in_array($val, $formats)) {
-                $formats[] = $val;
-            }
-        }
-        Config::set_output_format($formats);
-    }
-    
-    public function option_e($k, $v)
-    {
-        $this->option_ext($k, $v);
-    }
-    public function option_ext($k, $v)
-    {
-        $bool = self::boolval($v);
-        if ($bool === false) {
-            // `--ext=false` means no extension will be used
-            $v = "";
-            Config::setExt($v);
-        } elseif ($bool === null) {
-            // `--ext=true` means use the default extension,
-            // `--ext=".foo"` means use ".foo" as the extension
-            Config::setExt($v);
-        }
-    }
-    
-    public function option_g($k, $v)
-    {
-        $this->option_highlighter($k, $v);
-    }
-    public function option_highlighter($k, $v)
-    {
-        Config::setHighlighter($v);
-    }
-
-    public function option_i($k, $v)
-    {
-        $this->option_noindex($k, 'true');
-    }
-    public function option_noindex($k, $v)
-    {
-        Config::set_no_index(true);
-    }
-
-    public function option_r($k, $v)
-    {
-        $this->option_forceindex($k, 'true');
-    }
-    public function option_forceindex($k, $v)
-    {
-        Config::set_force_index(true);
-    }
-
-    public function option_t($k, $v)
-    {
-        $this->option_notoc($k, 'true');
-    }
-    public function option_notoc($k, $v)
-    {
-        Config::set_no_toc(true);
-    }
-
-    public function option_d($k, $v)
-    {
-        $this->option_docbook($k, $v);
-    }
-    public function option_docbook($k, $v)
-    {
-        if (is_array($v)) {
-            trigger_error("Can only parse one file at a time", E_USER_ERROR);
-        }
-        if (!file_exists($v) || is_dir($v) || !is_readable($v)) {
-            trigger_error(sprintf("'%s' is not a readable docbook file", $v), 
E_USER_ERROR);
-        }
-        Config::set_xml_root(dirname($v));
-        Config::set_xml_file($v);
-    }
-
-    public function option_o($k, $v)
-    {
-        $this->option_output($k, $v);
-    }
-    public function option_output($k, $v)
-    {
-        if (is_array($v)) {
-            trigger_error("Only a single output location can be supplied", 
E_USER_ERROR);
-        }
-        @mkdir($v, 0777, true);
-        if (!is_dir($v) || !is_readable($v)) {
-            trigger_error(sprintf("'%s' is not a valid directory", $v), 
E_USER_ERROR);
-        }
-        $v = (substr($v, strlen($v) - strlen(DIRECTORY_SEPARATOR)) == 
DIRECTORY_SEPARATOR) ? $v : ($v . DIRECTORY_SEPARATOR);
-        Config::set_output_dir($v);
-    }
-
-    public function option_p($k, $v)
-    {
-        if ($k == "P") {
-            return $this->option_package($k, $v);
-        }
-        $this->option_partial($k, $v);
-    }
-    public function option_partial($k, $v)
-    {
-        $render_ids = Config::render_ids();
-        foreach((array)$v as $i => $val) {
-            $recursive = true;
-            if (strpos($val, "=") !== false) {
-                list($val, $recursive) = explode("=", $val);
-
-                if (!is_numeric($recursive) && defined($recursive)) {
-                    $recursive = constant($recursive);
-                }
-                $recursive = (bool) $recursive;
-            }
-            $render_ids[$val] = $recursive;
-        }
-        Config::set_render_ids($render_ids);
-    }
-
-    public function option_package($k, $v) {
-        
-        foreach((array)$v as $package) {
-            if (!in_array($package, Config::getSupportedPackages())) {
-                $supported = implode(', ', Config::getSupportedPackages());
-                trigger_error("Invalid Package (Tried: '$package' Supported: 
'$supported')", E_USER_ERROR);
-            }
-        }
-        Config::set_package($v);
-    }
-
-    public function option_s($k, $v)
-    {
-        if ($k == "S") {
-            return $this->option_saveconfig($k, $v);
-        }
-        $this->option_skip($k, $v);
-    }
-    public function option_skip($k, $v)
-    {
-        $skip_ids = Config::skip_ids();
-        foreach((array)$v as $i => $val) {
-            $recursive = true;
-            if (strpos($val, "=") !== false) {
-                list($val, $recursive) = explode("=", $val);
-
-                if (!is_numeric($recursive) && defined($recursive)) {
-                    $recursive = constant($recursive);
-                }
-                $recursive = (bool) $recursive;
-            }
-            $skip_ids[$val] = $recursive;
-        }
-        Config::set_skip_ids($skip_ids);
-    }
-    public function option_saveconfig($k, $v)
-    {
-        if (is_array($v)) {
-            trigger_error(sprintf("You cannot pass %s more than once", $k), 
E_USER_ERROR);
-        }
-
-        // No arguments passed, default to 'true'
-        if (is_bool($v)) {
-            $v = "true";
-        }
-
-        $val = self::boolval($v);
-        if (is_bool($val)) {
-            Config::set_saveconfig($v);
-        } else {
-            trigger_error("yes/no || on/off || true/false || 1/0 expected", 
E_USER_ERROR);
-        }
-    }
-
-    public function option_v($k, $v)
-    {
-        if ($k[0] === 'V') {
-            $this->option_version($k, $v);
-            return;
-        }
-        $this->option_verbose($k, $v);
-    }
-
-    public function option_verbose($k, $v)
-    {
-        static $verbose = 0;
-
-        foreach((array)$v as $i => $val) {
-            foreach(explode("|", $val) as $const) {
-                if (defined($const)) {
-                    $verbose |= (int)constant($const);
-                } elseif (is_numeric($const)) {
-                    $verbose |= (int)$const;
-                } elseif (empty($const)) {
-                    $verbose = max($verbose, 1);
-                    $verbose <<= 1;
-                } else {
-                    trigger_error("Unknown option passed to --$k, '$const'", 
E_USER_ERROR);
-                }
-            }
-        }
-        Config::set_verbose($verbose);
-        error_reporting($GLOBALS['olderrrep'] | $verbose);
-    }
-
-    public function option_l($k, $v)
-    {
-        if ($k == "L") {
-            return $this->option_lang($k, $v);
-        }
-        $this->option_list($k, $v);
-    }
-    public function option_list($k, $v)
-    {
-        $packageList = Config::getSupportedPackages();
-        
-        echo "Supported packages:\n";
-        foreach ($packageList as $package) {
-            $formats = 
Format_Factory::createFactory($package)->getOutputFormats();
-            echo "\t" . $package . "\n\t\t" . implode("\n\t\t", $formats) . 
"\n";
-        }
-      
-        exit(0);
-    }
-
-    public function option_lang($k, $v)
-    {
-        Config::set_language($v);
-    }
-    public function option_c($k, $v)
-    {
-        if ($k == "C") {
-            return $this->option_css($k, $v);
-        }
-        $this->option_color($k, $v);
-    }
-    public function option_color($k, $v)
-    {
-        if (is_array($v)) {
-            trigger_error(sprintf("You cannot pass %s more than once", $k), 
E_USER_ERROR);
-        }
-        $val = self::boolval($v);
-        if (is_bool($val)) {
-            Config::setColor_output($val);
-        } else {
-            trigger_error("yes/no || on/off || true/false || 1/0 expected", 
E_USER_ERROR);
-        }
-    }
-    public function option_css($k, $v) {
-        $styles = array();
-        foreach((array)$v as $key => $val) {
-            if (!in_array($val, $styles)) {
-                $styles[] = $val;
-            }
-        }
-        Config::set_css($styles);
-    }
-
-    public function option_x($k, $v)
-    {
-        $this->option_xinclude($k, 'true');
-    }
-    public function option_xinclude($k, $v)
-    {
-        Config::set_process_xincludes(true);
-    }
-
-    /**
-     * Prints out the current PhD and PHP version.
-     * Exits directly.
-     *
-     * @return void
-     */
-    public function option_version($k, $v)
-    {
-        $color  = Config::phd_info_color();
-        $output = Config::phd_info_output();
-        fprintf($output, "%s\n", term_color('PhD Version: ' . Config::VERSION, 
$color));
-        fprintf($output, "%s\n", term_color('PHP Version: ' . phpversion(), 
$color));
-        fprintf($output, "%s\n", term_color('Copyright(c) 2007-2010 The PHP 
Documentation Group', $color));
-        exit(0);
-    }
-
-    public function option_h($k, $v)
-    {
-        $this->option_help($k, $v);
-    }
-    public function option_help($k, $v)
-    {
-        echo "PhD version: " .Config::VERSION;
-        echo "\nCopyright (c) 2007-2010 The PHP Documentation Group\n
-  -v
-  --verbose <int>            Adjusts the verbosity level
-  -f <formatname>
-  --format <formatname>      The build format to use
-  -P <packagename>
-  --package <packagename>    The package to use
-  -I
-  --noindex                  Do not index before rendering but load from cache
-                             (default: false)
-  -r
-  --forceindex               Force re-indexing under all circumstances
-                             (default: false)
-  -t
-  --notoc                    Do not rewrite TOC before rendering but load from 
cache
-                             (default: false)
-  -d <filename>
-  --docbook <filename>       The Docbook file to render from
-  -x
-  --xinclude                 Process XML Inclusions (XInclude)
-                             (default: false)
-  -p <id[=bool]>
-  --partial <id[=bool]>      The ID to render, optionally skipping its children
-                             chunks (default to true; render children)
-  -s <id[=bool]>
-  --skip <id[=bool]>         The ID to skip, optionally skipping its children
-                             chunks (default to true; skip children)
-  -l
-  --list                     Print out the supported packages and formats
-  -o <directory>
-  --output <directory>       The output directory (default: .)
-  -L <language>
-  --lang <language>          The language of the source file (used by the CHM
-                             theme). (default: en)
-  -c <bool>
-  --color <bool>             Enable color output when output is to a terminal
-                             (default: true; On Windows the default is false)
-  -C <filename>
-  --css <filename>           Link for an external CSS file.
-  -g <classname>
-  --highlighter <classname>  Use custom source code highlighting php class
-  -V
-  --version                  Print the PhD version information
-  -h
-  --help                     This help
-  -e <extension>
-  --ext <extension>          The alternative filename extension to use, 
including
-                             the dot. Use 'false' for no extension.
-  -S <bool>
-  --saveconfig <bool>        Save the generated config (default: false).
-
-Most options can be passed multiple times for greater effect.
-";
-        exit(0);
-    }
-
-    public function handlerForOption($opt)
-    {
-        if (method_exists($this, "option_{$opt}")) {
-            return array($this, "option_{$opt}");
-        } else {
-            return NULL;
-        }
-    }
-
-    public static function getopt()
-    {
-        $bop = new self;
-        $opts = $bop->getOptionList();
-        $args = getopt(implode('', array_values($opts)), array_keys($opts));
-        if ($args === false) {
-            trigger_error("Something happend with getopt(), please report a 
bug", E_USER_ERROR);
-        }
-
-        foreach ($args as $k => $v) {
-            $handler = $bop->handlerForOption($k);
-            if (is_callable($handler)) {
-                call_user_func($handler, $k, $v);
-            } else {
-                var_dump($k, $v);
-                trigger_error("Hmh, something weird has happend, I don't know 
this option", E_USER_ERROR);
-            }
-        }
-    }
-
-    /**
-     * Makes a string into a boolean (i.e. on/off, yes/no, ..)
-     *
-     * Returns boolean true/false on success, null on failure
-     * 
-     * @param string $val 
-     * @return bool
-     */
-    public static function boolval($val) {
-        if (!is_string($val)) {
-            return null;
-        }
-
-        switch ($val) {
-            case "on":
-                case "yes":
-                case "true":
-                case "1":
-                return true;
-            break;
-
-            case "off":
-                case "no":
-                case "false":
-                case "0":
-                return false;
-            break;
-
-            default:
-            return null;
-        }
-    }
-}
-
-/*
-* vim600: sw=4 ts=4 syntax=php et
-* vim<600: sw=4 ts=4
-*/
-

Reply via email to