Skip to content

Commit

Permalink
Merge pull request #40 from xp-framework/feature/global-package
Browse files Browse the repository at this point in the history
Add support for the global package
  • Loading branch information
thekid committed Mar 28, 2024
2 parents 802fbfd + b472246 commit 440bf0d
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 16 deletions.
49 changes: 38 additions & 11 deletions src/main/php/lang/reflection/Package.class.php
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<?php namespace lang\reflection;

use lang\{ClassLoader, IClassLoader, Reflection, IllegalArgumentException};
use lang\{ClassLoader, IClassLoader, Reflection, IllegalArgumentException, Value};

/**
* Represents a namespace, which may exist in various class loaders
*
* @test lang.reflection.unittest.PackageTest
*/
class Package {
class Package implements Value {
private $name;

/**
Expand All @@ -21,6 +21,9 @@ public function __construct(... $components) {
$this->name= rtrim(strtr(implode('.', $components), '\\', '.'), '.');
}

/** Returns whether this is the global package */
public function global(): bool { return '' === $this->name; }

/** Returns this package's name (in dotted form) */
public function name(): string { return $this->name; }

Expand All @@ -39,13 +42,16 @@ public function classLoaders() {
}

/**
* Returns this package's parent, if any
* Returns this package's parent. Returns NULL if this package refers to the
* global package.
*
* @return ?self
*/
public function parent() {
if ('' === $this->name) return null;

$p= strrpos($this->name, '.');
return false === $p ? null : new Package(substr($this->name, 0, $p));
return false === $p ? new Package() : new Package(substr($this->name, 0, $p));
}

/**
Expand All @@ -54,7 +60,7 @@ public function parent() {
* @return iterable
*/
public function children() {
$base= $this->name.'.';
$base= $this->name ? $this->name.'.' : '';
$loader= ClassLoader::getDefault();
foreach ($loader->packageContents($this->name) as $entry) {
if ('/' === $entry[strlen($entry) - 1]) {
Expand All @@ -70,7 +76,7 @@ public function children() {
*/
public function types() {
$ext= strlen(\xp::CLASS_FILE_EXT);
$base= $this->name.'.';
$base= $this->name ? $this->name.'.' : '';
$loader= ClassLoader::getDefault();
foreach ($loader->packageContents($this->name) as $entry) {
if (0 === substr_compare($entry, \xp::CLASS_FILE_EXT, -$ext)) {
Expand All @@ -87,15 +93,36 @@ public function types() {
* @throws lang.IllegalArgumentException
*/
public function type($name) {
if ('' === $this->name) return Reflection::type($name);

// Compare type package and this package
$type= strtr($name, '\\', '.');
$p= strrpos($type, '.');

if (false === $p) {
return Reflection::of($this->name.'.'.$type);
return Reflection::type($this->name.'.'.$type);
} else if (0 === strncmp($this->name, $type, $p)) {
return Reflection::of($type);
} else {
throw new IllegalArgumentException('Given type '.$type.' is not in package '.$this->name);
return Reflection::type($type);
}

throw new IllegalArgumentException('Given type '.$type.' is not in package '.$this->name);
}

/** @return string */
public function hashCode() { return md5($this->name); }

/** @return string */
public function toString() { return nameof($this).'<'.$this->name().'>'; }

/**
* Compares this member to another value
*
* @param var $value
* @return int
*/
public function compareTo($value) {
return $value instanceof self
? $this->name <=> $value->name
: 1
;
}
}
7 changes: 3 additions & 4 deletions src/main/php/lang/reflection/Type.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,12 @@ public function is($type): bool {
}

/**
* Returns this type's package, or NULL if this type is in the global namespace.
* Returns this type's package
*
* @return ?lang.reflection.Package
* @return lang.reflection.Package
*/
public function package() {
$name= $this->reflect->getNamespaceName();
return $name ? new Package($name) : null;
return new Package($this->reflect->getNamespaceName());
}

/**
Expand Down
25 changes: 25 additions & 0 deletions src/test/php/lang/reflection/unittest/PackageTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,21 @@ public function name($arg) {
Assert::equals('lang.reflection', (new Package($arg))->name());
}

#[Test]
public function global() {
Assert::true((new Package())->global());
}

#[Test, Values(['lang', 'lang.reflection', 'lang.reflect.unittest'])]
public function leveled($package) {
Assert::false((new Package($package))->global());
}

#[Test]
public function global_name() {
Assert::equals('', (new Package())->name());
}

#[Test]
public function create_via_components() {
Assert::equals('lang.reflection.unittest', (new Package('lang', 'reflection', 'unittest'))->name());
Expand All @@ -26,6 +41,16 @@ public function parent() {
Assert::equals(new Package('lang'), (new Package('lang.reflection'))->parent());
}

#[Test]
public function parent_of_toplevel() {
Assert::equals(new Package(), (new Package('lang'))->parent());
}

#[Test]
public function global_package_has_no_parent() {
Assert::null((new Package())->parent());
}

#[Test]
public function children() {
Assert::equals(
Expand Down
2 changes: 1 addition & 1 deletion src/test/php/lang/reflection/unittest/TypeTest.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public function package() {

#[Test]
public function global_namespace() {
Assert::null(Reflection::of(\Throwable::class)->package());
Assert::equals(new Package(), Reflection::of(\Throwable::class)->package());
}

#[Test]
Expand Down

0 comments on commit 440bf0d

Please sign in to comment.