Skip to content

Commit

Permalink
Merge pull request #3 from elecena/fix/truncating-the-file
Browse files Browse the repository at this point in the history
 JsonlParser: improve truncating the file when poping and pushing items
  • Loading branch information
macbre authored Nov 30, 2023
2 parents b6b85ce + c6ba82d commit d2311bf
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
22 changes: 20 additions & 2 deletions src/JsonlParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ public function __construct(protected $stream)
{
}

/**
* Initialize the parser from the given file.
*/
public static function fromFile(string $filename, string $mode = 'a+t'): self
{
$stream = fopen($filename, $mode);
return new self($stream);
}

public function push(array|string $item): void
{
$encoded = json_encode($item);
Expand Down Expand Up @@ -65,9 +74,10 @@ public function pop(): null|array|string

$buffer = strrev($buffer);

// truncate the stream and remove the trailing newline
// truncate the stream
// remove the trailing newline if the stream is now empty
$pos = ftell($this->stream);
ftruncate($this->stream, $pos < 1 ? 0 : $pos-1);
ftruncate($this->stream, $pos <= strlen(self::LINES_SEPARATOR) ? 0 : $pos);

return json_decode($buffer, associative: true);
}
Expand Down Expand Up @@ -103,4 +113,12 @@ public function count(): int

return $count;
}

/**
* Checks if there are no items in the stream.
*/
public function empty(): bool
{
return count($this) === 0;
}
}
40 changes: 40 additions & 0 deletions tests/JsonParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,44 @@ public function testPushItemsToFile(): void

fclose($stream); // this removes the file
}

public function testFromFile(): void
{
$tmpFilename = tempnam(directory: sys_get_temp_dir(), prefix: 'jsonld');

$parser = JsonlParser::fromFile($tmpFilename);
$this->assertCount(0, $parser);
$this->assertTrue($parser->empty());

$parser->push(self::ITEM_ONE);
$parser->push(self::ITEM_TWO);
$this->assertCount(2, $parser);
$this->assertFalse($parser->empty());

// now get one and push the next item
$this->assertSame(self::ITEM_TWO, $parser->pop());
$this->assertStringEqualsFile(
expectedFile: $tmpFilename,
actualString: json_encode(self::ITEM_ONE) . JsonlParser::LINES_SEPARATOR
);
$this->assertCount(1, $parser);
$parser->push(self::ITEM);
$this->assertStringEqualsFile(
expectedFile: $tmpFilename,
actualString: json_encode(self::ITEM_ONE) . JsonlParser::LINES_SEPARATOR . json_encode(self::ITEM) . JsonlParser::LINES_SEPARATOR
);
$this->assertCount(2, $parser);

// now, empty the file
$parser->pop();
$parser->pop();
$this->assertCount(0, $parser);
$this->assertTrue($parser->empty());
$this->assertStringEqualsFile(
expectedFile: $tmpFilename,
actualString: ''
);

unlink($tmpFilename);
}
}

0 comments on commit d2311bf

Please sign in to comment.