at 23.05-pre 3.7 kB view raw
1<section xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="sec-module-abstractions"> 2 <title>Abstractions</title> 3 <para> 4 If you find yourself repeating yourself over and over, it’s time to 5 abstract. Take, for instance, this Apache HTTP Server configuration: 6 </para> 7 <programlisting language="bash"> 8{ 9 services.httpd.virtualHosts = 10 { &quot;blog.example.org&quot; = { 11 documentRoot = &quot;/webroot/blog.example.org&quot;; 12 adminAddr = &quot;alice@example.org&quot;; 13 forceSSL = true; 14 enableACME = true; 15 enablePHP = true; 16 }; 17 &quot;wiki.example.org&quot; = { 18 documentRoot = &quot;/webroot/wiki.example.org&quot;; 19 adminAddr = &quot;alice@example.org&quot;; 20 forceSSL = true; 21 enableACME = true; 22 enablePHP = true; 23 }; 24 }; 25} 26</programlisting> 27 <para> 28 It defines two virtual hosts with nearly identical configuration; 29 the only difference is the document root directories. To prevent 30 this duplication, we can use a <literal>let</literal>: 31 </para> 32 <programlisting language="bash"> 33let 34 commonConfig = 35 { adminAddr = &quot;alice@example.org&quot;; 36 forceSSL = true; 37 enableACME = true; 38 }; 39in 40{ 41 services.httpd.virtualHosts = 42 { &quot;blog.example.org&quot; = (commonConfig // { documentRoot = &quot;/webroot/blog.example.org&quot;; }); 43 &quot;wiki.example.org&quot; = (commonConfig // { documentRoot = &quot;/webroot/wiki.example.com&quot;; }); 44 }; 45} 46</programlisting> 47 <para> 48 The <literal>let commonConfig = ...</literal> defines a variable 49 named <literal>commonConfig</literal>. The <literal>//</literal> 50 operator merges two attribute sets, so the configuration of the 51 second virtual host is the set <literal>commonConfig</literal> 52 extended with the document root option. 53 </para> 54 <para> 55 You can write a <literal>let</literal> wherever an expression is 56 allowed. Thus, you also could have written: 57 </para> 58 <programlisting language="bash"> 59{ 60 services.httpd.virtualHosts = 61 let commonConfig = ...; in 62 { &quot;blog.example.org&quot; = (commonConfig // { ... }) 63 &quot;wiki.example.org&quot; = (commonConfig // { ... }) 64 }; 65} 66</programlisting> 67 <para> 68 but not <literal>{ let commonConfig = ...; in ...; }</literal> since 69 attributes (as opposed to attribute values) are not expressions. 70 </para> 71 <para> 72 <emphasis role="strong">Functions</emphasis> provide another method 73 of abstraction. For instance, suppose that we want to generate lots 74 of different virtual hosts, all with identical configuration except 75 for the document root. This can be done as follows: 76 </para> 77 <programlisting language="bash"> 78{ 79 services.httpd.virtualHosts = 80 let 81 makeVirtualHost = webroot: 82 { documentRoot = webroot; 83 adminAddr = &quot;alice@example.org&quot;; 84 forceSSL = true; 85 enableACME = true; 86 }; 87 in 88 { &quot;example.org&quot; = (makeVirtualHost &quot;/webroot/example.org&quot;); 89 &quot;example.com&quot; = (makeVirtualHost &quot;/webroot/example.com&quot;); 90 &quot;example.gov&quot; = (makeVirtualHost &quot;/webroot/example.gov&quot;); 91 &quot;example.nl&quot; = (makeVirtualHost &quot;/webroot/example.nl&quot;); 92 }; 93} 94</programlisting> 95 <para> 96 Here, <literal>makeVirtualHost</literal> is a function that takes a 97 single argument <literal>webroot</literal> and returns the 98 configuration for a virtual host. That function is then called for 99 several names to produce the list of virtual host configurations. 100 </para> 101</section>