Code improvements in the spellchecker classes

This commit is contained in:
Aleksander Machniak
2024-03-17 10:19:25 +01:00
parent 4e7d5c601e
commit 3b159a1c25
11 changed files with 57 additions and 171 deletions

View File

@@ -1850,46 +1850,6 @@ parameters:
count: 1
path: program/lib/Roundcube/rcube_smtp.php
-
message: "#^Foreach overwrites \\$word with its value variable\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Negated boolean expression is always true\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset mixed does not exist on array\\{\\}\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset mixed on array\\{\\} in empty\\(\\) does not exist\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset non\\-falsy\\-string does not exist on array\\{\\}\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset non\\-falsy\\-string on array\\{\\} in empty\\(\\) does not exist\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset string does not exist on array\\{\\}\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Offset string on array\\{\\} in empty\\(\\) does not exist\\.$#"
count: 1
path: program/lib/Roundcube/rcube_spellchecker.php
-
message: "#^Call to function is_string\\(\\) with string will always evaluate to true\\.$#"
count: 1
@@ -2145,56 +2105,6 @@ parameters:
count: 1
path: program/lib/Roundcube/session/redis.php
-
message: "#^Method rcube_spellchecker_atd\\:\\:check\\(\\) should return bool but returns array\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/atd.php
-
message: "#^Method rcube_spellchecker_atd\\:\\:check\\(\\) should return bool but returns array\\<int, array\\<int, array\\<int, string\\>\\|bool\\|int\\|string\\|null\\>\\>\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/atd.php
-
message: "#^Call to function is_array\\(\\) with array will always evaluate to true\\.$#"
count: 3
path: program/lib/Roundcube/spellchecker/enchant.php
-
message: "#^Method rcube_spellchecker_enchant\\:\\:check\\(\\) should return bool but returns array\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/enchant.php
-
message: "#^Method rcube_spellchecker_enchant\\:\\:check\\(\\) should return bool but returns array\\<int, array\\<int, array\\|int\\|string\\|null\\>\\>\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/enchant.php
-
message: "#^Foreach overwrites \\$m with its value variable\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/googie.php
-
message: "#^Method rcube_spellchecker_googie\\:\\:check\\(\\) should return bool but returns array\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/googie.php
-
message: "#^Method rcube_spellchecker_googie\\:\\:check\\(\\) should return bool but returns array\\<int\\<0, max\\>, array\\<string\\>\\>\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/googie.php
-
message: "#^Method rcube_spellchecker_pspell\\:\\:check\\(\\) should return bool but returns array\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/pspell.php
-
message: "#^Method rcube_spellchecker_pspell\\:\\:check\\(\\) should return bool but returns array\\<int, array\\<int, array\\|bool\\|int\\|string\\|null\\>\\>\\.$#"
count: 1
path: program/lib/Roundcube/spellchecker/pspell.php
-
message: "#^Property rcube\\:\\:\\$storage \\(rcube_storage\\|null\\) does not accept StorageMock\\.$#"
count: 1
@@ -2205,11 +2115,6 @@ parameters:
count: 1
path: tests/Actions/Mail/Index.php
-
message: "#^Foreach overwrites \\$expected with its value variable\\.$#"
count: 1
path: tests/Browser/Components/App.php
-
message: "#^Parameter \\#1 \\$browser \\(Tests\\\\Browser\\\\Browser\\) of method Tests\\\\Browser\\\\Components\\\\App\\:\\:assert\\(\\) should be contravariant with parameter \\$browser \\(Laravel\\\\Dusk\\\\Browser\\) of method Laravel\\\\Dusk\\\\Component\\:\\:assert\\(\\)$#"
count: 1
@@ -2244,8 +2149,3 @@ parameters:
message: "#^Parameter \\#1 \\$browser \\(Tests\\\\Browser\\\\Browser\\) of method Tests\\\\Browser\\\\Components\\\\Toolbarmenu\\:\\:assert\\(\\) should be contravariant with parameter \\$browser \\(Laravel\\\\Dusk\\\\Browser\\) of method Laravel\\\\Dusk\\\\Component\\:\\:assert\\(\\)$#"
count: 1
path: tests/Browser/Components/Toolbarmenu.php
-
message: "#^Return type \\(bool\\|string\\) of method Installer\\:\\:getUrl\\(\\) should be covariant with return type \\(string\\) of method Laravel\\\\Dusk\\\\Console\\\\ChromeDriverCommand\\:\\:getUrl\\(\\)$#"
count: 1
path: tests/Browser/install.php

View File

@@ -9,11 +9,6 @@ parameters:
excludePaths:
- vendor
scanFiles:
# https://github.com/pear/pear-core-minimal/pull/15
# remove once new release (1.10.15) is tagged - https://github.com/pear/pear-core-minimal/tags
- vendor/pear/pear-core-minimal/src/PEAR.php
ignoreErrors:
# relax strict rules
- '~^Only booleans are allowed in .+, .+ given( on the (left|right) side)?\.~'

View File

@@ -24,7 +24,6 @@
*/
class rcube_spellchecker
{
private $matches = [];
private $options = [];
private $content;
private $engine;
@@ -90,16 +89,19 @@ class rcube_spellchecker
$languages = [];
foreach ($langs as $lang) {
$langc = strtolower(substr($lang, 0, 2));
$alias = !empty($rcube_language_aliases[$langc]) ? $rcube_language_aliases[$langc] : null;
if (!$alias) {
// @phpstan-ignore-next-line
if (array_key_exists($langc, $rcube_language_aliases)) {
$alias = $rcube_language_aliases[$langc];
} else {
$alias = $langc . '_' . strtoupper($langc);
}
if (!empty($rcube_languages[$lang])) {
if (array_key_exists($lang, $rcube_languages)) { // @phpstan-ignore-line
$languages[$lang] = $rcube_languages[$lang];
} elseif (preg_match('/^en_([A-Z]+)/', $lang, $m)) {
$languages[$lang] = sprintf('English (%s)', strtoupper($m[1]));
} elseif (!empty($rcube_languages[$alias])) {
} elseif (array_key_exists($alias, $rcube_languages)) { // @phpstan-ignore-line
$languages[$lang] = $rcube_languages[$alias];
} else {
$languages[$lang] = ucfirst($lang);
@@ -107,7 +109,7 @@ class rcube_spellchecker
}
// remove possible duplicates (#1489395)
$languages = array_unique($languages);
$languages = array_unique(array_filter($languages));
asort($languages);
@@ -141,10 +143,10 @@ class rcube_spellchecker
$this->content = preg_replace_callback('~(^|\s)(www.\S+|[a-z]+://\S+)~', $callback, $this->content);
if ($this->backend) {
$this->matches = $this->backend->check($this->content);
return $this->backend->check($this->content);
}
return $this->found() == 0;
return true;
}
/**
@@ -154,7 +156,7 @@ class rcube_spellchecker
*/
public function found()
{
return count($this->matches);
return $this->backend ? count($this->backend->matches) : 0;
}
/**
@@ -204,7 +206,8 @@ class rcube_spellchecker
// send output
$out = '<?xml version="1.0" encoding="' . RCUBE_CHARSET . '"?><spellresult charschecked="' . mb_strlen($this->content) . '">';
foreach ((array) $this->matches as $item) {
$matches = $this->backend ? $this->backend->matches : [];
foreach ($matches as $item) {
$out .= '<c o="' . $item[1] . '" l="' . $item[2] . '">';
$out .= is_array($item[4]) ? implode("\t", $item[4]) : $item[4];
$out .= '</c>';
@@ -223,8 +226,9 @@ class rcube_spellchecker
public function get()
{
$result = [];
$matches = $this->backend ? $this->backend->matches : [];
foreach ((array) $this->matches as $item) {
foreach ($matches as $item) {
if ($this->engine == 'pspell') {
$word = $item[0];
} else {
@@ -252,7 +256,7 @@ class rcube_spellchecker
*/
public function error()
{
return $this->error ?: ($this->backend ? $this->backend->error() : false);
return $this->error ?: ($this->backend ? $this->backend->error : false);
}
private function html2text($text)
@@ -312,10 +316,10 @@ class rcube_spellchecker
{
$this->load_dict();
foreach (explode(' ', $word) as $word) {
foreach (explode(' ', $word) as $w) {
// sanity check
if (strlen($word) < 512) {
$this->dict[] = $word;
if (strlen($w) < 512) {
$this->dict[] = $w;
$valid = true;
}
}

View File

@@ -26,7 +26,6 @@ class rcube_spellchecker_atd extends rcube_spellchecker_engine
public const SERVICE_HOST = 'service.afterthedeadline.com';
public const SERVICE_PORT = 80;
private $matches = [];
private $content;
private $langhosts = [
'fr' => 'fr.',
@@ -128,7 +127,7 @@ class rcube_spellchecker_atd extends rcube_spellchecker_engine
$result = new SimpleXMLElement($response);
} catch (Exception $e) {
$this->error = 'Unexpected response from server: ' . $response;
return [];
return false;
}
$matches = [];
@@ -161,7 +160,7 @@ class rcube_spellchecker_atd extends rcube_spellchecker_engine
$this->matches = $matches;
return $matches;
return count($matches) == 0;
}
/**
@@ -171,10 +170,10 @@ class rcube_spellchecker_atd extends rcube_spellchecker_engine
*/
public function get_suggestions($word)
{
$matches = $word ? $this->check($word) : $this->matches;
$this->check($word);
if (!empty($matches[0][4])) {
return $matches[0][4];
if (!empty($this->matches[0][4])) {
return $this->matches[0][4];
}
return [];
@@ -188,15 +187,14 @@ class rcube_spellchecker_atd extends rcube_spellchecker_engine
public function get_words($text = null)
{
if ($text) {
$matches = $this->check($text);
$this->check($text);
} else {
$matches = $this->matches;
$text = $this->content;
}
$result = [];
foreach ($matches as $m) {
foreach ($this->matches as $m) {
$result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
}

View File

@@ -25,7 +25,6 @@ class rcube_spellchecker_enchant extends rcube_spellchecker_engine
{
private $enchant_broker;
private $enchant_dictionary;
private $matches = [];
/**
* Return a list of languages supported by this backend
@@ -82,7 +81,7 @@ class rcube_spellchecker_enchant extends rcube_spellchecker_engine
$this->init();
if (!$this->enchant_dictionary) {
return [];
return true;
}
// tokenize
@@ -101,7 +100,7 @@ class rcube_spellchecker_enchant extends rcube_spellchecker_engine
} elseif (!enchant_dict_check($this->enchant_dictionary, $word)) {
$suggestions = enchant_dict_suggest($this->enchant_dictionary, $word);
if (is_array($suggestions) && count($suggestions) > self::MAX_SUGGESTIONS) {
if (count($suggestions) > self::MAX_SUGGESTIONS) {
$suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
}
@@ -112,7 +111,8 @@ class rcube_spellchecker_enchant extends rcube_spellchecker_engine
}
$this->matches = $matches;
return $matches;
return count($matches) == 0;
}
/**
@@ -130,11 +130,11 @@ class rcube_spellchecker_enchant extends rcube_spellchecker_engine
$suggestions = enchant_dict_suggest($this->enchant_dictionary, $word);
if (is_array($suggestions) && count($suggestions) > self::MAX_SUGGESTIONS) {
if (count($suggestions) > self::MAX_SUGGESTIONS) {
$suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
}
return is_array($suggestions) ? $suggestions : [];
return $suggestions;
}
/**

View File

@@ -25,8 +25,10 @@ abstract class rcube_spellchecker_engine
{
public const MAX_SUGGESTIONS = 10;
public $matches = [];
public $error;
protected $lang;
protected $error;
protected $dictionary;
protected $options = [];
protected $separator = '/[\s\r\n\t\(\)\/\[\]{}<>\"]+|[:;?!,\.](?=\W|$)/';
@@ -75,14 +77,4 @@ abstract class rcube_spellchecker_engine
* @return array List of misspelled words
*/
abstract public function get_words($text = null);
/**
* Returns error message
*
* @return string Error message
*/
public function error()
{
return $this->error;
}
}

View File

@@ -25,7 +25,6 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
{
public const GOOGIE_HOST = 'https://spell.roundcube.net';
private $matches = [];
private $content;
/**
@@ -54,12 +53,12 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
{
$this->content = $text;
$matches = [];
if (empty($text)) {
return $this->matches = $matches;
return true;
}
$this->matches = $matches = [];
$rcube = rcube::get_instance();
$client = $rcube->get_http_client();
@@ -105,8 +104,8 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
preg_match_all('/<c o="([^"]*)" l="([^"]*)" s="([^"]*)">([^<]*)<\/c>/', $response_body, $matches, \PREG_SET_ORDER);
// skip exceptions (if appropriate options are enabled)
foreach ($matches as $idx => $m) {
$word = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
foreach ($matches as $idx => $match) {
$word = mb_substr($text, $match[1], $match[2], RCUBE_CHARSET);
// skip exceptions
if ($this->dictionary->is_exception($word)) {
unset($matches[$idx]);
@@ -114,7 +113,9 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
}
}
return $this->matches = $matches;
$this->matches = $matches;
return count($this->matches) == 0;
}
/**
@@ -124,10 +125,10 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
*/
public function get_suggestions($word)
{
$matches = $word ? $this->check($word) : $this->matches;
$this->check($word);
if (!empty($matches[0][4])) {
$suggestions = explode("\t", $matches[0][4]);
if (!empty($this->matches[0][4])) {
$suggestions = explode("\t", $this->matches[0][4]);
if (count($suggestions) > self::MAX_SUGGESTIONS) {
$suggestions = array_slice($suggestions, 0, self::MAX_SUGGESTIONS);
}
@@ -146,15 +147,14 @@ class rcube_spellchecker_googie extends rcube_spellchecker_engine
public function get_words($text = null)
{
if ($text) {
$matches = $this->check($text);
$this->check($text);
} else {
$matches = $this->matches;
$text = $this->content;
}
$result = [];
foreach ($matches as $m) {
foreach ($this->matches as $m) {
$result[] = mb_substr($text, $m[1], $m[2], RCUBE_CHARSET);
}

View File

@@ -24,7 +24,6 @@
class rcube_spellchecker_pspell extends rcube_spellchecker_engine
{
private $plink;
private $matches = [];
/**
* Return a list of languages supported by this backend
@@ -87,7 +86,7 @@ class rcube_spellchecker_pspell extends rcube_spellchecker_engine
$this->init();
if (!$this->plink) {
return [];
return false;
}
// tokenize
@@ -116,7 +115,9 @@ class rcube_spellchecker_pspell extends rcube_spellchecker_engine
$diff += (strlen($word) - $len);
}
return $this->matches = $matches;
$this->matches = $matches;
return count($this->matches) == 0;
}
/**

View File

@@ -38,8 +38,7 @@ class App extends Component
*/
public function elements()
{
return [
];
return [];
}
/**
@@ -52,8 +51,8 @@ class App extends Component
public function assertEnv($browser, $key, $expected = null)
{
if (is_array($key)) {
foreach ($key as $name => $expected) {
Assert::assertEquals($expected, $browser->getEnv($name));
foreach ($key as $name => $value) {
Assert::assertEquals($value, $browser->getEnv($name));
}
} else {
Assert::assertEquals($expected, $browser->getEnv($key));

View File

@@ -64,11 +64,11 @@ class Installer extends ChromeDriverCommand
*
* @param string $url URL
*
* @return string|bool
* @return string
*/
protected function getUrl(string $url)
{
return file_get_contents($url);
return file_get_contents($url) ?: '';
}
}

View File

@@ -58,9 +58,6 @@ class Rcmail_RcmailUtils extends ActionTestCase
*/
public function test_mod_pref()
{
// FIXME: The test hangs for some reason, probably related with the extra DB connection
// $this->markTestIncomplete();
self::initDB('init');
$db = rcmail::get_instance()->get_dbh();