diff --git a/CHANGES.md b/CHANGES.md index b4fd91d..047411f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,18 @@ +## Release 0.5.1p74 du 12/05/2025-15:28 + +* `d274a65` améliorer status +* `2e026da` l'option -ww affiche la différence +* `8e7e59c` intégrer les méthodes de Cursor et KeyAccess +* `a587f99` installer completion pour pman +* `cc56dc9` renommer pdev en pmer +* `0a73ba3` améliorer ergonomie de p +* `aef0533` ajout str::split +* `87e262c` ajout cl::delv +* `a371a68` maj doc +* `d706122` ajout infos release + +## Release 0.5.0p82 du 30/04/2025-04:33 + ## Release 0.5.0p74 du 30/04/2025-04:31 * `3ee92ef` ajout str::replace diff --git a/README.md b/README.md new file mode 100644 index 0000000..eee5634 --- /dev/null +++ b/README.md @@ -0,0 +1,28 @@ +# nulib + + +## Release + +Exemple: release de la version 0.6.0 +~~~sh +version=0.6.0 + +## branche dev74 +git checkout dev74 + +prel -v$version + +_merge82 + +## branche dev82 +git checkout dev82 + +prel -C + +commit="$(git log --grep="Init changelog . version ${version}p82" --format=%H)" +git checkout dev74 +git cherry-pick "$commit" +pp -a +~~~ + +-*- coding: utf-8 mode: markdown -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8:noeol:binary \ No newline at end of file diff --git a/VERSION.txt b/VERSION.txt index 8f0916f..4b9fcbe 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1 +1 @@ -0.5.0 +0.5.1 diff --git a/bash/src/pman.sh b/bash/src/pman.sh index f2f5d3d..4a2d928 100644 --- a/bash/src/pman.sh +++ b/bash/src/pman.sh @@ -84,6 +84,12 @@ function _list_commits() { _filter_rel } +function _show_diff() { + local source="${1:-$SrcBranch}" dest="${2:-$DestBranch}" mergebase + setx mergebase=git merge-base "$dest" "$source" + git diff ${_sd_COLOR:+--color=$_sd_COLOR} "$mergebase..$source" +} + function _scripte() { echo >>"$script" echo "$comment$(qvals "$@")" >>"$script" diff --git a/bin/_merge82 b/bin/_merge82 index 8a4c2bc..e372fb8 100755 --- a/bin/_merge82 +++ b/bin/_merge82 @@ -1,4 +1,4 @@ #!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 -exec "$(dirname -- "$0")/pdev" --tech-merge -Bdev82 dev74 -a "git checkout dev74" "$@" +exec "$(dirname -- "$0")/pmer" --tech-merge -Bdev82 dev74 -a "git checkout dev74" "$@" diff --git a/bin/p b/bin/p index aedfdfc..1c52283 100755 --- a/bin/p +++ b/bin/p @@ -29,6 +29,9 @@ function git_statuses() { done } +# sans arguments, il y a un comportement spécial +[ $# -eq 0 ] && NoArgs=1 || NoArgs= + chdir= all= composer= @@ -43,6 +46,13 @@ Si l'option -a est utilisée, ce script accepte comme arguments une liste de pat ) parse_args "$@"; set -- "${args[@]}" +if [ -n "$NoArgs" ]; then + # si aucun argument n'est spécifié et si on n'est pas dans un projet git, + # afficher le status de tous les sous répertoires + setx toplevel=git_get_toplevel + [ -z "$toplevel" ] && all=1 +fi + setx OrigCwd=pwd if [ -n "$chdir" ]; then cd "$chdir" || die diff --git a/bin/pman b/bin/pman index 80a1021..123f193 100755 --- a/bin/pman +++ b/bin/pman @@ -78,7 +78,7 @@ function init_repo_action() { } function init_config_action() { - local -a push_branches; config + local -a push_branches; local config [ -f .pman.conf -a -z "$ForceCreate" ] && die "La configuration pman a déjà été initialisée" diff --git a/bin/pdev b/bin/pmer similarity index 95% rename from bin/pdev rename to bin/pmer index 03e827c..9a7daf8 100755 --- a/bin/pdev +++ b/bin/pmer @@ -11,8 +11,19 @@ function show_action() { local commits setx commits=_list_commits if [ -n "$commits" ]; then - einfo "Commits à fusionner $SrcBranch --> $DestBranch" - eecho "$commits" + if [ $ShowLevel -ge 2 ]; then + { + echo "\ +# Commits à fusionner $SrcBranch --> $DestBranch + +$commits +" + _sd_COLOR=always _show_diff + } | less -eRF + else + einfo "Commits à fusionner $SrcBranch --> $DestBranch" + eecho "$commits" + fi fi } @@ -148,6 +159,7 @@ ConfigFile= _Fake= _KeepScript= action=merge +ShowLevel=0 TechMerge= SquashMsg= [ -z "$PMAN_NO_PUSH" ] && Push=1 || Push= @@ -158,6 +170,7 @@ args=( " [source] CONFIGURATION + Le fichier .pman.conf contient la configuration des branches. Les variables supplémentaires suivantes peuvent être définies: BEFORE_MERGE_ @@ -176,7 +189,7 @@ fichier de configuration des branches. cette option est prioritaire sur --config par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe" --fake _Fake=1 "++option non documentée" --keep-script _KeepScript=1 "++option non documentée" - -w,--show action=show "\ + -w,--show '$action=show; inc@ ShowLevel' "\ lister les modifications qui seraient fusionnées dans la branche destination" -b,--rebase action=rebase "\ lancer git rebase -i sur la branche source. cela permet de réordonner les diff --git a/bin/prel b/bin/prel index e1af6eb..2ec3a31 100755 --- a/bin/prel +++ b/bin/prel @@ -11,8 +11,19 @@ function show_action() { local commits setx commits=_list_commits if [ -n "$commits" ]; then - einfo "Commits à fusionner $SrcBranch --> $DestBranch" - eecho "$commits" + if [ $ShowLevel -ge 2 ]; then + { + echo "\ +# Commits à fusionner $SrcBranch --> $DestBranch + +$commits +" + _sd_COLOR=always _show_diff + } | less -eRF + else + einfo "Commits à fusionner $SrcBranch --> $DestBranch" + eecho "$commits" + fi fi } @@ -194,6 +205,7 @@ ConfigFile= _Fake= _KeepScript= action=release +ShowLevel=0 [ -z "$PMAN_NO_MERGE" ] && Merge=1 || Merge= [ -z "$PMAN_NO_PUSH" ] && Push=1 || Push= Version= @@ -222,7 +234,7 @@ fichier de configuration des branches. cette option est prioritaire sur --config par défaut, utiliser le fichier .pman.conf dans le répertoire du dépôt s'il existe" --fake _Fake=1 "++option non documentée" --keep-script _KeepScript=1 "++option non documentée" - -w,--show action=show "\ + -w,--show '$action=show; inc@ ShowLevel' "\ lister les modifications qui seraient intégrées dans la release" --release action=release "++\ créer la release. diff --git a/bin/templ.sql b/bin/templ.sql index fb22c73..14c071c 100755 --- a/bin/templ.sql +++ b/bin/templ.sql @@ -29,7 +29,7 @@ for file in "$@"; do estep "Création de $file" cat >"$file" < + * $array = ["first", "second"] + * A::ensure_assoc($array, ["a", "b"]); + * // returns ["a" => "first", "b" => "second"] + * + */ + static final function ensure_assoc(?array &$array, array $keys, ?array $params=null): void { + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + $index = 0; + foreach ($keys as $key) { + if ($prefix !== null || $suffix !== null) { + $destKey = "$prefix$key$suffix"; + } else { + # préserver les clés numériques + $destKey = $key; + } + if ($array !== null && array_key_exists($destKey, $array)) continue; + while (in_array($index, $keys, true)) { + $index++; + } + if ($array !== null && array_key_exists($index, $array)) { + $array[$destKey] = $array[$index]; + unset($array[$index]); + $index++; + } + } + } + + /** + * s'assurer que $array contient toutes les clés de $defaults, avec la valeur + * par défaut le cas échéant + * + * $missings est un tableau indiquant des valeurs qui si elles sont dans + * $array, signifie que la clé correspondante doit être considérée comme + * inexistante (et donc remplacée par la valeur de $defaults) + */ + static final function ensure_keys(?array &$array, array $defaults, ?array $missings=null, ?array $params=null): void { + $keys = array_keys($defaults); + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + foreach ($keys as $key) { + $destKey = "$prefix$key$suffix"; + $haveMissing = $missings !== null && array_key_exists($key, $missings); + if ($array === null || !array_key_exists($destKey, $array)) { + $array[$destKey] = $defaults[$key]; + } elseif ($haveMissing && $array[$destKey] === $missings[$key]) { + $array[$destKey] = $defaults[$key]; + } + } + } + + /** + * supprimer dans $array les clés dont les valeurs correspondent au tableau + * $missings + */ + static final function delete_missings(?array &$array, array $missings, ?array $params=null): void { + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + foreach ($missings as $key => $missing) { + $destKey = "$prefix$key$suffix"; + if (array_key_exists($destKey, $array) && $array[$destKey] === $missing) { + unset($array[$destKey]); + } + } + } + + /** + * s'assurer que les clés dans $array sont dans le même ordre que dans $keys + * + * les clés supplémentaires sont poussées à la fin du tableau + */ + static final function ensure_order(?array &$array, array $keys, ?array $params=null): void { + if ($array === null) return; + + $prefix = $params["key_prefix"] ?? null; + $suffix = $params["key_suffix"] ?? null; + if ($prefix !== null || $suffix !== null) { + foreach ($keys as &$key) { + $key = "$prefix$key$suffix"; + }; unset($key); + } + + $destKeys = array_keys($array); + $keyCount = count($keys); + if (array_slice($destKeys, 0, $keyCount) === $keys) { + # si le tableau a déjà les bonnes clés dans le bon ordre, rien à faire + return; + } + + $ordered = []; + foreach ($keys as $key) { + if (array_key_exists($key, $array)) { + $ordered[$key] = $array[$key]; + unset($array[$key]); + } + } + $preserveKeys = $params["preserve_keys"] ?? false; + if ($preserveKeys) $array = cl::merge2($ordered, $array); + else $array = array_merge($ordered, $array); + } } diff --git a/php/src/app/RunFile.php b/php/src/app/RunFile.php index d76beb9..bd34357 100644 --- a/php/src/app/RunFile.php +++ b/php/src/app/RunFile.php @@ -460,7 +460,7 @@ class RunFile { $exitcode = null; $message = [ "status" => "$desc: EN COURS pid $data[pid]", - "started" => "Démarrée depuis $dateStart ($sinceStart)", + "started" => "Démarrée $sinceStart le $dateStart", "action" => $action, ]; } elseif ($this->isStopped($data)) { @@ -471,8 +471,9 @@ class RunFile { elseif ($exitcode === 0) $type = "success"; else $type = "danger"; $message = [ - "status" => "$desc: TERMINEE$duration", + "status" => "$desc: TERMINEE", "stopped" => "Arrêtée $sinceStop le $dateStop", + "duration" => $duration, "result" => $result, ]; } else { diff --git a/php/src/cl.php b/php/src/cl.php index 4978afe..2c2bac1 100644 --- a/php/src/cl.php +++ b/php/src/cl.php @@ -60,6 +60,35 @@ class cl { return $default; } + /** + * retourner la valeur à l'index $index, ou $default si le tableau est null + * ou vide, ou si l'index n'existe pas + * + * ici, l'index est le rang de la clé: 0 pour la première clé du tableau, 1 + * pour la deuxième, etc. + * + * si $index est négatif, il est compté à partir de la fin du tableau + */ + static final function nth(?iterable $iterable, int $index, $default=null) { + if ($iterable === null) return $default; + if ($index < 0 && !is_array($iterable)) { + $iterable = iterator_to_array($iterable, false); + } + if (is_array($iterable)) { + $keys = array_keys($iterable); + $count = count($keys); + while ($index < 0) $index += $count; + $key = $keys[$index] ?? null; + if ($key === null) return $default; + return $iterable[$key]; + } + foreach ($iterable as $value) { + if ($index === 0) return $value; + $index--; + } + return $default; + } + /** * retourner la dernière valeur de $array ou $default si le tableau est null * ou vide @@ -212,7 +241,7 @@ class cl { } /** - * obtenir la liste des clés finalement obtenues après l'appel à + * obtenir la liste des clés qui seraient finalement obtenues après l'appel à * {@link self::select()} avec le mapping spécifié */ static final function selected_keys(?array $mappings): array { @@ -255,7 +284,7 @@ class cl { * $includes qui ne sont pas mentionnées dans $excludes. * * - si $includes===null && $excludes===null, retourner le tableau inchangé - * - si $includes vaut null, prendre toutes les clés + * - si $includes vaut null, c'est comme si toutes les clés étaient incluses * */ static final function xselect($array, ?array $includes, ?array $excludes=null): ?array { @@ -302,6 +331,27 @@ class cl { } } + /** + * si $array est un array ou une instance de ArrayAccess&Traversable, + * supprimer le premier élément dont la valeur est $value + * + * @param array|ArrayAccess $array + */ + static final function delv(&$array, $value, bool $strict=false): void { + if (is_array($array)) { + $key = array_search($value, $array, $strict); + if ($key !== false) unset($array[$key]); + } elseif ($array instanceof ArrayAccess && $array instanceof Traversable) { + $found = false; + foreach ($array as $key => $val) { + if ($strict) $found = $val === $value; + else $found = $val == $value; + if ($found) break; + } + if ($found) $array->offsetUnset($key); + } + } + /** retourner le nombre d'éléments de $array */ static final function count(?array $array): int { return $array !== null? count($array): 0; @@ -348,15 +398,86 @@ class cl { ############################################################################# - static final function map($func, ?iterable $array): array { - $result = []; - if ($array !== null) { - $func = func::with($func); - foreach ($array as $key => $value) { - $result[$key] = $func->invoke([$value, $key]); + /** + * tester si $array satisfait les conditions de $filter + * - $filter est un scalaire, le transformer en [$filter] + * - sinon $filter doit être un tableau de scalaires + * + * les règles des conditions sont les suivantes: + * - une valeur séquentielle $key est équivalente à la valeur associative + * $key => true + * - une valeur associative $key => bool indique que la clé correspondante ne + * doit pas (resp. doit) exister selon que bool vaut false (resp. true) + * - une valeur associative $key => $value indique que la clé correspondante + * doit exiter avec la valeur spécifiée + */ + static final function filter(?array $array, $filter): bool { + if ($filter === null) return false; + if (!is_array($filter)) $filter = [$filter]; + if (!$filter) return false; + + $index = 0; + foreach ($filter as $key => $value) { + if ($key === $index) { + $index++; + if ($array === null) return false; + if (!array_key_exists($value, $array)) return false; + } elseif (is_bool($value)) { + if ($value) { + if ($array === null || !array_key_exists($key, $array)) return false; + } else { + if ($array !== null && array_key_exists($key, $array)) return false; + } + } else { + if ($array === null) return false; + if (!array_key_exists($key, $array)) return false; + if ($array[$key] !== $value) return false; } } - return $result; + return true; + } + + /** + * mapper le tableau source $array selon les règles suivantes illustrées dans + * l'exemple suivant: + * si + * $map = ["a", "b" => "x", "c" => function() { return "y"; }, "d" => null] + * alors retourner le tableau + * ["a" => $array["a"], "b" => $array["x"], "c" => "y", "d" => null] + * + * si une fonction est utilisée, sa signature est + * function(mixed $value, string|int $key, ?array $array) + */ + static function map(?array $array, ?array $map): ?array { + if ($map === null) return $array; + $index = 0; + $mapped = []; + foreach ($map as $key => $value) { + if ($key === $index) { + $index++; + if ($value === null) $mapped[] = null; + else $mapped[$value] = cl::get($array, $value); + } elseif (is_callable($value)) { + $func = func::with($value); + $value = cl::get($array, $key); + $mapped[$key] = $func->invoke([$value, $key, $array]); + } else { + if ($value === null) $mapped[$key] = null; + else $mapped[$key] = cl::get($array, $value); + } + } + return $mapped; + } + + static final function mapf(?iterable $items, $func): array { + $mapped = []; + if ($items !== null) { + $func = func::with($func); + foreach ($items as $key => $item) { + $mapped[$key] = $func->invoke([$item, $key, $items]); + } + } + return $mapped; } ############################################################################# diff --git a/php/src/db/CapacitorStorage.php b/php/src/db/CapacitorStorage.php index e7ff6af..ba00c07 100644 --- a/php/src/db/CapacitorStorage.php +++ b/php/src/db/CapacitorStorage.php @@ -677,7 +677,7 @@ abstract class CapacitorStorage { function _delete(CapacitorChannel $channel, $filter, $func, ?array $args): int { $this->_create($channel); if ($func === null) $func = CapacitorChannel::onDelete; - $onEach = func::with($func)->bind($channel); + $onDelete = func::with($func)->bind($channel); $db = $this->db(); # si on est déjà dans une transaction, désactiver la gestion des transactions $manageTransactions = $channel->isManageTransactions() && !$db->inTransaction(); @@ -693,8 +693,8 @@ abstract class CapacitorStorage { $all = $this->_allCached("delete", $channel, $filter); foreach ($all as $values) { $rowIds = $this->getRowIds($channel, $values); - $delete = boolval($onEach->invoke([$values["item"], $values, ...$args])); - if ($delete) { + $shouldDelete = boolval($onDelete->invoke([$values["item"], $values, ...$args])); + if ($shouldDelete) { $db->exec([ "delete", "from" => $tableName, diff --git a/php/src/db/_private/_select.php b/php/src/db/_private/_select.php index 80b0460..1e7f1d0 100644 --- a/php/src/db/_private/_select.php +++ b/php/src/db/_private/_select.php @@ -23,7 +23,8 @@ class _select extends _common { return preg_match("/^select\b/i", $sql); } - private static function add_prefix(string $col, ?string $prefix): string { + private static function add_prefix(?string $col, ?string $prefix): string { + $col ??= "null"; if ($prefix === null) return $col; if (strpos($col, ".") !== false) return $col; return "$prefix$col"; diff --git a/php/src/db/pgsql/Pgsql.php b/php/src/db/pgsql/Pgsql.php index dbcbedf..efc84a4 100644 --- a/php/src/db/pgsql/Pgsql.php +++ b/php/src/db/pgsql/Pgsql.php @@ -81,6 +81,12 @@ class Pgsql implements IDatabase { #if ($tmp !== null) $dbconn = $tmp; #else $dbconn = ["" => $dbconn]; } + unset($dbconn["type"]); + $name = $dbconn["name"] ?? null; + if ($name !== null) { + $dbconn[""] = $name; + unset($dbconn["name"]); + } $params["dbconn"] = $dbconn; } # dbconn diff --git a/php/src/db/sqlite/SqliteStorage.php b/php/src/db/sqlite/SqliteStorage.php index 4621cb2..7495b46 100644 --- a/php/src/db/sqlite/SqliteStorage.php +++ b/php/src/db/sqlite/SqliteStorage.php @@ -40,12 +40,20 @@ class SqliteStorage extends CapacitorStorage { return new _sqliteMigration($migrations, $channel->getName()); } - function channelExists(string $name): bool { - return null !== $this->db->get([ - "select name", + function channelExists(string $name, ?array &$row=null): bool { + $row = $this->db->one([ + "select", "from" => static::CHANNELS_TABLE, "where" => ["name" => $name], ]); + return $row !== null; + } + + function getChannels(): iterable { + return $this->db->all([ + "select", + "from" => static::CHANNELS_TABLE, + ]); } protected function _addToChannelsSql(CapacitorChannel $channel): array { diff --git a/php/src/php/func.php b/php/src/php/func.php index 675d359..f2d2883 100644 --- a/php/src/php/func.php +++ b/php/src/php/func.php @@ -59,9 +59,10 @@ class func { * @param bool $strict vérifier l'inexistence de la classe et l'existence de * la fonction (ne pas uniquement faire une vérification syntaxique) */ - static function verifix_function(&$func, bool $strict=true, ?string &$reason=null): bool { + static function verifix_function(&$func, ?array &$args=null, bool $strict=true, ?string &$reason=null): bool { if ($strict) $reason = null; if ($func instanceof ReflectionFunction) return true; + $rargs = null; if (is_string($func)) { $c = false; $f = $func; @@ -70,6 +71,7 @@ class func { $c = $func[0]; if (!array_key_exists(1, $func)) return false; $f = $func[1]; + $rargs = array_slice($func, 2); } else { return false; } @@ -90,6 +92,7 @@ class func { } } $func = [false, $f]; + if ($rargs) $args = cl::merge($rargs, $args); return true; } @@ -98,7 +101,7 @@ class func { * {@link self::verifix_function()} */ static function is_function($func, bool $strict=true, ?string &$reason=null): bool { - return self::verifix_function($func, $strict, $reason); + return self::verifix_function($func, $args, $strict, $reason); } ############################################################################# @@ -115,9 +118,10 @@ class func { * @param bool $strict vérifier l'existence de la classe (ne pas uniquement * faire une vérification syntaxique) */ - static function verifix_class(&$func, bool $strict=true, ?string &$reason=null): bool { + static function verifix_class(&$func, ?array &$args=null, bool $strict=true, ?string &$reason=null): bool { if ($strict) $reason = null; if ($func instanceof ReflectionClass) return true; + $rargs = null; if (is_string($func)) { $c = $func; $f = false; @@ -126,6 +130,7 @@ class func { $c = $func[0]; if (!array_key_exists(1, $func)) return false; $f = $func[1]; + $rargs = array_slice($func, 2); } else { return false; } @@ -139,6 +144,7 @@ class func { return false; } $func = [$c, false]; + if ($rargs) $args = cl::merge($rargs, $args); return true; } @@ -147,7 +153,7 @@ class func { * {@link self::verifix_class()} */ static function is_class($func, bool $strict=true, ?string &$reason=null): bool { - return self::verifix_class($func, $strict, $reason); + return self::verifix_class($func, $args, $strict, $reason); } ############################################################################# @@ -198,14 +204,16 @@ class func { * liée à une classe avant d'être utilisée * * @param bool $strict vérifier l'existence de la classe et de la méthode si + * @param array|null &$args * la méthode est liée (ne pas uniquement faire une vérification syntaxique) */ - static function verifix_static(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { + static function verifix_static(&$func, ?array &$args = null, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { if ($strict) $reason = null; if ($func instanceof ReflectionMethod) { $bound = false; return true; } + $rargs = null; if (is_string($func)) { if (!self::_parse_c_static($func, $c, $f, $bound)) return false; $cf = [$c, $f]; @@ -252,6 +260,7 @@ class func { self::_parse_static($f); } $cf[1] = $f; + $rargs = array_slice($func, 2); } else { return false; } @@ -274,6 +283,7 @@ class func { } } $func = $cf; + if ($rargs) $args = cl::merge($rargs, $args); return true; } @@ -282,7 +292,7 @@ class func { * {@link self::verifix_static()} */ static function is_static($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { - return self::verifix_static($func, $strict, $bound, $reason); + return self::verifix_static($func, $args, $strict, $bound, $reason); } ############################################################################# @@ -335,12 +345,13 @@ class func { * @param bool $strict vérifier l'existence de la classe et de la méthode si * la méthode est liée (ne pas uniquement faire une vérification syntaxique) */ - static function verifix_method(&$func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { + static function verifix_method(&$func, ?array &$args=null, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { if ($strict) $reason = null; if ($func instanceof ReflectionMethod) { $bound = false; return true; } + $rargs = null; if (is_string($func)) { if (!self::_parse_c_method($func, $c, $f, $bound)) return false; $cf = [$c, $f]; @@ -388,6 +399,7 @@ class func { self::_parse_method($f); } $cf[1] = $f; + $rargs = array_slice($func, 2); } else { return false; } @@ -410,6 +422,7 @@ class func { } } $func = $cf; + if ($rargs) $args = cl::merge($rargs, $args); return true; } @@ -418,7 +431,7 @@ class func { * {@link self::verifix_method()} */ static function is_method($func, bool $strict=true, ?bool &$bound=null, ?string &$reason=null): bool { - return self::verifix_method($func, $strict, $bound, $reason); + return self::verifix_method($func, $args, $strict, $bound, $reason); } ############################################################################# @@ -452,13 +465,13 @@ class func { return new self(self::TYPE_METHOD, $func, $args, false); } } - if (self::verifix_function($func, $strict, $reason)) { + if (self::verifix_function($func, $args, $strict, $reason)) { return new self(self::TYPE_FUNCTION, $func, $args, false, $reason); - } elseif (self::verifix_class($func, $strict, $reason)) { + } elseif (self::verifix_class($func, $args, $strict, $reason)) { return new self(self::TYPE_CLASS, $func, $args, false, $reason); - } elseif (self::verifix_method($func, $strict, $bound, $reason)) { + } elseif (self::verifix_method($func, $args, $strict, $bound, $reason)) { return new self(self::TYPE_METHOD, $func, $args, $bound, $reason); - } elseif (self::verifix_static($func, $strict, $bound, $reason)) { + } elseif (self::verifix_static($func, $args, $strict, $bound, $reason)) { return new self(self::TYPE_STATIC, $func, $args, $bound, $reason); } return null; diff --git a/php/src/str.php b/php/src/str.php index 347726b..2dc71ba 100644 --- a/php/src/str.php +++ b/php/src/str.php @@ -328,6 +328,22 @@ class str { else return preg_split('/\s+/', $s); } + /** + * découper la chaine: + * - avec preg_split si $sep est une expression régulière /re/ + * - avec explode sinon + */ + static final function split(string $sep, ?string $s): ?array { + if ($s === null) return null; + if ($sep === "") { + return [$s]; + } elseif (substr($sep, 0, 1) === "/") { + return preg_split($sep, $s); + } else { + return explode($sep, $s); + } + } + /** * joindre les éléments de $parts comme avec implode(), mais en ignorant les * valeurs fausses (cela n'inclue pas la chaine "0") diff --git a/php/tests/clTest.php b/php/tests/clTest.php index d2b834f..bedec17 100644 --- a/php/tests/clTest.php +++ b/php/tests/clTest.php @@ -12,10 +12,10 @@ class clTest extends TestCase { } function test_same_keys() { $array = ["a" => 42, "b" => "tesxt"]; $arrayKeys = array_keys($array); - $xarray = ["parasite0", "a" => 42, "parasite1", "b" => "tesxt"]; $xarrayKeys = array_keys($array); + $missingArray = ["c" => true]; $missingArrayKeys = array_keys($missingArray); $ref = ["a" => "int", "b" => "text"]; $refKeys = array_keys($ref); - $missingArray = ["c" => true]; $missingKeys = array_keys($missingArray); - $missingRef = ["c" => "bool"]; $missingKeys = array_keys($missingRef); + $missingRef = ["c" => "bool"]; $missingRefKeys = array_keys($missingRef); + $xarray = ["parasite0", "a" => 42, "parasite1", "b" => "tesxt"]; $this->checkKeys(null, null, true, [], [], []); $this->checkKeys(null, [], true, [], [], []); @@ -29,8 +29,8 @@ class clTest extends TestCase { $this->checkKeys($array, [], true, [], $arrayKeys, []); $this->checkKeys($array, $ref, true, $arrayKeys, [], []); - $this->checkKeys(cl::merge($array, $missingArray), $ref, true, $arrayKeys, $missingKeys, []); - $this->checkKeys($array, cl::merge($ref, $missingRef), false, $arrayKeys, [], $missingKeys); + $this->checkKeys(cl::merge($array, $missingArray), $ref, true, $arrayKeys, $missingArrayKeys, []); + $this->checkKeys($array, cl::merge($ref, $missingRef), false, $arrayKeys, [], $missingRefKeys); $this->checkKeys($xarray, $ref, false, $arrayKeys, [0, 1], []); } diff --git a/php/tests/php/funcTest.php b/php/tests/php/funcTest.php index f15ce27..a382660 100644 --- a/php/tests/php/funcTest.php +++ b/php/tests/php/funcTest.php @@ -295,14 +295,14 @@ namespace nulib\php { $workf = $func; $msg = var_export($func, true)." (strict)"; - self::assertSame($verifix1, func::verifix_function($workf, true), "$msg --> verifix"); + self::assertSame($verifix1, func::verifix_function($workf, $args, true), "$msg --> verifix"); if ($verifix1) { self::assertSame($func1, $workf, "$msg --> func"); } $workf = $func; $msg = var_export($func, true)." (lenient)"; - self::assertSame($verifix2, func::verifix_function($workf, false), "$msg --> verifix"); + self::assertSame($verifix2, func::verifix_function($workf, $args, false), "$msg --> verifix"); if ($verifix2) { self::assertSame($func2, $workf, "$msg --> func"); } @@ -595,7 +595,7 @@ namespace nulib\php { $workf = $func; $msg = var_export($func, true)." (strict)"; - self::assertSame($verifix1, func::verifix_static($workf, true, $bound), "$msg --> verifix"); + self::assertSame($verifix1, func::verifix_static($workf, $args, true, $bound), "$msg --> verifix"); if ($verifix1) { self::assertSame($bound1, $bound, "$msg --> bound"); self::assertSame($func1, $workf, "$msg --> func"); @@ -603,7 +603,7 @@ namespace nulib\php { $workf = $func; $msg = var_export($func, true)." (lenient)"; - self::assertSame($verifix2, func::verifix_static($workf, false, $bound), "$msg --> verifix"); + self::assertSame($verifix2, func::verifix_static($workf, $args, false, $bound), "$msg --> verifix"); if ($verifix2) { self::assertSame($bound2, $bound, "$msg --> bound"); self::assertSame($func2, $workf, "$msg --> func"); @@ -894,7 +894,7 @@ namespace nulib\php { $workf = $func; $msg = var_export($func, true)." (strict)"; - self::assertSame($verifix1, func::verifix_method($workf, true, $bound), "$msg --> verifix"); + self::assertSame($verifix1, func::verifix_method($workf, $args, true, $bound), "$msg --> verifix"); if ($verifix1) { self::assertSame($bound1, $bound, "$msg --> bound"); self::assertSame($func1, $workf, "$msg --> func"); @@ -902,7 +902,7 @@ namespace nulib\php { $workf = $func; $msg = var_export($func, true)." (lenient)"; - self::assertSame($verifix2, func::verifix_method($workf, false, $bound), "$msg --> verifix"); + self::assertSame($verifix2, func::verifix_method($workf, $args, false, $bound), "$msg --> verifix"); if ($verifix2) { self::assertSame($bound2, $bound, "$msg --> bound"); self::assertSame($func2, $workf, "$msg --> func"); diff --git a/wip/pman.md b/wip/pman.md index 1bd316a..3968ad8 100644 --- a/wip/pman.md +++ b/wip/pman.md @@ -6,7 +6,7 @@ outil pour gérer les projets PHP projets dépendants du projet courant * pver: gestion des versions. calculer la prochaine version en respectant semver -* pdev: gérer les branches de features et hotfixes. +* pmer: gérer les branches de features et hotfixes. * prel: faire une release. ces outils peuvent agir sur les projets dépendants: faire une release sur un projet downstream, ou synchroniser la version depuis un projet upstream