**Note:** Empty lines are ignored by the parser. * * @category Machine Learning * @package Rubix/ML * @author Andrew DalPino */ class NDJSON implements Extractor, Exporter { /** * The path to the file on disk. * * @var string */ protected string $path; /** * @param string $path * @throws InvalidArgumentException */ public function __construct(string $path) { if (empty($path)) { throw new InvalidArgumentException('Path cannot be empty.'); } if (is_dir($path)) { throw new InvalidArgumentException('Path must be to a file, folder given.'); } $this->path = $path; } /** * Export an iterable data table. * * @param iterable $iterator * @throws RuntimeException */ public function export(iterable $iterator) : void { if (is_file($this->path) and !is_writable($this->path)) { throw new RuntimeException("Path {$this->path} is not writable."); } if (!is_file($this->path) and !is_writable(dirname($this->path))) { throw new RuntimeException("Path {$this->path} is not writable."); } $handle = fopen($this->path, 'w'); if (!$handle) { throw new RuntimeException('Could not open file pointer.'); } $line = 1; foreach ($iterator as $row) { $length = fputs($handle, JSON::encode($row) . PHP_EOL); if ($length === false) { throw new RuntimeException("Could not write row on line $line."); } ++$line; } fclose($handle); } /** * Return an iterator for the records in the data table. * * @throws RuntimeException * @return \Generator */ public function getIterator() : Traversable { if (!is_file($this->path)) { throw new InvalidArgumentException("Path {$this->path} is not a file."); } if (!is_readable($this->path)) { throw new InvalidArgumentException("Path {$this->path} is not readable."); } $handle = fopen($this->path, 'r'); if (!$handle) { throw new RuntimeException('Could not open file pointer.'); } $line = 1; while (!feof($handle)) { $data = rtrim(fgets($handle) ?: ''); if (empty($data)) { continue; } try { yield JSON::decode($data); } catch (RuntimeException $exception) { throw new RuntimeException( "JSON Error on line $line: {$exception->getMessage()}", $exception->getCode(), $exception ); } ++$line; } fclose($handle); } }