<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>http://www.stuartellis.eu/</id>
  <title>StuartEllis.eu</title>
  <updated>2011-02-06T17:53:00Z</updated>
  <link rel="alternate" href="http://www.stuartellis.eu/"/>
  <link rel="self" href="http://www.stuartellis.eu/feed.xml"/>
  <author>
    <name>Stuart Ellis</name>
    <uri>http://www.stuartellis.eu</uri>
  </author>
  <entry>
    <id>tag:www.stuartellis.eu,2011-02-06:/articles/erb/</id>
    <title type="html">An Introduction to ERB Templating</title>
    <published>2011-02-06T17:53:00Z</published>
    <updated>2011-02-06T17:53:00Z</updated>
    <link rel="alternate" href="http://www.stuartellis.eu/articles/erb/"/>
    <content type="html">&lt;h2 id="overview"&gt;Overview&lt;/h2&gt;
&lt;p&gt;&lt;acronym title="Embedded RuBy"&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt;&lt;/acronym&gt; is a feature of Ruby that enables you to conveniently generate any kind of text, in any quantity, from templates. The templates themselves combine plain text with Ruby code for variable substitution and flow control, which makes them easy to write and maintain.&lt;/p&gt;
&lt;p&gt;Although &lt;span class="caps"&gt;ERB&lt;/span&gt; is most commonly seen generating Web pages, it is also used to produce &lt;span class="caps"&gt;XML&lt;/span&gt; documents, &lt;span class="caps"&gt;RSS&lt;/span&gt; feeds, source code, and other forms of structured text file. It can be extremely valuable when you need to create files which include many repetitions of a standard pattern, such as unit test suites.&lt;/p&gt;
&lt;p&gt;The main component of &lt;span class="caps"&gt;ERB&lt;/span&gt; is a library which you can call within your Ruby applications and Rake tasks. This library accepts any string as a template, and imposes no limitations on the source of the template. You may define a template entirely within your code, or store it in an external location and load it as required. This means that you can keep templates in files, &lt;span class="caps"&gt;SQL&lt;/span&gt; databases, or any other kind of storage that you want to use.&lt;/p&gt;
&lt;p&gt;Ruby distributions also include a command-line utility that enables you to process templates that are held in files without writing any additional code. Logically, this utility is called &lt;em&gt;erb&lt;/em&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt; is part of the Ruby standard library. You do not need to install any other software to use it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The supplied documentation for &lt;span class="caps"&gt;ERB&lt;/span&gt; provides a good introduction:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ri ERB&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="template-format"&gt;Writing Templates&lt;/h2&gt;
&lt;p&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt; copies the text portions of the template directly to the generated document, and only processes code that is identified by markers. Most &lt;span class="caps"&gt;ERB&lt;/span&gt; templates only use a combination of two tag markers, each of which cause the enclosed code to be handled in a particular way.&lt;/p&gt;
&lt;p&gt;A tag with an equals sign indicates that enclosed code is an &lt;em&gt;expression&lt;/em&gt;, and that the renderer should substitute the code element with the result of the code (as a string) when it renders the template. Use an expression to embed a line of code into the template, or to display the contents of a variable:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;Hello, &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@name&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;.&lt;tt&gt;
&lt;/tt&gt;Today is &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="co"&gt;Time&lt;/span&gt;.now.strftime(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;.&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tags without the equals sign denote that the enclosed code is a &lt;em&gt;scriptlet&lt;/em&gt;. Each scriptlet is caught and executed, and the final result of the code is then injected in to the output at the point of the scriptlet.&lt;/p&gt;
&lt;p&gt;Scriptlets are most commonly used for embedding loops or conditional logic into templates:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;for&lt;/span&gt; &lt;span class="iv"&gt;@item&lt;/span&gt; &lt;span class="r"&gt;in&lt;/span&gt; &lt;span class="iv"&gt;@shopping_list&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@item&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the scriptlets in this example enclose an expression. The scriptlets produce no text themselves, but cause the enclosed expression to run multiple times, and the result of the expression is written to the output each time.&lt;/p&gt;
&lt;p&gt;Comment markers use a hash sign:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%#&lt;/span&gt;&lt;span class="c"&gt; This is just a comment &lt;/span&gt;&lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, a newline character is added to the page after the position of each tag. To suppress this newline, use the optional parameter of &lt;em&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt;.new()&lt;/em&gt;, as explained below.&lt;/p&gt;
&lt;p&gt;Rails extends &lt;span class="caps"&gt;ERB&lt;/span&gt;, so that you can suppress the newline simply by adding a trailing hyphen to tags in Rails templates:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;for&lt;/span&gt; &lt;span class="iv"&gt;@item&lt;/span&gt; &lt;span class="r"&gt;in&lt;/span&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@item&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;-%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="erb-transforms"&gt;Using Text Transformation Methods&lt;/h3&gt;
&lt;p&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt; provides optional methods for transforming text:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;This will be HTML escaped: &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; h(this &amp;amp; that) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;This will be JSON encoded: &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; j(this &amp;amp; that) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;This will be converted to Textile markup: &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; t(this &amp;amp; that) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;This will be URL encoded: &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; u(this &amp;amp; that) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use these features your code must &lt;em&gt;include&lt;/em&gt; the module &lt;em&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt;::Util&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="erb-files"&gt;Conventions for Template Files&lt;/h3&gt;
&lt;p&gt;A file that contains an &lt;span class="caps"&gt;ERB&lt;/span&gt; template may have any name, but it is the convention that the name of file should end with the &lt;em&gt;.erb&lt;/em&gt; extension. Rails requires template files to have the extension of the output type, followed by &lt;em&gt;.erb&lt;/em&gt;, so that a name like &lt;em&gt;layout.html.erb&lt;/em&gt; indicates a &lt;span class="caps"&gt;HTML&lt;/span&gt; template. Some applications use the extension &lt;em&gt;.rhtml&lt;/em&gt; for &lt;span class="caps"&gt;HTML&lt;/span&gt; templates.&lt;/p&gt;
&lt;p&gt;If you store templates in files, it is good practice to keep each template in a separate file.&lt;/p&gt;
&lt;h2 id="erb-programming"&gt;Using the &lt;span class="caps"&gt;ERB&lt;/span&gt; Library&lt;/h2&gt;
&lt;p&gt;This is a very simple example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;erb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;weekday = &lt;span class="co"&gt;Time&lt;/span&gt;.now.strftime(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%A&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;simple_template = &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Today is &amp;lt;%= weekday %&amp;gt;.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;renderer = &lt;span class="co"&gt;ERB&lt;/span&gt;.new(simple_template)&lt;tt&gt;
&lt;/tt&gt;puts output = renderer.result()&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt; only processes the template when &lt;em&gt;result&lt;/em&gt; is called. This means that the output will show the values of variables as they are at the moment when the &lt;em&gt;result&lt;/em&gt; is rendered, not when the &lt;em&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt;&lt;/em&gt; object was defined.&lt;/p&gt;
&lt;p&gt;The code shown above will fail almost anywhere other than in a simple script. &lt;span class="caps"&gt;ERB&lt;/span&gt; gets variables from a &lt;em&gt;Binding&lt;/em&gt;, an object that provides access to the instance methods and variables that are owned by another object. If you do not specify a Binding, the &lt;em&gt;result()&lt;/em&gt; method gets a Binding from the top-level object, which will probably own very little. Fortunately, every Ruby class has a private &lt;em&gt;binding()&lt;/em&gt; instance method to provide Bindings that points to itself, so we can easily extend any object to provide &lt;span class="caps"&gt;ERB&lt;/span&gt; with a Binding.&lt;/p&gt;
&lt;p&gt;If the &lt;span class="caps"&gt;ERB&lt;/span&gt; object is enclosed in a method, and we want it to use the variables of the host object, we get a Binding for the host like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ShoppingList&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  attr_accessor &lt;span class="sy"&gt;:items&lt;/span&gt;, &lt;span class="sy"&gt;:template&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;render&lt;/span&gt;()&lt;tt&gt;
&lt;/tt&gt;    renderer.result(binding)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To enable &lt;span class="caps"&gt;ERB&lt;/span&gt; to use the variables from a separate object, we must first ensure that it has a public method to provide a Binding. We can then get a Binding at any later point:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;&lt;span class="r"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;ShoppingList&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  attr_accessor &lt;span class="sy"&gt;:items&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;initialize&lt;/span&gt;(items)&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="iv"&gt;@items&lt;/span&gt; = items&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Expose private binding() method.&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get_binding&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    binding()&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;list = &lt;span class="co"&gt;ShoppingList&lt;/span&gt;.new(items)&lt;tt&gt;
&lt;/tt&gt;renderer = &lt;span class="co"&gt;ERB&lt;/span&gt;.new(template)&lt;tt&gt;
&lt;/tt&gt;puts output = renderer.result(list.get_binding)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="erb-isolating"&gt;Running &lt;span class="caps"&gt;ERB&lt;/span&gt; in a Sandbox&lt;/h3&gt;
&lt;p&gt;You may protect your application from &lt;span class="caps"&gt;ERB&lt;/span&gt; by running it in a new thread. If you specify an integer as a second parameter when you create the renderer, then the template will be processed in a new thread which has a &lt;em&gt;safe level&lt;/em&gt; equal to the given integer:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;renderer = &lt;span class="co"&gt;ERB&lt;/span&gt;.new(template, &lt;span class="i"&gt;3&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Safe level 4 provides maximum isolation. At this level, the specified binding must be marked as trusted for &lt;span class="caps"&gt;ERB&lt;/span&gt; to use it.&lt;/p&gt;
&lt;p&gt;If you need to set the third or fourth parameters, but do not want &lt;span class="caps"&gt;ERB&lt;/span&gt; to run in a new thread, use 0 as the second parameter.&lt;/p&gt;
&lt;h3 id="erb-newlines"&gt;Suppressing Newlines&lt;/h3&gt;
&lt;p&gt;The third parameter of &lt;em&gt;new&lt;/em&gt; specifies optional modifiers, most of which alter when newline characters will be automatically added to the output. For example, &lt;span class="caps"&gt;ERB&lt;/span&gt; will not print newlines after tags if you give &lt;em&gt;&amp;gt;&lt;/em&gt; as the third parameter:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;renderer = &lt;span class="co"&gt;ERB&lt;/span&gt;.new(template, &lt;span class="i"&gt;3&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="erb-example"&gt;A Longer Example&lt;/h3&gt;
&lt;pre&gt;&lt;code class="language-rhtml"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;25&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;34&lt;tt&gt;
&lt;/tt&gt;35&lt;tt&gt;
&lt;/tt&gt;36&lt;tt&gt;
&lt;/tt&gt;37&lt;tt&gt;
&lt;/tt&gt;38&lt;tt&gt;
&lt;/tt&gt;39&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;40&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;41&lt;tt&gt;
&lt;/tt&gt;42&lt;tt&gt;
&lt;/tt&gt;43&lt;tt&gt;
&lt;/tt&gt;44&lt;tt&gt;
&lt;/tt&gt;45&lt;tt&gt;
&lt;/tt&gt;46&lt;tt&gt;
&lt;/tt&gt;47&lt;tt&gt;
&lt;/tt&gt;48&lt;tt&gt;
&lt;/tt&gt;49&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;50&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;51&lt;tt&gt;
&lt;/tt&gt;52&lt;tt&gt;
&lt;/tt&gt;53&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require 'erb'&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;def get_items()&lt;tt&gt;
&lt;/tt&gt;  ['bread', 'milk', 'eggs', 'spam']&lt;tt&gt;
&lt;/tt&gt;end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;def get_template()&lt;tt&gt;
&lt;/tt&gt;  %{&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="ta"&gt;&amp;lt;DOCTYPE&lt;/span&gt; &lt;span class="an"&gt;html&lt;/span&gt; &lt;span class="an"&gt;PUBLIC&lt;/span&gt; &lt;span class="er"&gt;"&lt;/span&gt;&lt;span class="an"&gt;-&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;W3C&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;DTD&lt;/span&gt; &lt;span class="an"&gt;XHTML&lt;/span&gt; &lt;span class="an"&gt;1.0&lt;/span&gt; &lt;span class="an"&gt;Strict&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;EN&lt;/span&gt;&lt;span class="er"&gt;"&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="er"&gt;"&lt;/span&gt;&lt;span class="an"&gt;http:&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;www.w3.org&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;TR&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;xhtml1&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;DTD&lt;/span&gt;&lt;span class="er"&gt;/&lt;/span&gt;&lt;span class="an"&gt;xhtml1-strict.dtd&lt;/span&gt;&lt;span class="er"&gt;"&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="ta"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="an"&gt;xmlns&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;http://www.w3.org/1999/xhtml&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;xml:lang&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;lang&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="ta"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="ta"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="an"&gt;http-equiv&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="an"&gt;content&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;text/html; charset=utf-8&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;/&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;            &lt;span class="ta"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Shopping List for &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@date&lt;/span&gt;.strftime(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%A, %d %B %Y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="ta"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="ta"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                 &lt;span class="ta"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Shopping List for &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="iv"&gt;@date&lt;/span&gt;.strftime(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;%A, %d %B %Y&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                &lt;span class="ta"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;You need to buy:&lt;span class="ta"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                &lt;span class="ta"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;for&lt;/span&gt; &lt;span class="iv"&gt;@item&lt;/span&gt; &lt;span class="r"&gt;in&lt;/span&gt; &lt;span class="iv"&gt;@items&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                    &lt;span class="ta"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%=&lt;/span&gt; h(&lt;span class="iv"&gt;@item&lt;/span&gt;) &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="ta"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                  &lt;span class="il"&gt;&lt;span class="idl"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="r"&gt;end&lt;/span&gt; &lt;span class="idl"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;                &lt;span class="ta"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="ta"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;        &lt;span class="ta"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  }&lt;tt&gt;
&lt;/tt&gt;end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;class ShoppingList&lt;tt&gt;
&lt;/tt&gt;  include ERB::Util&lt;tt&gt;
&lt;/tt&gt;  attr_accessor :items, :template, :date&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  def initialize(items, template, date=Time.now)&lt;tt&gt;
&lt;/tt&gt;    @date = date&lt;tt&gt;
&lt;/tt&gt;    @items = items&lt;tt&gt;
&lt;/tt&gt;    @template = template&lt;tt&gt;
&lt;/tt&gt;  end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  def render()&lt;tt&gt;
&lt;/tt&gt;    ERB.new(@template).result(binding)&lt;tt&gt;
&lt;/tt&gt;  end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  def save(file)&lt;tt&gt;
&lt;/tt&gt;    File.open(file, "w+") do |f|&lt;tt&gt;
&lt;/tt&gt;      f.write(render)&lt;tt&gt;
&lt;/tt&gt;    end&lt;tt&gt;
&lt;/tt&gt;  end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;end&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;list = ShoppingList.new(get_items, get_template)&lt;tt&gt;
&lt;/tt&gt;list.save(File.join(ENV['HOME'], 'list.html'))&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="other-resources"&gt;Running &lt;span class="caps"&gt;ERB&lt;/span&gt; from the Command-line&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;erb&lt;/em&gt; utility processes a given template and sends the result to the standard output. This enables you to generate files directly from templates, by redirecting the output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;erb my-template.txt.erb &amp;gt; new-file.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The template can automatically use built-in Ruby classes, such as &lt;em&gt;String&lt;/em&gt; and &lt;em&gt;File&lt;/em&gt;. To allow it to access standard or third-party libraries, use the &lt;em&gt;-r&lt;/em&gt; option. This option works in the same way as the &lt;em&gt;require&lt;/em&gt; keyword. This example processes a template that uses the &lt;em&gt;Abbrev&lt;/em&gt; and &lt;em&gt;IPAddr&lt;/em&gt; libraries:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;erb -r abbrev -r ipaddr my-template.txt.erb  &amp;gt; new-file.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the &lt;em&gt;-S&lt;/em&gt; option to specify a &lt;em&gt;safe level&lt;/em&gt; that isolates the template processing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;erb -S 4 my-template.txt.erb &amp;gt; new-file.txt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Safe levels are explained above.&lt;/p&gt;
&lt;h2 id="other-resources"&gt;Other Resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://ruby-doc.org/ruby-1.9/classes/ERB.html"&gt;The &lt;span class="caps"&gt;ERB&lt;/span&gt; documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;These books explain &lt;span class="caps"&gt;ERB&lt;/span&gt; (and many other things):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.pragprog.com/titles/ruby/programming-ruby"&gt;Programming Ruby&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.rubybestpractices.com/"&gt;Ruby Best Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <id>tag:www.stuartellis.eu,2011-02-06:/articles/rake/</id>
    <title type="html">Using Rake to Automate Tasks</title>
    <published>2011-02-06T17:52:00Z</published>
    <updated>2011-08-19T18:43:00Z</updated>
    <link rel="alternate" href="http://www.stuartellis.eu/articles/rake/"/>
    <content type="html">&lt;p&gt;Rake enables you to define a set of tasks and the dependencies between them in a file, and then have the right thing happen when you run any given task. Each task may be either one of the built-in types, or a block of your own Ruby code. It was originally created to handle software build processes, but the combination of convenience and flexibility that it provides has made it the standard method of job automation for Ruby projects.&lt;/p&gt;
&lt;p&gt;You may use supplied methods in your task code to conveniently set up common jobs, such as running test suites, publishing files and packaging software. Equally, you may call or write any other Ruby code into a Rake task, which means that it can automate just about anything.&lt;/p&gt;
&lt;p&gt;Crucially, you also write the task and dependency definitions themselves in Ruby, following a specific format. This means that you do not need to deal with any new syntax to start automating your routine jobs. Anyone with a basic knowledge of Ruby can understand and maintain Rake tasks.&lt;/p&gt;
&lt;h3 id="declarative"&gt;Rake is Declarative&lt;/h3&gt;
&lt;p&gt;Rake itself is designed to be a declarative system – you specify the result that you want, and Rake carries out the associated task and dependent tasks as necessary. This means that a set of correctly defined tasks will do as little or as much as is necessary to produce a known state.&lt;/p&gt;
&lt;p&gt;The task types that are supplied with Rake follow this approach. For example, the built-in types of tasks for creating file and directories creation automatically check for the specified item, and will not run if an up to date copy exists.&lt;/p&gt;
&lt;h3 id="rakefile-locations"&gt;Project and Global Rake Task Files&lt;/h3&gt;
&lt;p&gt;By default, the Rake utility checks the current working directory for a file with the name &lt;em&gt;Rakefile&lt;/em&gt; (with no extension). This enables you to add a file of Rake tasks to the source code of any application without conflicting with the names of existing files. If you would like to create one or more specifically named Rake files in a directory, use the file extension &lt;em&gt;.rake&lt;/em&gt; for them.&lt;/p&gt;
&lt;p&gt;To make a set of Rake tasks available for use from any directory, create a &lt;em&gt;.rake&lt;/em&gt; subdirectory within your home directory, and place the appropriate Rake files there. Any &lt;em&gt;rake&lt;/em&gt; command with the &lt;em&gt;-g&lt;/em&gt; option will use these global Rake files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake -g -T&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="installing-rake"&gt;Installing Rake&lt;/h2&gt;
&lt;p&gt;Rake is now part of the Ruby standard library, and will automatically be part of any Ruby 1.9 installation. Alternative Ruby implementations such as JRuby usually also include Rake.&lt;/p&gt;
&lt;p&gt;To install Rake for Ruby 1.8, use RubyGems:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install rake&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="running-rake"&gt;Using Existing Rake Tasks&lt;/h2&gt;
&lt;p&gt;Many Ruby projects and applications provide a set of Rake tasks, so you may well start using Rake before you have written a task file yourself. For example, every Ruby on Rails project automatically includes a large number of tasks which can be run from the root directory of the project.&lt;/p&gt;
&lt;h3 id="running-list"&gt;Getting a List of the Available Tasks&lt;/h3&gt;
&lt;p&gt;To see a list of all of the tasks available from the current Rake file, use the -T option of the rake utility:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake -T&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="running-task"&gt;Running a Task&lt;/h3&gt;
&lt;p&gt;To run a named task, specify the name of the task:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake my_task&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that the task name has no colon prefix here.&lt;/p&gt;
&lt;p&gt;To run a Rake file or directory task, use the name of the file or directory:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake mydoc.pdf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you call &lt;em&gt;rake&lt;/em&gt; without specifying any task, it automatically checks for a task named &lt;em&gt;default&lt;/em&gt;, and runs that task if one is found.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="running-options"&gt;Specifying Options&lt;/h3&gt;
&lt;p&gt;All of the options of the &lt;em&gt;rake&lt;/em&gt; utility may be called with either a single letter switch, or a longer word version. Note that command-line options may go before or after the name of the task, whichever you prefer:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake my_task --quiet
rake --quiet my_task&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The --quiet option suppresses any output that individual tasks would usually display in your terminal window, but allows errors to be shown normally.&lt;/p&gt;
&lt;p&gt;A later section explains some of the most used options. To see a list of all of the available options, run &lt;em&gt;rake&lt;/em&gt; with -h, or --help:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake -h
rake --help&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="writing-rakefiles"&gt;Writing Rake Files&lt;/h2&gt;
&lt;p&gt;A Rake file does not need to have anything in it, other than task definitions. In addition to the tasks, you may freely use standard Ruby elements, including constants and methods.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Remember to set a default task:&lt;/em&gt; It’s a good habit to specify a default task in each Rake file (as explained below).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="rake-taskdefinitions"&gt;Task Definitions&lt;/h3&gt;
&lt;p&gt;Each task definition consists of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A description&lt;/li&gt;
	&lt;li&gt;The name that identifies the task&lt;/li&gt;
	&lt;li&gt;The code to be executed by the task&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;In addition, you can specify input parameters for your tasks, and other tasks that are prerequisites.&lt;/p&gt;
&lt;p&gt;For standard tasks, the name of the task is a Ruby symbol, which means that it must be prefixed by a colon, and also must use only lowercase alphanumeric characters, with underscores instead of spaces. We only use the colon prefix for specifying task names within Rake files, not when we actually run the tasks.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Multiple Tasks with the Same Name&lt;/em&gt;: If you define two tasks with same name, Rake appends the second task of that name to the first.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The actual code for the task to run must be enclosed in a standard Ruby &lt;em&gt;do…end&lt;/em&gt; block. This is the structure of a simple task:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;One line task description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:name_of_task&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Your code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The task shown above accepts no input parameters, and has no prerequisites, so we completely omitted these items to make the definition more compact. If we did not include a description, the task would still work, but it would not appear on listings.&lt;/p&gt;
&lt;p&gt;This task depends on two other tasks:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Example of a task with prerequisites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:third_task&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;first_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;second_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Your code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we run the task shown above, Rake first checks the prerequisites. It then executes all of the prerequisite tasks before it actually carries out the requested task.&lt;/p&gt;
&lt;p&gt;To run a task, we simply call the &lt;em&gt;rake&lt;/em&gt; utility at a command prompt, and specify the task:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake name_of_task &lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The Initial Working Directory&lt;/em&gt;: To ensure that paths are consistent, all tasks run with an initial working directory that matches the directory of the Rake file that holds them. Do not assume that the working directory of a task is the current working directory of the user that runs the task.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="rake-taskarguments"&gt;Input Parameters for Tasks&lt;/h3&gt;
&lt;p&gt;Rake refers to the input parameters for tasks as &lt;em&gt;arguments&lt;/em&gt;. This task has both arguments and prerequisites:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Example of task with parameters and prerequisites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:my_task&lt;/span&gt;, [&lt;span class="sy"&gt;:first_arg&lt;/span&gt;, &lt;span class="sy"&gt;:second_arg&lt;/span&gt;] =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;first_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;second_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt; |t, args|&lt;tt&gt;
&lt;/tt&gt;  args.with_defaults(&lt;span class="sy"&gt;:first_arg&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Foo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="sy"&gt;:last_arg&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;First argument was: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;args.first_arg&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Second argument was: &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;args.second_arg&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line of the task assigns default values to the arguments.&lt;/p&gt;
&lt;p&gt;To run a task that requires arguments, we must specify the values for each of the arguments after the name of the task:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake my_task[one,two]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that there are no spaces where the task is specified, either between the name of the task and the opening square bracket, or between the first and second argument.&lt;/p&gt;
&lt;p&gt;If you do not give a value for an argument at the command-line, and the task does not specify a default value, the value of the argument is set to &lt;em&gt;nil&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="rake-defaulttask"&gt;Setting a Default Task&lt;/h3&gt;
&lt;p&gt;For convenience, define a dummy task called &lt;em&gt;default&lt;/em&gt; that depends on one or more of your tasks, and has no code itself. If a user runs the &lt;em&gt;rake&lt;/em&gt; utility without specifying a task, it automatically runs the &lt;em&gt;default&lt;/em&gt; task in the Rakefile.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;task &lt;span class="sy"&gt;:default&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;my_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This command now carries out the default task:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="invoking-tasks"&gt;Running One Task with Another&lt;/h3&gt;
&lt;p&gt;Normally, you link tasks together with dependencies. If you need to run a task from within another, use the &lt;em&gt;invoke&lt;/em&gt; method:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Example of task with invoke&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:first_task&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;Rake&lt;/span&gt;::&lt;span class="co"&gt;Task&lt;/span&gt;[&lt;span class="sy"&gt;:second_task&lt;/span&gt;].invoke&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code returns the specified task as a &lt;em&gt;Rake::Task&lt;/em&gt;, and calls the &lt;em&gt;invoke&lt;/em&gt; method of the task object.&lt;/p&gt;
&lt;h2 id="rake-filehandling"&gt;Managing Files and Directories with Rake&lt;/h2&gt;
&lt;h3 id="rake-filetasks"&gt;File and Directory Generation Tasks&lt;/h3&gt;
&lt;p&gt;File and directory creation tasks are identified by the item that they generate, rather than by an arbitrary name. Any file or directory task may use either full or partial names. Note that you must use &lt;em&gt;glob patterns&lt;/em&gt; to define any partial names, not regular expressions. This provides consistency with the standard Ruby file and directory functions, which also use glob patterns.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;file &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;mydoc.pdf&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;mydoc.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;mydoc.xslt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Code goes here...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If a task specifies a target file, then Rake checks both that the file exists, and also that it is not older than the files specified by any prerequisite tasks. Rake only runs the task associated with the file if the target is either not present, or if it is not up to date. As a result, Rake tasks can efficiently maintain even a very large set of files.&lt;/p&gt;
&lt;p&gt;Directory tasks just create the specified directories, if they do not already exist. These consist of the keyword &lt;em&gt;directory&lt;/em&gt;, followed by the directory itself. Directory tasks may not have either a code block, nor any prerequisites. Other tasks may use a directory task as a prerequisite:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;directory &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  file &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;html/contents.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;html/index.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Code goes here...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you would expect, standard tasks may have file or directory tasks as prerequisites:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;task &lt;span class="sy"&gt;:upload_page&lt;/span&gt; =&amp;gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;myfile.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Your code...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Rather than tying tasks to specific file or directory names, you may use FileLists or Rules, as explained below.&lt;/p&gt;
&lt;h3 id="rake-filelists"&gt;Defining Sets of Files with FileLists&lt;/h3&gt;
&lt;p&gt;A FileList is an array of complete and partial file names, written in the Rake file itself (or one of the imported modules).&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;my_files = &lt;span class="co"&gt;FileList&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;build/*.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;index.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Excluded Files:&lt;/em&gt; By default, FileLists never returns certain types of file, even if a glob would match them. Suppressed file types include administrative files and directories for version control systems, &lt;span class="caps"&gt;UNIX&lt;/span&gt; backup files, and core dumps.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="rake-clean"&gt;Using the Clean-up Tasks&lt;/h3&gt;
&lt;p&gt;Rake includes two tasks to clean up a set of files, so that you do not need to write code to handle this kind of job. Simply &lt;em&gt;require&lt;/em&gt; the &lt;em&gt;rake/clean&lt;/em&gt; module, and add values to the FileLists called &lt;em&gt;&lt;span class="caps"&gt;CLEAN&lt;/span&gt;&lt;/em&gt; and &lt;em&gt;&lt;span class="caps"&gt;CLOBBER&lt;/span&gt;&lt;/em&gt;, which are part of the module. Any file that is in the &lt;em&gt;&lt;span class="caps"&gt;CLEAN&lt;/span&gt;&lt;/em&gt; FileList will be deleted when you run the &lt;em&gt;clean&lt;/em&gt; task. Similarly, &lt;em&gt;clobber&lt;/em&gt; deletes anything included in the &lt;em&gt;&lt;span class="caps"&gt;CLOBBER&lt;/span&gt;&lt;/em&gt; list.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;rake/clean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;CLEAN&lt;/span&gt;.include(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;*.tmp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;CLOBBER&lt;/span&gt;.include(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;*.tmp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;build/*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Having two tasks with separate FileLists enables you to target either just those files that were created by running build tasks, or purge any file that should not be mixed in with the set. Set up the &lt;em&gt;&lt;span class="caps"&gt;CLEAN&lt;/span&gt;&lt;/em&gt; list to specifically handle temporary build files, and &lt;em&gt;&lt;span class="caps"&gt;CLOBBER&lt;/span&gt;&lt;/em&gt; to aggressively match all potentially unwanted files.&lt;/p&gt;
&lt;h3 id="file-utils"&gt;Other File Handling Methods&lt;/h3&gt;
&lt;p&gt;Rake automatically provides file handling methods, to enable you to write tasks that include the usual operations. For convenience, these methods have similar names to the equivalent &lt;span class="caps"&gt;UNIX&lt;/span&gt; utilities, such as cp and mv.&lt;/p&gt;
&lt;p&gt;Here are two contrived examples:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;task &lt;span class="sy"&gt;:copy_files&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  cp(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;readme.htm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;readme.htm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;), &lt;span class="sy"&gt;:verbose&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:mv_files&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  mv(&lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;readme.htm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;), &lt;span class="co"&gt;File&lt;/span&gt;.join(&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;release&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;index.htm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;), &lt;span class="sy"&gt;:verbose&lt;/span&gt; =&amp;gt; &lt;span class="pc"&gt;true&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These methods are provided by &lt;em&gt;RakeFileUtils&lt;/em&gt;, an extended version of the standard Ruby module &lt;em&gt;FileUtils&lt;/em&gt;. To see all of the available methods, refer to the &lt;em&gt;FileUtils&lt;/em&gt; documentation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ri FileUtils&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use the standard tasks where possible, rather than these utility methods.&lt;/p&gt;
&lt;h3 id="rake-filerules"&gt;Rules&lt;/h3&gt;
&lt;p&gt;A rule defines filenames, and a block of Ruby code. For each matching file, the rule creates and runs a new task with the specified code. You may use either names or regular expressions to define the files that match the rule.&lt;/p&gt;
&lt;h2 id="rubylibs-integration"&gt;Using Other Ruby Libraries in Rake Tasks&lt;/h2&gt;
&lt;p&gt;Your Rake files may reference other Rake files or Ruby modules. Use &lt;em&gt;require&lt;/em&gt; statements as normal to import modules, or other Rake files.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rake includes built-in methods for many common tasks, so before you write or import other code, check &lt;a href="http://rake.rubyforge.org/"&gt;the documentation&lt;/a&gt; to see if a suitable method already exists within Rake.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This example uses the &lt;span class="caps"&gt;ERB&lt;/span&gt; template system, which is part of the Ruby standard library:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;erb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;OUTPUT_FILE&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;README.html&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;TEMPLATE_FILE&lt;/span&gt;=&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;template.html.erb&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get_template&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;File&lt;/span&gt;.read(&lt;span class="co"&gt;TEMPLATE_FILE&lt;/span&gt;)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Builds the HTML file, using ERB.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;file &lt;span class="co"&gt;OUTPUT_FILE&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;File&lt;/span&gt;.open(&lt;span class="co"&gt;OUTPUT_FILE&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;w+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;) &lt;span class="r"&gt;do&lt;/span&gt; |f|&lt;tt&gt;
&lt;/tt&gt;    f.write(&lt;span class="co"&gt;ERB&lt;/span&gt;.new(get_template).result())&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:default&lt;/span&gt; =&amp;gt; [&lt;span class="co"&gt;OUTPUT_FILE&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code shown above uses a standard Ruby method from the &lt;em&gt;File&lt;/em&gt; class to get the template from a file as a string, creates an &lt;em&gt;&lt;span class="caps"&gt;ERB&lt;/span&gt;&lt;/em&gt; renderer to process the template string, and writes the output to the target file.&lt;/p&gt;
&lt;h2 id="shell-integration"&gt;Integrating with the Shell&lt;/h2&gt;
&lt;p&gt;Rake and Ruby work consistently across platforms, making them a portable alternative to shell scripts, but you may also use them as a means of automating platform-specific features. This section briefly describes how you can use the shell integration facility of Rake to call command-line utilities from within your own tasks.&lt;/p&gt;
&lt;h3 id="shell-commands"&gt;Using Shell Commands in Rake Tasks&lt;/h3&gt;
&lt;p&gt;To handle shell commands in your Rake tasks, use the &lt;em&gt;sh&lt;/em&gt; method. This is provided by an extension to the &lt;em&gt;FileUtils&lt;/em&gt; module, so you need to require that module in the task file before you can call the method:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;fileutils&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Stuff...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:run_command&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  sh &lt;span class="s"&gt;&lt;span class="dl"&gt;%{&lt;/span&gt;&lt;span class="k"&gt; space separated command and options &lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;sh&lt;/em&gt; method passes two outputs: a status, and the actual output of the command. This example from the Rake documentation makes it clear:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;sh &lt;span class="s"&gt;&lt;span class="dl"&gt;%{&lt;/span&gt;&lt;span class="k"&gt;grep pattern file&lt;/span&gt;&lt;span class="dl"&gt;}&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt; |ok, res|&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;if&lt;/span&gt; ! ok&lt;tt&gt;
&lt;/tt&gt;    puts &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;pattern not found (status = &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;res.exitstatus&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As always, remember that using shell commands restrict your software to systems that have those exact utilities installed. Use Ruby code unless you require the features of a particular command-line utility, such as a configuration tool that is specific to one operating system.&lt;/p&gt;
&lt;h3 id="shell-variables"&gt;Using Environment Variables&lt;/h3&gt;
&lt;p&gt;Rake automatically recognises the environment variables provided by the shell. You may also create or set environment variables specifically for tasks at the same time as you run Rake.&lt;/p&gt;
&lt;p&gt;This code uses two environment variables, the standard &lt;span class="caps"&gt;HOME&lt;/span&gt; variable, and a MY_VAR that was set at run-time:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Task description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:name_of_task&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  my_setting1 = &lt;span class="co"&gt;ENV&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;HOME&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  my_setting2 = &lt;span class="co"&gt;ENV&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;MY_VAR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Your code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See below for information on how to set variables at run-time.&lt;/p&gt;
&lt;h3 id="shell-output"&gt;Outputting Messages to the Shell&lt;/h3&gt;
&lt;p&gt;By default, Rake echoes error messages and the file handling operations of &lt;em&gt;RakeFileUtils&lt;/em&gt; to the shell. You can use standard Ruby methods to output your own messages as normal:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Task description&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:name_of_task&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  puts &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;foo bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Your output appears even if Rake runs with the --quiet or --silent options.&lt;/p&gt;
&lt;h2 id="scaling"&gt;Managing Large Numbers of Tasks&lt;/h2&gt;
&lt;p&gt;If the number of required tasks in a set begins to grow, you can ensure that they remain easy to use and maintain with two techniques. First, you can assign some of your tasks to separate &lt;em&gt;namespaces&lt;/em&gt;, so that task names remain unique and unambiguous. Second, you can write code into the Rake file to dynamically generate tasks, enabling it to create many variations of the same process, or adapt the available tasks to the host system.&lt;/p&gt;
&lt;h3 id="namespaces"&gt;Using Namespaces to Organize Tasks&lt;/h3&gt;
&lt;p&gt;To avoid duplicate or ambiguous names in large sets of tasks, enclose some of the tasks in namespaces. By convention, each namespace should be identified by one word, in lowercase. You may nest your namespaces, as this example shows:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;namespace &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;build&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# tasks...  &lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;namespace &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="c"&gt;# tasks...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  namespace &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;   &lt;span class="c"&gt;# tasks...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To reference a task that is within a namespace, prefix the name of the task with the namespace and a colon:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Example of a task with namespaced prerequisites&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;task &lt;span class="sy"&gt;:third_task&lt;/span&gt; =&amp;gt; [&lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;build:first_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;test:unit:second_task&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="c"&gt;# Your code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The command-line utility uses the same naming convention:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;localhost:railsapp me$ rake -T
(in /Users/me/railsapp)
...
rake rails:freeze:edge                    # Lock to latest Edge Rails
rake rails:freeze:gems                    # Lock this application to the current gems
rake rails:template                       # Applies the template supplied by LOCATION
rake rails:unfreeze                       # Unlock this application from freeze of gem
...&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above was taken from the task list of a standard Ruby on Rails application.&lt;/p&gt;
&lt;h3 id="dynamic-tasks"&gt;Defining Tasks Dynamically&lt;/h3&gt;
&lt;p&gt;To dynamically generate task definitions as the task file runs, directly integrate the definition keywords into Ruby code. All of the Rake keywords are actually Ruby methods that declare tasks, descriptions and namespaces as the tasks file is executed.&lt;/p&gt;
&lt;p&gt;The example shown below dynamically creates a suite of tasks by loading &lt;span class="caps"&gt;YAML&lt;/span&gt; format configuration files from a directory. It produces a separate namespace for each configuration file.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ruby"&gt;&lt;table class="CodeRay"&gt;&lt;tr&gt;
&lt;td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"&gt;&lt;pre&gt;1&lt;tt&gt;
&lt;/tt&gt;2&lt;tt&gt;
&lt;/tt&gt;3&lt;tt&gt;
&lt;/tt&gt;4&lt;tt&gt;
&lt;/tt&gt;5&lt;tt&gt;
&lt;/tt&gt;6&lt;tt&gt;
&lt;/tt&gt;7&lt;tt&gt;
&lt;/tt&gt;8&lt;tt&gt;
&lt;/tt&gt;9&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;10&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;11&lt;tt&gt;
&lt;/tt&gt;12&lt;tt&gt;
&lt;/tt&gt;13&lt;tt&gt;
&lt;/tt&gt;14&lt;tt&gt;
&lt;/tt&gt;15&lt;tt&gt;
&lt;/tt&gt;16&lt;tt&gt;
&lt;/tt&gt;17&lt;tt&gt;
&lt;/tt&gt;18&lt;tt&gt;
&lt;/tt&gt;19&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;20&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;21&lt;tt&gt;
&lt;/tt&gt;22&lt;tt&gt;
&lt;/tt&gt;23&lt;tt&gt;
&lt;/tt&gt;24&lt;tt&gt;
&lt;/tt&gt;25&lt;tt&gt;
&lt;/tt&gt;26&lt;tt&gt;
&lt;/tt&gt;27&lt;tt&gt;
&lt;/tt&gt;28&lt;tt&gt;
&lt;/tt&gt;29&lt;tt&gt;
&lt;/tt&gt;&lt;strong&gt;30&lt;/strong&gt;&lt;tt&gt;
&lt;/tt&gt;31&lt;tt&gt;
&lt;/tt&gt;32&lt;tt&gt;
&lt;/tt&gt;33&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
  &lt;td class="code"&gt;&lt;pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"&gt;require &lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;yaml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Uses FileList to get an Array of the configuration files&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;CONFIG_FILES&lt;/span&gt;=&lt;span class="co"&gt;FileList&lt;/span&gt;[&lt;span class="s"&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="k"&gt;config/*.yml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="c"&gt;# Returns the configuration from the file as a Hash object&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;def&lt;/span&gt; &lt;span class="fu"&gt;get_config&lt;/span&gt;(file)&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="co"&gt;YAML&lt;/span&gt;.load_file(file)&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="co"&gt;CONFIG_FILES&lt;/span&gt;.each &lt;span class="r"&gt;do&lt;/span&gt; |f|&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  config = get_config(f)&lt;tt&gt;
&lt;/tt&gt;  &lt;tt&gt;
&lt;/tt&gt;  namespace config[&lt;span class="sy"&gt;:name&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# Generate tasks&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;First task for &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;config[&lt;span class="sy"&gt;:name&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    task config[&lt;span class="sy"&gt;:first&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    desc &lt;span class="s"&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="k"&gt;Second task for &lt;/span&gt;&lt;span class="il"&gt;&lt;span class="idl"&gt;#{&lt;/span&gt;config[&lt;span class="sy"&gt;:name&lt;/span&gt;]&lt;span class="idl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    task config[&lt;span class="sy"&gt;:second&lt;/span&gt;] &lt;span class="r"&gt;do&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;      &lt;span class="c"&gt;# Code goes here&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;    &lt;span class="c"&gt;# more...&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;  &lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;span class="r"&gt;end&lt;/span&gt;&lt;tt&gt;
&lt;/tt&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;/tr&gt;&lt;/table&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This approach enables us to cleanly generate multiple tasks with appropriate namespaces. If we only needed to generate a task for each file, we could make an even simpler routine by using a Rule to create the tasks.&lt;/p&gt;
&lt;h2 id="running-rake-more"&gt;More Advanced Options for Running Rake Tasks&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;rake&lt;/em&gt; utility provides many options. Some of these options are useful in many situations for testing, or for working around issues with the host system.&lt;/p&gt;
&lt;h3 id="running-altfile"&gt;Specifying the Location of the Tasks File&lt;/h3&gt;
&lt;p&gt;To use a specific Rake file of your choice, use either -f, or --rakefile:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake --rakefile my_task_file my_task&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To use tasks from the Rake files from your &lt;em&gt;.rake&lt;/em&gt; directory, use the -g option:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake -g -T
rake -g my_task&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This option automatically uses all of the &lt;em&gt;.rake&lt;/em&gt; files in the directory.&lt;/p&gt;
&lt;h3 id="running-silent"&gt;Suppressing the Output of Tasks&lt;/h3&gt;
&lt;p&gt;The --quiet option only suppresses normal output. Use --silent to run Rake with absolutely no output at all:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake --silent my_task&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="running-env-variables"&gt;Specifying Environment Variables for a Task&lt;/h3&gt;
&lt;p&gt;To specify environment variables for your tasks along with your command, simply use the format &lt;em&gt;variable=value&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake my_task my_var1='Some value' my_var2='Another value'&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="running-debug"&gt;Debugging Tasks&lt;/h3&gt;
&lt;p&gt;Finally, to debug a Rake task, either use the --dry-run option to see what steps it will take, without actually executing them, or specify --trace to see detailed output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rake --dry-run my_task
rake --trace my_task&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Remember that Ruby itself includes a debugger that works on the command-line.&lt;/p&gt;
&lt;h2 id="automation-others"&gt;Other Automation Tools&lt;/h2&gt;
&lt;p&gt;Beyond Rake, Ruby has a broad range of other useful automation software. These are a few of the most well-known:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;a href="http://github.com/wycats/thor"&gt;Thor&lt;/a&gt; scripting framework provides a powerful general-purpose system for defining and running tasks.&lt;/li&gt;
	&lt;li&gt;
&lt;a href="http://www.capify.org/"&gt;Capistrano&lt;/a&gt; is the leading utility for automating server application deployments and upgrades.&lt;/li&gt;
	&lt;li&gt;
&lt;a href="http://rubyhitsquad.com/Vlad_the_Deployer.html"&gt;Vlad&lt;/a&gt; is a rival to Capistrano which directly extends Rake.&lt;/li&gt;
	&lt;li&gt;
&lt;a href="http://reductivelabs.com/products/puppet"&gt;Puppet&lt;/a&gt; enables you to automate the management of a network of varied systems, throughout their lifecycle.&lt;/li&gt;
	&lt;li&gt;
&lt;a href="http://wiki.opscode.com/display/chef/Home"&gt;Chef&lt;/a&gt; provides an alternative to Puppet that is perhaps more suited to Ruby developers who must maintain application servers.&lt;/li&gt;
&lt;/ul&gt;&lt;h2 id="resources"&gt;Useful Resources&lt;/h2&gt;
&lt;h3 id="tutorials"&gt;Tutorials&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://www.railsenvy.com/2007/6/11/ruby-on-rails-rake-tutorial"&gt;Ruby on Rails Rake Tutorial&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://docs.rubyrake.org/"&gt;The official Rake tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h3 id="reference"&gt;Reference Documents&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://rake.rubyforge.org/"&gt;The official &lt;span class="caps"&gt;API&lt;/span&gt; documentation&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.martinfowler.com/articles/rake.html"&gt;Martin Fowler’s guide to Rake&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://ghouston.blogspot.com/2008/07/rake-quick-reference.html"&gt;Rake Quick Reference, by Greg Hudson&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;h3 id="tips"&gt;Hints and Tips&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://blog.jayfields.com/2006/11/ruby-testing-rake-tasks.html"&gt;Jay Fields on Testing Rake Tasks&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;&lt;a href="http://www.jbarnette.com/2009/08/27/on-rake.html"&gt;John Barnette on Rake&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
  </entry>
  <entry>
    <id>tag:www.stuartellis.eu,2011-02-06:/articles/unix-security-features/</id>
    <title type="html">Linux and UNIX Security Features</title>
    <published>2011-02-06T17:50:00Z</published>
    <updated>2011-02-06T17:50:00Z</updated>
    <link rel="alternate" href="http://www.stuartellis.eu/articles/unix-security-features/"/>
    <content type="html">&lt;p&gt;An introduction to the security facilities of Open Source &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like operating systems, focusing on Linux distributions.&lt;/p&gt;
&lt;h2 id="feature-accounts"&gt;User Accounts&lt;/h2&gt;
&lt;p&gt;Every &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system includes a root account, which is the only account that may directly carry out administrative functions. All of the other accounts on the system are &lt;em&gt;unprivileged&lt;/em&gt;. This means these accounts have no rights beyond access to files marked with appropriate permissions, and the ability to launch network services.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Network Ports&lt;/em&gt;: Only the root account may launch network services that use port numbers lower than 1024. Any account may start network services that use higher port numbers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each user should have a single account on the system. Network services may also have their own separate accounts, in order to be able to access those files on the system that they require. Utilities enable authorized users to temporarily obtain root privileges when necessary, so that administrators may manage the system with their own user accounts.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Avoid Logging in as root&lt;/em&gt;: You do not need to log in with the root account in order to manage any aspect of your system. Use tools such as su or sudo when you need to carry out an administrative task that requires root privileges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For convenience, accounts may be members of one or more &lt;em&gt;groups&lt;/em&gt;. If a group is assigned access to a resource, then every member of the group automatically has that access.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;User Private Groups&lt;/em&gt;: On many distributions, each account is automatically made the sole member of a group with the same name as the account. This enables you to easily limit access to particular files or directories, by associating them with a group that will only ever have one member.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The majority of &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems use a &lt;em&gt;Pluggable Authentication Modules (&lt;span class="caps"&gt;PAM&lt;/span&gt;)&lt;/em&gt; facility to manage access by users. For each login attempt or password change, the relevant service runs the configured &lt;em&gt;&lt;span class="caps"&gt;PAM&lt;/span&gt;&lt;/em&gt; modules in sequence. Some modules support authentication sources, such as locally-stored files or &lt;em&gt;&lt;span class="caps"&gt;LDAP&lt;/span&gt;&lt;/em&gt; directory services. Administrators may enable other modules that carry out setup tasks during the login process, or check login requests against particular criteria, such as a list of time periods when access is permitted.&lt;/p&gt;
&lt;h2 id="feature-permissions"&gt;File Permissions&lt;/h2&gt;
&lt;p&gt;Every file and directory on a &lt;span class="caps"&gt;UNIX&lt;/span&gt;-style system is marked with three sets of file permissions that determine how it may be accessed, and by whom:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The permissions for the &lt;em&gt;owner&lt;/em&gt;, the specific account that is responsible for the file&lt;/li&gt;
	&lt;li&gt;The permissions for the &lt;em&gt;group&lt;/em&gt; that may use the file&lt;/li&gt;
	&lt;li&gt;The permissions that apply to all &lt;em&gt;other&lt;/em&gt; accounts&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Each set may have none or more of the following permissions on the item:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;read&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;write&lt;/em&gt;&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;execute&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;A user may only run a program file if they belong to a set that has the &lt;em&gt;execute&lt;/em&gt; permission. For directories, the &lt;em&gt;execute&lt;/em&gt; permission indicates that users in the relevant set may see the files within it, although they may not actually read, write or execute any file unless the permissions of that file permit it. Executable files with the &lt;em&gt;setUID&lt;/em&gt; property automatically run with the privileges of the file owner, rather than the account that activates them. Avoid setting the execute permission or setUID on any file or directory unless you specifically require it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;root Ignores File Permissions&lt;/em&gt;: The root account has full access to every file on the system, regardless of the permissions attached to that file.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The majority of files on a &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system are owned by the root account, and have permissions that restrict or block access from all other accounts. Avoid modifying the permissions on system files and directories.&lt;/p&gt;
&lt;p&gt;Historically, user home directories on &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems were publicly readable, to facilitate sharing between academic colleagues. Unfortunately, some popular operating systems still make user home directories publicly readable by default.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Access Control Lists&lt;/em&gt;: Many, but not all, modern &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems include support for a more flexible set of permissions known as &lt;em&gt;Access Control Lists&lt;/em&gt; (ACLs). Unfortunately, some common applications are not fully compatible with &lt;span class="caps"&gt;ACL&lt;/span&gt; permissions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="feature-data-verification"&gt;Data Verification&lt;/h2&gt;
&lt;p&gt;To create a checksum for a file, or to test a file against a checksum, use the &lt;em&gt;sha1sum&lt;/em&gt; utility. SHA1 supersedes the older MD5 method, and you should always use SHA1. For more information about about sha1sum, refer to the manual:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;man sha1sum&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open Source &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems also supply the &lt;span class="caps"&gt;GNU&lt;/span&gt; Privacy Guard (GnuPG) system for encrypting and digitally signing files, such as emails. Many documents refer to GnuPG as &lt;em&gt;gpg&lt;/em&gt;, which is the name of the main GnuPG command.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;GnuPG Follows the OpenPGP Standard&lt;/em&gt;: The files that you sign or encrypt with GnuPG are compatible with other applications that follow the &lt;em&gt;OpenPGP&lt;/em&gt; standard.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The Evolution email application automatically supports both signing and encrypting emails with GnuPG. Evolution is the default email application for several of the main Linux distributions, including Fedora, Novell Linux Desktop, Red Hat Enterprise Linux, and Ubuntu.&lt;/p&gt;
&lt;p&gt;To use other GnuPG features in the &lt;span class="caps"&gt;GNOME&lt;/span&gt; desktop environment, install Seahorse through the standard software management tool for your distribution. For more information on Seahorse, refer to the project Web site:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.gnome.org/projects/seahorse/"&gt;http://www.gnome.org/projects/seahorse/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To integrate GnuPG with Mozilla Thunderbird, add the Enigmail extension to Thunderbird. Refer to the Enigmail Web page for installation instructions and other details:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://enigmail.mozdev.org/"&gt;http://enigmail.mozdev.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For more information on GnuPG itself, refer to the project Web site:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.gnupg.org/"&gt;http://www.gnupg.org/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="feature-data-encryption"&gt;Encrypted Storage&lt;/h2&gt;
&lt;p&gt;Create one or more &lt;em&gt;encrypted volumes&lt;/em&gt; for your sensitive files. Each volume is a single file which may enclose other files and directories of your choice. To access the contents of the volume, you must provides the correct decryption password to a utility, which then makes the volume available as if it were a directory or drive. The contents of an encrypted volume cannot be read when the volume is not mounted. You may store or copy encrypted volume files as you wish without affecting their security.&lt;/p&gt;
&lt;p&gt;The cross-platform Truecrypt utility enables you to create and access your encrypted volumes with all popular operating systems:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.truecrypt.org/"&gt;http://www.truecrypt.org/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In extreme cases, you may decide to encrypt an entire disk partition that holds or caches data, so that none of the contents may be read by unauthorized persons. On Linux you may use either &lt;a href="http://luks.endorphin.org/"&gt;&lt;span class="caps"&gt;LUKS&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://reboot.animeirc.de/cryptofs/"&gt;CryptoFS&lt;/a&gt;, or &lt;a href="http://encfs.sourceforge.net/"&gt;EncFS&lt;/a&gt; to encrypt disks. Unfortunately, many &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems do not yet integrate support for disk encryption facilities into their installation and management software, which makes configuration and maintenance more difficult. Disk encryption also reduces performance, and this may not be acceptable for systems that run demanding applications.&lt;/p&gt;
&lt;h2 id="feature-ssh"&gt;Secure Remote Access with OpenSSH&lt;/h2&gt;
&lt;p&gt;Every common &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system today includes a version of &lt;em&gt;OpenSSH&lt;/em&gt;, an implementation of the &lt;em&gt;&lt;span class="caps"&gt;SSH&lt;/span&gt;&lt;/em&gt; standard for secure remote access. An &lt;span class="caps"&gt;SSH&lt;/span&gt; service uses strong encryption by default, and provides the following facilities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remote command-line access&lt;/li&gt;
	&lt;li&gt;Remote command execution&lt;/li&gt;
	&lt;li&gt;Remote access to graphical software&lt;/li&gt;
	&lt;li&gt;File transfers&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;In addition, the forwarding features of &lt;span class="caps"&gt;SSH&lt;/span&gt; allow you to &lt;em&gt;tunnel&lt;/em&gt; connections to other services through &lt;span class="caps"&gt;SSH&lt;/span&gt;. A tunneled service benefits from the same security and data compression features as the built-in facilities of &lt;span class="caps"&gt;SSH&lt;/span&gt;. This enables you to protect almost all communications between any &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems, even when the traffic passes over open wireless networks or the public Internet.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;SSH&lt;/span&gt; software not only encrypts the connection between systems, but also uses a system of keys to provide &lt;em&gt;mutual authentication&lt;/em&gt; between each party. Each &lt;span class="caps"&gt;SSH&lt;/span&gt; client utility automatically checks the identity of any remote system that it connects to, by verifying the key. Similarly, users may identify themselves to systems with a key, rather than typing potentially crackable passwords.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Use &lt;span class="caps"&gt;SSH&lt;/span&gt; by Default&lt;/em&gt;: &lt;span class="caps"&gt;SSH&lt;/span&gt; potentially offers the most secure method of remote access available today. The standard Open Source desktop environments now also support &lt;span class="caps"&gt;SSH&lt;/span&gt; as a standard method for working with remote files. Only enable access to your systems through other services if you need to do so in order to meet a specific requirement.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Most Linux distributions include the OpenSSH client by default. The OpenSSH service as usually offered as an option, although some distributions also provide it by default. Mac OS X includes both the OpenSSH service, and the client utilities. To access &lt;span class="caps"&gt;SSH&lt;/span&gt; services from Microsoft Windows systems, install PuTTY. You may download PuTTY from the main project Web site:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.chiark.greenend.org.uk/%7Esgtatham/putty/"&gt;http://www.chiark.greenend.org.uk/%7Esgtatham/putty/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;FileZilla, WinSCP, and other file transfer utilities for Microsoft Windows also support &lt;span class="caps"&gt;SSH&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The OpenBSD project maintains the OpenSSH software and Web site:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.openssh.com/"&gt;http://www.openssh.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="feature-sw-manage"&gt;Software Management&lt;/h2&gt;
&lt;p&gt;The majority of Linux distributions incorporate software management facilities based on &lt;em&gt;package&lt;/em&gt; files and sets of specially prepared Web sites, known as &lt;em&gt;repositories&lt;/em&gt; or &lt;em&gt;channels&lt;/em&gt;. Package management utilities construct or update working copies of software from these packages, and execute any other setup tasks that packages require. Repositories enable the management tools to automatically provide the correct version of each software product, by downloading the required packages directly from the relevant repository. Most systems also use checksums and digital signature tests to ensure that packages are authentic and correct.&lt;/p&gt;
&lt;p&gt;In addition, package management tools can identify outdated versions of software by checking the software installed on a system against the packages in the repositories. This means that you can ensure that all of the supported software on your system does not suffer from a known security vulnerability, simply by running the update routine.&lt;/p&gt;
&lt;p&gt;Most desktop systems now automatically alert you when new versions of the installed packages are released to the repositories, and provide options to update your system. Graphical interfaces to their software management tools also enable you to browse and select new software from the available packages.&lt;/p&gt;
&lt;p&gt;Use packages from repositories whenever possible, in order to guarantee the provenance of the software on your system, and to ensure that it remains current. If you use software from elsewhere then you will need to verify, install, and update those products yourself. In these cases, download the software directly from the Web site of the manufacturer. Package management tools cannot inventory, check, or maintain any software that was compiled from source code, so you must be particularly careful when you use manually compiled products.&lt;/p&gt;
&lt;p&gt;For historical reasons, the main Linux distributions use different package management products. Fedora, Red Hat Enterprise Linux, and related distributions, use the &lt;span class="caps"&gt;RPM&lt;/span&gt; package format, and their software management facility is known as &lt;span class="caps"&gt;YUM&lt;/span&gt;. Debian, Ubuntu, and their derivatives, use the &lt;span class="caps"&gt;APT&lt;/span&gt; management system and the &lt;span class="caps"&gt;DEB&lt;/span&gt; package format. These systems and package formats are largely equivalent.&lt;/p&gt;
&lt;h2 id="feature-integrity-testing"&gt;Host Integrity Testing&lt;/h2&gt;
&lt;p&gt;To verify that a running system has not been compromised or tampered with, use an integrity testing facility. All host integrity testing software verifies a complete copy of a system by testing each file against a previously made checksum. Solaris and FreeBSD distributions both now include integrity testing utilities for this purpose. You may also use a cross-platform integrity monitoring system, such as Samhain or Osiris. Both Osiris and Samhain support centralized system auditing for multiple systems.&lt;/p&gt;
&lt;p&gt;Since system configurations vary, administrators must configure the integrity tester to exclude the particular directories and files that are expected to change on a system, before creating an initial checksum database for that system. Integrity testing can then compare the checksums of each file against the database, and report on any disparity.&lt;/p&gt;
&lt;h2 id="feature-recovery"&gt;System Recovery&lt;/h2&gt;
&lt;p&gt;You may easily restore program files for all of the software that is included with your distribution with the software management tools. In order to fully recover a system from accident, or deliberate compromise, you must also have access to copies of the data, configuration, and log files. These files require some form of separate backup mechanism.&lt;/p&gt;
&lt;p&gt;All effective backup systems provide the ability to restore versions of your files from several earlier points in time. You may discover that the current system is damaged or compromised at any time, and need to revert to previous versions of key files, so keeping only one additional copy of a key file should not be considered an adequate backup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Duplicates Are Not Archives&lt;/em&gt;: File synchronization software and &lt;span class="caps"&gt;RAID&lt;/span&gt; storage make duplicate copies of the current files, and may act as a safeguard against data loss from hardware failures. Unlike backup systems, these measures do not provide access to previous versions of files.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Distributions provide a wide range of backup tools, and leave it to the administrator to configure a suitable backup arrangement for their systems.&lt;/p&gt;
&lt;h2 id="feature-allocation"&gt;Resource Allocation Controls&lt;/h2&gt;
&lt;p&gt;You may configure several mechanisms to limit the resources that an application or user account may consume. On systems with multiple users, enforce resource limits to ensure that no user may accidental or deliberately cause facilities to fail by using all of the available resources. Since the correct resource allocations vary widely, administrators must configure appropriate limits for the system.&lt;/p&gt;
&lt;p&gt;To set resource limits for individual applications, add a ulimit setting to the shell script that launches them. For more information about about ulimit, refer to the manual for the bash shell:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;info bash&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;&lt;span class="caps"&gt;PAM&lt;/span&gt;&lt;/em&gt; login system includes a module to enforce certain resource limits for entire user sessions. The restrictions that this imposes may be circumvented, but they do provide some defence against accidental problems.&lt;/p&gt;
&lt;p&gt;You must specifically enable storage quotas on each disk partition, if you require them. Quotas prevent users from overloading the storage and backup facilities, but quota management is often an administrative matter rather than a direct security concern. Configuring storage quotas is beyond the scope of this document.&lt;/p&gt;
&lt;h2 id="feature-audit"&gt;Monitoring and Audit Facilities&lt;/h2&gt;
&lt;p&gt;On Linux systems, the &lt;em&gt;syslog&lt;/em&gt; and &lt;em&gt;klogd&lt;/em&gt; services record activity as it is reported by different parts of the system. The Linux kernel reports to klogd, whilst the other services and facilities on the system send log messages to a syslog service. Distributions provide several tools for reading and analyzing the system log files.&lt;/p&gt;
&lt;p&gt;Several facilities on any &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system may also email reports and notifications directly to the root account, via the &lt;em&gt;&lt;span class="caps"&gt;SMTP&lt;/span&gt;&lt;/em&gt; service. Edit the aliases file to redirect messages for root to another email address, and you will receive these emails at the specified address.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Automatic Log Summaries&lt;/em&gt;: Many distributions automatically send daily reports to the email address for root that summarize the activity logged by syslog and klogd.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To provide a central logging facility for your network, first select one of your systems as the log host. Configure the syslog services on your other systems to forward the information that they receive to the syslog service on the log host. You may then run analyzers on the log host to monitor events across the network.&lt;/p&gt;
&lt;p&gt;For detailed real-time monitoring of the systems on your network, install &lt;span class="caps"&gt;SNMP&lt;/span&gt; agents that report to a management service such as Nagios or OpenNMS. &lt;span class="caps"&gt;SNMP&lt;/span&gt; is beyond the scope of this document.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Monitoring Network Appliances&lt;/em&gt;: Many network appliances, such as routers, support the syslog and &lt;span class="caps"&gt;SNMP&lt;/span&gt; standards. This enables you to monitor both &lt;span class="caps"&gt;UNIX&lt;/span&gt; systems and other network devices with the same log hosts and &lt;span class="caps"&gt;SNMP&lt;/span&gt; services.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Refer to the man page for basic information about syslogd:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;man syslogd&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Similarly, for more on klogd, refer to the man page:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;man klogd&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Both syslog and &lt;span class="caps"&gt;SNMP&lt;/span&gt; rely on software dispatching messages to a central service. If you configure &lt;em&gt;process accounting&lt;/em&gt; on a system it maintains records of all the processes that are run on that system. Linux includes some support for process accounting, and distributions supply packages for &lt;span class="caps"&gt;GNU&lt;/span&gt; Accounting Utilities. Refer to the Web page for more information on the &lt;span class="caps"&gt;GNU&lt;/span&gt; Accounting Utilities:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.gnu.org/software/acct/"&gt;http://www.gnu.org/software/acct/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Fedora and Red Hat Enterprise Linux systems also offer the LAuS (Linux Auditing System) framework. For more information on this, refer to the man pages for auditd:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;man auditd&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="feature-firewall"&gt;The System Firewall&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;netfilter&lt;/em&gt; framework included in the Linux kernel restricts incoming and outgoing network connections according to a set of rules that have been defined by the administrator. Several Linux distributions configure firewall rules by default, and offer utilities for managing simple firewall configurations. You may also manage the firewall rules on any Linux system with the standard iptables and ip6tables command-line utilities, or with third-party utilities such as &lt;a href="http://www.fs-security.com/"&gt;Firestarter&lt;/a&gt;. If you decide to use iptables, remember that it only configures restrictions for IP version 4 connections, and that you will need to use ip6tables to setup rules for IP version 6 as well.&lt;/p&gt;
&lt;p&gt;Fedora, Mandriva, Red Hat, and &lt;span class="caps"&gt;SUSE&lt;/span&gt; automatically enable the firewall and supply their own graphical configuration utilities. You must manually configure and enable the firewall on Debian and Ubuntu systems. Current releases of Ubuntu include a command-line utility called &lt;em&gt;ufw&lt;/em&gt; for firewall configuration.&lt;/p&gt;
&lt;p&gt;Those Linux distributions that enable a firewall by default use a netfilter configuration that blocks connections from other systems. Any attempt by a remote system to access a service on a blocked port simply fails. This means that no other system may connect to an installed service, unless you specifically choose to unblock the relevant port.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Use Only One Means Of Managing Your Firewall&lt;/em&gt;: Every firewall utility modifies the current firewall rules on the system. To ensure that your firewall operates correctly, select one method of managing the configuration, and avoid editing the firewall rules by other means.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="feature-isolation"&gt;Application Isolation&lt;/h2&gt;
&lt;p&gt;The most common &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like operating systems provide several methods of limiting the ability of a program to affect either other running programs, or the host system itself.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Mandatory Access Control (&lt;span class="caps"&gt;MAC&lt;/span&gt;)&lt;/em&gt; supplements the normal &lt;span class="caps"&gt;UNIX&lt;/span&gt; security facilities of a system by enforcing absolute limits that cannot be circumvented by any program or account.&lt;/li&gt;
	&lt;li&gt;
&lt;em&gt;Virtualization&lt;/em&gt; enables you to assign a limited set of hardware resources to a virtual machine, which may be monitored and backed up by separate processes on the host system.&lt;/li&gt;
	&lt;li&gt;The &lt;em&gt;chroot&lt;/em&gt; utility runs programs within a specified working directory, and prevents them from accessing any other directory on that system.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The administrator may setup guest operating systems in virtual environments for specific tasks, and restrict these guests far more than would be possible for a multi-purpose system. Each specialized system may include far less software, and this also simplifies every administrative task, including &lt;span class="caps"&gt;MAC&lt;/span&gt; configuration. Neither &lt;span class="caps"&gt;MAC&lt;/span&gt; nor virtualization prevent individual applications or services from being compromised, misconfigured or malfunctioning, but may prevent a problem from escalating.&lt;/p&gt;
&lt;p&gt;At the simplest level, the &lt;em&gt;SELinux&lt;/em&gt; framework can provide &lt;span class="caps"&gt;MAC&lt;/span&gt; facilities, to enforce a policy that defines the access permitted to programs or accounts on the system. SELinux was actually created by the &lt;span class="caps"&gt;NSA&lt;/span&gt; to meet the needs of government agencies handling classified data, and enables administrators to develop extremely detailed and precise security configurations that encompass the entire operating system. Many developers and administrators consider SELinux too high a maintenance burden to implement fully.&lt;/p&gt;
&lt;p&gt;Fedora and Red Hat Enterprise Linux systems automatically include a limited SELinux policy that restricts many standard network services, without affecting users or other programs. These distributions also provide some simple management tools for customizing the default policy and troubleshooting SELinux issues, but no tools to assist with developing new policies.&lt;/p&gt;
&lt;p&gt;Ubuntu, &lt;span class="caps"&gt;SUSE&lt;/span&gt;, and Mandriva do not enable SELinux by default. Instead, they provide the &lt;em&gt;AppArmor&lt;/em&gt; facility. AppArmor configuration is much simpler than SELinux, but it offers more limited capabilities.&lt;/p&gt;
&lt;p&gt;Several Open Source solutions exist to run complete operating systems within a virtual environment. By far the most popular are are &lt;em&gt;Xen&lt;/em&gt; and &lt;span class="caps"&gt;KVM&lt;/span&gt;. Xen enables you to configure a system to act as a host for multiple virtual environments, all of which are controlled by a single hypervisor. Current Linux distributions on machines that include CPUs with virtualization support may run the simpler and more flexible &lt;span class="caps"&gt;KVM&lt;/span&gt;. The current &lt;span class="caps"&gt;KVM&lt;/span&gt; offers significantly higher performance than the &lt;span class="caps"&gt;QEMU&lt;/span&gt; machine emulator that is it based upon. The original &lt;span class="caps"&gt;QEMU&lt;/span&gt; software operates too slowly for production applications, although it remains useful for testing and development work.&lt;/p&gt;
&lt;p&gt;The older &lt;em&gt;chroot&lt;/em&gt; facility is universally available, but was originally designed for development tasks rather than security, and may be circumvented. Developers use this facility for building and testing software in a clean environment. Historically, administrators also used &lt;em&gt;chroot&lt;/em&gt; to run potentially unsafe network services such as &lt;span class="caps"&gt;FTP&lt;/span&gt; servers within specially designed environments. Several tools exist to simplify constructing and maintaining chroot environments.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Applications May Escape chroot&lt;/em&gt;: Any application that is able to run arbitrary commands can execute code to gain access to the main system. To ensure the security of the chroot environment, avoid including shells, compilers, or script interpreters within the chroot directory. Any application that runs with root privileges may also escape the restrictions of chroot.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For more information about chroot, refer to the manual:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;info chroot&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="unix-malware"&gt;A Note on Viruses and Malware&lt;/h2&gt;
&lt;p&gt;The security features of &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems described above combine to form a strong defense against malware:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Software is often supplied in the form of packages, rather than programs&lt;/li&gt;
	&lt;li&gt;If you download a working program, it cannot run until you choose to mark the files as executable&lt;/li&gt;
	&lt;li&gt;By default, applications such as the OpenOffice.org suite and the Evolution email client do not run programs embedded in emails or documents&lt;/li&gt;
	&lt;li&gt;Web browsers require you to approve the installation of plug-ins&lt;/li&gt;
	&lt;li&gt;Software vulnerabilities can be rapidly closed by vendors supplying updated packages to the repositories&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Although a virus could be written for use against current &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems, no effective malware is known to exist. It is likely that any future malware would need the consent of a user on the system in order to install itself, significantly reducing the possibility that any such software would be able to spread across networks.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.stuartellis.eu,2011-02-06:/articles/installing-ruby/</id>
    <title type="html">Installing Ruby</title>
    <published>2011-02-06T17:49:00Z</published>
    <updated>2011-02-06T17:49:00Z</updated>
    <link rel="alternate" href="http://www.stuartellis.eu/articles/installing-ruby/"/>
    <content type="html">&lt;p&gt;Installing Ruby itself is quick and easy, but this page also covers a few additional steps that are needed for an ideal Ruby 1.8 environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installing a C compiler, so that RubyGems can compile native extensions for the gems that you install.&lt;/li&gt;
	&lt;li&gt;Ensuring that the installed copy of RubyGems package manager is at least version 1.3.6, so that third-party libraries and frameworks install correctly.&lt;/li&gt;
	&lt;li&gt;Setting up a private gem directory within your home directory, so that you can add and remove gems without any risk of disrupting the system copy of Ruby.&lt;/li&gt;
&lt;/ul&gt;&lt;blockquote&gt;
&lt;p&gt;The installation notes for Linux were adapted from posts on &lt;a href="http://www.hackido.com/2009/11/install-ruby-on-rails-on-ubuntu-karmic.html"&gt;Hackido&lt;/a&gt; and &lt;a href="http://ascarter.net/2010/05/10/rails-development-on-ubuntu-10.04.html"&gt;Coding in the Rain&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="linux-install"&gt;Installing Ruby on Linux&lt;/h2&gt;
&lt;p&gt;All of the Linux distributions provide packages for Ruby. Ubuntu and other Debian-based systems split Ruby into multiple packages, so you need to specify several packages to get the complete set. To install Ruby on Ubuntu, enter the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install ruby irb rdoc ruby-dev libopenssl-ruby libreadline-ruby&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Debian and Ubuntu distributions also provide packages of example code:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install ruby1.8-examples&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once the package is installed, check /usr/share/doc/ruby1.8-examples/ for the example scripts.&lt;/p&gt;
&lt;h3 id="linux-compiler"&gt;Installing a C Compiler&lt;/h3&gt;
&lt;p&gt;Run this command to install a C compiler:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install build-essential&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="linux-rubygems"&gt;Installing RubyGems&lt;/h3&gt;
&lt;p&gt;Download RubyGems directly from the RubyForge Web site. Vendor packages for RubyGems are always out of date, as new versions of RubyGems are released quite frequently.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wget http://rubyforge.org/frs/download.php/70696/rubygems-1.3.7.tgz
tar xvzf rubygems-1.3.7.tgz
cd rubygems-1.3.7
sudo ruby setup.rb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On Ubuntu and other Debian-based systems, run this command to register &lt;em&gt;gem1.8&lt;/em&gt; with the alias &lt;em&gt;gem&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo update-alternatives --install /usr/bin/gem gem /usr/bin/gem1.8 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, run this command to test that everything is working as it should:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem --version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may delete the tar (.tgz) file and the uncompressed directory once you have run the setup script.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Install Gems To Your Home Directory:&lt;/em&gt; This ensures that RubyGems installs and updates packages to your home directory, leaving the system copies untouched.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="homedir-gems"&gt;Recommended: Installing Gems to Your Home Directory&lt;/h3&gt;
&lt;p&gt;Where possible, avoid installing gems into the global system. This ensures that the gems that you install are easy to identify and manage, and do not interfere with the global Ruby installation.&lt;/p&gt;
&lt;p&gt;As of RubyGems 1.3, RubyGems will automatically install gems into the directory specified by the GEM_HOME environment variable if the system location is not accessible. You will see that directories are created within your GEM_HOME directory to store gem files. This means that RubyGems will do the right thing when managing packages, provided that you do &lt;strong&gt;not&lt;/strong&gt; run the &lt;em&gt;gem&lt;/em&gt; utility with administrative privileges.&lt;/p&gt;
&lt;p&gt;To do this, edit the &lt;em&gt;.profile&lt;/em&gt; file in your home directory, and add or amend it to include these lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export GEM_HOME=$HOME/gems
export PATH=$GEM_HOME/bin:$PATH&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This takes effect the next time that you login or create a terminal window.&lt;/p&gt;
&lt;p&gt;The presence of the &lt;em&gt;bin&lt;/em&gt; subdirectory on your &lt;span class="caps"&gt;PATH&lt;/span&gt; enables you to use any command-line utilities that are installed with your gem packages.&lt;/p&gt;
&lt;h3 id="linux-sqlite"&gt;Installing SQLite on Linux for Ruby&lt;/h3&gt;
&lt;p&gt;To use the default Ruby on Rails configuration and other applications that depend upon SQLite, you need to install it separately. On Ubuntu and Debian-like systems, run this command to install SQLite:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt-get install libsqlite3-dev sqlite3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then install the Ruby driver for SQLite:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install sqlite3-ruby&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="install-windows"&gt;Ruby on Microsoft Windows&lt;/h2&gt;
&lt;p&gt;To install Ruby on Windows, first go to the &lt;a href="http://www.rubyinstaller.org/"&gt;RubyInstaller project Website&lt;/a&gt;. Download both the RubyInstaller and the Development Kit. The Development Kit provides a C compiler. Ignore the One-Click Installer options, as the One-Click Installer has been superseded by the RubyInstaller.&lt;/p&gt;
&lt;p&gt;Run the Ruby Installer, and accept the defaults. This automatically installs RubyGems. Follow &lt;a href="http://wiki.github.com/oneclick/rubyinstaller/development-kit"&gt;the instructions&lt;/a&gt; to setup the Development Kit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to have an archive utility installed, as Windows does not include support for the 7Zip format used to compress the Development Kit.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id="windows-proxies"&gt;Enabling Ruby and RubyGems to Work with an &lt;span class="caps"&gt;NTLM&lt;/span&gt; Web Proxy&lt;/h3&gt;
&lt;p&gt;To enable your Ruby installation with work with web proxy servers that require Windows authentication (known as &lt;span class="caps"&gt;NTLM&lt;/span&gt; authentication), use &lt;a href="http://rubyforge.org/projects/rubysspi/"&gt;rubysspi&lt;/a&gt;. This package includes several features to allow RubyGems and Ruby standard libraries to use such proxy servers.&lt;/p&gt;
&lt;p&gt;If RubyGems is not able to fetch gem packages at this point, use your Web browser to download the &lt;em&gt;rubysspi&lt;/em&gt; gem to your hard drive. Run the &lt;em&gt;gem&lt;/em&gt; utility, specifying the full name of the downloaded package file. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;gem install rubysspi-1.3.1.gem&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To enable RubyGems to work with &lt;span class="caps"&gt;NTLM&lt;/span&gt; proxies, simply install the gem and copy the file &lt;em&gt;spa.rb&lt;/em&gt; from the package directory (e.g. &lt;em&gt;C:\Ruby\lib\ruby\gems\1.8\gems\rubysspi-1.3.1&lt;/em&gt;) to the Ruby &lt;em&gt;site&lt;/em&gt; directory, which is &lt;em&gt;C:\Ruby\lib\ruby\site_ruby\1.8&lt;/em&gt; for Ruby 1.8.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;copy C:\Ruby\lib\ruby\gems\1.8\gems\rubysspi-1.3.1\spa.rb C:\Ruby\lib\ruby\site_ruby\1.8&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;RubyGems will then use remote servers as normal, transparently logging on to the default proxy server for the Windows installation with the credentials of the logged-in user. To set the default proxy server, go to &lt;em&gt;Start &amp;gt; Control Panel &amp;gt; Network and Internet &amp;gt; Internet Options &amp;gt; Connections &amp;gt; &lt;span class="caps"&gt;LAN&lt;/span&gt; Settings&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="windows-sqlite"&gt;Installing SQLite on Windows for Ruby&lt;/h3&gt;
&lt;p&gt;To use the default Ruby on Rails configuration and other applications that depend upon SQLite, you need to install it separately. Luis Lavena provides &lt;a href="http://blog.mmediasys.com/2009/07/06/getting-started-with-rails-and-sqlite3/"&gt;full instructions for setting up Rails and SQLite on Windows&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alternatively, you can use &lt;a href="http://copiousfreetime.rubyforge.org/amalgalite/"&gt;Amalgalite&lt;/a&gt;, which provides SQLite as a Ruby library. Install the &lt;a href="http://copiousfreetime.rubyforge.org/activerecord-amalgalite-adapter/"&gt;ActiveRecord adapter for Amalgalite&lt;/a&gt; to use Amalgalite with Ruby on Rails.&lt;/p&gt;
&lt;h2 id="osx-install"&gt;Ruby on Mac OS X&lt;/h2&gt;
&lt;p&gt;Current versions of Mac OS X include Ruby, along with Rails and supporting libraries. To install a C compiler, run the XCode Tools setup. The XCode Tools package is on the OS X Install &lt;span class="caps"&gt;DVD&lt;/span&gt; provided with current Macs, in the Optional Installs folder.&lt;/p&gt;</content>
  </entry>
  <entry>
    <id>tag:www.stuartellis.eu,2011-02-06:/articles/linux-with-active-directory/</id>
    <title type="html">Adding a Linux Server to an Active Directory Domain</title>
    <published>2011-02-06T17:46:00Z</published>
    <updated>2011-02-06T17:46:00Z</updated>
    <link rel="alternate" href="http://www.stuartellis.eu/articles/linux-with-active-directory/"/>
    <content type="html">&lt;p&gt;These notes were written for a Fedora system, which is closely related to Red Hat Enterprise Linux and CentOS, but the software described is available for every Open Source operating system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Privileged Commands&lt;/em&gt;: The prefix # indicates commands that require root privileges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="intro"&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Integrating a Linux server with an Active Directory consists of several steps, and is not difficult if one simply follows the instructions for each step. The main difficulty is in understanding what each system does.&lt;/p&gt;
&lt;p&gt;&lt;acronym title="Pluggable Authentication Modules"&gt;&lt;span class="caps"&gt;PAM&lt;/span&gt;&lt;/acronym&gt; is a flexible authentication system that is now incorporated into most &lt;span class="caps"&gt;UNIX&lt;/span&gt; variants. When any &lt;span class="caps"&gt;PAM&lt;/span&gt;-aware service is presented with a username and password, then these are simply passed on to &lt;span class="caps"&gt;PAM&lt;/span&gt;. &lt;span class="caps"&gt;PAM&lt;/span&gt; can be configured to consult multiple information sources and perform various other actions as part of the login process.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://kerberos.mit.edu"&gt;Kerberos&lt;/a&gt; is a technical standard that enables secure communication between all users and systems that are part of a single &lt;em&gt;Kerberos realm&lt;/em&gt;. Each Kerberos &lt;acronym title="Key Distribution Center"&gt;&lt;span class="caps"&gt;KDC&lt;/span&gt;&lt;/acronym&gt; service for a realm has a copy of the database that holds user and system records. Several providers offer server software that implements Kerberos, and Microsoft Active Directory is one such product.&lt;/p&gt;
&lt;p&gt;There are several similarities between Kerberos and &lt;span class="caps"&gt;LANMAN&lt;/span&gt;, the authentication technology used by Windows NT 4.0. A Kerberos realm equates to an NT &lt;em&gt;domain&lt;/em&gt;, and &lt;span class="caps"&gt;KDC&lt;/span&gt; servers hold copies of the accounts database just as &lt;span class="caps"&gt;LANMAN&lt;/span&gt; &lt;em&gt;domain controllers&lt;/em&gt; did. With Windows 2000 and above a Windows (Active Directory) &lt;em&gt;domain&lt;/em&gt; actually is a Kerberos realm, the &lt;em&gt;domain controllers&lt;/em&gt; are Kerberos Key Distribution Centers for that realm, and the client systems use the Kerberos protocol to authenticate users with the domain controller servers. To ease the transition, Microsoft continue to use &lt;span class="caps"&gt;LANMAN&lt;/span&gt; terminology, and Active Directory domain controllers act as both &lt;span class="caps"&gt;LANMAN&lt;/span&gt; domain controllers, and KDCs.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;LANMAN&lt;/span&gt; clients automatically located a domain controller by querying the network &lt;span class="caps"&gt;WINS&lt;/span&gt; service.  Kerberos KDCs have special &lt;span class="caps"&gt;SRV&lt;/span&gt; records in &lt;span class="caps"&gt;DNS&lt;/span&gt;, and the clients query &lt;span class="caps"&gt;DNS&lt;/span&gt; to find an available server to authenticate with. Active Directory automatically injects &lt;span class="caps"&gt;SRV&lt;/span&gt; records for the domain controllers into Microsoft &lt;span class="caps"&gt;DNS&lt;/span&gt; zones.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.samba.org/"&gt;Samba&lt;/a&gt; is a suite of software for &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems that handles file sharing, printer sharing and logons in a Windows-compatible way. The main Samba service provides the functions of Windows File and Printer sharing (technically known as &lt;em&gt;&lt;span class="caps"&gt;SMB&lt;/span&gt;&lt;/em&gt; or &lt;em&gt;&lt;span class="caps"&gt;CIFS&lt;/span&gt;&lt;/em&gt;), and may also act as a &lt;span class="caps"&gt;LANMAN&lt;/span&gt; domain controller.&lt;/p&gt;
&lt;p&gt;The Samba suite provides a separate Winbind service that supports both &lt;span class="caps"&gt;PAM&lt;/span&gt; and the main Samba service. When a user attempts to login to a server running Winbind then &lt;span class="caps"&gt;PAM&lt;/span&gt; or the Samba service may  call it to verify the account with a remote domain controller. Winbind works with both NT 4.0 domains and Active Directory domains.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;UNIX&lt;/span&gt;-like systems store information about users differently to Windows, and this means that even if a user is listed in Active Directory then Samba must have some information about the user account in it’s own database. Equally, having a user account on a &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system does not allow the user to access files and printers through the Samba service unless the user has a listing in the Samba user database.&lt;/p&gt;
&lt;h2 id="prerequisites"&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Samba 3 is needed for a &lt;span class="caps"&gt;UNIX&lt;/span&gt;-like system to join Active Directory as a full &lt;em&gt;member server&lt;/em&gt;. This version is now included with every current Open Source operating system.&lt;/p&gt;
&lt;p&gt;On a Fedora or Red Hat system, install the following packages:&lt;/p&gt;
&lt;p&gt;Samba:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;redhat-config-samba&lt;/li&gt;
	&lt;li&gt;samba-common&lt;/li&gt;
	&lt;li&gt;samba-client&lt;/li&gt;
	&lt;li&gt;samba&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Kerberos:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pam_krb5&lt;/li&gt;
	&lt;li&gt;krb5-workstation&lt;/li&gt;
	&lt;li&gt;krb5-libs&lt;/li&gt;
	&lt;li&gt;krbafs&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Before starting this process, ensure that the Linux system is networking correctly, and has a valid entry in &lt;span class="caps"&gt;DNS&lt;/span&gt;. Also ensure that you know:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The &lt;span class="caps"&gt;DNS&lt;/span&gt; name of a DC server.&lt;/li&gt;
	&lt;li&gt;An Active Directory username and password that has the right to add machines to the Active Directory.&lt;/li&gt;
	&lt;li&gt;The Organizational Unit (OU) that you want the Linux server to be listed in.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;If your network still uses &lt;span class="caps"&gt;WINS&lt;/span&gt; then you also need to know the &lt;em&gt;IP address&lt;/em&gt; of the &lt;span class="caps"&gt;WINS&lt;/span&gt; server (it’s probably the DC that is configured with the &lt;em&gt;&lt;span class="caps"&gt;PDC&lt;/span&gt; emulator role&lt;/em&gt;).&lt;/p&gt;
&lt;h2 id="docs"&gt;Documentation&lt;/h2&gt;
&lt;p&gt;Samba includes a very complete set of documentation. The relevant sections are in the Samba &lt;span class="caps"&gt;HOWTO&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Joining Active Directory As A Member Server (Chapter 7)&lt;/li&gt;
	&lt;li&gt;Synchronising Accounts with Winbind (Chapter 21)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;For &lt;span class="caps"&gt;PAM&lt;/span&gt; the documentation is here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/usr/share/doc/pam-0.77/html/index.html&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This walk-through was also very useful for me:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.flatmtn.com/computer/Linux-EmailServer.html"&gt;http://www.flatmtn.com/computer/Linux-EmailServer.html&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="config-kerberos"&gt;Configure Kerberos&lt;/h2&gt;
&lt;p&gt;Samba 3 uses the Kerberos protocol to authenticate with Active Directory, so you need to configure the Linux system to act as a Kerberos client for the realm (domain) for this facility to work. Fedora supplies   the &lt;span class="caps"&gt;MIT&lt;/span&gt; Kerberos software. If the &lt;em&gt;krb5-workstation&lt;/em&gt; package has been installed then the necessary client programs will be in /usr/kerberos/bin/.&lt;/p&gt;
&lt;p&gt;The name of the Active Directory Kerberos realm is the same as it’s domain name. Usernames are also the same, but are suffixed with the name of the realm that they are part of. In standard Kerberos all names are in upper case, e.g.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;MROBERTS@ADEXAMPLE.LOCAL&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Active Directory domain controllers are registered in &lt;span class="caps"&gt;DNS&lt;/span&gt;, so you do not need to manually specify the servers. Instead edit /etc/krb5.conf to enable &lt;span class="caps"&gt;DNS&lt;/span&gt; lookups. The libdefaults section should read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[libdefaults]
ticket_lifetime = 24000
default_realm = ADEXAMPLE.LOCAL
dns_lookup_realm = yes
dns_lookup_kdc = yes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Comment out the realms and domain_realms sections.&lt;/p&gt;
&lt;p&gt;To test that Kerberos is configured correctly, use the kinit command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kinit MROBERTS@ADEXAMPLE.LOCAL&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="config-samba"&gt;Configure Samba&lt;/h2&gt;
&lt;p&gt;The supplied Samba configuration file is very long, and most of the settings are not necessary for AD membership. Make a copy of the file and create a blank one:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# cp /etc/samba/smb.conf /samba/smb.conf.original&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An example smb.conf for an Active Directory member server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[global]&lt;/code&gt;

&lt;code&gt;socket options = TCP_NODELAY
SO_RCVBUF=8192
SO_SNDBUF=8192&lt;/code&gt;

&lt;code&gt;workgroup = ADEXAMPLE
server string = Samba Server&lt;/code&gt;

&lt;code&gt;local master = no
domain master = no
preferred master = no
wins support = no
wins server = 10.0.1.2
dns proxy = no&lt;/code&gt;

&lt;code&gt;realm = ADEXAMPLE.LOCAL
security = ADS&lt;/code&gt;

&lt;code&gt;password server = ms-dc-01.adexample.local&lt;/code&gt;

&lt;code&gt;winbind separator = +
winbind use default domain = yes
idmap uid = 10000-20000
idmap gid = 10000-20000
winbind enum users = yes
winbind enum groups = yes&lt;/code&gt;

&lt;code&gt;template homedir = /home/%U
template shell = /bin/nologin&lt;/code&gt;

&lt;code&gt;log file = /var/log/samba/%m.log
max log size = 5000&lt;/code&gt;

&lt;code&gt;printcap name = /etc/printcap
load printers = no&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you want the main Samba service to provide access to home directories or printers, add these stanzas. For printer sharing you should also change &lt;em&gt;load printers = no&lt;/em&gt; to read &lt;em&gt;load printers = yes&lt;/em&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[homes]
comment = Home Directories
browseable = no
writable = yes&lt;/code&gt;

&lt;code&gt;[printers]
comment = All Printers
path = /var/spool/samba
browseable = no
guest ok = no
writable = no
printable = yes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you have edited the smb.conf file, run the testparm utility to check that the Samba configuration is valid:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# testparm&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="add-ad"&gt;Add the System to Active Directory&lt;/h2&gt;
&lt;p&gt;First you must login to the Active Directory with kinit, since no other method has been setup yet:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# kinit USER@ADEXAMPLE.LOCAL&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may then use the net utility to create a machine account for the new member server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# net ads join "Example-OU\Example-OU"&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="config-winbind"&gt;Configure Winbind&lt;/h2&gt;
&lt;p&gt;Once Samba is configured you must set the nsswitch system to use Winbind to verify accounts that do not exist on the local system. In the file /etc/nsswitch.conf amend the lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;passwd:     files
shadow:     files
group:      files&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;passwd:     files winbind
shadow:     files
group:      files winbind&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Winbind has better performance when run in &lt;em&gt;double daemon&lt;/em&gt; mode. In the file /etc/sysconfig/samba amend the line:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WINBINDOPTIONS=""&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;WINBINDOPTIONS="-B"&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="nscd"&gt;Disable &lt;span class="caps"&gt;NSCD&lt;/span&gt;
&lt;/h2&gt;
&lt;p&gt;The service &lt;em&gt;&lt;span class="caps"&gt;NSCD&lt;/span&gt;&lt;/em&gt; (Name Service Caching Daemon) seriously interferes with Winbind authentication and &lt;em&gt;must&lt;/em&gt; be completely disabled before enabling Winbind.&lt;/p&gt;
&lt;p&gt;To do this, edit /etc/nscd.conf. Edit these three lines:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enable-cache            passwd          yes
enable-cache            group           yes
enable-cache            hosts           yes&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;They should read:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;enable-cache            passwd          no
enable-cache            group           no
enable-cache            hosts           no&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This disables all &lt;span class="caps"&gt;NSCD&lt;/span&gt; caching.&lt;/p&gt;
&lt;p&gt;To make the new configuration active, restart the network service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /sbin/service network restart&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="using-winbind"&gt;Configure Services To Use Winbind&lt;/h2&gt;
&lt;p&gt;The &lt;span class="caps"&gt;PAM&lt;/span&gt; configuration for Samba itself does not need to be modified for Winbind. By default the main Samba service ignores &lt;span class="caps"&gt;PAM&lt;/span&gt;, and will either use Winbind or an internal account database to authenticate users.&lt;/p&gt;
&lt;p&gt;Most other modern services on Linux use the &lt;span class="caps"&gt;PAM&lt;/span&gt; system for authentication. If you want to use Winbind with &lt;em&gt;every&lt;/em&gt; service on the system that supports &lt;span class="caps"&gt;PAM&lt;/span&gt;, then modify /etc/pam.d/system-auth. If you only want specific services to use Winbind for authentication then you need to modify individual configuration files in /etc/pam.d/. Several services have their own file, but a number of services use the &lt;em&gt;login&lt;/em&gt; facility, controlled by /etc/pam.d/login.&lt;/p&gt;
&lt;p&gt;Add two lines to the appropriate &lt;span class="caps"&gt;PAM&lt;/span&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auth sufficient /lib/security/pam_winbind.so&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;account sufficient /lib/security/pam_winbind.so&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Amend all other &lt;em&gt;auth&lt;/em&gt; and &lt;em&gt;account&lt;/em&gt; types from &lt;em&gt;required&lt;/em&gt; to &lt;em&gt;sufficient&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Note that &lt;span class="caps"&gt;PAM&lt;/span&gt; reads the file sequentially, so where there are multiple &lt;em&gt;sufficient&lt;/em&gt; sources the first successful one is used. Think carefully about the sequence in which you wish the system to check authentication services. A laptop may be off the main network more often than it is on it, and will be unable to access internal authentication services whilst it is disconnected.&lt;/p&gt;
&lt;p&gt;If you edit the &lt;span class="caps"&gt;PAM&lt;/span&gt; configuration file for a service, you must restart that service for the changes to take effect.&lt;/p&gt;
&lt;p&gt;Default /etc/pam.d./sshd settings:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auth      required     pam_stack.so service=system-auth
auth      required     pam_nologin.so
account   required     pam_stack.so service=system-auth
password  required     pam_stack.so service=system-auth
session   required     pam_stack.so service=system-auth
session   required     pam_limits.so
session   optional     pam_console.so&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example /etc/pam.d/sshd using Winbind:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auth      required     pam_nologin.so
auth      sufficient   pam_stack.so service=system-auth
auth      sufficient   pam_winbind.so&lt;/code&gt;

&lt;code&gt;account    sufficient  pam_stack.so service=system-auth
account    sufficient  pam_winbind.so&lt;/code&gt;

&lt;code&gt;password  required     pam_stack.so service=system-auth&lt;/code&gt;

&lt;code&gt;session    sufficient  pam_stack.so service=system-auth
session   required     pam_limits.so
session   optional     pam_console.so&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span class="caps"&gt;PAM&lt;/span&gt; does not guarantee that the user will have a home directory available, and without one the login process will fail. If you want to automatically use a home directory stored on another server, investigate automount.&lt;/p&gt;
&lt;p&gt;If you would like to automatically create local home directories for new users as they login, then you could use this line in the &lt;span class="caps"&gt;PAM&lt;/span&gt; configuration:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;session required pam_mkhomedir.so skel=/etc/skel/ umask=0022&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If at all possible, create any local home directories with another means, before the user concerned can sign in. The easiest way may be to add the facility to your account creation scripts. By default &lt;span class="caps"&gt;SSH&lt;/span&gt; (and an increasing number of other services) do not run with root privileges through the login process, which means that they cannot create home directories as pam_mkhomedir.so mandates. Forcing services to run as root is not recommended.&lt;/p&gt;
&lt;h2 id="enabling-services"&gt;Enable the Services&lt;/h2&gt;
&lt;p&gt;You can start the main smb service for Samba by typing:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /sbin/service smb start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make the smb service automatically start on boot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /sbin/chkconfig --level 345 smb on&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To run Winbind:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /sbin/service winbind start&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To make Winbind automatically start on boot:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# /sbin/chkconfig --level 345 winbind on&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The main Samba service does &lt;strong&gt;not&lt;/strong&gt; need to be running for Winbind to operate.&lt;/p&gt;
&lt;h2 id="usernames"&gt;Tip: Username Formats&lt;/h2&gt;
&lt;p&gt;Kerberos usernames use this format, and must be in uppercase:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;AUSER@ADEXAMPLE.LOCAL&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Winbind usernames have the format:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ADEXAMPLE+auser&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you enable the setting &lt;em&gt;winbind use default domain&lt;/em&gt; (as shown in the example smb.conf above), users may just specify an account name:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;auser
&lt;/code&gt;&lt;/pre&gt;</content>
  </entry>
</feed>


