Skip to content
This repository has been archived by the owner on May 28, 2019. It is now read-only.

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
ezzatron committed Apr 8, 2014
2 parents de3af2b + e6c8f26 commit c62a811
Show file tree
Hide file tree
Showing 10 changed files with 91 additions and 57 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Confetti changelog

## 0.2.0 (2014-04-08)

- **[BC BREAK]** Return errors as the third tuple element, instead of throwing
exceptions.

## 0.1.0 (2014-04-07)

- **[NEW]** Initial implementation.
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

*Streaming data transformation system for PHP.*

[![The most recent stable version is 0.1.0][version-image]][Semantic versioning]
[![The most recent stable version is 0.2.0][version-image]][Semantic versioning]
[![Current build status image][build-image]][Current build status]
[![Current coverage status image][coverage-image]][Current coverage status]

Expand Down Expand Up @@ -108,15 +108,15 @@ class Rot13Transform implements TransformInterface
{
public function transform($data, &$context, $isEnd = false)
{
return array(str_rot13($data), strlen($data));
return array(str_rot13($data), strlen($data), null);
}
}
```

The transform receives an arbitrary amount of data as a string, and returns an
tuple (array) where the first element is the transformed data, and the second
element is the amount of data consumed in bytes. In this example, the data is
always completely consumed.
tuple (array) where the first element is the transformed data, the second
element is the amount of data consumed in bytes (in this example, the data is
always completely consumed), and the third element is any error that occurred.

This transform can now be utilized in several ways. To apply the transform to a
string, simply call `transform()` with a boolean true for the `$isEnd` argument:
Expand Down Expand Up @@ -217,20 +217,20 @@ class Base64DecodeTransform extends AbstractTransform
{
$consume = $this->blocksSize(strlen($data), 4, $isEnd);
if (!$consume) {
return array('', 0);
return array('', 0, null);
}

$consumedData = substr($data, 0, $consume);
if (1 === strlen(rtrim($consumedData, '=')) % 4) {
throw new Exception('Base64 decode failed.');
return array('', 0, new Exception('Base64 decode failed.'));
}

$outputBuffer = base64_decode($consumedData, true);
if (false === $outputBuffer) {
throw new Exception('Base64 decode failed.');
return array('', 0, new Exception('Base64 decode failed.'));
}

return array($outputBuffer, $consume);
return array($outputBuffer, $consume, null);
}
}
```
Expand All @@ -239,7 +239,7 @@ This transform will now decode blocks of base64 data and append the result to
the output buffer. The call to `AbstractTransform::blocksSize()` ensures that
data is only consumed in blocks of 4 bytes at a time. If an invalid byte is
passed, or the data stream ends at an invalid number of bytes, an exception is
thrown to indicate the error.
returned as the third tuple element to indicate the error.

## The context parameter

Expand Down Expand Up @@ -272,7 +272,7 @@ class Md5Transform implements TransformInterface
$output = '';
}

return array($output, strlen($data));
return array($output, strlen($data), null);
}
}
```
Expand Down Expand Up @@ -316,4 +316,4 @@ $stream->end('bar'); // outputs '3858f62230ac3c915f300c664312c63f'
[Current coverage status]: https://coveralls.io/r/eloquent/confetti
[eloquent/confetti]: https://packagist.org/packages/eloquent/confetti
[Semantic versioning]: http://semver.org/
[version-image]: http://img.shields.io/:semver-0.1.0-yellow.svg "This project uses semantic versioning"
[version-image]: http://img.shields.io/:semver-0.2.0-yellow.svg "This project uses semantic versioning"
29 changes: 14 additions & 15 deletions src/AbstractNativeStreamFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

namespace Eloquent\Confetti;

use Exception;
use php_user_filter;

/**
Expand All @@ -35,14 +34,14 @@ public function onCreate()
/**
* Filter the input data through the transform.
*
* @param resource $input The input bucket brigade.
* @param resource $output The output bucket brigade.
* @param integer &$consumedBytes The number of bytes consumed.
* @param boolean $isEnd True if the stream is closing.
* @param resource $input The input bucket brigade.
* @param resource $output The output bucket brigade.
* @param integer &$consumed The number of bytes consumed.
* @param boolean $isEnd True if the stream is closing.
*
* @return integer The result code.
*/
public function filter($input, $output, &$consumedBytes, $isEnd)
public function filter($input, $output, &$consumed, $isEnd)
{
if ($isEnd) {
$bucket = stream_bucket_new(STDIN, '');
Expand All @@ -55,18 +54,14 @@ public function filter($input, $output, &$consumedBytes, $isEnd)
$this->buffer .= $bucket->data;
$bufferLength = strlen($this->buffer);

try {
list($outputBuffer, $thisConsumedBytes) = $this->transform
->transform($this->buffer, $this->context, $isEnd);
} catch (Exception $e) {
return PSFS_ERR_FATAL;
}
list($outputBuffer, $thisConsumed, $error) = $this->transform
->transform($this->buffer, $this->context, $isEnd);

$consumedBytes += $thisConsumedBytes;
if ($bufferLength === $thisConsumedBytes) {
$consumed += $thisConsumed;
if ($bufferLength === $thisConsumed) {
$this->buffer = '';
} else {
$this->buffer = substr($this->buffer, $thisConsumedBytes);
$this->buffer = substr($this->buffer, $thisConsumed);
}

if ('' !== $outputBuffer) {
Expand All @@ -75,6 +70,10 @@ public function filter($input, $output, &$consumedBytes, $isEnd)
$hasOutput = true;
}

if (null !== $error) {
return PSFS_ERR_FATAL;
}

$bucket = stream_bucket_make_writeable($input);
}

Expand Down
15 changes: 9 additions & 6 deletions src/CompoundTransform.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ public function transforms()
* @param mixed &$context An arbitrary context value.
* @param boolean $isEnd True if all supplied data must be transformed.
*
* @return tuple<string,integer> A 2-tuple of the transformed data, and the number of bytes consumed.
* @throws Exception If the data cannot be transformed.
* @return tuple<string,integer,mixed> A 3-tuple of the transformed data, the number of bytes consumed, and any resulting error.
*/
public function transform($data, &$context, $isEnd = false)
{
Expand All @@ -73,7 +72,7 @@ public function transform($data, &$context, $isEnd = false)
// Transform the data using the inner most transform. This step is
// performed separately as unlike the outer transforms no buffering
// is performed.
list($data, $actualBytesConsumed) = $this->innerTransform->transform(
list($data, $actualConsumed, $error) = $this->innerTransform->transform(
$data,
$context[$this->innerTransform]->context,
$isEnd
Expand All @@ -82,26 +81,30 @@ public function transform($data, &$context, $isEnd = false)
// Iterate through each of the inner transforms, shunting output data
// from one to the input buffer of the next.
foreach ($this->outerTransforms as $transform) {
if (null !== $error) {
return array($data, $actualConsumed, $error);
}

$currentContext = $context[$transform];
$currentContext->buffer .= $data;

list($data, $bytesConsumed) = $transform->transform(
list($data, $consumed, $error) = $transform->transform(
$currentContext->buffer,
$currentContext->context,
$isEnd
);

$currentContext->buffer = substr(
$currentContext->buffer,
$bytesConsumed
$consumed
);

if (false === $currentContext->buffer) {
$currentContext->buffer = '';
}
}

return array($data, $actualBytesConsumed);
return array($data, $actualConsumed, $error);
}

private function createContext()
Expand Down
5 changes: 1 addition & 4 deletions src/TransformInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

namespace Eloquent\Confetti;

use Exception;

/**
* The interface implemented by stream transforms.
*/
Expand All @@ -37,8 +35,7 @@ interface TransformInterface
* @param mixed &$context An arbitrary context value.
* @param boolean $isEnd True if all supplied data must be transformed.
*
* @return tuple<string,integer> A 2-tuple of the transformed data, and the number of bytes consumed.
* @throws Exception If the data cannot be transformed.
* @return tuple<string,integer,mixed> A 3-tuple of the transformed data, the number of bytes consumed, and any resulting error.
*/
public function transform($data, &$context, $isEnd = false);
}
25 changes: 13 additions & 12 deletions src/TransformStream.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace Eloquent\Confetti;

use Evenement\EventEmitter;
use Exception as NativeException;
use React\Stream\Util;
use React\Stream\WritableStreamInterface;

Expand Down Expand Up @@ -194,16 +193,8 @@ private function transformBuffer()
break;
}

try {
list($outputBuffer, $consumed) = $this->transform
->transform($this->buffer, $this->context, $this->isEnding);
} catch (NativeException $e) {
$this->hasError = true;
$this->emit('error', array($e, $this));
$this->doClose();

return false;
}
list($output, $consumed, $error) = $this->transform
->transform($this->buffer, $this->context, $this->isEnding);

$totalConsumed += $consumed;

Expand All @@ -213,7 +204,17 @@ private function transformBuffer()
$this->buffer = substr($this->buffer, $consumed);
}

$this->emit('data', array($outputBuffer, $this));
if ($this->isEnding || '' !== $output) {
$this->emit('data', array($output, $this));
}

if (null !== $error) {
$this->hasError = true;
$this->emit('error', array($error, $this));
$this->doClose();

return false;
}

if ($this->isEnding && $bufferLength === $consumed) {
$this->doClose();
Expand Down
8 changes: 4 additions & 4 deletions test/src/Base64DecodeTransform.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@ public function transform($data, &$context, $isEnd = false)
{
$consume = $this->blocksSize(strlen($data), 4, $isEnd);
if (!$consume) {
return array('', 0);
return array('', 0, null);
}

$consumedData = substr($data, 0, $consume);
if (1 === strlen(rtrim($consumedData, '=')) % 4) {
throw new Exception('Base64 decode failed.');
return array('', 0, new Exception('Base64 decode failed.'));
}

$outputBuffer = base64_decode($consumedData, true);
if (false === $outputBuffer) {
throw new Exception('Base64 decode failed.');
return array('', 0, new Exception('Base64 decode failed.'));
}

return array($outputBuffer, $consume);
return array($outputBuffer, $consume, null);
}
}
2 changes: 1 addition & 1 deletion test/src/Md5Transform.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ public function transform($data, &$context, $isEnd = false)
$output = '';
}

return array($output, strlen($data));
return array($output, strlen($data), null);
}
}
2 changes: 1 addition & 1 deletion test/src/Rot13Transform.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ class Rot13Transform implements TransformInterface
{
public function transform($data, &$context, $isEnd = false)
{
return array(str_rot13($data), strlen($data));
return array(str_rot13($data), strlen($data), null);
}
}
33 changes: 31 additions & 2 deletions test/suite/CompoundTransformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

namespace Eloquent\Confetti;

use Base64DecodeTransform;
use Md5Transform;
use Phake;
use PHPUnit_Framework_TestCase;
use Rot13Transform;

Expand All @@ -34,7 +36,7 @@ public function testTransforms()
public function testTransform()
{
$input = 'foobar';
$expected = array(str_rot13(md5(str_rot13($input))), strlen($input));
$expected = array(str_rot13(md5(str_rot13($input))), strlen($input), null);
$result = $this->transform->transform($input, $context, true);

$this->assertSame($expected, $result);
Expand All @@ -43,7 +45,7 @@ public function testTransform()
public function testTransformWithEmptyString()
{
$input = '';
$expected = array(str_rot13(md5(str_rot13($input))), strlen($input));
$expected = array(str_rot13(md5(str_rot13($input))), strlen($input), null);
$result = $this->transform->transform($input, $context, true);

$this->assertSame($expected, $result);
Expand All @@ -65,4 +67,31 @@ public function testTransformByteByByte()

$this->assertSame($expected, $result);
}

public function testTransformErrorSingleTransform()
{
$this->transform = new CompoundTransform(array(new Base64DecodeTransform));
list($output, $consumed, $error) = $this->transform->transform('!!!!', $context, true);

$this->setExpectedException('Exception', 'Base64 decode failed.');
throw $error;
}

public function testTransformErrorMultipleTransforms()
{
$this->transformA = Phake::partialMock('Base64DecodeTransform');
$this->transformB = Phake::partialMock('Base64DecodeTransform');
$this->transformC = Phake::partialMock('Base64DecodeTransform');
$this->transforms = array($this->transformA, $this->transformB, $this->transformC);
$this->transform = new CompoundTransform($this->transforms);
list($output, $consumed, $error) = $this->transform->transform('ISEhIQ==', $context, true);

Phake::inOrder(
Phake::verify($this->transformA)->transform('ISEhIQ==', $this->anything(), true),
Phake::verify($this->transformB)->transform('!!!!', $this->anything(), true)
);
Phake::verify($this->transformC, Phake::never())->transform(Phake::anyParameters());
$this->setExpectedException('Exception', 'Base64 decode failed.');
throw $error;
}
}

0 comments on commit c62a811

Please sign in to comment.