Assembla home | Assembla project page
 

root/trunk/Phergie/Plugin/Spellcheck.php

Revision 273, 8.1 kB (checked in by Seldaek, 2 months ago)

* Plugins that can't load now return error messages to say why
fixes #35

Line 
1 <?php
2
3 /**
4  * Handles requests for checking spelling of specified words and returning
5  * either confirmation of correctly spelled words or potential correct
6  * spellings for misspelled words.
7  */
8 class Phergie_Plugin_SpellCheck extends Phergie_Plugin_Abstract_Base
9 {
10     /**
11      * Indicates that a local directory is required for this plugin
12      *
13      * @var bool
14      */
15     protected $needsDir = true;
16
17     /**
18      * Spell check dictionary handler
19      *
20      * @var resource
21      */
22     protected $pspell;
23
24     /**
25      * Limit on the number of potential correct spellings returned
26      *
27      * @var int
28      */
29     protected $limit;
30
31     /**
32      * Obtains configuration settings and initializes the spell check
33      * dictionary handler.
34      *
35      * @return void
36      */
37     public function onInit()
38     {
39         $config = pspell_config_create($this->getPluginIni('lang'));
40         pspell_config_personal($config, $this->dir . 'custom.pws');
41         pspell_config_repl($config, $this->dir . 'custom.repl');
42         $this->pspell = pspell_new_config($config);
43
44         $this->limit = $this->getPluginIni('limit');
45         if (!$this->limit) {
46             $this->limit = 5;
47         }
48     }
49
50     /**
51      * Returns whether or not the plugin's dependencies are met.
52      *
53      * @param Phergie_Driver_Abstract $client Client instance
54      * @param array $plugins List of short names for plugins that the
55      *                       bootstrap file intends to instantiate
56      * @see Phergie_Plugin_Abstract_Base::checkDependencies()
57      * @return bool TRUE if dependencies are met, FALSE otherwise
58      */
59     static public function checkDependencies(Phergie_Driver_Abstract $client, array $plugins)
60     {
61         $errors = array();
62
63         if (!extension_loaded('pspell')) {
64             $errors[] = 'pspell php extension is required';
65         }
66         if (!$client->getIni('spellcheck.lang')) {
67             $errors[] = 'Ini setting spellcheck.lang must be filled-in';
68         }
69
70         return empty($errors) ? true : $errors;
71     }
72
73     /**
74      * Intercepts and handles requests for spell checks.
75      *
76      * @return void
77      */
78     public function onPrivmsg()
79     {
80         $source = $this->event->getSource();
81         $message = $this->event->getArgument(1);
82         $target = $this->event->getNick();
83
84         // Command prefix check
85         $prefix = preg_quote(trim($this->getIni('command_prefix')));
86         $bot = preg_quote($this->getIni('nick'));
87         $exp = '(?:(?:' . $bot . '\s*[:,>]?\s+(?:' . $prefix . ')?)|(?:' . $prefix . '))';
88
89         // Do spell checking of the given word
90         if (preg_match('#(?:^' . $exp . 'spell(?:check)?\s+(\S+)|(\S+)\s*\(sp\??\))#i', $message, $m)) {
91             $word = (!empty($m[1]) ? $m[1] : $m[2]);
92             if (!pspell_check($this->pspell, $word)) {
93                 $suggestions = pspell_suggest($this->pspell, $word);
94                 if (empty($suggestions)) {
95                     $this->doPrivmsg($source, 'I could not find any suggestions for ' . $word);
96                 } else {
97                     $suggestions = array_splice($suggestions, 0, $this->limit);
98                     $this->doPrivmsg($source, $target . ': Suggestions for \'' . $word . '\': ' . implode(', ', $suggestions));
99                 }
100             } else {
101                 $this->doPrivmsg($source, $target . ': The word ' . $word . ' seems to be spelled correctly.');
102             }
103         // Check to see if if someone is trying to add a word or an replacement to the custom dictionary.
104         } elseif (preg_match('#^' . $exp . 'add(word|repl(?:ace(?:ment)?)?)\s+(\S+)(?:\s+(\S+))?#i', $message, $m)) {
105             if ($this->fromAdmin()) {
106                 $m = array_pad($m, 4, null);
107                 $addWord = (substr(strtolower($m[1]), 0, 4) == 'word');
108                 $correct = ($addWord ? $m[2] : $m[3]);
109                 $mispelled = ($addWord ? $m[3] : $m[2]);
110
111                 // Check to see if the correct word is empty or not, its required in both cases
112                 if (empty($correct)) {
113                     return;
114                 }
115
116                 // pSpell doesn't like hyphenated words so check for them
117                 if (strpos($correct, '-') !== false || strpos($mispelled, '-') !== false) {
118                     $this->doNotice($target, 'You can not add hyphenated words to the dictionary.');
119                     return;
120                 }
121
122                 // Check to see if the given word is in the dictionary already
123                 if (!pspell_check($this->pspell, $m[2])) {
124                     if ($addWord) {
125                         if (pspell_add_to_personal($this->pspell, $correct)) {
126                             pspell_save_wordlist($this->pspell);
127                             $this->doNotice($target, 'Added the word "' . $correct . '" to the personal dictionary.');
128                         } else {
129                             $this->doNotice($target, 'Could not add the word "' . $correct . '" to the personal dictionary.');
130                         }
131                     } else {
132                         // Check to see if both the mispelled and correct word start with the same letter
133                         if (substr(strtolower($mispelled), 0, 1) != substr(strtolower($correct), 0, 1)) {
134                             $this->doNotice($target, 'Both the correct and mispelled word of the replacement need to start with the same letter.');
135                         }
136
137                         if (pspell_store_replacement($this->pspell, $mispelled, $correct)) {
138                             pspell_save_wordlist($this->pspell);
139                             $this->doNotice($target, 'Added the replacement "' . $correct . '" for the word "' . $mispelled . '".');
140                         } else {
141                             $this->doNotice($target, 'Could not add the replacement "' . $correct . '" for the word "' . $mispelled . '".');
142                         }
143                     }
144                 } else {
145                     $this->doNotice($target, 'The word "' . $m[2] . '" seems to be in the dictionary already.');
146                 }
147             } else {
148                 $this->doNotice($target, 'You do not have permission to add words to the dictionary.');
149             }
150         }
151     }
152
153     /**
154      * Parses incoming CTCP action requests for spelling suggestions.
155      *
156      * @return void
157      */
158     public function onAction()
159     {
160         $message = $this->event->getArgument(1);
161         $target = $this->event->getNick();
162
163         if (preg_match('#(\S+)\s*\(sp\??\)#i', $message, $m)) {
164             $word = $m[1];
165             if (!pspell_check($this->pspell, $word)) {
166                 $suggestions = pspell_suggest($this->pspell, $word);
167                 if (empty($suggestions)) {
168                     $this->doPrivmsg($target, 'I could not find any suggestions for ' . $word);
169                 } else {
170                     $suggestions = array_splice($suggestions, 0, $this->limit);
171                     $this->doPrivmsg($target, $target . ': Suggestions for \'' . $word . '\': ' . implode(', ', $suggestions));
172                 }
173             } else {
174                 $this->doPrivmsg($target, $target . ': The word ' . $word . ' seems to be spelled correctly.');
175             }
176         }
177     }
178
179     /**
180      * Parses incoming CTCP request for spelling suggestions.
181      *
182      * @return void
183      */
184     public function onCtcp()
185     {
186         $source = $this->event->getSource();
187         $ctcp = $this->event->getArgument(1);
188
189         if (preg_match('{spell(?:[\s_+-]*check)?\s+(\S+)}ix', $ctcp, $m)) {
190             $word = $m[1];
191             if (!pspell_check($this->pspell, $word)) {
192                 $suggestions = pspell_suggest($this->pspell, $word);
193                 if (empty($suggestions)) {
194                     $this->doPrivmsg($source, 'I could not find any suggestions for ' . $word);
195                 } else {
196                     $suggestions = array_splice($suggestions, 0, $this->limit);
197                     $this->doPrivmsg($source, $target . ': Suggestions for \'' . $word . '\': ' . implode(', ', $suggestions));
198                 }
199             } else {
200                 $this->doPrivmsg($source, $target . ': The word ' . $word . ' seems to be spelled correctly.');
201             }
202         }
203     }
204 }
205
Note: See TracBrowser for help on using the browser.