1
0
mirror of https://github.com/danielstjules/Stringy.git synced 2025-08-12 08:14:06 +02:00

Update ArrayAccess interface implementation, add details to readme

This commit is contained in:
Daniel St. Jules
2014-02-06 18:27:21 -05:00
parent ebc58a51ef
commit 3f5b6a2413
3 changed files with 83 additions and 101 deletions

View File

@@ -126,32 +126,39 @@ echo S::swapCase($string, 'UTF-8'); // 'fÒÔ bÀŘ'
## Implemented Interfaces ## Implemented Interfaces
`Stringy\Stringy` implements the `IteratorAggregate` interface. This allows you `Stringy\Stringy` implements the `IteratorAggregate` interface, meaning that
to use `foreach` with an instance of the class: `foreach` can be used with an instance of the class:
``` php ``` php
$stringy = S::create('Fòô Bàř', 'UTF-8'); $stringy = S::create('Fòô Bàř', 'UTF-8');
foreach ($stringy as $char) { foreach ($stringy as $char) {
echo $char; echo $char;
} }
// 'Fòô Bàř' // 'Fòô Bàř'
$array = array();
foreach ($stringy as $pos => $char) {
$array[$pos] = $char;
}
// array('F', 'ò', 'ô', ' ', 'B', 'à', 'ř')
``` ```
It also implements the `Countable` interface, enabling the use of `count()` to It implements the `Countable` interface, enabling the use of `count()` to
retrieve the number of characters in the string, given the encoding: retrieve the number of characters in the string:
``` php ``` php
$stringy = S::create('Fòô', 'UTF-8'); $stringy = S::create('Fòô', 'UTF-8');
count($stringy); // 3 count($stringy); // 3
``` ```
Furthermore, the `ArrayAccess` interface has been implemented. As a result,
`isset()` can be used to check if a character at a specific index exists. And
since `Stringy\Stringy` is immutable, any call to `offsetSet` or `offsetUnset`
will throw an exception. `offsetGet` has been implemented, however, and accepts
both positive and negative indexes. Invalid indexes result in an
`OutOfBoundsException`.
``` php
$stringy = S::create('Bàř', 'UTF-8');
echo $stringy[2]; // 'ř'
echo $stringy[-2]; // 'à'
isset($stringy[-4]); // false
```
## Methods ## Methods
In the list below, any static method other than S::create refers to a method in In the list below, any static method other than S::create refers to a method in

View File

@@ -88,78 +88,69 @@ class Stringy implements \Countable, \IteratorAggregate, \ArrayAccess
} }
/** /**
* Returns whether or not a character exists at the given index. Implements * Returns whether or not a character exists at an index. Offsets may be
* negative to count from the last character in the string. Implements
* part of the ArrayAccess interface. * part of the ArrayAccess interface.
* *
* @param mixed $offset The index to check * @param mixed $offset The index to check
* @return boolean Whether or not the index exists * @return boolean Whether or not the index exists
*/ */
public function offsetExists($offset) { public function offsetExists($offset) {
return ($this->length() > (int) $offset); $length = $this->length();
$offset = (int) $offset;
if ($offset >= 0) {
return ($length > $offset);
}
return ($length >= abs($offset));
} }
/** /**
* Returns the character at the given index, otherwise null if none exists. * Returns the character at the given index. Offsets may be negative to
* Implements part of the ArrayAccess interface. * count from the last character in the string. Implements part of the
* ArrayAccess interface, and throws an OutOfBoundsException if the index
* does not exist.
* *
* @param mixed $offset The index from which to retrieve the char * @param mixed $offset The index from which to retrieve the char
* @return mixed The character if it exists, else null * @return mixed The character at the specified index
* @throws \OutOfBoundsException If the positive or negative offset does
* not exist
*/ */
public function offsetGet($offset) { public function offsetGet($offset) {
$offset = (int) $offset; $offset = (int) $offset;
if ($this->length() <= $offset) { $length = $this->length();
return null;
if (($offset >= 0 && $length <= $offset) || $length < abs($offset)) {
throw new \OutOfBoundsException('No character exists at the index');
} }
return $this->at($offset); return mb_substr($this->str, $offset, 1, $this->encoding);
} }
/** /**
* Sets the character at the given offset. The value to set is truncated * Implements part of the ArrayAccess interface, but throws an exception
* to a single character. If the offset is null or exceeds the length * when called. This maintains the immutability of Stringy objects.
* of the string, it is appended to the end. Implements part of the
* ArrayAccess interface.
* *
* @param mixed $offset The index at which to replace the character * @param mixed $offset The index of the character
* @param mixed $value Value to set * @param mixed $value Value to set
* @throws \Exception When called
*/ */
public function offsetSet($offset, $value) { public function offsetSet($offset, $value) {
$length = $this->length(); // Stringy is immutable, cannot directly set char
if ($offset === null || $length <= (int) $offset) { throw new \Exception('Stringy object is immutable, cannot modify char');
$this->str .= $value;
return;
}
$offset = (int) $offset;
$value = mb_substr($value, 0, 1, $this->encoding);
$start = mb_substr($this->str, 0, $offset, $this->encoding);
$end = mb_substr($this->str, $offset + 1, $length, $this->encoding);
$this->str = $start . $value . $end;
} }
/** /**
* Deletes character at the given offset. Implements part of the * Implements part of the ArrayAccess interface, but throws an exception
* ArrayAccess interface. * when called. This maintains the immutability of Stringy objects.
* *
* @param mixed $offset The index at which to delete the character * @param mixed $offset The index of the character
* @throws \Exception When called
*/ */
public function offsetUnset($offset) { public function offsetUnset($offset) {
$length = $this->length(); // Don't allow directly modifying the string
if ($offset === null || $length <= (int) $offset) { throw new \Exception('Stringy object is immutable, cannot unset char');
return;
}
$offset = (int) $offset;
if ($offset === $length - 1) {
$this->str = $this->substr(0, $length - 1)->str;
}
$start = mb_substr($this->str, 0, $offset, $this->encoding);
$end = mb_substr($this->str, $offset + 1, $length, $this->encoding);
$this->str = $start . $end;
} }
/** /**

View File

@@ -95,16 +95,26 @@ class StringyTestCase extends CommonTest
$this->assertEquals(array('F', 'ò', 'ô', ' ', 'B', 'à', 'ř'), $keyValResult); $this->assertEquals(array('F', 'ò', 'ô', ' ', 'B', 'à', 'ř'), $keyValResult);
} }
public function testOffsetExists() /**
* @dataProvider offsetExistsProvider()
*/
public function testOffsetExists($expected, $offset)
{ {
$stringy = S::create('fòô', 'UTF-8'); $stringy = S::create('fòô', 'UTF-8');
$this->assertEquals($expected, $stringy->offsetExists($offset));
$this->assertEquals($expected, isset($stringy[$offset]));
}
$this->assertTrue($stringy->offsetExists(0)); public function offsetExistsProvider()
$this->assertTrue($stringy->offsetExists(2)); {
$this->assertFalse($stringy->offsetExists(3)); return array(
array(true, 0),
$this->assertTrue(isset($stringy[2])); array(true, 2),
$this->assertFalse(isset($stringy[3])); array(false, 3),
array(true, -1),
array(true, -3),
array(false, -4)
);
} }
public function testOffsetGet() public function testOffsetGet()
@@ -113,61 +123,35 @@ class StringyTestCase extends CommonTest
$this->assertEquals('f', $stringy->offsetGet(0)); $this->assertEquals('f', $stringy->offsetGet(0));
$this->assertEquals('ô', $stringy->offsetGet(2)); $this->assertEquals('ô', $stringy->offsetGet(2));
$this->assertEquals(null, $stringy->offsetGet(3));
$this->assertEquals('ô', $stringy[2]); $this->assertEquals('ô', $stringy[2]);
$this->assertEquals(null, $stringy[3]);
} }
/** /**
* @dataProvider offsetSetProvider() * @expectedException \OutOfBoundsException
*/ */
public function testOffsetSet($expected, $offset, $value) public function testOffsetGetOutOfBounds()
{ {
$stringy = S::create('fòô', 'UTF-8'); $stringy = S::create('fòô', 'UTF-8');
$stringy->offsetSet($offset, $value); $test = $stringy[3];
$this->assertEquals($expected, (string) $stringy);
$stringy = S::create('fòô', 'UTF-8');
$stringy[$offset] = $value;
$this->assertEquals($expected, (string) $stringy);
}
public function offsetSetProvider()
{
return array(
array('ôòô', 0, 'ô'),
array('fòo', 2, 'o'),
array('fòôô', 3, 'ô'),
array('fòôô', 8, 'ô'),
array('fòôô', null, 'ô'),
array('fô', 1, ''),
array('fbô', 1, 'bar')
);
} }
/** /**
* @dataProvider offsetUnsetProvider() * @expectedException \Exception
*/ */
public function testOffsetUnset($expected, $offset) public function testOffsetSet()
{ {
$stringy = S::create('fòô', 'UTF-8'); $stringy = S::create('fòô', 'UTF-8');
$stringy->offsetUnset($offset); $stringy[1] = 'invalid';
$this->assertEquals($expected, (string) $stringy);
$stringy = S::create('fòô', 'UTF-8');
unset($stringy[$offset]);
$this->assertEquals($expected, (string) $stringy);
} }
public function offsetUnsetProvider() /**
* @expectedException \Exception
*/
public function testOffsetUnset()
{ {
return array( $stringy = S::create('fòô', 'UTF-8');
array('òô', 0), unset($stringy[1]);
array('fô', 1),
array('fò', 2),
array('fòô', 3)
);
} }
/** /**