Skip to content

Commit 03fe350

Browse files
author
Jordan Hall
committed
2 parents 71d0dc8 + db3565e commit 03fe350

File tree

5 files changed

+166
-61
lines changed

5 files changed

+166
-61
lines changed

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This PHP library can be used to look up information about a word, including the
1111
* Number of syllables
1212
* Offensive or not
1313
* Portmanteaus
14+
* Plural / singular
1415

1516
## Installation
1617

@@ -31,9 +32,12 @@ $word = new Word('cat');
3132

3233
$rhymes = $word->rhymes();
3334
$halfRhymes = $word->halfRhymes();
34-
$numberOfSyllables = $word->syllables(); // Returns an integer
35-
$isOffensive = $word->offensive(); // Returns true/false
3635
$portmanteaus = $word->portmanteaus();
36+
37+
$numberOfSyllables = $word->syllables(); // Returns an integer
38+
$isOffensive = $word->offensive(); // Returns true/false
39+
$plural = $word->plural(); // Returns `Word` object
40+
$singular = $word->singular(); // Returns `Word` object
3741
```
3842

3943
Most methods will return an array of `Word` objects, unless specified otherwise.

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
"require": {
66
"php": "^7.0",
77
"rapidwebltd/rw-file-cache": "^1.2",
8-
"snipe/banbuilder": "^2.2"
8+
"divineomega/is_offensive": "^1.0",
9+
"davechild/textstatistics": "^1.0",
10+
"doctrine/inflector": "^1.2"
911
},
1012
"require-dev": {
1113
"phpunit/phpunit": "^5.7",

src/Pluralizer.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace DivineOmega\WordInfo;
4+
5+
use Doctrine\Common\Inflector\Inflector;
6+
7+
class Pluralizer
8+
{
9+
private $irregular = [
10+
'goose' => 'geese',
11+
];
12+
13+
private $uncountable = [
14+
'audio',
15+
'education',
16+
'love',
17+
'pokemon',
18+
'mathematics',
19+
];
20+
21+
private $word;
22+
23+
public function __construct(Word $word)
24+
{
25+
$this->word = $word;
26+
}
27+
28+
public function pluralize()
29+
{
30+
if ($this->isUncountable()) {
31+
return new Word($this->word);
32+
}
33+
34+
foreach ($this->irregular as $singular => $plural) {
35+
if ($singular == $this->word) {
36+
return new Word($plural);
37+
}
38+
}
39+
40+
$plural = Inflector::pluralize((string) $this->word);
41+
42+
return new Word($plural);
43+
}
44+
45+
public function singularize()
46+
{
47+
if ($this->isUncountable()) {
48+
return new Word($this->word);
49+
}
50+
51+
foreach ($this->irregular as $singular => $plural) {
52+
if ($plural == $this->word) {
53+
return new Word($singular);
54+
}
55+
}
56+
57+
$singular = Inflector::singularize((string) $this->word);
58+
59+
return new Word($singular);
60+
}
61+
62+
private function isUncountable()
63+
{
64+
return in_array($this->word, $this->uncountable);
65+
}
66+
}

src/Word.php

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<?php
2+
23
namespace DivineOmega\WordInfo;
34

5+
use DaveChild\TextStatistics\Syllables;
46
use rapidweb\RWFileCache\RWFileCache;
5-
use Snipe\BanBuilder\CensorWords;
6-
7-
class Word {
87

8+
class Word
9+
{
910
private $word;
1011
private $cache;
1112

@@ -22,7 +23,7 @@ public function __toString()
2223

2324
private function setupCache()
2425
{
25-
$this->cache = new RWFileCache;
26+
$this->cache = new RWFileCache();
2627
$this->cache->changeConfig(['cacheDirectory' => '/tmp/php-word-info-cache/']);
2728
}
2829

@@ -45,22 +46,22 @@ public function rhymes($halfRhymes = false)
4546

4647
$rhymes = [];
4748

48-
foreach($responseItems as $responseItem) {
49+
foreach ($responseItems as $responseItem) {
4950
if ($halfRhymes) {
5051
if ($responseItem->score < 300) {
51-
$rhymes[] = new Word($responseItem->word);
52+
$rhymes[] = new self($responseItem->word);
5253
}
5354
} else {
54-
if($responseItem->score == 300) {
55-
$rhymes[] = new Word($responseItem->word);
56-
}
55+
if ($responseItem->score == 300) {
56+
$rhymes[] = new self($responseItem->word);
57+
}
5758
}
5859
}
5960

6061
sort($rhymes);
6162

6263
$this->cache->set($cacheKey, $rhymes);
63-
64+
6465
return $rhymes;
6566
}
6667

@@ -69,35 +70,24 @@ public function halfRhymes()
6970
return $this->rhymes(true);
7071
}
7172

72-
private function wordInfo()
73+
public function syllables()
7374
{
74-
$cacheKey = $this->word.'.info';
75-
76-
$value = $this->cache->get($cacheKey);
77-
78-
if ($value) {
79-
return $value;
80-
}
81-
82-
$response = file_get_contents('http://rhymebrain.com/talk?function=getWordInfo&word='.urlencode($this->word));
83-
$wordInfo = json_decode($response);
84-
85-
$this->cache->set($cacheKey, $wordInfo);
75+
return Syllables::syllableCount($this->word);
76+
}
8677

87-
return $wordInfo;
78+
public function plural()
79+
{
80+
return (new Pluralizer($this))->pluralize();
8881
}
8982

90-
public function syllables()
83+
public function singular()
9184
{
92-
return $this->wordInfo()->syllables;
85+
return (new Pluralizer($this))->singularize();
9386
}
9487

9588
public function offensive()
9689
{
97-
$censor = new CensorWords;
98-
$censor->setDictionary(['en-uk', 'en-us']);
99-
$result = $censor->censorString($this->word);
100-
return count($result['matched'])>0;
90+
return is_offensive($this->word);
10191
}
10292

10393
public function portmanteaus()
@@ -115,11 +105,11 @@ public function portmanteaus()
115105

116106
$portmanteaus = [];
117107

118-
foreach($responseItems as $responseItem) {
119-
$responseItemPortmanteaus = array_map(function($portmanteauString) {
108+
foreach ($responseItems as $responseItem) {
109+
$responseItemPortmanteaus = array_map(function ($portmanteauString) {
120110
return new Word($portmanteauString);
121111
}, explode(',', $responseItem->combined));
122-
112+
123113
$portmanteaus = array_merge($portmanteaus, $responseItemPortmanteaus);
124114
}
125115

@@ -129,5 +119,4 @@ public function portmanteaus()
129119

130120
return $portmanteaus;
131121
}
132-
133-
}
122+
}

tests/Unit/WordTest.php

Lines changed: 67 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
<?php
22

3-
use PHPUnit\Framework\TestCase;
43
use DivineOmega\WordInfo\Word;
4+
use PHPUnit\Framework\TestCase;
55

66
final class WordTest extends TestCase
77
{
88
public function testRhymes()
99
{
1010
$rhymes = (new Word('cat'))->rhymes();
1111

12-
$expected = ['aristocrat', 'at', 'bat', 'caveat', 'chat', 'democrat', 'diplomat',
13-
'fat', 'flat', 'habitat', 'hat', 'mat', 'pat', 'rat', 'sat', 'spat',
14-
'stat', 'tat', 'that', 'thermostat', 'vat'];
12+
$expected = ['aristocrat', 'at', 'bat', 'caveat', 'chat', 'democrat', 'diplomat',
13+
'fat', 'flat', 'habitat', 'hat', 'mat', 'pat', 'rat', 'sat', 'spat',
14+
'stat', 'tat', 'that', 'thermostat', 'vat', ];
1515

1616
$this->assertEquals($expected, $rhymes);
1717
}
@@ -20,9 +20,9 @@ public function testHalfRhymes()
2020
{
2121
$rhymes = (new Word('violet'))->halfRhymes();
2222

23-
$expected = ['cyclist', 'finalist', 'hybridised', 'iodised', 'ionised', 'lionised',
24-
'motorcyclist', 'nihilist', 'piloted', 'pirated', 'playacted', 'revivalist',
25-
'rioted', 'scientist', 'semifinalist', 'survivalist'];
23+
$expected = ['cyclist', 'finalist', 'hybridised', 'iodised', 'ionised', 'lionised',
24+
'motorcyclist', 'nihilist', 'piloted', 'pirated', 'playacted', 'revivalist',
25+
'rioted', 'scientist', 'semifinalist', 'survivalist', ];
2626

2727
$this->assertEquals($expected, $rhymes);
2828
}
@@ -95,20 +95,20 @@ public function testPortmanteaus1()
9595
{
9696
$portmanteaus = (new Word('computer'))->portmanteaus();
9797

98-
$expected = ['computarena', 'computarise', 'computarisen', 'computarises', 'computarising', 'computaristocratic', 'computaroma',
99-
'computarose', 'computaround', 'computarousal', 'computarouse', 'computaroused', 'computarousing', 'computarrange',
98+
$expected = ['computarena', 'computarise', 'computarisen', 'computarises', 'computarising', 'computaristocratic', 'computaroma',
99+
'computarose', 'computaround', 'computarousal', 'computarouse', 'computaroused', 'computarousing', 'computarrange',
100100
'computarranged', 'computarrangement', 'computarrangements', 'computarranging', 'computarray', 'computarrears', 'computarrest',
101-
'computarrested', 'computarresting', 'computarrests', 'computarrhythmias', 'computarrival', 'computarrivals', 'computarrive',
102-
'computarrived', 'computarrives', 'computarriving', 'computerena', 'computeriginal', 'computeriginality', 'computeriginally',
103-
'computeriginals', 'computeriginate', 'computeriginated', 'computeriginates', 'computeriginating', 'computerine', 'computerise',
104-
'computerisen', 'computerises', 'computerising', 'computeristocratic', 'computermination', 'computeroma', 'computerose',
105-
'computeround', 'computerousal', 'computerouse', 'computeroused', 'computerousing', 'computerrain', 'computerrestrial',
106-
'computerrific', 'computerrrange', 'computerrranged', 'computerrrangement', 'computerrrangements', 'computerrranging',
107-
'computerrray', 'computerrrears', 'computerrrest', 'computerrrested', 'computerrresting', 'computerrrests', 'computerrrhythmias',
108-
'computerrrival', 'computerrrivals', 'computerrrive', 'computerrrived', 'computerrrives', 'computerrriving', 'computerus',
109-
'computeryrannical', 'computoriginal', 'computoriginality', 'computoriginally', 'computoriginals', 'computoriginate',
110-
'computoriginated', 'computoriginates', 'computoriginating', 'computyrannical', 'incomputer', 'outcomputer', 'silicaomputer',
111-
'silicomputer', 'welcomputer'];
101+
'computarrested', 'computarresting', 'computarrests', 'computarrhythmias', 'computarrival', 'computarrivals', 'computarrive',
102+
'computarrived', 'computarrives', 'computarriving', 'computerena', 'computeriginal', 'computeriginality', 'computeriginally',
103+
'computeriginals', 'computeriginate', 'computeriginated', 'computeriginates', 'computeriginating', 'computerine', 'computerise',
104+
'computerisen', 'computerises', 'computerising', 'computeristocratic', 'computermination', 'computeroma', 'computerose',
105+
'computeround', 'computerousal', 'computerouse', 'computeroused', 'computerousing', 'computerrain', 'computerrestrial',
106+
'computerrific', 'computerrrange', 'computerrranged', 'computerrrangement', 'computerrrangements', 'computerrranging',
107+
'computerrray', 'computerrrears', 'computerrrest', 'computerrrested', 'computerrresting', 'computerrrests', 'computerrrhythmias',
108+
'computerrrival', 'computerrrivals', 'computerrrive', 'computerrrived', 'computerrrives', 'computerrriving', 'computerus',
109+
'computeryrannical', 'computoriginal', 'computoriginality', 'computoriginally', 'computoriginals', 'computoriginate',
110+
'computoriginated', 'computoriginates', 'computoriginating', 'computyrannical', 'incomputer', 'outcomputer', 'silicaomputer',
111+
'silicomputer', 'welcomputer', ];
112112

113113
$this->assertEquals($expected, $portmanteaus);
114114
}
@@ -117,10 +117,54 @@ public function testPortmanteaus2()
117117
{
118118
$portmanteaus = (new Word('cheese'))->portmanteaus();
119119

120-
$expected = ['chease', 'cheased', 'cheasel', 'cheasement', 'cheasements', 'cheases', 'cheasier', 'cheasiest', 'cheasily', 'cheasing',
121-
'cheasy', 'cheasygoing', 'chies', 'chiheese', 'chiis', 'chization', 'chys'];
120+
$expected = ['chease', 'cheased', 'cheasel', 'cheasement', 'cheasements', 'cheases', 'cheasier', 'cheasiest', 'cheasily', 'cheasing',
121+
'cheasy', 'cheasygoing', 'chies', 'chiheese', 'chiis', 'chization', 'chys', ];
122122

123123
$this->assertEquals($expected, $portmanteaus);
124124
}
125125

126-
}
126+
private function getSingularToPluralData()
127+
{
128+
return [
129+
'cat' => 'cats',
130+
'mitten' => 'mittens',
131+
'sausage' => 'sausages',
132+
'child' => 'children',
133+
'goose' => 'geese',
134+
'person' => 'people',
135+
'woman' => 'women',
136+
'man' => 'men',
137+
'audio' => 'audio',
138+
'education' => 'education',
139+
'rice' => 'rice',
140+
'love' => 'love',
141+
'pokemon' => 'pokemon',
142+
'sheep' => 'sheep',
143+
'sex' => 'sexes',
144+
'mouse' => 'mice',
145+
'mathematics' => 'mathematics',
146+
'information' => 'information',
147+
'tooth' => 'teeth',
148+
];
149+
}
150+
151+
public function testPluralise()
152+
{
153+
$data = $this->getSingularToPluralData();
154+
155+
foreach ($data as $singular => $plural) {
156+
$word = new Word($singular);
157+
$this->assertEquals($plural, $word->plural());
158+
}
159+
}
160+
161+
public function testSingularise()
162+
{
163+
$data = $this->getSingularToPluralData();
164+
165+
foreach ($data as $singular => $plural) {
166+
$word = new Word($plural);
167+
$this->assertEquals($singular, $word->singular());
168+
}
169+
}
170+
}

0 commit comments

Comments
 (0)