lib.attrsets.genAttrs': init (#436434)

* lib.attrsets.genAttrs': init

* lib.attrsets.genAttrs: rewrite with lib.attrsets.genAttrs'

* lib.attrsets.{genAttrs,genAttrs'}: add tests

* Update lib/attrsets.nix

Co-authored-by: Johannes Kirschbauer <hsjobeki+github@gmail.com>

* Update lib/attrsets.nix

Co-authored-by: Johannes Kirschbauer <hsjobeki+github@gmail.com>

* lib.attrsets.genAttrs': document and test attrName collision

---------

Co-authored-by: Johannes Kirschbauer <hsjobeki+github@gmail.com>
This commit is contained in:
Plume
2025-09-01 17:58:28 +08:00
committed by GitHub
parent 0696dd4a7a
commit 0477b30ab6
3 changed files with 72 additions and 1 deletions

View File

@@ -1226,7 +1226,44 @@ rec {
::: :::
*/ */
genAttrs = names: f: listToAttrs (map (n: nameValuePair n (f n)) names); genAttrs = names: f: genAttrs' names (n: nameValuePair n (f n));
/**
Like `genAttrs`, but allows the name of each attribute to be specified in addition to the value.
The applied function should return both the new name and value as a `nameValuePair`.
::: {.warning}
In case of attribute name collision the first entry determines the value,
all subsequent conflicting entries for the same name are silently ignored.
:::
# Inputs
`xs`
: A list of strings `s` used as generator.
`f`
: A function, given a string `s` from the list `xs`, returns a new `nameValuePair`.
# Type
```
genAttrs' :: [ Any ] -> (Any -> { name :: String; value :: Any; }) -> AttrSet
```
# Examples
:::{.example}
## `lib.attrsets.genAttrs'` usage example
```nix
genAttrs' [ "foo" "bar" ] (s: nameValuePair ("x_" + s) ("y_" + s))
=> { x_foo = "y_foo"; x_bar = "y_bar"; }
```
:::
*/
genAttrs' = xs: f: listToAttrs (map f xs);
/** /**
Check whether the argument is a derivation. Any set with Check whether the argument is a derivation. Any set with

View File

@@ -207,6 +207,7 @@ let
mapAttrsRecursive mapAttrsRecursive
mapAttrsRecursiveCond mapAttrsRecursiveCond
genAttrs genAttrs
genAttrs'
isDerivation isDerivation
toDerivation toDerivation
optionalAttrs optionalAttrs

View File

@@ -2006,6 +2006,39 @@ runTests {
# ATTRSETS # ATTRSETS
testGenAttrs = {
expr = attrsets.genAttrs [ "foo" "bar" ] (name: "x_" + name);
expected = {
foo = "x_foo";
bar = "x_bar";
};
};
testGenAttrs' = {
expr = attrsets.genAttrs' [ "foo" "bar" ] (s: nameValuePair ("x_" + s) ("y_" + s));
expected = {
x_foo = "y_foo";
x_bar = "y_bar";
};
};
testGenAttrs'Example2 = {
expr = attrsets.genAttrs' [
{
x = "foo";
y = "baz";
}
] (s: lib.nameValuePair ("x_" + s.x) ("y_" + s.y));
expected = {
x_foo = "y_baz";
};
};
testGenAttrs'ConflictingName = {
# c.f. warning of genAttrs'
expr = attrsets.genAttrs' [ "foo" "bar" "baz" ] (s: nameValuePair "foo" s);
expected = {
foo = "foo";
};
};
testConcatMapAttrs = { testConcatMapAttrs = {
expr = expr =
concatMapAttrs concatMapAttrs