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

Add Dir and File class #49

Merged
merged 2 commits into from
Jan 2, 2024
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
20 changes: 19 additions & 1 deletion src/VM/Core/Runtime/BasicObject/Kernel/Kernel.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,23 @@
namespace RubyVM\VM\Core\Runtime\BasicObject\Kernel;

use RubyVM\VM\Core\Runtime\BasicObject\BasicObject;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Comparable\String_;
use RubyVM\VM\Exception\RubyVMException;

abstract class Kernel extends BasicObject {}
abstract class Kernel extends BasicObject
{
public function __dir__(): String_
{
if (!$this->context instanceof \RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface) {
throw new RubyVMException('A context is not injected');
}

return String_::createBy(
$this->context
->instructionSequence()
->body()
->info()
->path(),
);
}
}
80 changes: 80 additions & 0 deletions src/VM/Core/Runtime/BasicObject/Kernel/Object_/Enumerable/Dir.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Enumerable;

use RubyVM\VM\Core\Runtime\Attribute\BindAliasAs;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Comparable\String_;
use RubyVM\VM\Core\Runtime\BasicObject\Symbolizable;
use RubyVM\VM\Core\Runtime\BasicObject\SymbolizeInterface;
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\SymbolInterface;
use RubyVM\VM\Exception\RuntimeException;

#[BindAliasAs('Dir')]
class Dir extends Enumerable implements RubyClassInterface, SymbolizeInterface
{
use Symbolizable;
protected ?\ArrayIterator $iterator = null;

/**
* @var \DirectoryIterator[]
*/
protected array $files = [];

protected string $directory;

public function __construct(protected SymbolInterface $symbol)
{
$this->directory = (string) $this->symbol;
$this->files = array_values(
iterator_to_array(
new \DirectoryIterator($this->symbol->valueOf()),
)
);
}

public static function pwd(): RubyClassInterface
{
return String_::createBy(getcwd());
}

public function getIterator(): \ArrayIterator
{
return $this->iterator ??= new \ArrayIterator($this->files);
}

public function offsetExists(mixed $offset): bool
{
return (bool) $this->offsetGet($offset);
}

public function offsetGet(mixed $offset): mixed
{
return $this->files[$offset] ?? throw new RuntimeException(
sprintf('File not found #%s', $offset),
);
}

public function offsetSet(mixed $offset, mixed $value): void
{
throw new RuntimeException('File cannot set');
}

public function offsetUnset(mixed $offset): void
{
throw new RuntimeException('File cannot unset');
}

public function count(): int
{
return count($this->files);
}

public static function createBy(?string $directory = null): self
{
return new self(new StringSymbol((string) ($directory ?? getcwd())));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

namespace RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Enumerable\IO;

use RubyVM\VM\Core\Runtime\Attribute\BindAliasAs;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Comparable\String_;
use RubyVM\VM\Core\Runtime\BasicObject\SymbolizeInterface;
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\YARV\Essential\Symbol\NilSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\NumberSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;
use RubyVM\VM\Core\YARV\Essential\Symbol\SymbolInterface;
use RubyVM\VM\Exception\RuntimeException;

#[BindAliasAs('File')]
class File extends IO implements RubyClassInterface, SymbolizeInterface
{
public function __construct(protected NilSymbol|StringSymbol $path, protected StringSymbol $mode, protected NumberSymbol $permission)
{
$this->path = $path;
$this->mode = $mode;
$this->permission = $permission;
}

public function getIterator(): \Traversable
{
throw new RuntimeException('File cannot iterate');
}

public function offsetExists(mixed $offset): bool
{
throw new RuntimeException('File cannot exists');
}

public function offsetGet(mixed $offset): mixed
{
throw new RuntimeException('File cannot get');
}

public function offsetSet(mixed $offset, mixed $value): void
{
throw new RuntimeException('File cannot set');
}

public function offsetUnset(mixed $offset): void
{
throw new RuntimeException('File cannot unset');
}

public function count(): int
{
throw new RuntimeException('File cannot count');
}

public static function read(String_ $path): String_
{
return String_::createBy(
file_get_contents(
(string) $path,
),
);
}

public static function createBy(?string $path = null, ?string $mode = null, ?int $permission = null): self
{
return new self(
$path === null
? new NilSymbol()
: new StringSymbol($path),
new StringSymbol($mode ?? 'r'),
new NumberSymbol($permission ?? 0666),
);
}

public function symbol(): SymbolInterface
{
return $this->path;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Enumerable\IO;

use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Enumerable\Enumerable;

abstract class IO extends Enumerable {}
14 changes: 13 additions & 1 deletion src/VM/Core/Runtime/Executor/CallBlockHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

use RubyVM\VM\Core\Runtime\Attribute\WithContext;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Class_;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Comparable\Integer_;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Comparable\String_;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Object_\Enumerable\Array_;
use RubyVM\VM\Core\Runtime\Essential\RubyClassInterface;
use RubyVM\VM\Core\Runtime\Executor\Context\ContextInterface;
Expand Down Expand Up @@ -33,7 +35,17 @@ public function send(string $name, CallInfoInterface $callInfo, ?ExecutorInterfa
];
}

return $this->{$name}(...$arguments);
$result = $this->{$name}(...$arguments);

if (is_int($result)) {
return Integer_::createBy($result);
}

if (is_string($result)) {
return String_::createBy($result);
}

return $result;
}

return $this->{$name}(
Expand Down
3 changes: 2 additions & 1 deletion src/VM/Core/Runtime/Main.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@
namespace RubyVM\VM\Core\Runtime;

use RubyVM\VM\Core\Helper\ClassHelper;
use RubyVM\VM\Core\Runtime\BasicObject\Kernel\Kernel;
use RubyVM\VM\Core\Runtime\BasicObject\Symbolizable;
use RubyVM\VM\Core\Runtime\Essential\MainInterface;
use RubyVM\VM\Core\YARV\Criterion\ShouldBeRubyClass;
use RubyVM\VM\Core\YARV\Essential\Symbol\StringSymbol;
use RubyVM\VM\Exception\OperationProcessorException;

class Main implements MainInterface
class Main extends Kernel implements MainInterface
{
use ShouldBeRubyClass;
use Symbolizable;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

declare(strict_types=1);

namespace Tests\RubyVM\Version\RubyVM\Call\BasicObject\Kernel\Object_\Enumerable;

use RubyVM\VM\Core\Runtime\Executor\ExecutedStatus;
use Tests\RubyVM\Helper\TestApplication;

/**
* @internal
*
* @coversNothing
*/
class DirTest extends TestApplication
{
public function testPwd(): void
{
$rubyVMManager = $this->createRubyVMFromCode(
<<< '_'
puts Dir.pwd + "\n"
_,
);

$executor = $rubyVMManager
->rubyVM
->disassemble();

$this->assertSame(ExecutedStatus::SUCCESS, $executor->execute()->executedStatus);
$dir = getcwd();
$this->assertSame("{$dir}\n", $rubyVMManager->stdOut->readAll());
}

public function testCount(): void
{
$rubyVMManager = $this->createRubyVMFromCode(
<<< '_'
puts Dir.new(Dir.pwd).count.to_s + "\n"
_,
);

$executor = $rubyVMManager
->rubyVM
->disassemble();

$this->assertSame(ExecutedStatus::SUCCESS, $executor->execute()->executedStatus);
$count = count(iterator_to_array(new \DirectoryIterator(getcwd() ?: './')));
$this->assertSame("{$count}\n", $rubyVMManager->stdOut->readAll());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

declare(strict_types=1);

namespace Tests\RubyVM\Version\RubyVM\Call\BasicObject\Kernel\Object_\Enumerable;

use RubyVM\VM\Core\Runtime\Executor\ExecutedStatus;
use Tests\RubyVM\Helper\TestApplication;

/**
* @internal
*
* @coversNothing
*/
class FileTest extends TestApplication
{
public function testRead(): void
{
$file = __FILE__;

$rubyVMManager = $this->createRubyVMFromCode(
<<< _
puts File.read("{$file}") + "\n"
_,
);

$executor = $rubyVMManager
->rubyVM
->disassemble();

$this->assertSame(ExecutedStatus::SUCCESS, $executor->execute()->executedStatus);
$this->assertSame(file_get_contents($file) . "\n", $rubyVMManager->stdOut->readAll());
}
}