]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Irc/extlib/phergie/Phergie/Plugin/Help.php
Merged in Phergie changes
[quix0rs-gnu-social.git] / plugins / Irc / extlib / phergie / Phergie / Plugin / Help.php
1 <?php
2 /**
3  * Phergie
4  *
5  * PHP version 5
6  *
7  * LICENSE
8  *
9  * This source file is subject to the new BSD license that is bundled
10  * with this package in the file LICENSE.
11  * It is also available through the world-wide-web at this URL:
12  * http://phergie.org/license
13  *
14  * @category  Phergie
15  * @package   Phergie_Plugin_Help
16  * @author    Phergie Development Team <team@phergie.org>
17  * @copyright 2008-2010 Phergie Development Team (http://phergie.org)
18  * @license   http://phergie.org/license New BSD License
19  * @link      http://pear.phergie.org/package/Phergie_Plugin_Help
20  */
21
22 /**
23  * Provides access to descriptions of plugins and the commands they provide.
24  *
25  * @category Phergie
26  * @package  Phergie_Plugin_Help
27  * @author   Phergie Development Team <team@phergie.org>
28  * @license  http://phergie.org/license New BSD License
29  * @link     http://pear.phergie.org/package/Phergie_Plugin_Help
30  * @uses     Phergie_Plugin_Command pear.phergie.org
31  */
32 class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
33 {
34     /**
35      * Registry of help data indexed by plugin name
36      *
37      * @var array
38      */
39     protected $registry;
40
41     /**
42      * Checks for dependencies.
43      *
44      * @return void
45      */
46     public function onLoad()
47     {
48         $this->getPluginHandler()->getPlugin('Command');
49     }
50
51     /**
52      * Creates a registry of plugin metadata on connect.
53      *
54      * @return void
55      */
56     public function onConnect()
57     {
58         $this->populateRegistry();
59     }
60
61     /**
62      * Creates a registry of plugin metadata.
63      *
64      * @return void
65      */
66     public function populateRegistry()
67     {
68         $this->registry = array();
69
70         foreach ($this->plugins as $plugin) {
71             $class = new ReflectionClass($plugin);
72             $pluginName = strtolower($plugin->getName());
73
74             // Parse the plugin description
75             $docblock = $class->getDocComment();
76             $annotations = $this->getAnnotations($docblock);
77             if (isset($annotations['pluginDesc'])) {
78                 $pluginDesc = implode(' ', $annotations['pluginDesc']);
79             } else {
80                 $pluginDesc = $this->parseShortDescription($docblock);
81             }
82             $this->registry[$pluginName] = array(
83                 'desc' => $pluginDesc,
84                 'cmds' => array()
85             );
86
87             // Parse command method descriptions
88             $methodPrefix = Phergie_Plugin_Command::METHOD_PREFIX;
89             $methodPrefixLength = strlen($methodPrefix);
90             foreach ($class->getMethods() as $method) {
91                 if (strpos($method->getName(), $methodPrefix) !== 0) {
92                     continue;
93                 }
94
95                 $cmd = strtolower(substr($method->getName(), $methodPrefixLength));
96                 $docblock = $method->getDocComment();
97                 $annotations = $this->getAnnotations($docblock);
98
99                 if (isset($annotations['pluginCmd'])) {
100                     $cmdDesc = implode(' ', $annotations['pluginCmd']);
101                 } else {
102                     $cmdDesc = $this->parseShortDescription($docblock);
103                 }
104
105                 $cmdParams = array();
106                 if (!empty($annotations['param'])) {
107                     foreach ($annotations['param'] as $param) {
108                         $match = null;
109                         if (preg_match('/\h+\$([^\h]+)\h+/', $param, $match)) {
110                             $cmdParams[] = $match[1];
111                         }
112                     }
113                 }
114
115                 $this->registry[$pluginName]['cmds'][$cmd] = array(
116                     'desc' => $cmdDesc,
117                     'params' => $cmdParams
118                 );
119             }
120
121             if (empty($this->registry[$pluginName]['cmds'])) {
122                 unset($this->registry[$pluginName]);
123             }
124         }
125     }
126
127     /**
128      * Displays a list of plugins with help information available or
129      * commands available for a specific plugin.
130      *
131      * @param string $query Optional short name of a plugin for which commands
132      *        should be returned or a command; if unspecified, a list of
133      *        plugins with help information available is returned
134      *
135      * @return void
136      */
137     public function onCommandHelp($query = null)
138     {
139         if ($query == 'refresh') {
140             $this->populateRegistry();
141         }
142
143         $nick = $this->getEvent()->getNick();
144         $delay = $this->getConfig('help.delay', 2);
145
146         // Handle requests for a plugin list
147         if (!$query) {
148             $msg = 'These plugins have help information available: '
149                  . implode(', ', array_keys($this->registry));
150             $this->doPrivmsg($nick, $msg);
151             return;
152         }
153
154         // Handle requests for plugin information
155         $query = strtolower($query);
156         if (isset($this->registry[$query])
157             && empty($this->registry[$query]['cmds'][$query])) {
158             $msg = $query . ' - ' . $this->registry[$query]['desc'];
159             $this->doPrivmsg($nick, $msg);
160
161             $msg = 'Available commands - '
162                  . implode(', ', array_keys($this->registry[$query]['cmds']));
163             $this->doPrivmsg($nick, $msg);
164
165             if ($this->getConfig('command.prefix')) {
166                 $msg
167                     = 'Note that these commands must be prefixed with "'
168                     . $this->getConfig('command.prefix')
169                     . '" (without quotes) when issued in a public channel.';
170                 $this->doPrivmsg($nick, $msg);
171             }
172
173             return;
174         }
175
176         // Handle requests for command information
177         foreach ($this->registry as $plugin => $data) {
178             if (empty($data['cmds'])) {
179                 continue;
180             }
181
182             $result = preg_grep('/^' . $query . '$/i', array_keys($data['cmds']));
183             if (!$result) {
184                 continue;
185             }
186
187             $cmd = $data['cmds'][array_shift($result)];
188             $msg = $query;
189             if (!empty($cmd['params'])) {
190                 $msg .= ' [' . implode('] [', $cmd['params']) . ']';
191             }
192             $msg .= ' - ' . $cmd['desc'];
193             $this->doPrivmsg($nick, $msg);
194         }
195     }
196
197     /**
198      * Parses and returns the short description from a docblock.
199      *
200      * @param string $docblock Docblock comment code
201      *
202      * @return string Short description (i.e. content from the start of the
203      *         docblock up to the first double-newline)
204      */
205     protected function parseShortDescription($docblock)
206     {
207         $desc = preg_replace(
208             array('#^\h*\*\h*#m', '#^/\*\*\h*\v+\h*#', '#(?:\r?\n){2,}.*#s', '#\s*\v+\s*#'),
209             array('', '', '', ' '),
210             $docblock
211         );
212         return $desc;
213     }
214
215     /**
216      * Taken from PHPUnit/Util/Test.php and modified to fix an issue with
217      * tag content spanning multiple lines.
218      *
219      * PHPUnit
220      *
221      * Copyright (c) 2002-2010, Sebastian Bergmann <sb@sebastian-bergmann.de>.
222      * All rights reserved.
223      *
224      * Redistribution and use in source and binary forms, with or without
225      * modification, are permitted provided that the following conditions
226      * are met:
227      *
228      *   * Redistributions of source code must retain the above copyright
229      *     notice, this list of conditions and the following disclaimer.
230      *
231      *   * Redistributions in binary form must reproduce the above copyright
232      *     notice, this list of conditions and the following disclaimer in
233      *     the documentation and/or other materials provided with the
234      *     distribution.
235      *
236      *   * Neither the name of Sebastian Bergmann nor the names of his
237      *     contributors may be used to endorse or promote products derived
238      *     from this software without specific prior written permission.
239      *
240      * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
241      * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
242      * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
243      * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
244      * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
245      * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
246      * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
247      * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
248      * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
249      * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
250      * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
251      * POSSIBILITY OF SUCH DAMAGE.
252      *
253      * @param string $docblock docblock to parse
254      *
255      * @return array
256      */
257     protected function getAnnotations($docblock)
258     {
259         $annotations = array();
260
261         $regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?(?:\*\/|\* @)/ms';
262
263         if (preg_match_all($regex, $docblock, $matches)) {
264             $numMatches = count($matches[0]);
265
266             for ($i = 0; $i < $numMatches; ++$i) {
267                 $annotation = $matches['value'][$i];
268                 $annotation = preg_replace('/\s*\v+\s*\*\s*/', ' ', $annotation);
269                 $annotation = rtrim($annotation);
270                 $annotations[$matches['name'][$i]][] = $annotation;
271             }
272         }
273
274         return $annotations;
275     }
276 }