Skip to content

Commit

Permalink
Added Plurals
Browse files Browse the repository at this point in the history
  • Loading branch information
olvlvl committed Sep 18, 2016
1 parent eabe802 commit 0c0bdd9
Show file tree
Hide file tree
Showing 2 changed files with 358 additions and 0 deletions.
155 changes: 155 additions & 0 deletions lib/Plurals.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
<?php

/*
* This file is part of the ICanBoogie package.
*
* (c) Olivier Laviale <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ICanBoogie\CLDR;

use ICanBoogie\CLDR\Plurals\Rule;
use ICanBoogie\CLDR\Plurals\Samples;

/**
* Representation of plurals
*/
class Plurals extends \ArrayObject
{
const COUNT_ZERO = 'zero';
const COUNT_ONE = 'one';
const COUNT_TWO = 'two';
const COUNT_FEW = 'few';
const COUNT_MANY = 'many';
const COUNT_OTHER = 'other';

const RULE_COUNT_PREFIX = 'pluralRule-count-';

/**
* @var Rule[][]
*/
private $rules = [];

/**
* @var Samples[][]
*/
private $samples = [];

/**
* @param number $number
* @param string $locale
*
* @return string One of `COUNT_*`.
*/
public function rule_for($number, $locale)
{
foreach ($this->rule_instances_for($locale) as $count => $rule)
{
if ($rule->validate($number))
{
return $count;
}
}

return self::COUNT_OTHER; // @codeCoverageIgnore
}

/**
* @param string $locale
*
* @return string[]
*/
public function rules_for($locale)
{
return array_keys($this->rule_instances_for($locale));
}

/**
* @param string $locale
*
* @return Samples[]
*/
public function samples_for($locale)
{
$samples = &$this->samples[$locale];

return $samples ?: $samples = $this->create_samples_for($locale);
}

/**
* @param string $locale
*
* @return Rule[]
*/
private function rule_instances_for($locale)
{
$rules = &$this->rules[$locale];

return $rules ?: $rules = $this->create_rules_for($locale);
}

/**
* @param string $locale
*
* @return Rule[]
*/
private function create_rules_for($locale)
{
$rules = [];
$prefix_length = strlen(self::RULE_COUNT_PREFIX);

foreach ($this[$locale] as $count => $rule_string)
{
$count = substr($count, $prefix_length);
$rules[$count] = Rule::from($this->extract_rule($rule_string));
}

return $rules;
}

/**
* @param string $rule_string
*
* @return string
*/
private function extract_rule($rule_string)
{
$rule = explode('@', $rule_string, 2);
$rule = array_shift($rule);
$rule = trim($rule);

return $rule;
}

/**
* @param string $locale
*
* @return Samples[]
*/
private function create_samples_for($locale)
{
$samples = [];
$prefix_length = strlen(self::RULE_COUNT_PREFIX);

foreach ($this[$locale] as $count => $rule_string)
{
$count = substr($count, $prefix_length);
$samples[$count] = Samples::from($this->extract_samples($rule_string));
}

return $samples;
}

/**
* @param string $rule_string
*
* @return string
*/
private function extract_samples($rule_string)
{
return substr($rule_string, strpos($rule_string, '@'));
}
}
203 changes: 203 additions & 0 deletions tests/PluralsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

/*
* This file is part of the ICanBoogie package.
*
* (c) Olivier Laviale <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ICanBoogie\CLDR;

use ICanBoogie\CLDR\Plurals\Samples;

/**
* @group plurals
*/
class PluralsTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Plurals
*/
private $plurals;

public function setUp()
{
$plurals = &$this->plurals;

if (!$plurals)
{
$plurals = new Plurals(get_repository()->supplemental['plurals']);
}
}

/**
* @dataProvider provide_test_samples_for
*
* @param string $locale
* @param array $expected_keys
*/
public function test_samples_for($locale, array $expected_keys)
{
$samples = $this->plurals->samples_for($locale);

$this->assertSame($expected_keys, array_keys($samples));
$this->assertContainsOnlyInstancesOf(Samples::class, $samples);
}

public function provide_test_samples_for()
{
return [

[ 'fr', [

Plurals::COUNT_ONE,
Plurals::COUNT_OTHER

] ],

[ 'ar', [

Plurals::COUNT_ZERO,
Plurals::COUNT_ONE,
Plurals::COUNT_TWO,
Plurals::COUNT_FEW,
Plurals::COUNT_MANY,
Plurals::COUNT_OTHER

] ],

[ 'bs', [

Plurals::COUNT_ONE,
Plurals::COUNT_FEW,
Plurals::COUNT_OTHER

] ],

];
}

public function test_samples_should_be_the_same_for_the_same_locale()
{
$samples = $this->plurals->samples_for('fr');

$this->assertSame($samples, $this->plurals->samples_for('fr'));
}

/**
* @dataProvider provide_test_rules_for
*
* @param string $locale
* @param array $expected_keys
*/
public function test_rules_for($locale, array $expected_keys)
{
$rules = $this->plurals->rules_for($locale);

$this->assertSame($expected_keys, $rules);
}

public function provide_test_rules_for()
{
return [

[ 'fr', [

Plurals::COUNT_ONE,
Plurals::COUNT_OTHER

] ],

[ 'ar', [

Plurals::COUNT_ZERO,
Plurals::COUNT_ONE,
Plurals::COUNT_TWO,
Plurals::COUNT_FEW,
Plurals::COUNT_MANY,
Plurals::COUNT_OTHER

] ],

[ 'bs', [

Plurals::COUNT_ONE,
Plurals::COUNT_FEW,
Plurals::COUNT_OTHER

] ],

];
}

/**
* @dataProvider provide_test_rule_for
*
* @param number $number
* @param string $locale
* @param string $expected
*/
public function test_rule_for($number, $locale, $expected)
{
$this->assertSame($expected, $this->plurals->rule_for($number, $locale));
}

public function provide_test_rule_for()
{
return [

[ 0, 'ar', Plurals::COUNT_ZERO ],
[ 1, 'ar', Plurals::COUNT_ONE ],
[ 1.0, 'ar', Plurals::COUNT_ONE ],
[ '1.0000', 'ar', Plurals::COUNT_ONE ],
[ 2, 'ar', Plurals::COUNT_TWO ],
[ '2.0000', 'ar', Plurals::COUNT_TWO ],
[ 3, 'ar', Plurals::COUNT_FEW ],
[ 20, 'ar', Plurals::COUNT_MANY ],
[ 100000, 'ar', Plurals::COUNT_OTHER ],

];
}

/**
* @dataProvider provide_test_rule_with_samples
*
* @param string $locale
*/
public function test_rule_with_samples($locale)
{
$plurals = $this->plurals;
$samples = $plurals->samples_for($locale);

foreach ($samples as $expected => $sample)
{
foreach ($sample as $i => $number)
{
$count = $plurals->rule_for($number, $locale);

try {
$this->assertSame($expected, $count);
} catch (\Exception $e) {
$this->fail("Expected `$expected` but got `$count` for number `$number` ($locale, $i)");
}
}
}
}

public function provide_test_rule_with_samples()
{
return [

[ 'az' ],
[ 'be' ],
[ 'br' ],
[ 'cy' ],
[ 'fr' ],
[ 'naq' ],

];
}
}

0 comments on commit 0c0bdd9

Please sign in to comment.