277 lines
9.2 KiB
PHP
277 lines
9.2 KiB
PHP
<?php
|
|
/**
|
|
* Phergie
|
|
*
|
|
* PHP version 5
|
|
*
|
|
* LICENSE
|
|
*
|
|
* This source file is subject to the new BSD license that is bundled
|
|
* with this package in the file LICENSE.
|
|
* It is also available through the world-wide-web at this URL:
|
|
* http://phergie.org/license
|
|
*
|
|
* @category Phergie
|
|
* @package Phergie_Plugin_Help
|
|
* @author Phergie Development Team <team@phergie.org>
|
|
* @copyright 2008-2010 Phergie Development Team (http://phergie.org)
|
|
* @license http://phergie.org/license New BSD License
|
|
* @link http://pear.phergie.org/package/Phergie_Plugin_Help
|
|
*/
|
|
|
|
/**
|
|
* Provides access to descriptions of plugins and the commands they provide.
|
|
*
|
|
* @category Phergie
|
|
* @package Phergie_Plugin_Help
|
|
* @author Phergie Development Team <team@phergie.org>
|
|
* @license http://phergie.org/license New BSD License
|
|
* @link http://pear.phergie.org/package/Phergie_Plugin_Help
|
|
* @uses Phergie_Plugin_Command pear.phergie.org
|
|
*/
|
|
class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
|
|
{
|
|
/**
|
|
* Registry of help data indexed by plugin name
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $registry;
|
|
|
|
/**
|
|
* Checks for dependencies.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function onLoad()
|
|
{
|
|
$this->getPluginHandler()->getPlugin('Command');
|
|
}
|
|
|
|
/**
|
|
* Creates a registry of plugin metadata on connect.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function onConnect()
|
|
{
|
|
$this->populateRegistry();
|
|
}
|
|
|
|
/**
|
|
* Creates a registry of plugin metadata.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function populateRegistry()
|
|
{
|
|
$this->registry = array();
|
|
|
|
foreach ($this->plugins as $plugin) {
|
|
$class = new ReflectionClass($plugin);
|
|
$pluginName = strtolower($plugin->getName());
|
|
|
|
// Parse the plugin description
|
|
$docblock = $class->getDocComment();
|
|
$annotations = $this->getAnnotations($docblock);
|
|
if (isset($annotations['pluginDesc'])) {
|
|
$pluginDesc = implode(' ', $annotations['pluginDesc']);
|
|
} else {
|
|
$pluginDesc = $this->parseShortDescription($docblock);
|
|
}
|
|
$this->registry[$pluginName] = array(
|
|
'desc' => $pluginDesc,
|
|
'cmds' => array()
|
|
);
|
|
|
|
// Parse command method descriptions
|
|
$methodPrefix = Phergie_Plugin_Command::METHOD_PREFIX;
|
|
$methodPrefixLength = strlen($methodPrefix);
|
|
foreach ($class->getMethods() as $method) {
|
|
if (strpos($method->getName(), $methodPrefix) !== 0) {
|
|
continue;
|
|
}
|
|
|
|
$cmd = strtolower(substr($method->getName(), $methodPrefixLength));
|
|
$docblock = $method->getDocComment();
|
|
$annotations = $this->getAnnotations($docblock);
|
|
|
|
if (isset($annotations['pluginCmd'])) {
|
|
$cmdDesc = implode(' ', $annotations['pluginCmd']);
|
|
} else {
|
|
$cmdDesc = $this->parseShortDescription($docblock);
|
|
}
|
|
|
|
$cmdParams = array();
|
|
if (!empty($annotations['param'])) {
|
|
foreach ($annotations['param'] as $param) {
|
|
$match = null;
|
|
if (preg_match('/\h+\$([^\h]+)\h+/', $param, $match)) {
|
|
$cmdParams[] = $match[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
$this->registry[$pluginName]['cmds'][$cmd] = array(
|
|
'desc' => $cmdDesc,
|
|
'params' => $cmdParams
|
|
);
|
|
}
|
|
|
|
if (empty($this->registry[$pluginName]['cmds'])) {
|
|
unset($this->registry[$pluginName]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Displays a list of plugins with help information available or
|
|
* commands available for a specific plugin.
|
|
*
|
|
* @param string $query Optional short name of a plugin for which commands
|
|
* should be returned or a command; if unspecified, a list of
|
|
* plugins with help information available is returned
|
|
*
|
|
* @return void
|
|
*/
|
|
public function onCommandHelp($query = null)
|
|
{
|
|
if ($query == 'refresh') {
|
|
$this->populateRegistry();
|
|
}
|
|
|
|
$nick = $this->getEvent()->getNick();
|
|
$delay = $this->getConfig('help.delay', 2);
|
|
|
|
// Handle requests for a plugin list
|
|
if (!$query) {
|
|
$msg = 'These plugins have help information available: '
|
|
. implode(', ', array_keys($this->registry));
|
|
$this->doPrivmsg($nick, $msg);
|
|
return;
|
|
}
|
|
|
|
// Handle requests for plugin information
|
|
$query = strtolower($query);
|
|
if (isset($this->registry[$query])
|
|
&& empty($this->registry[$query]['cmds'][$query])) {
|
|
$msg = $query . ' - ' . $this->registry[$query]['desc'];
|
|
$this->doPrivmsg($nick, $msg);
|
|
|
|
$msg = 'Available commands - '
|
|
. implode(', ', array_keys($this->registry[$query]['cmds']));
|
|
$this->doPrivmsg($nick, $msg);
|
|
|
|
if ($this->getConfig('command.prefix')) {
|
|
$msg
|
|
= 'Note that these commands must be prefixed with "'
|
|
. $this->getConfig('command.prefix')
|
|
. '" (without quotes) when issued in a public channel.';
|
|
$this->doPrivmsg($nick, $msg);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Handle requests for command information
|
|
foreach ($this->registry as $plugin => $data) {
|
|
if (empty($data['cmds'])) {
|
|
continue;
|
|
}
|
|
|
|
$result = preg_grep('/^' . $query . '$/i', array_keys($data['cmds']));
|
|
if (!$result) {
|
|
continue;
|
|
}
|
|
|
|
$cmd = $data['cmds'][array_shift($result)];
|
|
$msg = $query;
|
|
if (!empty($cmd['params'])) {
|
|
$msg .= ' [' . implode('] [', $cmd['params']) . ']';
|
|
}
|
|
$msg .= ' - ' . $cmd['desc'];
|
|
$this->doPrivmsg($nick, $msg);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Parses and returns the short description from a docblock.
|
|
*
|
|
* @param string $docblock Docblock comment code
|
|
*
|
|
* @return string Short description (i.e. content from the start of the
|
|
* docblock up to the first double-newline)
|
|
*/
|
|
protected function parseShortDescription($docblock)
|
|
{
|
|
$desc = preg_replace(
|
|
array('#^\h*\*\h*#m', '#^/\*\*\h*\v+\h*#', '#(?:\r?\n){2,}.*#s', '#\s*\v+\s*#'),
|
|
array('', '', '', ' '),
|
|
$docblock
|
|
);
|
|
return $desc;
|
|
}
|
|
|
|
/**
|
|
* Taken from PHPUnit/Util/Test.php and modified to fix an issue with
|
|
* tag content spanning multiple lines.
|
|
*
|
|
* PHPUnit
|
|
*
|
|
* Copyright (c) 2002-2010, Sebastian Bergmann <sb@sebastian-bergmann.de>.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
*
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
*
|
|
* * Neither the name of Sebastian Bergmann nor the names of his
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
* @param string $docblock docblock to parse
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function getAnnotations($docblock)
|
|
{
|
|
$annotations = array();
|
|
|
|
$regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?(?:\*\/|\* @)/ms';
|
|
|
|
if (preg_match_all($regex, $docblock, $matches)) {
|
|
$numMatches = count($matches[0]);
|
|
|
|
for ($i = 0; $i < $numMatches; ++$i) {
|
|
$annotation = $matches['value'][$i];
|
|
$annotation = preg_replace('/\s*\v+\s*\*\s*/', ' ', $annotation);
|
|
$annotation = rtrim($annotation);
|
|
$annotations[$matches['name'][$i]][] = $annotation;
|
|
}
|
|
}
|
|
|
|
return $annotations;
|
|
}
|
|
}
|