diff --git a/lib/attrsets.nix b/lib/attrsets.nix index f5184af423097c..4161fa546c8fa1 100644 --- a/lib/attrsets.nix +++ b/lib/attrsets.nix @@ -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 @@ -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 @@ -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; @@ -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: @@ -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; }; @@ -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 {} + 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"; @@ -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 @@ -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 @@ -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; + }