Updated phergie library

This commit is contained in:
Luke Fitzgerald 2010-06-30 09:33:29 -07:00
parent 0b2bbd20aa
commit bf6ecfbffc
35 changed files with 2765 additions and 651 deletions

View File

@ -37,7 +37,7 @@ class Phergie_Autoload
*/
public function __construct()
{
$path = dirname(__FILE__);
$path = realpath(dirname(__FILE__) . '/..');
$includePath = get_include_path();
$includePathList = explode(PATH_SEPARATOR, $includePath);
if (!in_array($path, $includePathList)) {
@ -54,9 +54,6 @@ class Phergie_Autoload
*/
public function load($class)
{
if (substr($class, 0, 8) == 'Phergie_') {
$class = substr($class, 8);
}
include str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
}

View File

@ -53,6 +53,14 @@ class Phergie_Connection
*/
protected $transport;
/**
* Encoding method for the connection, defaults to ISO-8859-1 but can
* be set to UTF8 if necessary
*
* @var strng
*/
protected $encoding;
/**
* Nick that the client will use
*
@ -99,6 +107,9 @@ class Phergie_Connection
public function __construct(array $options = array())
{
$this->transport = 'tcp';
$this->encoding = 'ISO-8859-1';
// @note this may need changed to something different, for broader support.
// @note also may need to make use of http://us.php.net/manual/en/function.stream-encoding.php
$this->setOptions($options);
}
@ -229,6 +240,37 @@ class Phergie_Connection
return $this->transport;
}
/**
* Sets the encoding for the connection to use.
*
* @param string $encoding Encoding to use (ex: ASCII, ISO-8859-1, UTF8, etc.)
*
* @return Phergie_Connection Provides a fluent interface
*/
public function setEncoding($encoding)
{
$this->encoding = (string) $encoding;
if (!in_array($this->encoding, mb_list_encodings())) {
throw new Phergie_Connection_Exception(
'Encoding ' . $this->encoding . ' is not supported',
Phergie_Connection_Exception::ENCODING_NOT_SUPPORTED
);
}
return $this;
}
/**
* Returns the encoding in use by the connection.
*
* @return string Encoding (ex: ASCII, ISO-8859-1, UTF8, etc.)
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Sets the nick that the client will use.
*

View File

@ -0,0 +1,39 @@
<?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
* @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
*/
/**
* Exceptions related to handling databases for plugins.
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Db_Exception extends Phergie_Exception
{
/**
* Error indicating that a directory needed to support database
* functionality was unable to be created.
*/
const ERR_UNABLE_TO_CREATE_DIRECTORY = 1;
}

View File

@ -0,0 +1,49 @@
<?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
* @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_Command
*/
/**
* Database management class. Provides a base API for managing databases
* within
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Db_Manager
*/
abstract class Phergie_Db_Manager
{
/**
* Returns a connection to the database.
*
* @return object
*/
public abstract function getDb();
/**
* Checks if a table/collection exists within the database.
*
* @param string $table Table/collection name to check for
*
* @return boolean
*/
public abstract function hasTable($table);
}

View File

@ -0,0 +1,117 @@
<?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
* @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
*/
/**
* Provides basic management for SQLite databases
*
* @category Phergie
* @package Phergie
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Db_Sqlite extends Phergie_Db_Manager
{
/**
* Database connection
*
* @var PDO
*/
protected $db;
/**
* Database file path
*
* @var string
*/
protected $dbFile;
/**
* Allows setting of the database file path when creating the class.
*
* @param string $dbFile database file path (optional)
*
* @return void
*/
public function __construct($dbFile = null)
{
if ($dbFile != null) {
$this->setDbFile($dbFile);
}
}
/**
* Sets the database file path.
*
* @param string $dbFile SQLite database file path
*
* @return null
*/
public function setDbFile($dbFile)
{
if (is_string($dbFile) && !empty($dbFile)) {
$this->dbFile = $dbFile;
}
}
/**
* Returns a configured database connection.
*
* @return PDO
*/
public function getDb()
{
if (!empty($this->db)) {
return $this->db;
}
$dir = dirname($this->dbFile);
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
throw new Phergie_Db_Exception(
'Unable to create directory',
Phergie_Db_Exception::ERR_UNABLE_TO_CREATE_DIRECTORY
);
}
$this->db = new PDO('sqlite:' . $this->dbFile);
return $this->db;
}
/**
* Returns whether a given table exists in the database.
*
* @param string $table Name of the table to check for
*
* @return boolean TRUE if the table exists, FALSE otherwise
*/
public function hasTable($table)
{
$db = $this->getDb();
return (bool) $db->query(
'SELECT COUNT(*) FROM sqlite_master WHERE name = '
. $db->quote($table)
)->fetchColumn();
}
}

View File

@ -46,4 +46,9 @@ class Phergie_Driver_Exception extends Phergie_Exception
* Error indicating that an attempt to initiate a connection failed
*/
const ERR_CONNECTION_ATTEMPT_FAILED = 3;
/**
* Error indicating that an attempt to send data via a connection failed
*/
const ERR_CONNECTION_WRITE_FAILED = 4;
}

View File

@ -67,6 +67,9 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
*/
protected function send($command, $args = '')
{
$connection = $this->getConnection();
$encoding = $connection->getEncoding();
// Require an open socket connection to continue
if (empty($this->socket)) {
throw new Phergie_Driver_Exception(
@ -86,13 +89,33 @@ class Phergie_Driver_Streams extends Phergie_Driver_Abstract
$end = count($args) - 1;
$args[$end] = ':' . $args[$end];
$args = implode(' ', $args);
} else {
$args = ':' . $args;
}
$buffer .= ' ' . $args;
}
// Transmit the command over the socket connection
fwrite($this->socket, $buffer . "\r\n");
$attempts = $written = 0;
$temp = $buffer . "\r\n";
$is_multibyte = !substr($encoding, 0, 8) === 'ISO-8859' && $encoding !== 'ASCII' && $encoding !== 'CP1252';
$length = ($is_multibyte) ? mb_strlen($buffer, '8bit') : strlen($buffer);
while (true) {
$written += (int) fwrite($this->socket, $temp);
if ($written < $length) {
$temp = substr($temp, $written);
$attempts++;
if ($attempts == 3) {
throw new Phergie_Driver_Exception(
'Unable to write to socket',
Phergie_Driver_Exception::ERR_CONNECTION_WRITE_FAILED
);
}
} else {
break;
}
}
// Return the command string that was transmitted
return $buffer;

View File

@ -152,6 +152,22 @@ class Phergie_Event_Handler implements IteratorAggregate, Countable
return $events;
}
/**
* Removes a single event from the event queue.
*
* @param Phergie_Event_Command $event Event to remove
*
* @return Phergie_Event_Handler Provides a fluent interface
*/
public function removeEvent(Phergie_Event_Command $event)
{
$key = array_search($event, $this->events);
if ($key !== false) {
unset($this->events[$key]);
}
return $this;
}
/**
* Returns an iterator for the current event queue.
*

View File

@ -240,6 +240,24 @@ class Phergie_Event_Request
return $this;
}
/**
* Sets the value of a single argument for the request.
*
* @param mixed $argument Integer position (starting from 0) or the
* equivalent string name of the argument from self::$map
* @param string $value Value to assign to the argument
*
* @return Phergie_Event_Request Provides a fluent interface
*/
public function setArgument($argument, $value)
{
$argument = $this->resolveArgument($argument);
if ($argument !== null) {
$this->arguments[$argument] = (string) $value;
}
return $this;
}
/**
* Returns the arguments for the request.
*

View File

@ -66,6 +66,13 @@ abstract class Phergie_Plugin_Abstract
*/
protected $event;
/**
* Plugin short name
*
* @var string
*/
protected $name;
/**
* Returns the short name for the plugin based on its class name.
*
@ -73,7 +80,23 @@ abstract class Phergie_Plugin_Abstract
*/
public function getName()
{
return substr(strrchr(get_class($this), '_'), 1);
if (empty($this->name)) {
$this->name = substr(strrchr(get_class($this), '_'), 1);
}
return $this->name;
}
/**
* Sets the short name for the plugin.
*
* @param string $name Plugin short name
*
* @return Phergie_Plugin_Abstract Provides a fluent interface
*/
public function setName($name)
{
$this->name = (string) $name;
return $this;
}
/**

View File

@ -0,0 +1,108 @@
<?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_Censor
* @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_Censor
*/
/**
* Facilitates censoring of event content or discardment of events
* containing potentially offensive phrases depending on the value of the
* configuration setting censor.mode ('off', 'censor', 'discard'). Also
* provides access to a web service for detecting censored words so that
* other plugins may optionally integrate and adjust behavior accordingly to
* prevent discardment of events.
*
* @category Phergie
* @package Phergie_Plugin_Censor
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Censor
* @uses extension soap
*/
class Phergie_Plugin_Censor extends Phergie_Plugin_Abstract
{
/**
* SOAP client to interact with the CDYNE Profanity Filter API
*
* @var SoapClient
*/
protected $soap;
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
if (!extension_loaded('soap')) {
$this->fail('The PHP soap extension is required');
}
if (!in_array($this->config['censor.mode'], array('censor', 'discard'))) {
$this->plugins->removePlugin($this);
}
}
/**
* Returns a "clean" version of a given string.
*
* @param string $string String to clean
*
* @return string Cleaned string
*/
public function cleanString($string)
{
if (empty($this->soap)) {
$this->soap = new SoapClient('http://ws.cdyne.com/ProfanityWS/Profanity.asmx?wsdl');
}
$params = array('Text' => $string);
$response = $this->soap->SimpleProfanityFilter($params);
return $response->SimpleProfanityFilterResult->CleanText;
}
/**
* Processes events before they are dispatched and either censors their
* content or discards them if they contain potentially offensive
* content.
*
* @return void
*/
public function preDispatch()
{
$events = $this->events->getEvents();
foreach ($events as $event) {
switch ($event->getType()) {
case Phergie_Event_Request::TYPE_PRIVMSG:
case Phergie_Event_Request::TYPE_ACTION:
case Phergie_Event_Request::TYPE_NOTICE:
$text = $event->getArgument(1);
$clean = $this->cleanString($text);
if ($text != $clean) {
if ($this->config['censor.mode'] == 'censor') {
$event->setArgument(1, $clean);
} else {
$this->events->removeEvent($event);
}
}
break;
}
}
}
}

View File

@ -0,0 +1,147 @@
<?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_Cron
* @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_Cron
*/
/**
* Allows callbacks to be registered for asynchronous execution.
*
* @category Phergie
* @package Phergie_Plugin_Cron
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Cron
*/
class Phergie_Plugin_Cron extends Phergie_Plugin_Abstract
{
/**
* Array of all registered callbacks with delays and arguments
*
* @var array
*/
protected $callbacks;
/**
* Returns a human-readable representation of a callback for debugging
* purposes.
*
* @param callback $callback Callback to analyze
*
* @return string|boolean String representation of the callback or FALSE
* if the specified value is not a valid callback
*/
protected function getCallbackString($callback)
{
if (!is_callable($callback)) {
return false;
}
if (is_array($callback)) {
$class = is_string($callback[0]) ?
$callback[0] : get_class($callback[0]);
$method = $class . '::' . $callback[1];
return $method;
}
return $callback;
}
/**
* Registers a callback for execution sometime after a given delay
* relative to now.
*
* @param callback $callback Callback to be registered
* @param int $delay Delay in seconds from now when the callback
* will be executed
* @param array $arguments Arguments to pass to the callback when
* it's executed
* @param bool $repeat TRUE to automatically re-register the
* callback for the same delay after it's executed, FALSE
* otherwise
*
* @return void
*/
public function registerCallback($callback, $delay,
array $arguments = array(), $repeat = false)
{
$callbackString = $this->getCallbackString($callback);
if ($callbackString === false) {
echo 'DEBUG(Cron): Invalid callback specified - ',
var_export($callback, true), PHP_EOL;
return;
}
$registered = time();
$scheduled = $registered + $delay;
$this->callbacks[] = array(
'callback' => $callback,
'delay' => $delay,
'arguments' => $arguments,
'registered' => $registered,
'scheduled' => $scheduled,
'repeat' => $repeat,
);
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $scheduled), PHP_EOL;
}
/**
* Handles callback execution.
*
* @return void
*/
public function onTick()
{
$now = time();
foreach ($this->callbacks as $key => &$callback) {
$callbackString = $this->getCallbackString($callback);
$scheduled = $callback['scheduled'];
if ($time < $scheduled) {
continue;
}
if (empty($callback['arguments'])) {
call_user_func($callback['callback']);
} else {
call_user_func_array(
$callback['callback'],
$callback['arguments']
);
}
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $scheduled), ',',
' executed at ', date('H:i:s', $now), PHP_EOL;
if ($callback['repeat']) {
$callback['scheduled'] = $time + $callback['delay'];
echo 'DEBUG(Cron): Callback ', $callbackString,
' scheduled for ', date('H:i:s', $callback['scheduled']),
PHP_EOL;
} else {
echo 'DEBUG(Cron): Callback ', $callbackString,
' removed from callback list', PHP_EOL;
unset($this->callbacks[$key]);
}
}
}
}

View File

@ -223,6 +223,10 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
*/
public function onCommandGmap($location)
{
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
$location = utf8_encode($location);
$url = 'http://maps.google.com/maps/geo';
$params = array(
@ -232,20 +236,17 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
'sensor' => 'false',
'oe' => 'utf8',
'mrt' => 'all',
'key' => $this->_config['google.key']
'key' => $this->getConfig('google.key')
);
$response = $this->http->get($url, $params);
$json = (array) $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
$json = $response->getContent();
if (!empty($json)) {
$qtd = count($json['Placemark']);
$qtd = count($json->Placemark);
if ($qtd > 1) {
if ($qtd <= 3) {
foreach ($json['Placemark'] as $places) {
$xy = $places['Point']['coordinates'];
$address = utf8_decode($places['address']);
foreach ($json->Placemark as $places) {
$xy = $places->Point->coordinates;
$address = utf8_decode($places->address);
$url = 'http://maps.google.com/maps?sll=' . $xy[1] . ','
. $xy[0] . '&z=15';
$msg = $nick . ' -> ' . $address . ' - ' . $url;
@ -259,8 +260,8 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
$this->doPrivmsg($source, $msg);
}
} elseif ($qtd == 1) {
$xy = $json['Placemark'][0]['Point']['coordinates'];
$address = utf8_decode($json['Placemark'][0]['address']);
$xy = $json->Placemark[0]->Point->coordinates;
$address = utf8_decode($json->Placemark[0]->address);
$url = 'http://maps.google.com/maps?sll=' . $xy[1] . ',' . $xy[0]
. '&z=15';
$msg = $nick . ' -> ' . $address . ' - ' . $url;
@ -322,54 +323,44 @@ class Phergie_Plugin_Google extends Phergie_Plugin_Abstract
/**
* Performs a Google search to convert a value from one unit to another.
*
* @param string $unit Source metric
* @param string $to Value to be converted
* @param string $unit2 Destination metric
* @param string $query Query of the form "[quantity] [unit] to [unit2]"
*
* @return void
*
* @pluginCmd [unit] [to] [unit2] Convert a value from one metric to another
* @pluginCmd [quantity] [unit] to [unit2] Convert a value from one
* metric to another
*/
public function onCommandConvert($unit, $to, $unit2)
public function onCommandConvert($query)
{
$url = 'http://www.google.com/search?q='
. urlencode($unit . ' ' . $to . ' ' . $unit2);
$url = 'http://www.google.com/search?q=' . urlencode($query);
$response = $this->http->get($url);
$contents = $response->getContent();
$event = $this->getEvent();
$source = $event->getSource();
$nick = $event->getNick();
if (empty($contents)) {
$this->doPrivmsg(
$target,
$nick . ', sorry, I can\'t give you an answer right now.'
);
if ($response->isError()) {
$code = $response->getCode();
$message = $response->getMessage();
$this->doNotice($nick, 'ERROR: ' . $code . ' ' . $message);
return;
}
$doc = new DomDocument;
$doc->loadHTML($contents);
foreach ($doc->getElementsByTagName('h2') as $element) {
if ($element->getAttribute('class') == 'r') {
$children = $element->childNodes;
$start = strpos($contents, '<h3 class=r>');
if ($start !== false) {
$end = strpos($contents, '</b>', $start);
$text = strip_tags(substr($contents, $start, $end - $start));
$text = str_replace(
array(chr(195), chr(151), chr(160)),
array('x', '', ' '),
$children->item(0)->nodeValue
);
if ($children->length >= 3) {
$text
.= '^' . $children->item(1)->nodeValue
. $children->item(2)->nodeValue;
}
}
);
}
if (isset($text)) {
$this->doPrivmsg($source, $nick . ': ' . $text);
} else {
$this->doPrivmsg($target, $nick . ', sorry I can\'t do that.');
$this->doNotice($nick, 'Sorry I couldn\'t find an answer.');
}
}
}

View File

@ -28,7 +28,7 @@
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Plugin_Handler implements IteratorAggregate
class Phergie_Plugin_Handler implements IteratorAggregate, Countable
{
/**
* Current list of plugin instances
@ -122,6 +122,37 @@ class Phergie_Plugin_Handler implements IteratorAggregate
return $this;
}
/**
* Returns metadata corresponding to a specified plugin.
*
* @param string $plugin Short name of the plugin class
* @throws Phergie_Plugin_Exception Class file can't be found
*
* @return array|boolean Associative array containing the path to the
* class file and its containing directory as well as the full
* class name
*/
public function getPluginInfo($plugin)
{
foreach (array_reverse($this->paths) as $path) {
$file = $path['path'] . $plugin . '.php';
if (file_exists($file)) {
$path = array(
'dir' => $path['path'],
'file' => $file,
'class' => $path['prefix'] . $plugin,
);
return $path;
}
}
// If the class can't be found, display an error
throw new Phergie_Plugin_Exception(
'Class file for plugin "' . $plugin . '" cannot be found',
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
);
}
/**
* Adds a plugin instance to the handler.
*
@ -143,22 +174,13 @@ class Phergie_Plugin_Handler implements IteratorAggregate
}
// Attempt to locate and load the class
foreach (array_reverse($this->paths) as $path) {
$file = $path['path'] . $plugin . '.php';
if (file_exists($file)) {
$info = $this->getPluginInfo($plugin);
$file = $info['file'];
$class = $info['class'];
include_once $file;
$class = $path['prefix'] . $plugin;
if (class_exists($class)) {
break;
}
unset($class);
}
}
// If the class can't be found, display an error
if (!isset($class)) {
if (!class_exists($class, false)) {
throw new Phergie_Plugin_Exception(
'Class file for plugin "' . $plugin . '" cannot be found',
'File "' . $file . '" does not contain class "' . $class . '"',
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND
);
}
@ -190,11 +212,7 @@ class Phergie_Plugin_Handler implements IteratorAggregate
$instance = new $class;
}
// Configure and add the instance
$instance->setPluginHandler($this);
$instance->setConfig($this->config);
$instance->setEventHandler($this->events);
$instance->onLoad();
// Store the instance
$this->plugins[$index] = $instance;
$plugin = $instance;
@ -205,6 +223,12 @@ class Phergie_Plugin_Handler implements IteratorAggregate
$this->plugins[strtolower($plugin->getName())] = $plugin;
}
// Configure and initialize the instance
$plugin->setPluginHandler($this);
$plugin->setConfig($this->config);
$plugin->setEventHandler($this->events);
$plugin->onLoad();
return $plugin;
}
@ -289,13 +313,19 @@ class Phergie_Plugin_Handler implements IteratorAggregate
* loading them if they are not already loaded and autoloading is
* enabled.
*
* @param array $names List of short names of the plugin classes
* @param array $names Optional list of short names of the plugin
* classes to which the returned plugin list will be limited,
* defaults to all presently loaded plugins
*
* @return array Associative array mapping plugin class short names to
* corresponding plugin instances
* @return array Associative array mapping lowercased plugin class short
* names to corresponding plugin instances
*/
public function getPlugins(array $names)
public function getPlugins(array $names = array())
{
if (empty($names)) {
return $this->plugins;
}
$plugins = array();
foreach ($names as $name) {
$plugins[$name] = $this->getPlugin($name);
@ -409,4 +439,14 @@ class Phergie_Plugin_Handler implements IteratorAggregate
}
return true;
}
/**
* Returns the number of plugins contained within the handler.
*
* @return int Plugin count
*/
public function count()
{
return count($this->plugins);
}
}

View File

@ -191,7 +191,8 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
}
/**
* Taken from PHPUnit/Util/Test.php:436
* Taken from PHPUnit/Util/Test.php:243 and modified to fix an issue
* with tag content spanning multiple lines.
*
* PHPUnit
*
@ -235,13 +236,16 @@ class Phergie_Plugin_Help extends Phergie_Plugin_Abstract
{
$annotations = array();
$regex = '/@(?P<name>[A-Za-z_-]+)(?:[ \t]+(?P<value>.*?))?[ \t]*\r?$/m';
$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) {
$annotations[$matches['name'][$i]][] = $matches['value'][$i];
$annotation = $matches['value'][$i];
$annotation = preg_replace('/\s*\v+\s*\*\s*/', ' ', $annotation);
$annotation = rtrim($annotation);
$annotations[$matches['name'][$i]][] = $annotation;
}
}

View File

@ -37,6 +37,43 @@ class Phergie_Plugin_Http_Response
*/
protected $code;
/**
* HTTP response strings
*
* @var array
*/
protected $codeStrings = array(
0 => 'No Response',
100 => 'Continue',
200 => 'OK',
201 => 'Created',
204 => 'No Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
408 => 'Request Timeout',
410 => 'Gone',
413 => 'Request Entity Too Large',
414 => 'Request URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Method Not Implemented',
503 => 'Service Unavailable',
506 => 'Variant Also Negotiates'
);
/**
* Description of the HTTP response code or the error message if no HTTP
* response was received
@ -89,6 +126,22 @@ class Phergie_Plugin_Http_Response
return $this->code;
}
/**
* Returns the HTTP response code text.
*
* @return string Response code text
*/
public function getCodeAsString()
{
$code = $this->code;
if (!isset($this->codeStrings[$code])) {
return 'Unkown HTTP Status';
}
return $this->codeStrings[$code];
}
/**
* Returns whether the response indicates a client- or server-side error.
*

View File

@ -62,7 +62,6 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
*/
public function onConnect()
{
// Construct a new data source
$this->source = new Phergie_Plugin_Php_Source_Local;
}
@ -75,14 +74,13 @@ class Phergie_Plugin_Php extends Phergie_Plugin_Abstract
*/
public function onCommandPhp($functionName)
{
// Search for the function
$nick = $this->event->getNick();
if ($function = $this->source->findFunction($functionName)) {
$msg = 'PHP ' . $function['name'] . ': ' . $function['description'];
$msg = $nick . ': ' . $function['description'];
$this->doPrivmsg($this->event->getSource(), $msg);
} else {
$msg = 'Search for function ' . $functionName . ' returned no results.';
$this->doNotice($nick, $msg);
}
// Return the result to the source
$this->doPrivmsg($this->getEvent()->getSource(), $msg);
}
}

View File

@ -65,6 +65,7 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
// @todo Modify this to be rethrown as an appropriate
// Phergie_Plugin_Exception and handled in Phergie_Plugin_Php
} catch (PDOException $e) {
echo 'PDO failure: '.$e->getMessage();
}
}
@ -114,8 +115,12 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
protected function buildDatabase($rebuild = false)
{
// Check to see if the functions table exists
$table = $this->database->exec("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
$checkstmt = $this->database->query("SELECT COUNT(*) FROM `sqlite_master` WHERE `name` = 'functions'");
$checkstmt->execute();
$result = $checkstmt->fetch(PDO::FETCH_ASSOC);
unset( $checkstmt );
$table = $result['COUNT(*)'];
unset( $result );
// If the table doesn't exist, create it
if (!$table) {
$this->database->exec('CREATE TABLE `functions` (`name` VARCHAR(255), `description` TEXT)');
@ -160,7 +165,7 @@ class Phergie_Plugin_Php_Source_Local implements Phergie_Plugin_Php_Source
// ... it's the last part of the complete function description
$completeLine = $firstPart . ' ' . $line;
$firstPart = '';
if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.\-_]*)$}', $completeLine, $matches)) {
if (preg_match('{^([^\s]*)[\s]?([^)]*)\(([^\)]*)\)[\sU]+([\sa-zA-Z0-9\.,\-_()]*)$}', $completeLine, $matches)) {
$valid[] = $matches;
}
}

View File

@ -0,0 +1,96 @@
<?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_Reload
* @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_Reload
*/
/**
* Facilitates reloading of individual plugins for development purposes.
* Note that, because existing class definitions cannot be removed from
* memory, increased memory usage is an expected result of using this plugin.
*
* @category Phergie
* @package Phergie_Plugin_Reload
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Reload
* @uses Phergie_Plugin_Command pear.phergie.org
*/
class Phergie_Plugin_Reload extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$this->getPluginHandler()->getPlugin('Command');
}
/**
* Reloads a specified plugin.
*
* @param string $plugin Short name of the plugin to reload
*
* @return void
*/
public function onCommandReload($plugin)
{
$plugin = ucfirst($plugin);
if (!$this->plugins->hasPlugin($plugin)) {
echo 'DEBUG(Reload): ' . ucfirst($plugin) . ' is not loaded yet, loading', PHP_EOL;
$this->plugins->getPlugin($plugin);
return;
}
try {
$info = $this->plugins->getPluginInfo($plugin);
} catch (Phergie_Plugin_Exception $e) {
$source = $this->event->getSource();
$nick = $this->event->getNick();
$this->doNotice($source, $nick . ': ' . $e->getMessage());
return;
}
$class = $info['class'];
$contents = file_get_contents($info['file']);
$newClass = $class . '_' . sha1($contents);
if (class_exists($newClass, false)) {
echo 'DEBUG(Reload): Class ', $class, ' has not changed since last reload', PHP_EOL;
return;
}
$contents = preg_replace(
array('/<\?(?:php)?/', '/class\s+' . $class . '/i'),
array('', 'class ' . $newClass),
$contents
);
eval($contents);
$instance = new $newClass;
$instance->setName($plugin);
$this->plugins
->removePlugin($plugin)
->addPlugin($instance);
echo 'DEBUG(Reload): Reloaded ', $class, ' to ', $newClass, PHP_EOL;
}
}

View File

@ -27,16 +27,16 @@
* @package Phergie_Plugin_Remind
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Drink
* @link http://pear.phergie.org/package/Phergie_Plugin_Remind
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Helper_Time pear.phergie.org
* @uses Phergie_Plugin_Time pear.phergie.org
*/
class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
{
/**
* Number of reminders to show in public.
*/
const PUBLIC_REMINDERS = 3;
protected $publicReminders = 3;
/**
* PDO resource for a SQLite database containing the reminders.
@ -64,11 +64,31 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
*/
public function onLoad()
{
$this->getPluginHandler()->getPlugin('Command');
$path = dirname(__FILE__) . '/reminder.db';
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Time');
}
/**
* Creates the database if it does not already exist.
*
* @return void
*/
public function onConnect()
{
$dir = dirname(__FILE__) . '/' . $this->getName();
$path = $dir . '/reminder.db';
if (!file_exists($dir)) {
mkdir($dir);
}
if (isset($this->config['remind.use_memory'])) {
$this->keepListInMemory = (bool)$this->config['remind.use_memory'];
$this->keepListInMemory = (bool) $this->config['remind.use_memory'];
}
if (isset($this->config['remind.public_reminders'])) {
$this->publicReminders = (int) $this->config['remind.public_reminders'];
$this->publicReminders = max($this->publicReminders, 0);
}
try {
@ -222,19 +242,19 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
// fetch and deliver messages
$reminders = $this->fetchMessages($channel, $nick);
if (count($reminders) > self::PUBLIC_REMINDERS) {
$msgs = array_slice($reminders, 0, self::PUBLIC_REMINDERS);
$privmsgs = array_slice($reminders, self::PUBLIC_REMINDERS);
if (count($reminders) > $this->publicReminders) {
$msgs = array_slice($reminders, 0, $this->publicReminders);
$privmsgs = array_slice($reminders, $this->publicReminders);
} else {
$msgs = $reminders;
$privmsgs = false;
}
foreach ($msgs as $msg) {
$ts = new Phergie_Plugin_Helper_Time($msg['time']);
$ts = $this->plugins->time->getCountdown($msg['time']);
$formatted = sprintf(
'%s: (from %s, %s ago) %s',
$nick, $msg['sender'], $ts->getCountdown(), $msg['message']
$nick, $msg['sender'], $ts, $msg['message']
);
$this->doPrivmsg($channel, $formatted);
$this->deleteMessage($msg['rowid'], $channel, $nick);
@ -242,10 +262,10 @@ class Phergie_Plugin_Remind extends Phergie_Plugin_Abstract
if ($privmsgs) {
foreach ($privmsgs as $msg) {
$ts = new Phergie_Plugin_Helper_Time($msg['time']);
$ts = $this->plugins->time->getCountdown($msg['time']);
$formatted = sprintf(
'from %s, %s ago: %s',
$msg['sender'], $ts->getCountdown(), $msg['message']
$msg['sender'], $ts, $msg['message']
);
$this->doPrivmsg($nick, $formatted);
$this->deleteMessage($msg['rowid'], $channel, $nick);

View File

@ -0,0 +1,120 @@
<?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_TerryChay
* @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_TerryChay
*/
/**
* Handles requests for checking spelling of specified words and returning
* either confirmation of correctly spelled words or potential correct
* spellings for misspelled words.
*
* @category Phergie
* @package Phergie_Plugin_SpellCheck
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_TerryChay
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses extension pspell
*/
class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract
{
/**
* Spell check dictionary handler
*
* @var resource
*/
protected $pspell;
/**
* Limit on the number of potential correct spellings returned
*
* @var int
*/
protected $limit;
/**
* Check for dependencies.
*
* @return void
*/
public function onLoad()
{
if (!extension_loaded('pspell')) {
$this->fail('pspell php extension is required');
}
if (!$this->getConfig('spellcheck.lang')) {
$this->fail('Setting spellcheck.lang must be filled-in');
}
$this->plugins->getPlugin('Command');
set_error_handler(array($this, 'loadDictionaryError'));
$this->pspell = pspell_new($this->getConfig('spellcheck.lang'));
restore_error_handler();
$this->limit = $this->getConfig('spellcheck.limit', 5);
}
/**
* Intercepts and handles requests for spell checks.
*
* @param string $word the string to perform checks against
*
* @return void
*/
public function onCommandSpell($word)
{
$source = $this->event->getSource();
$target = $this->event->getNick();
$message = $target . ': The word "' . $word;
$message .= '" seems to be spelt correctly.';
if (!pspell_check($this->pspell, $word)) {
$suggestions = pspell_suggest($this->pspell, $word);
$message = $target;
$message .= ': I could not find any suggestions for "' . $word . '".';
if (!empty($suggestions)) {
$suggestions = array_splice($suggestions, 0, $this->limit);
$message = $target . ': Suggestions for "';
$message .= $word . '": ' . implode(', ', $suggestions) . '.';
}
}
$this->doPrivmsg($source, $message);
}
/**
* Handle any errors from loading dictionary
*
* @param integer $errno Error code
* @param string $errstr Error message
* @param string $errfile File that errored
* @param integer $errline Line where the error happened
*
* @return void
*/
protected function loadDictionaryError($errno, $errstr, $errfile, $errline)
{
$this->fail($errstr);
}
}

View File

@ -0,0 +1,261 @@
<?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_Url
* @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_Url
*/
/**
* Responds to a request for a TLD (formatted as .tld where tld is the TLD to
* be looked up) with its corresponding description.
*
* @category Phergie
* @package Phergie_Plugin_Tld
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Tld
* @uses Phergie_Plugin_Http pear.phergie.org
*
* @pluginDesc Provides information for a top level domain.
*/
class Phergie_Plugin_Tld extends Phergie_Plugin_Abstract
{
/**
* connection to the database
* @var PDO
*/
protected $db;
/**
* Some fixed TLD values, keys must be lowercase
* @var array
*/
protected static $fixedTlds;
/**
* Prepared statement for selecting a single tld
* @var PDOStatement
*/
protected $select;
/**
* Prepared statement for selecting all tlds
* @var PDOStatement
*/
protected $selectAll;
/**
* Checks for dependencies, sets up database and hard coded values
*
* @return void
*/
public function onLoad()
{
$help = $this->getPluginHandler()->getPlugin('Help');
$help->register($this);
if (!is_array(self::$fixedTlds)) {
self::$fixedTlds = array(
'phergie' => 'You can find Phergie at http://www.phergie.org',
'spoon' => 'Don\'t you know? There is no spoon!',
'poo' => 'Do you really think that\'s funny?',
'root' => 'Diagnostic marker to indicate '
. 'a root zone load was not truncated.'
);
}
try {
$dbFile = dirname(__FILE__) . '/Tld/tld.db';
$dbManager = new Phergie_Db_Sqlite($dbFile);
$this->db = $dbManager->getDb();
if (!$dbManager->hasTable('tld')) {
$query = 'CREATE TABLE tld ('
. 'tld VARCHAR(20), '
. 'type VARCHAR(20), '
. 'description VARCHAR(255))';
$this->db->exec($query);
// prepare a statement to populate the table with
// tld information
$insert = $this->db->prepare(
'INSERT INTO tld
(tld, type, description)
VALUES (:tld, :type, :description)'
);
// grab tld data from iana.org...
$contents = file_get_contents(
'http://www.iana.org/domains/root/db/'
);
// ...and then parse it out
$regex = '{<tr class="iana-group[^>]*><td><a[^>]*>\s*\.?([^<]+)\s*'
. '(?:<br/><span[^>]*>[^<]*</span>)?</a></td><td>\s*'
. '([^<]+)\s*</td><td>\s*([^<]+)\s*}i';
preg_match_all($regex, $contents, $matches, PREG_SET_ORDER);
foreach ($matches as $match) {
list(, $tld, $type, $description) = array_pad($match, 4, null);
$type = trim(strtolower($type));
if ($type != 'test') {
$tld = trim(strtolower($tld));
$description = trim($description);
switch ($tld) {
case 'com':
$description = 'Commercial';
break;
case 'info':
$description = 'Information';
break;
case 'net':
$description = 'Network';
break;
case 'org':
$description = 'Organization';
break;
case 'edu':
$description = 'Educational';
break;
case 'name':
$description = 'Individuals, by name';
break;
}
if (empty($tld) || empty($description)) {
continue;
}
$regex = '{(^(?:Reserved|Restricted)\s*(?:exclusively\s*)?'
. '(?:for|to)\s*(?:members of\s*)?(?:the|support)?'
. '\s*|\s*as advised.*$)}i';
$description = preg_replace($regex, '', $description);
$description = ucfirst(trim($description));
$data = array_map(
'html_entity_decode', array(
'tld' => $tld,
'type' => $type,
'description' => $description
)
);
$insert->execute($data);
}
}
unset(
$insert,
$matches,
$match,
$contents,
$tld,
$type,
$description,
$data,
$regex
);
}
// Create a prepared statements for retrieving TLDs
$this->select = $this->db->prepare(
'SELECT type, description '
. 'FROM tld WHERE LOWER(tld) = LOWER(:tld)'
);
$this->selectAll = $this->db->prepare(
'SELECT tld, type, description FROM tld'
);
} catch (PDOException $e) {
}
}
/**
* takes a tld in the format '.tld' and returns its related data
*
* @param string $tld tld to process
*
* @return null
*
* @pluginCmd .[tld] request details about the tld
*/
public function onCommandTld($tld)
{
$tld = ltrim($tld, '.');
$description = $this->getTld($tld);
$this->doPrivmsg(
$this->event->getSource(),
"{$this->getEvent()->getNick()}: .{$tld} -> "
. ($description ? $description : 'Unknown TLD')
);
}
/**
* Retrieves the definition for a given TLD if it exists
*
* @param string $tld TLD to search for
*
* @return string Definition of the given TLD
*/
public function getTld($tld)
{
$tld = trim(strtolower($tld));
if (isset(self::$fixedTlds[$tld])) {
return self::$fixedTlds[$tld];
} else {
if ($this->select->execute(array('tld' => $tld))) {
$tlds = $this->select->fetch();
if (is_array($tlds)) {
return '(' . $tlds['type'] . ') ' . $tlds['description'];
}
}
}
return false;
}
/**
* Retrieves a list of all the TLDs and their definitions
*
* @return array Array of all the TLDs and their definitions
*/
public function getTlds()
{
if ($this->selectAll->execute()) {
$tlds = $this->selectAll->fetchAll();
if (is_array($tlds)) {
$tldinfo = array();
foreach ($tlds as $key => $tld) {
if (!empty($tld['tld'])) {
$tldinfo[$tld['tld']] = "({$tld['type']}) "
. $tld['description'];
}
}
unset($tlds);
return $tldinfo;
}
}
return false;
}
}

View File

@ -31,6 +31,7 @@
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url
* @uses Phergie_Plugin_Http pear.phergie.org
*/
class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
{
@ -42,7 +43,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
*
* @var string
*/
protected $baseFormat = '%nick%: %message%';
protected $baseFormat = '%message%';
protected $messageFormat = '[ %link% ] %title%';
/**
@ -184,7 +185,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// make the shortener configurable
$shortener = $this->getConfig('url.shortener', 'Trim');
$shortener = "Phergie_Plugin_Url_Shorten_{$shortener}";
$this->shortener = new $shortener;
$this->shortener = new $shortener($this->plugins->getPlugin('Http'));
if (!$this->shortener instanceof Phergie_Plugin_Url_Shorten_Abstract) {
$this->fail("Declared shortener class {$shortener} is not of proper ancestry");
@ -192,17 +193,9 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// Get a list of valid TLDs
if (!is_array($this->tldList) || count($this->tldList) <= 6) {
/* Omitted for port
if ($this->pluginLoaded('Tld')) {
$this->tldList = Phergie_Plugin_Tld::getTlds();
if (is_array($this->tldList)) {
$this->tldList = array_keys($this->tldList);
}
}
*/
if (!is_array($this->tldList) || count($this->tldList) <= 0) {
$this->tldList = array('ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa', 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'biz', 'bj', 'bl', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc', 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu', 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'eh', 'er', 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg', 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk', 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq', 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp', 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly', 'ma', 'mc', 'md', 'me', 'mf', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp', 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc', 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe', 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're', 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl', 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th', 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua', 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws', 'ye', 'yt', 'yu', 'za', 'zm', 'zw');
}
$tldPath = dirname(__FILE__) . '/Url/url.tld.txt';
$this->tldList = explode("\n", file_get_contents($tldPath));
$this->debug('Loaded ' . count($this->tldList) . ' tlds');
rsort($this->tldList);
}
@ -215,6 +208,7 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
'merge_links' => 'mergeLinks',
'title_length' => 'titleLength',
'show_errors' => 'showErrors',
'expire' => 'expire',
) as $config => $local) {
if (isset($this->config["url.{$config}"])) {
$this->$local = $this->config["uri.{$config}"];
@ -306,6 +300,10 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
// Convert url
$shortenedUrl = $this->shortener->shorten($url);
if (!$shortenedUrl) {
$this->debug('Invalid Url: Unable to shorten. (' . $url . ')');
continue;
}
// Prevent spamfest
if ($this->checkUrlCache($url, $shortenedUrl)) {
@ -624,73 +622,29 @@ class Phergie_Plugin_Url extends Phergie_Plugin_Abstract
*/
public function getTitle($url)
{
$opts = array(
'http' => array(
$http = $this->plugins->getPlugin('Http');
$options = array(
'timeout' => 3.5,
'method' => 'GET',
'user_agent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.12) Gecko/20080201 Firefox/2.0.0.12'
)
);
$context = stream_context_create($opts);
if ($page = fopen($url, 'r', false, $context)) {
stream_set_timeout($page, 3.5);
$data = stream_get_meta_data($page);
foreach ($data['wrapper_data'] as $header) {
if (preg_match('/^Content-Type: ([^;]+)/', $header, $match)
&& !preg_match('#^(text/x?html|application/xhtml+xml)$#', $match[1])
) {
$title = $match[1];
}
}
if (!isset($title)) {
$content = '';
$tstamp = time() + 5;
$response = $http->get($url, array(), $options);
while ($chunk = fread($page, 64)) {
$data = stream_get_meta_data($page);
if ($data['timed_out']) {
$this->debug('Url Timed Out: ' . $url);
$this->errorStatus = true;
break;
$header = $response->getHeaders('Content-Type');
if (!preg_match('#^(text/x?html|application/xhtml+xml)(?:;.*)?$#', $header)) {
$title = $header;
}
$content .= $chunk;
// Check for timeout
if (time() > $tstamp) break;
// Try to read title
if (preg_match('#<title[^>]*>(.*)#is', $content, $m)) {
// Start another loop to grab some more data in order to be sure we have the complete title
$content = $m[1];
$loop = 2;
while (($chunk = fread($page, 64)) && $loop-- && !strstr($content, '<')) {
$content .= $chunk;
// Check for timeout
if (time() > $tstamp) break;
$content = $response->getContent();
if (empty($title)) {
if (preg_match('#<title[^>]*>(.*?)</title>#is', $content, $match)) {
$title = html_entity_decode(trim($match[1]));
}
preg_match('#^([^<]*)#is', $content, $m);
$title = preg_replace('#\s+#', ' ', $m[1]);
$title = trim($this->decode($title, $this->titleLength));
break;
}
// Title won't appear beyond that point so stop parsing
if (preg_match('#</head>|<body#i', $content)) {
break;
}
}
}
fclose($page);
} else if (!$this->errorStatus) {
$this->debug('Couldn\t Open Url: ' . $url);
}
if (empty($title)) {
if ($this->errorStatus) {
if (!$this->showErrors || empty($this->errorMessage)) {
return;
}
$title = $this->errorMessage;
$this->errorStatus = false;
$this->errorMessage = null;
if ($response->isError()) {
$title = $response->getCodeAsString();
} else {
$title = 'No Title';
}

View File

@ -27,15 +27,79 @@
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Url
* @uses Phergie_Plugin_Http pear.phergie.org
*/
abstract class Phergie_Plugin_Url_Shorten_Abstract
{
protected $http;
/**
* Takes a long url and returns a shortened link
* Constructor
*
* @param Phergie_Plugin_Http $http instance of the http plugin
*/
public function __construct(Phergie_Plugin_Http $http)
{
$this->http = $http;
}
/**
* Returns an array of request parameters given a url to shorten. The
* following keys are valid request parameters:
*
* * 'uri': the URI for the request (required)
* * 'query': an array of key-value pairs sent in a GET request
* * 'post': an array of key-value pairs sent in a POST request
* * 'callback': to be called after the request is finished. Should accept
* a Phergie_Plugin_Http_Response object and return either the shortened
* url or false if an error has occured.
*
* If the 'post' key is present a POST request shall be made; otherwise
* a GET request will be made. The 'post' key can be an empty array and
* a post request will still be made.
*
* If no callback is provided the contents of the response will be returned.
*
* @param string $url the url to shorten
*
* @return string string the shortened url
* @return array the request parameters
*/
public abstract function shorten($url);
protected abstract function getRequestParams($url);
/**
* Shortens a given url.
*
* @param string $url the url to shorten
*
* @return string the shortened url or false on a failure
*/
public function shorten($url)
{
$defaults = array('get' => array(), 'post' => array(), 'callback' => null);
$options = array('timeout' => 2);
$params = $this->getRequestParams($url) + $defaults;
// Should some kind of notice be thrown? Maybe just if getRequestParams does not return an array?
if (!is_array($params) || empty($params['uri'])) {
return $url;
}
if (!empty($params['post'])) {
$response = $this->http->post($params['uri'], $params['get'], $params['post'], $options);
} else {
$response = $this->http->get($params['uri'], $params['get'], $options);
}
if (is_callable($params['callback'])) {
return call_user_func($params['callback'], $response);
}
$code = $response->getCode();
$content = trim($response->getContent);
if ($code < 200 || $code >= 300 || empty($content)) {
return false;
}
return $response->getContent();
}
}

View File

@ -31,14 +31,34 @@
class Phergie_Plugin_Url_Shorten_Trim extends Phergie_Plugin_Url_Shorten_Abstract
{
/**
* Short a URL through the tr.im api
* Returns an array of request parameters given a url to shorten. The
* following keys are valid request parameters:
*
* @param string $url the url to shorten
*
* @return string string the shortened url
* @return array the request parameters
*/
public function shorten($url)
protected function getRequestParams($url)
{
return file_get_contents('http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url));
return array(
'uri' => 'http://api.tr.im/v1/trim_simple?url=' . rawurlencode($url),
'callback' => array($this, 'onComplete')
);
}
/**
* Callback for when the URL has been shortened. Checks for error messages.
*
* @param Phergie_Plugin_Http_Response $response the response object
*
* @return string|bool the shortened url or false on failure
*/
protected function onComplete($response)
{
if (strpos($response->getContent(), 'Error: ') === 0) {
return false;
}
return $response->getContent();
}
}

View File

@ -0,0 +1,273 @@
ac
ad
ae
aero
af
ag
ai
al
am
an
ao
aq
ar
arpa
as
asia
at
au
aw
ax
az
ba
bb
bd
be
bf
bg
bh
bi
biz
bj
bl
bm
bn
bo
br
bs
bt
bv
bw
by
bz
ca
cat
cc
cd
cf
cg
ch
ci
ck
cl
cm
cn
co
com
coop
cr
cu
cv
cx
cy
cz
de
dj
dk
dm
do
dz
ec
edu
ee
eg
eh
er
es
et
eu
fi
fj
fk
fm
fo
fr
ga
gb
gd
ge
gf
gg
gh
gi
gl
gm
gn
gov
gp
gq
gr
gs
gt
gu
gw
gy
hk
hm
hn
hr
ht
hu
id
ie
il
im
in
info
int
io
iq
ir
is
it
je
jm
jo
jobs
jp
ke
kg
kh
ki
km
kn
kp
kr
kw
ky
kz
la
lb
lc
li
lk
lr
ls
lt
lu
lv
ly
ma
mc
md
me
mf
mg
mh
mil
mk
ml
mm
mn
mo
mobi
mp
mq
mr
ms
mt
mu
museum
mv
mw
mx
my
mz
na
name
nc
ne
net
nf
ng
ni
nl
no
np
nr
nu
nz
om
org
pa
pe
pf
pg
ph
pk
pl
pm
pn
pr
pro
ps
pt
pw
py
qa
re
ro
rs
ru
rw
sa
sb
sc
sd
se
sg
sh
si
sj
sk
sl
sm
sn
so
sr
st
su
sv
sy
sz
tc
td
tel
tf
tg
th
tj
tk
tl
tm
tn
to
tp
tr
travel
tt
tv
tw
tz
ua
ug
uk
um
us
uy
uz
va
vc
ve
vg
vi
vn
vu
wf
ws
ye
yt
yu
za
zm
zw

View File

@ -0,0 +1,132 @@
<?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_Weather
* @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_Weather
*/
/**
* Detects and responds to requests for current weather conditions in a
* particular location using data from a web service. Requires registering
* with weather.com to obtain authentication credentials, which must be
* stored in the configuration settings weather.partner_id and
* weather.license_key for the plugin to function.
*
* @category Phergie
* @package Phergie_Plugin_Weather
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie_Plugin_Weather
* @link http://www.weather.com/services/xmloap.html
* @uses Phergie_Plugin_Command pear.phergie.org
* @uses Phergie_Plugin_Http pear.phergie.org
* @uses extension SimpleXML
*/
class Phergie_Plugin_Weather extends Phergie_Plugin_Abstract
{
/**
* Checks for dependencies.
*
* @return void
*/
public function onLoad()
{
$plugins = $this->getPluginHandler();
$plugins->getPlugin('Command');
$plugins->getPlugin('Http');
if (empty($this->config['weather.partner_id'])
|| empty($this->config['weather.license_key'])) {
$this->fail('weather.partner_id and weather.license_key must be specified');
}
}
/**
* Returns a weather report for a specified location.
*
* @param string $location Zip code or city/state/country specification
*
* @return void
*/
public function onCommandWeather($location)
{
$response = $this->plugins->http->get(
'http://xoap.weather.com/search/search',
array('where' => $location)
);
if ($response->isError()) {
$this->doNotice(
$this->event->getNick(),
'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
);
return;
}
$nick = $this->event->getNick();
$xml = $response->getContent();
if (count($xml->loc) == 0) {
$this->doNotice($nick, 'No results for that location.');
return;
}
$where = (string) $xml->loc[0]['id'];
$response = $this->plugins->http->get(
'http://xoap.weather.com/weather/local/' . $where,
array(
'cc' => '*',
'link' => 'xoap',
'prod' => 'xoap',
'par' => $this->config['weather.partner_id'],
'key' => $this->config['weather.license_key'],
)
);
if ($response->isError()) {
$this->doNotice(
$this->event->getNick(),
'ERROR: ' . $response->getCode() . ' ' . $response->getMessage()
);
return;
}
$xml = $response->getContent();
$weather = 'Weather for ' . (string) $xml->loc->dnam . ' - ';
$weather .= 'Current temperature ' .
(string) $xml->cc->tmp .
(string) $xml->head->ut . ' / ';
if ((string) $xml->head->ut == 'F') {
$weather .= round(((((int) $xml->cc->tmp - 32) * 5) / 9)) . 'C';
} else {
$weather .= round(((((int) $xml->cc->tmp * 9) / 5) + 32)) . 'F';
}
$weather .=
', Relative humidity ' . (string) $xml->cc->hmid . '%' .
', Current conditions ' . (string) $xml->cc->t .
', Last update ' . (string) $xml->cc->lsup .
' [ http://weather.com/weather/today/' .
str_replace(
array('(', ')', ',', ' '),
array('', '', '', '+'),
(string) $xml->loc->dnam
) .
' ]';
$this->doPrivmsg($this->event->getSource(), $nick . ': ' . $weather);
}
}

View File

@ -12,7 +12,8 @@ return array(
'realname' => 'Matthew Turland',
'nick' => 'Phergie2',
// 'password' => 'password goes here if needed',
// 'transport' => 'ssl' // uncomment to connect using SSL
// 'transport' => 'ssl', // uncomment to connect using SSL
// 'encoding' => 'UTF8', // uncomment if using UTF8
)
),

View File

@ -37,6 +37,41 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
*/
protected $handler;
/**
* Mock Phergie_Config instance passed to the plugin handler constructor
*
* @var Phergie_Config
*/
protected $config;
/**
* Mock Phergie_Event_Handler instance passed to the plugin handler
* constructor
*
* @var Phergie_Event_Handler
*/
protected $events;
/**
* Returns a mock plugin instance.
*
* @param string $name Optional short name for the mock plugin, defaults
* to 'TestPlugin'
* @param array $methods Optional list of methods to override
*
* @return Phergie_Plugin_Abstract
*/
protected function getMockPlugin($name = 'TestPlugin', array $methods = array())
{
$methods[] = 'getName';
$plugin = $this->getMock('Phergie_Plugin_Abstract', $methods);
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue($name));
return $plugin;
}
/**
* Sets up a new handler instance before each test.
*
@ -44,69 +79,191 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
*/
public function setUp()
{
$this->config = $this->getMock('Phergie_Config');
$this->events = $this->getMock('Phergie_Event_Handler');
$this->handler = new Phergie_Plugin_Handler(
new Phergie_Config(),
new Phergie_Event_Handler()
$this->config,
$this->events
);
}
/**
* Destroys the handler instance after each test
* Tests iterability of the plugin handler.
*
* @return void
*/
public function tearDown()
{
unset($this->handler);
}
/**
* Ensures that we can iterate over the handler
*
* @return void
*/
public function testImplementsIterator()
public function testImplementsIteratorAggregate()
{
$reflection = new ReflectionObject($this->handler);
$this->assertTrue(
$reflection->implementsInterface('IteratorAggregate')
$reflection->implementsInterface('IteratorAggregate'),
'Handler does not implement IteratorAggregate'
);
$this->assertType(
'Iterator', $this->handler->getIterator(),
'getIterator() must actually return an Iterator'
'Iterator',
$this->handler->getIterator(),
'getIterator() must return an iterator'
);
}
/**
* Ensures a newly instantiated handler does not have plugins associated
* with it
* Tests countability of the plugin handler.
*
* @depends testImplementsIterator
* @return void
*/
public function testImplementsCountable()
{
$reflection = new ReflectionObject($this->handler);
$this->assertTrue(
$reflection->implementsInterface('Countable'),
'Handler does not implement Countable'
);
$this->assertType(
'int',
count($this->handler),
'count() must return an integer'
);
}
/**
* Tests the plugin handler exposing added plugins as instance
* properties of the handler via isset().
*
* @return void
*/
public function testImplementsIsset()
{
$pluginName = 'TestPlugin';
$this->assertFalse(isset($this->handler->{$pluginName}));
$plugin = $this->getMockPlugin($pluginName);
$this->handler->addPlugin($plugin);
$this->assertTrue(isset($this->handler->{$pluginName}));
}
/**
* Tests the plugin handler exposing added plugins as instance
* properties of the handler.
*
* @depends testImplementsIsset
* @return void
*/
public function testImplementsGet()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
$name = $plugin->getName();
$getPlugin = $this->handler->getPlugin($name);
$this->assertTrue(isset($this->handler->$name));
$get = $this->handler->$name;
$this->assertSame($getPlugin, $get);
}
/**
* Tests the plugin handler allowing for plugin removal via unset().
*
* @depends testImplementsGet
* @return void
*/
public function testImplementsUnset()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
unset($this->handler->{$plugin->getName()});
$this->assertFalse($this->handler->hasPlugin($plugin->getName()));
}
/**
* Tests the plugin handler executing a callback on all contained
* plugins where one plugin short-circuits the process.
*
* @return void
*/
public function testImplementsCallWithShortCircuit()
{
$plugin1 = $this->getMockPlugin('TestPlugin1', array('callback'));
$plugin1
->expects($this->once())
->method('callback')
->will($this->returnValue(false));
$this->handler->addPlugin($plugin1);
$plugin2 = $this->getMockPlugin('TestPlugin2', array('callback'));
$plugin2
->expects($this->exactly(0))
->method('callback');
$this->handler->addPlugin($plugin2);
$this->assertFalse($this->handler->callback());
}
/**
* Tests the plugin handler executing a callback on all contained
* plugins where no plugins short-circuit the process.
*
* @return void
*/
public function testImplementsCallWithoutShortCircuit()
{
foreach (range(1, 2) as $index) {
$plugin = $this->getMockPlugin('TestPlugin' . $index, array('callback'));
$plugin
->expects($this->once())
->method('callback');
$this->handler->addPlugin($plugin);
}
$this->assertTrue($this->handler->callback());
}
/**
* Tests a newly instantiated handler not having plugins associated with
* it.
*
* @depends testImplementsCountable
* @return void
*/
public function testEmptyHandlerHasNoPlugins()
{
$count = 0;
foreach ($this->handler as $plugin) {
$count++;
}
$this->assertEquals(0, $count);
$this->assertEquals(0, count($this->handler));
}
/**
* Ensures a newly instantiated handler does not default to autoload
* Tests a newly instantiated handler not having autoloading enabled by
* default.
*
* @return void
*/
public function testDefaultsToNotAutoload()
public function testGetAutoloadDefaultsToNotAutoload()
{
$this->assertFalse($this->handler->getAutoload());
}
/**
* addPath provides a fluent interface
* Tests setAutoload().
*
* @depends testGetAutoloadDefaultsToNotAutoload
* @return void
*/
public function testSetAutoload()
{
$this->assertSame(
$this->handler->setAutoload(true),
$this->handler,
'setAutoload() does not provide a fluent interface'
);
$this->assertTrue(
$this->handler->getAutoload(),
'setAutoload() had no effect on getAutoload()'
);
}
/**
* Tests addPath() providing a fluent interface.
*
* @return void
*/
@ -117,7 +274,8 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
}
/**
* addPath throws an exception when it cannot read the directory
* Tests addPath() throwing an exception when it cannot read the
* directory.
*
* @return void
*/
@ -133,122 +291,113 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return;
}
$this->fail('An expected exception has not been raised.');
$this->fail('An expected exception has not been raised');
}
/**
* adds a path into the plugin handler and then ensures that files
* in that location can be found
* Tests adding a path to the plugin handler.
*
* @return void
*/
public function testAddPath()
{
$plugin_name = 'Mock';
$pluginName = 'Mock';
try {
$this->handler->addPlugin($plugin_name);
$this->handler->addPlugin($pluginName);
} catch(Phergie_Plugin_Exception $e) {
$this->assertEquals(
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
$e->getCode()
);
}
if (!isset($e)) {
$this->fail('Plugin loaded, path was already present');
}
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
try {
$this->handler->addPlugin($plugin_name);
$this->handler->addPlugin($pluginName);
} catch(Phergie_Plugin_Exception $e) {
$this->fail(
'After adding the directory, the plugin was still '
. 'not found.'
);
$this->fail('Added path, plugin still not found');
}
return;
}
$this->fail(
'Before adding the directory, an expected exception '
. 'was not raised'
);
}
/**
* addPlugin returns the plugin instance that was added
* Tests addPlugin() returning an added plugin instance.
*
* @return void
*/
public function testAddPluginByInstanceReturnsPluginInstance() {
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$returned_plugin = $this->handler->addPlugin($plugin);
$this->assertSame(
$returned_plugin,
$plugin,
'addPlugin returns the same instance that is passed to it'
);
}
/**
* Can add a plugin to the handler by shortname
*
* @return void
*/
public function testAddPluginToHandlerByShortname()
public function testAddPluginByInstanceReturnsPluginInstance()
{
$plugin_name = 'Mock';
$plugin = $this->getMockPlugin();
$returnedPlugin = $this->handler->addPlugin($plugin);
$this->assertSame(
$returnedPlugin,
$plugin,
'addPlugin() does not return the instance passed to it'
);
}
/**
* Tests adding a plugin to the handler using the plugin's short name.
*
* @return void
*/
public function testAddPluginByShortName()
{
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$returned_plugin = $this->handler->addPlugin($plugin_name);
$this->assertTrue($this->handler->hasPlugin($plugin_name));
$returnedPlugin = $this->handler->addPlugin($pluginName);
$this->assertTrue($this->handler->hasPlugin($pluginName));
$this->assertType(
'Phergie_Plugin_Mock',
$this->handler->getPlugin($plugin_name)
$this->handler->getPlugin($pluginName)
);
$this->assertSame(
$this->handler->getPlugin($plugin_name),
$returned_plugin,
'Handler contains plugin when added by shortname.'
$this->handler->getPlugin($pluginName),
$returnedPlugin,
'Handler does not contain added plugin'
);
}
/**
* Can add a plugin to the handler by instance
* Tests adding a plugin instance to the handler.
*
* @return void
*/
public function testAddPluginToHandlerByInstance()
public function testAddPluginByInstance()
{
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$returned_plugin = $this->handler->addPlugin($plugin);
$plugin = $this->getMockPlugin();
$returnedPlugin = $this->handler->addPlugin($plugin);
$this->assertTrue($this->handler->hasPlugin('TestPlugin'));
$this->assertSame(
$plugin, $returned_plugin,
'addPlugin returns the same plugin'
$plugin,
$returnedPlugin,
'addPlugin() does not return added plugin instance'
);
$this->assertSame(
$plugin, $this->handler->getPlugin('TestPlugin'),
'getPlugin returns the same plugin'
$plugin,
$this->handler->getPlugin('TestPlugin'),
'getPlugin() does not return added plugin instance'
);
}
/**
* addPlugin throws an exception when it can't find the plugin
* Tests addPlugin() throwing an exception when the plugin class file
* can't be found.
*
* @return void
*/
public function testAddPluginThrowsExceptionIfCannotFindPlugin()
public function testAddPluginThrowsExceptionWhenPluginFileNotFound()
{
try {
$this->handler->addPlugin('TestPlugin');
@ -260,12 +409,68 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return;
}
$this->fail('An expected exception has not been raised.');
$this->fail('An expected exception has not been raised');
}
/**
* addPlugin throws an exception when trying to instantiate a
* class that doesn't extend from Phergie_Plugin_Abstract
* Recursively removes all files and subdirectories in a directory.
*
* @param string $path Directory path
* @return void
*/
private function removeDirectory($path)
{
if (file_exists($path)) {
$it = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($path),
RecursiveIteratorIterator::CHILD_FIRST
);
foreach ($it as $entry) {
if ($it->isDot()) {
continue;
}
if ($entry->isDir()) {
rmdir($entry->getPathname());
} else {
unlink($entry->getPathname());
}
}
}
}
/**
* Tests addPlugin() throwing an exception when the plugin class file is
* found, but does not contain the plugin class as expected.
*
* @return void
*/
public function testAddPluginThrowsExceptionWhenPluginClassNotFound()
{
$path = sys_get_temp_dir() . '/Phergie/Plugin';
$this->removeDirectory(dirname($path));
mkdir($path, 0777, true);
touch($path . '/TestPlugin.php');
$this->handler->addPath($path, 'Phergie_Plugin_');
try {
$this->handler->addPlugin('TestPlugin');
} catch(Phergie_Plugin_Exception $e) { }
if (isset($e)) {
$this->assertEquals(
Phergie_Plugin_Exception::ERR_CLASS_NOT_FOUND,
$e->getCode()
);
} else {
$this->fail('An expected exception has not been raised');
}
$this->removeDirectory(dirname($path));
}
/**
* Tests addPlugin() throwing an exception when trying to instantiate a
* class that doesn't extend Phergie_Plugin_Abstract.
*
* @return void
*/
@ -281,11 +486,11 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return;
}
$this->fail('An expected exception has not been raised.');
$this->fail('An expected exception has not been raised');
}
/**
* addPlugin throws an exception when trying to instantiate a
* Tests addPlugin() throwing an exception when trying to instantiate a
* class that can't be instantiated.
*
* @return void
@ -303,143 +508,88 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return;
}
$this->fail('An expected exception has not been raised.');
$this->fail('An expected exception has not been raised');
}
/**
* addPlugin with shortname and arguments passes args to constructor
*
* @return null
*/
public function testAddPluginShortnamePassesArgsToConstructor()
{
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$arguments = array('a', 'b', 'c');
$plugin = $this->handler->addPlugin($plugin_name, $arguments);
$this->assertAttributeSame(
$arguments,
'args',
$plugin,
'Arguments passed in to addPlugin match the arguments '
. 'the Mock plugin constructor received'
);
}
/**
* addPlugin passes Phergie_Config to instantiated plugin
*
* @return null
*/
public function testAddPluginPassesPhergieConfigToInstantiatedPlugin()
{
$my_config = new Phergie_Config();
$my_config['my_option'] = 'my_value';
// create a new handler with this config
unset($this->handler);
$this->handler = new Phergie_Plugin_Handler(
$my_config,
new Phergie_Event_Handler()
);
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($plugin_name);
$this->assertSame(
$my_config,
$plugin->getConfig(),
'addPlugin passes Phergie_Config to instantiated plugin'
);
}
/**
* addPlugin passes Phergie_Event_Handler to instantiated plugin
*
* @return null
*/
public function testAddPluginPassesPhergieEventHandlerToInstantiatedPlugin()
{
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue('TestPlugin'));
$my_event_handler = new Phergie_Event_Handler();
$my_event_handler->addEvent($plugin, 'ping');
// create a new plugin handler with this event handler
unset($this->handler);
$this->handler = new Phergie_Plugin_Handler(
new Phergie_Config(),
$my_event_handler
);
$plugin_name = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($plugin_name);
$this->assertSame(
$my_event_handler,
$plugin->getEventHandler(),
'addPlugin passes Phergie_Event_Handler to instantiated plugin'
);
}
/**
* @todo addPlugin calls onLoad() to instantiated plugin
*/
/**
* implements __isset
* Tests adding a plugin by its short name with arguments passed to the
* plugin constructor.
*
* @return void
*/
public function testPluginHandlerImplementsIsset()
public function testAddPluginShortNamePassesArgsToConstructor()
{
$plugin_name = 'TestPlugin';
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$this->assertFalse(isset($this->handler->{$plugin_name}));
$plugin = $this->getMock('Phergie_Plugin_Abstract');
$plugin
->expects($this->any())
->method('getName')
->will($this->returnValue($plugin_name));
$this->handler->addPlugin($plugin);
$this->assertTrue(isset($this->handler->{$plugin_name}));
$arguments = array('a', 'b', 'c');
$plugin = $this->handler->addPlugin($pluginName, $arguments);
$this->assertAttributeSame(
$arguments,
'arguments',
$plugin,
'Arguments do not match'
);
}
/**
* addPlugin() returns the same plugin when requested twice
* Tests addPlugin() passing Phergie_Config to an instantiated plugin.
*
* @return void
*/
public function testAddPluginPassesConstructorArguments()
{
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->addPlugin($pluginName);
$this->assertSame(
$this->config,
$plugin->getConfig(),
'Phergie_Config instances do not match'
);
$this->assertSame(
$this->events,
$plugin->getEventHandler(),
'Phergie_Event_Handler instances do not match'
);
}
/**
* Tests addPlugin() calling onLoad() on an instantiated plugin.
*
* @return void
*/
public function testAddPluginCallsOnLoadOnInstantiatedPlugin()
{
$plugin = $this->getMockPlugin(null, array('onLoad'));
$plugin
->expects($this->once())
->method('onLoad');
$this->handler->addPlugin($plugin);
}
/**
* Tests addPlugin() returning the same plugin when called twice.
*
* @return void
*/
public function testAddPluginReturnsSamePluginWhenAskedTwice()
{
$plugin_name = 'Mock';
$pluginName = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin1 = $this->handler->addPlugin($plugin_name);
$plugin2 = $this->handler->addPlugin($plugin_name);
$plugin1 = $this->handler->addPlugin($pluginName);
$plugin2 = $this->handler->addPlugin($pluginName);
$this->assertSame($plugin1, $plugin2);
}
/**
* Tests an exception is thrown when trying to get a plugin
* that is not already loaded and autoload is off
* Tests getPlugin() throwing an exception when trying to get an
* unloaded plugin with autoload disabled.
*
* @depends testDefaultsToNotAutoload
* @depends testGetAutoloadDefaultsToNotAutoload
* @return void
*/
public function testExceptionThrownWhenLoadingPluginWithoutAutoload()
@ -456,6 +606,134 @@ class Phergie_Plugin_HandlerTest extends PHPUnit_Framework_TestCase
return;
}
$this->fail('An expected exception has not been raised.');
$this->fail('An expected exception has not been raised');
}
/**
* Tests addPlugins() with a plugin short name and no plugin constructor
* arguments.
*
* @depends testAddPluginByShortName
* @depends testAddPluginByInstance
* @return void
*/
public function testAddPluginsWithoutArguments()
{
$prefix = 'Phergie_Plugin_';
$this->handler->addPath(dirname(__FILE__), $prefix);
$plugin = 'Mock';
$this->handler->addPlugins(array($plugin));
$returnedPlugin = $this->handler->getPlugin($plugin);
$this->assertContains(
get_class($returnedPlugin),
$prefix . $plugin,
'Short name plugin not of expected class'
);
}
/**
* Tests addPlugins() with a plugin short name and plugin constructor
* arguments.
*
* @depends testAddPluginByShortName
* @depends testAddPluginByInstance
* @return void
*/
public function testAddPluginsWithArguments()
{
$prefix = 'Phergie_Plugin_';
$this->handler->addPath(dirname(__FILE__), $prefix);
$arguments = array(1, 2, 3);
$plugin = array('Mock', $arguments);
$this->handler->addPlugins(array($plugin));
$returnedPlugin = $this->handler->getPlugin('Mock');
$this->assertEquals(
$arguments,
$returnedPlugin->getArguments(),
'Constructor arguments for instance plugin do not match'
);
}
/**
* Tests removePlugin() with a plugin instance.
*
* @depends testAddPluginByInstance
* @return void
*/
public function testRemovePluginByInstance()
{
$plugin = $this->getMockPlugin();
$this->handler->addPlugin($plugin);
$this->handler->removePlugin($plugin);
$this->assertFalse(
$this->handler->hasPlugin($plugin->getName()),
'Plugin was not removed'
);
}
/**
* Tests removePlugin() with a plugin short name.
*
* @depends testAddPluginByShortName
* @return void
*/
public function testRemovePluginByShortName()
{
$plugin = 'Mock';
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$this->handler->addPlugin($plugin);
$this->handler->removePlugin($plugin);
$this->assertFalse(
$this->handler->hasPlugin($plugin),
'Plugin was not removed'
);
}
/**
* Tests getPlugin() when the plugin is not already loaded and
* autoloading is disabled.
*
* @depends testSetAutoload
* @return void
*/
public function testGetPluginWithAutoloadEnabled()
{
$this->handler->setAutoload(true);
$this->handler->addPath(dirname(__FILE__), 'Phergie_Plugin_');
$plugin = $this->handler->getPlugin('Mock');
$this->assertType(
'Phergie_Plugin_Mock',
$plugin,
'Retrieved plugin not of expected class'
);
}
/**
* Tests getPlugins().
*
* @depends testGetPluginWithAutoloadEnabled
* @return void
*/
public function testGetPlugins()
{
$plugin1 = $this->getMockPlugin('TestPlugin1');
$this->handler->addPlugin($plugin1);
$plugin2 = $this->getMockPlugin('TestPlugin2');
$this->handler->addPlugin($plugin2);
$expected = array(
'testplugin1' => $plugin1,
'testplugin2' => $plugin2,
);
$actual = $this->handler->getPlugins();
$this->assertEquals($expected, $actual);
$actual = $this->handler->getPlugins(array('testplugin1', 'testplugin2'));
$this->assertEquals($expected, $actual);
}
}

View File

@ -21,7 +21,7 @@
/**
* Creates a plugin on the filesystem that can be used by
* Phergie_Plugin_Handler's addPath utility to be located and loaded.
* Phergie_Plugin_Handler::addPath() to be located and loaded.
*
* @category Phergie
* @package Phergie_Tests
@ -32,18 +32,30 @@
class Phergie_Plugin_Mock extends Phergie_Plugin_Abstract
{
/**
* holds the arguments that were passed in to the constructor
* Arguments passed to the constructor
*
* @var array
*/
protected $args;
protected $arguments;
/**
* processes a variable number of arguments into the args property
* Stores all arguments for later use.
*
* @return null
* @return void
*/
public function __construct()
{
$this->args = func_get_args();
$this->arguments = func_get_args();
}
/**
* Returns all constructor arguments.
*
* @return array Enumerated array containing the arguments passed to the
* constructor in order
*/
public function getArguments()
{
return $this->arguments;
}
}

View File

@ -0,0 +1,205 @@
<?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
* @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
*/
require_once dirname(__FILE__) . '/TestCase.php';
/**
* Unit test suite for Pherge_Plugin_SpellCheck.
*
* @category Phergie
* @package Phergie_Tests
* @author Phergie Development Team <team@phergie.org>
* @license http://phergie.org/license New BSD License
* @link http://pear.phergie.org/package/Phergie
*/
class Phergie_Plugin_SpellCheckTest extends Phergie_Plugin_TestCase
{
/**
* Current SpellCheck plugin instance
*
* @var Phergie_Plugin_SpellCheck
*/
protected $spell;
/**
* Sets up the fixture, for example, opens a network connection.
* This method is called before a test is executed.
*
* @return void
*/
protected function setUp()
{
$this->config = array('spellcheck.lang' => 'en');
$this->spell = new Phergie_Plugin_SpellCheck();
$this->setPlugin(new Phergie_Plugin_Command());
$config = $this->plugin->getConfig();
$handler = new Phergie_Plugin_Handler($config, $this->handler);
$this->plugin->setPluginHandler($handler);
$handler->addPlugin($this->plugin);
$handler->addPlugin($this->spell);
$this->spell->setEventHandler($this->handler);
$this->spell->setConnection($this->connection);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #zftalk
* @eventArg spell
*/
public function testSpell()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$this->assertDoesNotHaveEvent(Phergie_Event_Command::TYPE_PRIVMSG);
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell test
*/
public function testSpellTest()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('test', $args[1]);
$this->assertContains('correct', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell testz
*/
public function testSpellTestz()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){4}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell testz
*/
public function testSpellMoreSuggestions()
{
$config = $this->spell->getConfig();
$this->copyEvent();
$config['spellcheck.limit'] = 6;
$this->spell->onLoad();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertRegExp('/([a-z]+, ){5}/', $args[1]);
$this->assertContains('testz', $args[1]);
$this->assertContains('test,', $args[1]);
}
}
/**
* @event Phergie_Event_Request::privmsg
* @eventArg #phergie
* @eventArg spell qwertyuiopasdfghjklzxcvbnm
*/
public function testSpellNoSuggestions()
{
$this->spell->onLoad();
$this->copyEvent();
$this->plugin->onPrivMsg();
$events = $this->getResponseEvents(Phergie_Event_Command::TYPE_PRIVMSG);
$this->assertEquals(1, count($events));
foreach ($events as $event) {
$args = $event->getArguments();
$this->assertEquals('#phergie', $args[0]);
$this->assertContains('CheckSpellUser:', $args[1]);
$this->assertContains('find any suggestions', $args[1]);
}
}
/**
* Copy event from command to spell plugin
*
* @return void
*/
protected function copyEvent()
{
$hostmask = Phergie_Hostmask::fromString('CheckSpellUser!test@testing.org');
$event = $this->plugin->getEvent();
$event->setHostmask($hostmask);
$this->spell->setEvent($event);
}
}

View File

@ -45,6 +45,9 @@
<include name="Phergie/Connection/Exception.php" />
<include name="Phergie/Connection/Handler.php" />
<include name="Phergie/Connection.php" />
<include name="Phergie/Db/Exception.php" />
<include name="Phergie/Db/Manager.php" />
<include name="Phergie/Db/Sqlite.php" />
<include name="Phergie/Driver/Abstract.php" />
<include name="Phergie/Driver/Exception.php" />
<include name="Phergie/Driver/Streams.php" />