The Ruby Behind Chef

On September 14th I presented a live webinar on The Ruby Behind Chef. There is quite a bit of Ruby behind Chef and it is rather complex. Watch the recording below to hear me explain core Ruby topics by creating our own version of Chef: T-Rex Chef.

In the presentation, I focus on demystifying the recipe domain specific language (DSL) by showing that what you’re reading are Ruby methods being invoked. Ruby can be tricky because a lot of the other characters used to denote method arguments and commands are missing.

I also explain Ruby’s blocks. In Ruby, every method can be given a block, leaving it up to the method author if they want to evaluate them. I show both how Ruby blocks can be explicitly named and invoked or implicitly described and invoked.

At the end, I answered a few questions that I have included here in this post.

Q&A

Why was Ruby chosen as a language for Chef, not Python for example?

Ruby was probably initially chosen for Chef because of the tools that it originated from using that language. I believe Ruby remained and will remain for some time because of the power and flexibility that it provides.

When you are writing your resources within an recipe file you are actually writing Ruby code. That means there is incredible power immediately available to you if you needed to iterate over a data collection, calculate a value, or make an API call to an endpoint. But you also do not have to use it and you are still able to compose your desired state in a language that almost has a natural language approach that is more accessible to new or novice users stepping into the role of managing the infrastructure.

Is there a list the topics of ruby that one needs to be familiar with, to write cookbooks?

Within our documentation we provide a resource for some Ruby topics (https://docs.chef.io/ruby.html). I believe this covers quite a few of the most common concepts one would need to understand to be successful composing recipes.

As your challenges grow and your skills grow the need for more Ruby skills will grow and from that point I would strongly suggest building your Ruby skills through Ruby tutorials or exercises like the ones found at exercism.io (http://exercism.io).

What does the # mean in File#read?

Within Ruby documentation the hash symbol is placed between a class and an instance method. This means that if you created an instance of the ‘File’ class you would have access to a method with the name ‘read’.

Alternatively you will see class methods shown with a period between the class or module and the method. This means that the method is available to the class or module. This means you do not need to create an instance of the class to invoke the method. You can simply execute that method with the class itself. This is similar to static methods in Java/C#.

What is the :: notation you see in front of classes and other things sometimes. In particular with nothing in front of the initial ::

An example from the Chef-Client cookbook.

class ::Chef::Recipe
include ::Opscode::ChefClient::Helpers
end

The ‘::’ is called the unary operator that allows you to traverse the class or module namespaces that may be specified within a different namespace. At first it was easier for me to think of this operator as something similar to the character used for paths (forward slash or backslash). When you define that operator you are traversing through namespaces which are similar to directories.

By placing that ‘::’ at the start of the class or module name you are resetting your path back to the beginning; similar to how you might specify a directory with a proceeding forward slash or ‘C:\’. Resetting this path ensures that you walking the correct path to the correct class or module that you are hoping to find.

Sometimes this is not absolutely necessary because Ruby is able to determine the class or module without it. It first attempts to find it locally, relative to the namespace you currently reside, and then it looks from the top-level. Specifying, when it is not necessary, does not hurt and often times makes it more clear.

Where this is necessary is when there is a possible collision. Take for example Ruby’s File class and Chef::Resource::File. If you were in the namespace Chef::Resource and used File, Ruby would assume you meant Chef::Resource::File and not ::File. Which means you would likely receive an error if you were to attempt to use a method like ‘File.exist?(filename)’. To ensure you would use Ruby’s File class you would place the ‘::’ in front of File to reset the namespace to ensure Ruby used the correct class for you.

Why doesn’t ‘chef generate cookbook’ create the following directories: ‘templates’; ‘resources’; and ‘files’?

The new ‘chef’ command-line application packaged with the Chef Development Kit (Chef DK) generates a number of files and directories for you. However, there was a conscious choice to stop automatically generating a few directories because they were not standard to every cookbook.

The good news is that if you want a template you can use the ‘chef’ to generate a template and it will automatically generate the ‘templates’ directory for you. This is the same for ‘resources’ as well when you use ‘chef’ to generate an ‘lwrp’.

So take a look at the additional generators within the ‘chef’ command-line tool and see which one is right for you.

Franklin Webber

College dropout, turned instructor who found software development because everything else in his life was going too well. Forged by the fires of tech support, quality assurance and software development, he now brings technology to the hungry, sullied masses with raw energy, immeasurable empathy and a strong injection of humor.