Page MenuHomeDevCentral

No OneTemporary

diff --git a/composer.json b/composer.json
index d7263af..57d349e 100644
--- a/composer.json
+++ b/composer.json
@@ -1,72 +1,75 @@
{
"name": "keruald/keruald",
"type": "library",
"description": "Modular libraries to build frameworks and applications",
"keywords": [
"framework",
"keruald"
],
"license": "BSD-2-Clause",
"homepage": "https://keruald.nasqueron.org",
"authors": [
{
"name": "Sébastien Santoro",
"email": "dereckson@espace-win.org"
},
{
"name": "Keruald contributors"
}
],
"provide": {
"psr/simple-cache-implementation": "1.0|2.0|3.0"
},
"require": {
"psr/simple-cache": "^1.0|^2.0|^3.0",
"ext-intl": "*"
},
"require-dev": {
"ext-mbstring": "*",
"ext-mysqli": "*",
"ext-pdo": "*",
"ext-xmlwriter": "*",
"nasqueron/codestyle": "^0.1.2",
"phan/phan": "^5.3.1",
"phpunit/phpunit": "^10.2",
"symfony/yaml": "^6.0.3",
"squizlabs/php_codesniffer": "^4.0.0"
},
"suggest": {
"ext-memcached": "*",
"ext-redis": "*"
},
"replace": {
"keruald/cache": "0.1.0",
"keruald/commands": "0.0.1",
"keruald/database": "0.6.0",
"keruald/github": "0.2.1",
"keruald/omnitools": "0.16.0",
- "keruald/report": "0.1.0"
+ "keruald/report": "0.1.0",
+ "keruald/yaml": "0.1.0"
},
"autoload": {
"psr-4": {
"Keruald\\Cache\\": "cache/src/",
"Keruald\\Cache\\Tests\\": "cache/tests/",
"Keruald\\Commands\\": "commands/src/",
"Keruald\\Commands\\Tests\\": "commands/tests/",
"Keruald\\Database\\": "database/src/",
"Keruald\\Database\\Tests\\": "database/tests/",
"Keruald\\GitHub\\": "github/src/",
"Keruald\\GitHub\\Tests\\": "github/tests/",
"Keruald\\OmniTools\\": "omnitools/src/",
"Keruald\\OmniTools\\Tests\\": "omnitools/tests/",
"Keruald\\Reporting\\": "report/src/",
- "Keruald\\Reporting\\Tests\\": "report/tests/"
+ "Keruald\\Reporting\\Tests\\": "report/tests/",
+ "Keruald\\Yaml\\": "yaml/src/",
+ "Keruald\\Yaml\\Tests\\": "yaml/tests/"
}
},
"scripts": {
"lint-src": "find */src -type f -name '*.php' | xargs -n1 php -l",
"lint-tests": "find */tests -type f -name '*.php' | xargs -n1 php -l",
"test": "vendor/bin/phpunit"
},
"minimum-stability": "dev"
}
diff --git a/metadata.yml b/metadata.yml
index 96602b1..e8eff33 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,38 +1,40 @@
# -------------------------------------------------------------
# Metadata for Keruald packages
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Project: Keruald
# Description: Configuration for utilities
# License: Trivial work, not eligible to copyright.
#
# If eligible, this data is made available under
# the Public Domain Dedication and License v1.0
# whose full text can be found at:
# http://opendatacommons.org/licenses/pddl/1.0/
# -------------------------------------------------------------
# -------------------------------------------------------------
# Packages
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# Each package matches the following artifacts:
#
# — a subdirectory here
# — a main repository on DevCentral
# — a mirror repository on GitHub in keruald/ organization
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
packages:
- cache
- commands
- database
- github
- omnitools
- report
+ - yaml
packages_namespaces:
cache: Keruald\Cache
commands: Keruald\Commands
database: Keruald\Database
github: Keruald\GitHub
omnitools: Keruald\OmniTools
report: Keruald\Reporting
+ yaml: Keruald\Yaml
diff --git a/phpcs.xml b/phpcs.xml
index d89230c..6b8f384 100644
--- a/phpcs.xml
+++ b/phpcs.xml
@@ -1,58 +1,61 @@
<?xml version="1.0"?>
<!--
=============================================================
PHP_CodeSniffer configuration
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project: Keruald
License: Trivial work, not eligible to copyright
Source file: _templates/phpcs.xml.in
=============================================================
<auto-generated>
This file is automatically generated from a template.
Changes to this file may cause incorrect behavior
and will be lost if the state is redeployed.
</auto-generated>
-->
<ruleset name="Nasqueron">
<rule ref="vendor/nasqueron/codestyle/CodeSniffer/ruleset.xml" />
<!--
OmniTools exception
Allow dprint_r() and dieprint_r() legacy debug function names
-->
<rule ref="Generic.NamingConventions.CamelCapsFunctionName.NotCamelCaps">
<exclude-pattern>*/_register_to_global_space.php</exclude-pattern>
</rule>
<!--
Database exception
Allow unused parameters
-->
<rule ref="Generic.CodeAnalysis.UnusedFunctionParameter">
<exclude-pattern>database/src/*</exclude-pattern>
</rule>
<file>cache/src</file>
<file>cache/tests</file>
<file>commands/src</file>
<file>commands/tests</file>
<file>database/src</file>
<file>database/tests</file>
<file>github/src</file>
<file>github/tests</file>
<file>omnitools/src</file>
<file>omnitools/tests</file>
<file>report/src</file>
<file>report/tests</file>
+ <file>yaml/src</file>
+ <file>yaml/tests</file>
+
</ruleset>
diff --git a/phpunit.xml b/phpunit.xml
index e545b4e..5fc519b 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -1,65 +1,69 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
=============================================================
PHPUnit configuration
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project: Keruald
License: Trivial work, not eligible to copyright
Source file: _templates/phpunit.xml.in
=============================================================
<auto-generated>
This file is automatically generated from a template.
Changes to this file may cause incorrect behavior
and will be lost if the state is redeployed.
</auto-generated>
-->
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.3/phpunit.xsd"
displayDetailsOnTestsThatTriggerDeprecations="true"
displayDetailsOnTestsThatTriggerErrors="true"
displayDetailsOnTestsThatTriggerWarnings="true"
displayDetailsOnTestsThatTriggerNotices="true"
bootstrap="vendor/autoload.php"
cacheDirectory=".phpunit.cache"
stopOnFailure="false">
<php>
<ini name="display_errors" value="On" />
<ini name="display_startup_errors" value="On" />
<ini name="error_reporting" value="On" />
</php>
<testsuites>
<testsuite name="Unit tests for keruald/cache">
<directory suffix="Test.php">./cache/tests</directory>
</testsuite>
<testsuite name="Unit tests for keruald/commands">
<directory suffix="Test.php">./commands/tests</directory>
</testsuite>
<testsuite name="Unit tests for keruald/database">
<directory suffix="Test.php">./database/tests</directory>
</testsuite>
<testsuite name="Unit tests for keruald/github">
<directory suffix="Test.php">./github/tests</directory>
</testsuite>
<testsuite name="Unit tests for keruald/omnitools">
<directory suffix="Test.php">./omnitools/tests</directory>
</testsuite>
<testsuite name="Unit tests for keruald/report">
<directory suffix="Test.php">./report/tests</directory>
</testsuite>
+ <testsuite name="Unit tests for keruald/yaml">
+ <directory suffix="Test.php">./yaml/tests</directory>
+ </testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">cache/src/</directory>
<directory suffix=".php">commands/src/</directory>
<directory suffix=".php">database/src/</directory>
<directory suffix=".php">github/src/</directory>
<directory suffix=".php">omnitools/src/</directory>
<directory suffix=".php">report/src/</directory>
+ <directory suffix=".php">yaml/src/</directory>
</include>
</source>
</phpunit>
diff --git a/yaml/composer.json b/yaml/composer.json
new file mode 100644
index 0000000..61bb0f2
--- /dev/null
+++ b/yaml/composer.json
@@ -0,0 +1,41 @@
+{
+ "name": "keruald/yaml",
+ "description": "YAML parser",
+ "license": "BSD-2-Clause",
+ "repositories": [
+ {
+ "type": "vcs",
+ "url": "https://github.com/keruald/yaml"
+ }
+ ],
+ "authors": [
+ {
+ "name": "Sébastien Santoro",
+ "email": "dereckson@espace-win.org"
+ }
+ ],
+ "keywords": [
+ "keruald",
+ "YAML"
+ ],
+ "support": {
+ "irc": "irc://irc.libera.chat/nasqueron",
+ "issues": "https://devcentral.nasqueron.org"
+ },
+ "require": {
+ "keruald/omnitools": "^0.16.0",
+ "php": ">=8.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "12.*"
+ },
+ "autoload": {
+ "psr-4": {
+ "Keruald\\Yaml\\": "src/",
+ "Keruald\\Yaml\\Tests\\": "tests/"
+ }
+ },
+ "scripts": {
+ "test": "phpunit tests"
+ }
+}
diff --git a/yaml/src/Parser.php b/yaml/src/Parser.php
new file mode 100644
index 0000000..c3ccb65
--- /dev/null
+++ b/yaml/src/Parser.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Keruald\Yaml;
+
+use Symfony\Component\Yaml\Tag\TaggedValue;
+use Symfony\Component\Yaml\Yaml;
+
+use Keruald\Yaml\Tags\Tag;
+
+use InvalidArgumentException;
+
+class Parser {
+
+ /**
+ * @var array<string, Tag>
+ */
+ private array $tags = [];
+
+ ///
+ /// Configure
+ ///
+
+ public function withTagClass (string $type) : self {
+ $tag = new $type();
+
+ return $this->withTag($tag);
+ }
+
+ public function withTag (Tag $tag) : self {
+ $tag->register($this->tags);
+
+ return $this;
+ }
+
+ ///
+ /// Parse
+ ///
+
+ /**
+ * @throws InvalidArgumentException if a tag is not defined at parser level
+ */
+ public function parse (string $expression) : mixed {
+ $flags = Yaml::PARSE_CUSTOM_TAGS;
+ $parsed = Yaml::parse($expression, $flags);
+
+ return $this->resolve($parsed);
+ }
+
+ /**
+ * @throws InvalidArgumentException if the file is not found
+ * @throws InvalidArgumentException if a tag is not defined at parser level
+ */
+ public function parseFile (string $filename) : mixed {
+ if (!file_exists($filename)) {
+ throw new InvalidArgumentException("File not found: $filename");
+ }
+
+ $flags = Yaml::PARSE_CUSTOM_TAGS;
+ $parsed = Yaml::parseFile($filename, $flags);
+
+ return $this->resolve($parsed);
+ }
+
+ private function resolve (mixed $data) {
+ if ($data instanceof TaggedValue) {
+ $tag = $data->getTag();
+
+ if (!array_key_exists($tag, $this->tags)) {
+ throw new InvalidArgumentException("Tag not found: $tag");
+ }
+
+ $tagHandler = $this->tags[$tag];
+
+ return $tagHandler->handle($data->getValue());
+ }
+
+ if (is_array($data)) {
+ foreach ($data as $key => $value) {
+ $data[$key] = $this->resolve($value);
+ }
+ }
+
+ return $data;
+ }
+
+}
diff --git a/yaml/src/Tags/EnvTag.php b/yaml/src/Tags/EnvTag.php
new file mode 100644
index 0000000..1955067
--- /dev/null
+++ b/yaml/src/Tags/EnvTag.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Keruald\Yaml\Tags;
+
+use Keruald\OmniTools\OS\Environment;
+
+/**
+ * Represents an environment variable
+ */
+class EnvTag extends Tag {
+
+ public function getPrimaryTag () : string {
+ return "tag:keruald.nasqueron.org,2025:env";
+ }
+
+ public function getPrivateTag () : string {
+ return "env";
+ }
+
+ /**
+ * @throws \InvalidArgumentException when the variable does not exist.
+ */
+ public function handle (mixed $data) : string {
+ $key = (string)$data;
+
+ return Environment::get($key);
+ }
+
+}
diff --git a/yaml/src/Tags/Tag.php b/yaml/src/Tags/Tag.php
new file mode 100644
index 0000000..99e7493
--- /dev/null
+++ b/yaml/src/Tags/Tag.php
@@ -0,0 +1,18 @@
+<?php
+
+namespace Keruald\Yaml\Tags;
+
+abstract class Tag {
+
+ public abstract function getPrimaryTag () : string;
+
+ public abstract function getPrivateTag () : string;
+
+ public abstract function handle (mixed $data) : mixed;
+
+ public function register (&$tags) : void {
+ $tags[$this->getPrimaryTag()] = $this;
+ $tags[$this->getPrivateTag()] = $this;
+ }
+
+}
diff --git a/yaml/tests/ParserTest.php b/yaml/tests/ParserTest.php
new file mode 100644
index 0000000..06f2002
--- /dev/null
+++ b/yaml/tests/ParserTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Keruald\Yaml\Tests;
+
+use Keruald\Yaml\Parser;
+
+use PHPUnit\Framework\TestCase;
+
+use InvalidArgumentException;
+
+class ParserTest extends TestCase {
+
+ private Parser $parser;
+
+ protected function setUp () : void {
+ $this->parser = new Parser;
+ }
+
+ public function testParse () {
+ $this->assertEquals(666, $this->parser->parse("666"));
+ $this->assertEquals("", $this->parser->parse(""));
+ }
+
+ public function testParseUnknownTag () {
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage("Tag not found: foo");
+
+ $this->parser->parse("!foo 4");
+ }
+
+ public function testParseFile () {
+ $expected = [
+ "example" => [
+ "foo" => "bar",
+ "skills" => [
+ "quux",
+ "baz",
+ ],
+ ],
+ ];
+
+ $actual = $this->parser->parseFile(__DIR__ . "/data/example.yaml");
+
+ $this->assertEquals($expected, $actual);
+ }
+
+}
diff --git a/yaml/tests/Tags/EnvTagTest.php b/yaml/tests/Tags/EnvTagTest.php
new file mode 100644
index 0000000..52d51d9
--- /dev/null
+++ b/yaml/tests/Tags/EnvTagTest.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Keruald\Yaml\Tests\Tags;
+
+use Keruald\Yaml\Parser;
+use Keruald\Yaml\Tags\EnvTag;
+use PHPUnit\Framework\TestCase;
+
+class EnvTagTest extends TestCase {
+
+ private EnvTag $tag;
+
+ protected function setUp () : void {
+ $this->tag = new EnvTag();
+
+ $_ENV["ORBEON_DB_HOST"] = "localhost";
+ $_ENV["ORBEON_DB_PORT"] = "5432";
+
+ $_SERVER["ORBEON_DB_NAME"] = "orbeon_db";
+ }
+
+ public function testHandle () {
+ $this->assertEquals("localhost", $this->tag->handle("ORBEON_DB_HOST"));
+ }
+
+ public function testHandleWithServerVariable () {
+ $this->assertEquals("orbeon_db", $this->tag->handle("ORBEON_DB_NAME"));
+ }
+
+ public function testHandleWithMissingVariable () {
+ $this->assertEquals("5432", $this->tag->handle("ORBEON_DB_PORT"));
+ }
+
+ ///
+ /// Integration
+ ///
+
+ public function testFullParse () {
+ $yamlContent = <<<YAML
+database:
+ host: !env ORBEON_DB_HOST
+ port: !env ORBEON_DB_PORT
+ name: !env ORBEON_DB_NAME
+ pool_size: 10
+YAML;
+
+ $expected = [
+ "database" => [
+ "host" => "localhost",
+ "port" => "5432",
+ "name" => "orbeon_db",
+ "pool_size" => 10,
+ ],
+ ];
+
+ $parser = new Parser();
+ $parser->withTagClass(EnvTag::class);
+ $actual = $parser->parse($yamlContent);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+}
diff --git a/yaml/tests/Tags/TagTest.php b/yaml/tests/Tags/TagTest.php
new file mode 100644
index 0000000..7e614e4
--- /dev/null
+++ b/yaml/tests/Tags/TagTest.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Keruald\Yaml\Tests\Tags;
+
+use Keruald\Yaml\Tags\Tag;
+use PHPUnit\Framework\TestCase;
+
+class TagTest extends TestCase {
+
+ public static function provideTag () : Tag {
+ return new class () extends Tag {
+ public function getPrimaryTag () : string {
+ return "tag:example.com,2000:test";
+ }
+
+ public function getPrivateTag () : string {
+ return "test";
+ }
+
+ public function handle (mixed $data) : string {
+ return "";
+ }
+ };
+ }
+
+ public function testRegister () {
+ $handlers = [];
+
+ $tag = self::provideTag();
+ $tag->register($handlers);
+
+ $this->assertArrayHasKey("tag:example.com,2000:test", $handlers);
+ $this->assertArrayHasKey("test", $handlers);
+ }
+
+}
diff --git a/yaml/tests/data/example.yaml b/yaml/tests/data/example.yaml
new file mode 100644
index 0000000..f8d8bbb
--- /dev/null
+++ b/yaml/tests/data/example.yaml
@@ -0,0 +1,5 @@
+example:
+ foo: bar
+ skills:
+ - quux
+ - baz

File Metadata

Mime Type
text/x-diff
Expires
Fri, Oct 31, 02:18 (21 h, 54 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3116761
Default Alt Text
(17 KB)

Event Timeline