Page MenuHomeDevCentral

Add more useful high-order functions
Closed, ResolvedPublic

Description

From my experiences with high-order functions in Rust, I'd like the following methods to generate composer.json blocks in T1680 from packages metadata.

We've some metadata we convert into PHP arrays (packages as a vector, packages_namespaces as a hashmap):

metadata.yml
packages:
    - commands
    - database
    - omnitools
    - report

packages_namespaces:
    commands: Keruald\Commands
    database: Keruald\Database
    omnitools: Keruald\OmniTools
    report: Keruald\Reporting

Map key and values

The map method doesn't allow to map values into keys. A mapValuesAndKeys method would allow to build arrays like:

composer.json
{
    "replace": {
        "keruald/commands": "self.version",
        "keruald/database": "self.version",
        "keruald/omnitools": "self.version",
        "keruald/report": "self.version"
    }, ...
}

Note the values from packages become here keys.

We can accept two callbacks arguments formats, so we can use ($value) for vectors and ($key, $value) for hashmaps.
Both will return an array with two elements [key, value].

So we can do:

_utils/templates/generate-compose-json.php
function getReplace(array $packages) : array {
    return HashMap::from($packages)
                  ->mapValuesAndKeys(fn($v) => ["keruald/$v", "self.version"])
                  ->toArray();
}

Flatmap

Here, we need to add two elements for each value of package_namespaces, one for tests, one for src:

composer.json
{
    "autoload": {
        "psr-4": {
            "Keruald\\Commands\\": "commands/src/",
            "Keruald\\Commands\\Tests\\": "commands/tests/",
            "Keruald\\Database\\": "database/src/",
            "Keruald\\Database\\Tests\\": "database/tests/",
            "Keruald\\OmniTools\\": "omnitools/src/",
            "Keruald\\OmniTools\\Tests\\": "omnitools/tests/",
            "Keruald\\Reporting\\": "report/src/",
            "Keruald\\Reporting\\Tests\\": "report/tests/"
        }
    }, ...
}

A regular map function will work, with a flat map variant.

The concept of the flat map is we return an iterable, and the key/values are added to the mapped hashmap:

_utils/templates/generate-compose-json.php
function getAutoload(array $packages_namespaces) : array {
    return [
        "psr-4" => HashMap::from($packages_namespaces)
                          ->flatMap(fn($package, $ns) => [
                              $ns . '\\'        => $package . "/src/",
                              $ns . '\\Tests\\' => $package . "/tests/",
                          ])
                          ->toArray()                                                                                                                                                                                
    ];                                                                                                                                                                         
}