Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve documentation and examples #27

Merged
merged 2 commits into from
May 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 31 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# clue/reactphp-ndjson

[![CI status](https://github.com/clue/reactphp-ndjson/workflows/CI/badge.svg)](https://github.com/clue/reactphp-ndjson/actions)
[![CI status](https://github.com/clue/reactphp-ndjson/actions/workflows/ci.yml/badge.svg)](https://github.com/clue/reactphp-ndjson/actions)
[![installs on Packagist](https://img.shields.io/packagist/dt/clue/ndjson-react?color=blue&label=installs%20on%20Packagist)](https://packagist.org/packages/clue/ndjson-react)

Streaming newline-delimited JSON ([NDJSON](http://ndjson.org/)) parser and encoder for [ReactPHP](https://reactphp.org/).
Expand All @@ -10,7 +10,7 @@ file to store any kind of (uniform) structured data, such as a list of user
objects or log entries. It uses a simple newline character between each
individual record and as such can be both used for efficient persistence and
simple append-style operations. This also allows it to be used in a streaming
context, such as a simple inter-process commmunication (IPC) protocol or for a
context, such as a simple inter-process communication (IPC) protocol or for a
remote procedure call (RPC) mechanism. This library provides a simple
streaming API to process very large NDJSON files with thousands or even millions
of rows efficiently without having to load the whole file into memory at once.
Expand Down Expand Up @@ -39,7 +39,7 @@ of rows efficiently without having to load the whole file into memory at once.

## Support us

We invest a lot of time developing, maintaining and updating our awesome
We invest a lot of time developing, maintaining, and updating our awesome
open-source projects. You can help us sustain this high-quality of our work by
[becoming a sponsor on GitHub](https://github.com/sponsors/clue). Sponsors get
numerous benefits in return, see our [sponsoring page](https://github.com/sponsors/clue)
Expand Down Expand Up @@ -75,7 +75,7 @@ no "outer array" to be modified). This makes it a perfect fit for a streaming
context, for line-oriented CLI tools (such as `grep` and others) or for a logging
context where you want to append records at a later time. Additionally, this
also allows it to be used in a streaming context, such as a simple inter-process
commmunication (IPC) protocol or for a remote procedure call (RPC) mechanism.
communication (IPC) protocol or for a remote procedure call (RPC) mechanism.

The newline character at the end of each line allows for some really simple
*framing* (detecting individual records). While each individual line is valid
Expand Down Expand Up @@ -134,12 +134,12 @@ as parsed values instead of just chunks of strings:
```

```php
$stdin = new ReadableResourceStream(STDIN);
$stdin = new React\Stream\ReadableResourceStream(STDIN);

$stream = new Decoder($stdin);
$ndjson = new Clue\React\NDJson\Decoder($stdin);

$stream->on('data', function ($data) {
// data is a parsed element from the JSON stream
$ndjson->on('data', function ($data) {
// $data is a parsed element from the JSON stream
// line 1: $data = (object)array('name' => 'test', 'active' => true);
// line 2: $data = (object)array('name' => 'hello wörld', 'active' => true);
var_dump($data);
Expand All @@ -157,9 +157,9 @@ This means that, by default, JSON objects will be emitted as a `stdClass`.
This behavior can be controlled through the optional constructor parameters:

```php
$stream = new Decoder($stdin, true);
$ndjson = new Clue\React\NDJson\Decoder($stdin, true);

$stream->on('data', function ($data) {
$ndjson->on('data', function ($data) {
// JSON objects will be emitted as assoc arrays now
});
```
Expand All @@ -171,15 +171,15 @@ unreasonably long lines. It accepts an additional argument if you want to change
this from the default of 64 KiB:

```php
$stream = new Decoder($stdin, false, 512, 0, 64 * 1024);
$ndjson = new Clue\React\NDJson\Decoder($stdin, false, 512, 0, 64 * 1024);
```

If the underlying stream emits an `error` event or the plain stream contains
any data that does not represent a valid NDJson stream,
it will emit an `error` event and then `close` the input stream:

```php
$stream->on('error', function (Exception $error) {
$ndjson->on('error', function (Exception $error) {
// an error occured, stream will close next
});
```
Expand All @@ -190,7 +190,7 @@ followed by an `end` event on success or an `error` event for
incomplete/invalid JSON data as above:

```php
$stream->on('end', function () {
$ndjson->on('end', function () {
// stream successfully ended, stream will close next
});
```
Expand All @@ -199,7 +199,7 @@ If either the underlying stream or the `Decoder` is closed, it will forward
the `close` event:

```php
$stream->on('close', function () {
$ndjson->on('close', function () {
// stream closed
// possibly after an "end" event or due to an "error" event
});
Expand All @@ -209,7 +209,7 @@ The `close(): void` method can be used to explicitly close the `Decoder` and
its underlying stream:

```php
$stream->close();
$ndjson->close();
```

The `pipe(WritableStreamInterface $dest, array $options = array(): WritableStreamInterface`
Expand All @@ -218,7 +218,7 @@ Please note that the `Decoder` emits decoded/parsed data events, while many
(most?) writable streams expect only data chunks:

```php
$stream->pipe($logger);
$ndjson->pipe($logger);
```

For more details, see ReactPHP's
Expand All @@ -234,12 +234,12 @@ and accepts its data through the same interface, but handles any data as complet
JSON elements instead of just chunks of strings:

```php
$stdout = new WritableResourceStream(STDOUT);
$stdout = new React\Stream\WritableResourceStream(STDOUT);

$stream = new Encoder($stdout);
$ndjson = new Clue\React\NDJson\Encoder($stdout);

$stream->write(array('name' => 'test', 'active' => true));
$stream->write(array('name' => 'hello wörld', 'active' => true));
$ndjson->write(array('name' => 'test', 'active' => true));
$ndjson->write(array('name' => 'hello wörld', 'active' => true));
```
```
{"name":"test","active":true}
Expand All @@ -248,13 +248,13 @@ $stream->write(array('name' => 'hello wörld', 'active' => true));

The `Encoder` supports the same parameters as the underlying
[`json_encode()`](https://www.php.net/manual/en/function.json-encode.php) function.
This means that, by default, unicode characters will be escaped in the output.
This means that, by default, Unicode characters will be escaped in the output.
This behavior can be controlled through the optional constructor parameters:

```php
$stream = new Encoder($stdout, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
$ndjson = new Clue\React\NDJson\Encoder($stdout, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);

$stream->write('hello wörld');
$ndjson->write('hello wörld');
```
```
"hello wörld"
Expand All @@ -268,7 +268,7 @@ any data that can not be represented as a valid NDJSON stream,
it will emit an `error` event and then `close` the input stream:

```php
$stream->on('error', function (Exception $error) {
$ndjson->on('error', function (Exception $error) {
// an error occured, stream will close next
});
```
Expand All @@ -277,7 +277,7 @@ If either the underlying stream or the `Encoder` is closed, it will forward
the `close` event:

```php
$stream->on('close', function () {
$ndjson->on('close', function () {
// stream closed
// possibly after an "end" event or due to an "error" event
});
Expand All @@ -287,22 +287,22 @@ The `end(mixed $data = null): void` method can be used to optionally emit
any final data and then soft-close the `Encoder` and its underlying stream:

```php
$stream->end();
$ndjson->end();
```

The `close(): void` method can be used to explicitly close the `Encoder` and
its underlying stream:

```php
$stream->close();
$ndjson->close();
```

For more details, see ReactPHP's
[`WritableStreamInterface`](https://github.com/reactphp/stream#writablestreaminterface).

## Install

The recommended way to install this library is [through Composer](https://getcomposer.org).
The recommended way to install this library is [through Composer](https://getcomposer.org/).
[New to Composer?](https://getcomposer.org/doc/00-intro.md)

This project follows [SemVer](https://semver.org/).
Expand All @@ -317,12 +317,12 @@ See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades.
This project aims to run on any platform and thus does not require any PHP
extensions and supports running on legacy PHP 5.3 through current PHP 8+ and
HHVM.
It's *highly recommended to use PHP 7+* for this project.
It's *highly recommended to use the latest supported PHP version* for this project.

## Tests

To run the test suite, you first need to clone this repo and then install all
dependencies [through Composer](https://getcomposer.org):
dependencies [through Composer](https://getcomposer.org/):

```bash
$ composer install
Expand All @@ -331,7 +331,7 @@ $ composer install
To run the test suite, go to the project root and run:

```bash
$ php vendor/bin/phpunit
$ vendor/bin/phpunit
```

## License
Expand Down
8 changes: 3 additions & 5 deletions examples/91-benchmark-count.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,18 @@
// 3) pipe NDJSON into benchmark script:
// $ php examples/91-benchmark-count.php < title.ratings.ndjson

use Clue\React\NDJson\Decoder;
use React\EventLoop\Loop;
use React\Stream\ReadableResourceStream;

require __DIR__ . '/../vendor/autoload.php';

if (extension_loaded('xdebug')) {
echo 'NOTICE: The "xdebug" extension is loaded, this has a major impact on performance.' . PHP_EOL;
}

$decoder = new Decoder(new ReadableResourceStream(STDIN), true);
$ndjson = new Clue\React\NDJson\Decoder(new React\Stream\ReadableResourceStream(STDIN), true);

$count = 0;
$decoder->on('data', function () use (&$count) {
$ndjson->on('data', function () use (&$count) {
++$count;
});

Expand All @@ -36,7 +34,7 @@
printf("\r%d records in %0.3fs...", $count, microtime(true) - $start);
});

$decoder->on('close', function () use (&$count, $report, $start) {
$ndjson->on('close', function () use (&$count, $report, $start) {
$now = microtime(true);
Loop::cancelTimer($report);

Expand Down
18 changes: 7 additions & 11 deletions examples/validate.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,20 @@

// $ php examples/validate.php < examples/users.ndjson

use Clue\React\NDJson\Decoder;
use Clue\React\NDJson\Encoder;
use React\EventLoop\Loop;
use React\Stream\ReadableResourceStream;
use React\Stream\WritableResourceStream;

require __DIR__ . '/../vendor/autoload.php';

$exit = 0;
$in = new ReadableResourceStream(STDIN);
$out = new WritableResourceStream(STDOUT);
$info = new WritableResourceStream(STDERR);
$in = new React\Stream\ReadableResourceStream(STDIN);
$out = new React\Stream\WritableResourceStream(STDOUT);
$info = new React\Stream\WritableResourceStream(STDERR);

$decoder = new Decoder($in);
$encoder = new Encoder($out);
$decoder->pipe($encoder);
$ndjson = new Clue\React\NDJson\Decoder($in);
$encoder = new Clue\React\NDJson\Encoder($out);
$ndjson->pipe($encoder);

$decoder->on('error', function (Exception $e) use ($info, &$exit) {
$ndjson->on('error', function (Exception $e) use ($info, &$exit) {
$info->write('ERROR: ' . $e->getMessage() . PHP_EOL);
$exit = 1;
});
Expand Down