Skip to content

Commit

Permalink
lib/attrsets: document all the functions
Browse files Browse the repository at this point in the history
  • Loading branch information
zimbatm committed Mar 9, 2016
1 parent a086858 commit 523e328
Showing 1 changed file with 109 additions and 28 deletions.
137 changes: 109 additions & 28 deletions lib/attrsets.nix
Expand Up @@ -12,9 +12,15 @@ rec {
inherit (builtins) attrNames listToAttrs hasAttr isAttrs getAttr;


/* Return an attribute from nested attribute sets. For instance
["x" "y"] applied to some set e returns e.x.y, if it exists. The
default value is returned otherwise. */
/* Return an attribute from nested attribute sets.
Example:
x = { a = { b = 3; }; }
attrByPath ["a" "b"] 6 x
=> 3
attrByPath ["z" "z"] 6 x
=> 6
*/
attrByPath = attrPath: default: e:
let attr = head attrPath;
in
Expand All @@ -24,8 +30,15 @@ rec {
else default;

/* Return if an attribute from nested attribute set exists.
For instance ["x" "y"] applied to some set e returns true, if e.x.y exists. False
is returned otherwise. */
Example:
x = { a = { b = 3; }; }
hasAttrByPath ["a" "b"] x
=> true
hasAttrByPath ["z" "z"] x
=> false
*/
hasAttrByPath = attrPath: e:
let attr = head attrPath;
in
Expand All @@ -35,14 +48,28 @@ rec {
else false;


/* Return nested attribute set in which an attribute is set. For instance
["x" "y"] applied with some value v returns `x.y = v;' */
/* Return nested attribute set in which an attribute is set.
Example:
setAttrByPath ["a" "b"] 3
=> { a = { b = 3; }; }
*/
setAttrByPath = attrPath: value:
if attrPath == [] then value
else listToAttrs
[ { name = head attrPath; value = setAttrByPath (tail attrPath) value; } ];


/* Like `getAttrPath' without a default value. If it doesn't find the
path it will throw.
Example:
x = { a = { b = 3; }; }
getAttrFromPath ["a" "b"] x
=> 3
getAttrFromPath ["z" "z"] x
=> error: cannot find attribute `z.z'
*/
getAttrFromPath = attrPath: set:
let errorMsg = "cannot find attribute `" + concatStringsSep "." attrPath + "'";
in attrByPath attrPath (abort errorMsg) set;
Expand Down Expand Up @@ -109,9 +136,11 @@ rec {
) (attrNames set)
);

/* foldAttrs: apply fold functions to values grouped by key. Eg accumulate values as list:
foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }]
=> { a = [ 2 3 ]; }
/* Apply fold functions to values grouped by key.
Example:
foldAttrs (n: a: [n] ++ a) [] [{ a = 2; } { a = 3; }]
=> { a = [ 2 3 ]; }
*/
foldAttrs = op: nul: list_of_attrs:
fold (n: a:
Expand Down Expand Up @@ -147,7 +176,12 @@ rec {


/* Utility function that creates a {name, value} pair as expected by
builtins.listToAttrs. */
builtins.listToAttrs.
Example:
nameValuePair "some" 6
=> { name = "some"; value = 6; }
*/
nameValuePair = name: value: { inherit name value; };


Expand Down Expand Up @@ -248,11 +282,19 @@ rec {
listToAttrs (map (n: nameValuePair n (f n)) names);


/* Check whether the argument is a derivation. */
isDerivation = x: isAttrs x && x ? type && x.type == "derivation";
/* Check whether the argument is a derivation. Any set with
{ type = "derivation"; } counts as a derivation.
Example:
nixpkgs = import <nixpkgs> {}
isDerivation nixpkgs.ruby
=> true
isDerivation "foobar"
=> false
*/
isDerivation = x: isAttrs x && x ? type && x.type == "derivation";

/* Convert a store path to a fake derivation. */
/* Converts a store path to a fake derivation. */
toDerivation = path:
let path' = builtins.storePath path; in
{ type = "derivation";
Expand All @@ -262,32 +304,49 @@ rec {
};


/* If the Boolean `cond' is true, return the attribute set `as',
otherwise an empty attribute set. */
/* If `cond' is true, return the attribute set `as',
otherwise an empty attribute set.
Example:
optionalAttrs (true) { my = "set"; }
=> { my = "set"; }
optionalAttrs (false) { my = "set"; }
=> { }
*/
optionalAttrs = cond: as: if cond then as else {};


/* Merge sets of attributes and use the function f to merge attributes
values. */
values.
Example:
zipAttrsWithNames ["a"] (name: vs: vs) [{a = "x";} {a = "y"; b = "z";}]
=> { a = ["x" "y"]; }
*/
zipAttrsWithNames = names: f: sets:
listToAttrs (map (name: {
inherit name;
value = f name (catAttrs name sets);
}) names);

# implentation note: Common names appear multiple times in the list of
# names, hopefully this does not affect the system because the maximal
# laziness avoid computing twice the same expression and listToAttrs does
# not care about duplicated attribute names.
/* Implentation note: Common names appear multiple times in the list of
names, hopefully this does not affect the system because the maximal
laziness avoid computing twice the same expression and listToAttrs does
not care about duplicated attribute names.
Example:
zipAttrsWith (name: values: values) [{a = "x";} {a = "y"; b = "z";}]
=> { a = ["x" "y"]; b = ["z"] }
*/
zipAttrsWith = f: sets: zipAttrsWithNames (concatMap attrNames sets) f sets;
/* Like `zipAttrsWith' with `(name: values: value)' as the function.
Example:
zipAttrs [{a = "x";} {a = "y"; b = "z";}]
=> { a = ["x" "y"]; b = ["z"] }
*/
zipAttrs = zipAttrsWith (name: values: values);

/* backward compatibility */
zipWithNames = zipAttrsWithNames;
zip = builtins.trace "lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;


/* Does the same as the update operator '//' except that attributes are
merged until the given pedicate is verified. The predicate should
accept 3 arguments which are the path to reach the attribute, a part of
Expand Down Expand Up @@ -351,6 +410,15 @@ rec {
!(isAttrs lhs && isAttrs rhs)
) lhs rhs;

/* Returns true if the pattern is contained in the set. False otherwise.
FIXME(zimbatm): this example doesn't work !!!
Example:
sys = mkSystem { }
matchAttrs { cpu = { bits = 64; }; } sys
=> true
*/
matchAttrs = pattern: attrs:
fold or false (attrValues (zipAttrsWithNames (attrNames pattern) (n: values:
let pat = head values; val = head (tail values); in
Expand All @@ -359,10 +427,23 @@ rec {
else pat == val
) [pattern attrs]));

# override only the attributes that are already present in the old set
# useful for deep-overriding
/* Override only the attributes that are already present in the old set
useful for deep-overriding.
Example:
x = { a = { b = 4; c = 3; }; }
overrideExisting x { a = { b = 6; d = 2; }; }
=> { a = { b = 6; d = 2; }; }
*/
overrideExisting = old: new:
old // listToAttrs (map (attr: nameValuePair attr (attrByPath [attr] old.${attr} new)) (attrNames old));


/*** deprecated stuff ***/

deepSeqAttrs = throw "removed 2016-02-29 because unused and broken";
zipWithNames = zipAttrsWithNames;
zip = builtins.trace
"lib.zip is deprecated, use lib.zipAttrsWith instead" zipAttrsWith;

}

1 comment on commit 523e328

@nixos-discourse
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commit has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/new-users-using-nixos-wrong/9973/41

Please sign in to comment.