Reader small image

You're reading from  Mastering Chef

Product typeBook
Published inJun 2015
Reading LevelIntermediate
Publisher
ISBN-139781783981564
Edition1st Edition
Languages
Tools
Right arrow
Author (1)
Mayank Joshi
Mayank Joshi
author image
Mayank Joshi

Mayank Joshi works for Indix as a DevOps engineer. He has worn many hats during his 10-year long career. He has been a developer, a systems analyst, a systems administrator, a software consultant, and for the past 6 years, he has been fascinated with the phenomenal growth witnessed in cloud environments and the challenges of automation associated with the hosting of the infrastructure in such environments. Prior to Indix, he worked for start-ups such as SlideShare, R&D organizations such as CDAC, and even had a stint at a highly automated chemical plant of IFFCO.
Read more about Mayank Joshi

Right arrow

Chapter 3. Chef and Ruby

When we say that we will be specifying our infrastructure as a code using Chef, what we mean is that we'll be writing code using domain-specific language (DSL) provided by Chef. This code will be executed by chef-client on the concerned machine, and the machine will be bootstrapped as per the guidelines we specify in our code. The DSL provided by Chef is very much like Rake tasks, and Ruby developers will find themselves at home when writing Chef code.

Chef DSL is actually a Ruby DSL, and one can use the full power of Ruby as a programming language when trying to write Chef code. The term "Chef code" is used loosely here, to specify recipes, roles, environments, templates, resources, attributes, libraries, and so on.

Chef provides a DSL that you can use to write your recipes and roles, describe environments, write custom resource providers and libraries, and so on.

The code that you'll write will be stored as Ruby files in the Chef repository. When these files are uploaded...

Ruby


Ruby is a simple, dynamic programming language created by Yukihiro Matsumoto (also known as Matz). The language is a blend of features provided in different languages such as Perl, Smalltalk, Lisp, and so on. Ruby was developed with an aim to provide a new language that balanced functional programming with imperative programming.

As mentioned earlier, you don't have to be a hardcore Ruby developer. Following are the things that we'll cover in this chapter, which will allow you to make the best use of Chef:

  • Variables and types

  • Basic operations

  • Conditional statements and loops

  • Blocks

  • Arrays and hashes

Yeah, we just need to learn about these five components of the language and we are all set to conquer the world of Chef.

However, before we go ahead with our journey into the fascinating world of Ruby, let's take a quick look at IRB. This is one of those tools that can really help you while playing with small Ruby code snippets.

IRB


IRB is an acronym for "interactive Ruby". It's a tool that provided alongside Ruby interpreter, which allows for the interactive execution of Ruby expressions. These expressions are delivered to IRB using standard input.

Let's quickly see IRB in action:

  ~  irb
2.1-head :001 >

When we enter the irb command, it throws a shell at us. The format of the shell prompt is as follows:

$RUBY_VERSION :$LINE_NUMBER >

You can customize this prompt to your liking. However, for now, just remember that whatever expression you enter at the prompt is interpreted as a Ruby expression and is evaluated right away.

Consider the following as an example:

irb
2.1-head :001 > 2+3
 => 5

As you can see, we entered an arithmetic expression to compute the sum of two numbers, 2 and 3, and in return IRB returned us the output of computation.

To exit out of IRB, just issue the quit or exit command at the prompt.

To learn more about IRB and how to customize it to your liking, read the IRB documentation at http...

Variables and types


If you are new to programming, then just for a quick reference: a variable is nothing, but a memory location where we can save some data. This memory location can be easily referenced by a name and that name is called the variable name. Many languages such as C, Java, and so on, force you to declare variables before you use them, and they also expect you to specify the type associated with the variable. For example. if you want to store a number in the memory in a C program, you'd say the following:

int x = 10;

This will create a 2 byte memory space and that memory space will contain a binary associated with 10. The memory location where 10 is stored can be referenced through a variable name called x.

Ruby, on the other hand, is pretty lenient and it doesn't expect you to specify data type associated with a variable. Ruby, hence, belongs to a family of programming languages that are called dynamically typed languages. Unlike strongly typed languages, dynamic languages do...

Symbols


Symbols look like variables, however, with a colon (:) prefixed. For example, :symbol_1. Symbols need not be predeclared and assigned a value. Ruby guarantees that the symbol has a particular value, no matter where it appears in a Ruby program.

Symbols are very useful because a given symbol name refers to the same object throughout a Ruby program. Two strings with the same content are two different objects; however, for a given name, there can only be one single symbol object. Let's examine the following example to illustrate this fact:

irb
2.1-head :001 > puts "string".object_id
70168328185680
 => nil
2.1-head :002 > puts "string".object_id
70168328173400
 => nil
2.1-head :003 > puts :symbol.object_id
394888
 => nil
2.1-head :004 > puts :symbol.object_id
394888
nil

As you can see, we started by creating a string object with the string value and sought its object ID using the object_id method. Next, we tried the same thing once more. In both the cases, we received...

Basic operations


Like all other programming languages, Ruby comes packed with a whole bunch of operators.

Arithmetic operators

Assume a = 2 and b = 4.

Operator

Description

Example

+

Addition: Adds values on either side of the operator

a + b will give 6

-

Subtraction: Subtracts the right-hand side operand from the left-hand side operand

a – b will give -2

*

Multiplication: Multiplies values on either side of the operator

a * b will give 8

/

Division: Divides the left-hand side operand by the right-hand side operand

b / a will give 2

%

Modulus: Divides the left-hand side operand by the right-hand side operand and returns the remainder

b % a will give 0

**

Exponent: Performs exponential (power) calculations on operators

a ** b will give 2 to the power of 4, which is 16

Comparison operators

Conditional statements and loops


Conditional statements and loops allow developers to branch off from the serial flow of execution of code and also iterate through the code. Ruby provides multiple ways to do this job. Let's look at a few of them.

The if statement

The if statement is pretty much a basic branching statement that's provided by many programming languages. It's pretty much how we use the "if" statement in natural language—if it's true, do this; if it's not, do something else.

x=2
if x == 2
  puts "True"
else
  puts "False"
end

If we need to check for multiple conditions, we get an elsif statement, that we can embed between the if and else statements:

height = 164
if height > 170
  puts "Tall"
elsif height > 160
  puts "Normal"
else
  puts "Dwarf"
end

The fun part of doing this in Ruby is that you can assign values returned by the if, elsif, and else blocks. For example, you might want to save the Tall, Normal, or Dwarf message inside some variable for later use. You can do this...

Methods


Ruby methods are what we refer to as functions in some other programming languages. Many a times, we would want all the statements, operators, and so on that we saw earlier, to be bundled together and used as a single unit. Methods are means to accomplish this feat.

In Ruby, a method name should begin with a lowercase letter. Methods should be defined before they are called upon, otherwise an exception is raised by Ruby.

The syntax to define a method is as follows:

def method_name [([arg [= default]]...[, *arg [, &expr ]])]
end

Let's look at a few different examples to make this syntax more clear.

Example 1—a simple method:

def method
  # Method definition goes here
end

Example 2—a method with two arguments:

def method (arg1, arg2)
   #  Method definition goes here
end

Example 3—a method with two arguments having some default values. This will pass default values to the arguments if the method is called without passing the required parameters:

def method (arg1=val1, arg2=val2)   #  Method...

Arrays


Arrays and hashes are perhaps the two data structures that will be used the most by developers who are writing the Chef code. Be it fetching attributes or values from data bags, you'll be finding these two data structures almost everywhere.

Arrays are an ordered collection of objects that can be accessed through an integer index. Each element of an array can be referenced through an index. The first element of the array is referenced through index number 0 and so on. Ruby also provides support for negative integers as indexes. -1 refers to the last element of the array, -2 is the second last element, and so on.

Unlike other languages, arrays in Ruby aren't tied to one single data type, and they aren't fixed in size either. Ruby arrays grow automatically while elements are added to it. Ruby arrays can also hold other array objects, thereby allowing us to set up multidimensional arrays.

Creating an array

There are multiple ways to create arrays.

Way 1—using the new method of the Array class...

Bang methods


As you might have noticed, we used two different variants of the same method in our previous example where we explained destructive and nondestructive ways of selecting elements from an array. The bang sign after a method doesn't necessarily mean that the method would be destructive, nor does it imply that methods without a bang sign are always nondestructive. It's just a means of specifying the fact that the methods with the ! sign affixed to the method name are more dangerous as compared to methods without it.

The bang methods are generally used to do modifications in place. Now, what this means is that, say I've an x = [1,2,3,4,5] array and I want to remove all elements from this array that are greater than 2. If I chose x.select, then the x array would remain the same; however, a new array object containing [3,4,5] would be returned. However, if I were to choose x.select!, then the x array itself would be modified:

2.1-head :001 > x=[1,2,3,4,5]
 => [1, 2, 3, 4, 5]
2...

Hashes


Hashes are also known as associative arrays, and they are dictionary-like objects, comprising keys and their associated values. Hashes are very similar to arrays; however, while arrays allow only integers to be used as an index, hashes, on the other hand, can use any object as a key.

Creating hashes

Hashes can be created easily using their implicit form as follows:

scores = { "A" => 85, "B" => 70, "C" => 60, "D" => 50, "E" => 35 }

Here, A, B, C, D, and E are keys having associated values 85, 70, 60, 50, and 35, respectively.

Hashes also allow for a form wherein keys are always symbols:

scores = { :A => 85, :B => 70, :C => 60, :D => 50, :E => 35 }

We may access each key's value using the corresponding symbol as follows:

scores[:A] #=> 85

We can also create a new hash using the new method of the Hash class:

scores = Hash.new
scores["A"] = 85

If no default value is set while creating a hash, then, when we try to access the key, it'll return nil. One can...

Classes and objects


Object-oriented programming is a paradigm that has become the foundation of many modern programming languages, and it's at the core of Ruby. In short, the object-oriented programming sees the world as data, modeled in code by "objects". When working with data, this model of programming is most apt, as it allows us to model our program as we would see the real world.

The object-oriented programming paradigm, or OOPs as it's popularly called, is based upon a few principles, let's look at them one at a time:

  • Encapsulation: This is a concept that ensures a certain functionality is hidden from the rest of the code. Its primary use is to ensure that the underlying data is protected, and can only be manipulated in a way the object desires. Ruby accomplishes this by creating objects. The objects expose certain interfaces (also known as methods), using which the interaction can happen with those objects.

  • Polymorphism: This is the ability to represent the same thing in multiple forms...

Summary


This brings us to the end of our journey in to the world of Ruby. We have looked at variables, operators, statements, and methods, and eventually had a sneak peek into the world of OOPs. We have learned about classes, objects, and modules. We'll make use of most of the stuff we learned here throughout this book. We'll be extending our knowledge of Ruby as and when we move on to structures involving JSON objects and so on.

In the next chapter, we'll cover concepts such as organizations, groups, and users, and how you can allow for fine-grained access to different types of objects on the Chef server.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering Chef
Published in: Jun 2015Publisher: ISBN-13: 9781783981564
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Mayank Joshi

Mayank Joshi works for Indix as a DevOps engineer. He has worn many hats during his 10-year long career. He has been a developer, a systems analyst, a systems administrator, a software consultant, and for the past 6 years, he has been fascinated with the phenomenal growth witnessed in cloud environments and the challenges of automation associated with the hosting of the infrastructure in such environments. Prior to Indix, he worked for start-ups such as SlideShare, R&D organizations such as CDAC, and even had a stint at a highly automated chemical plant of IFFCO.
Read more about Mayank Joshi

Operator

Description

Example

==

Checks whether the values of the two operands are equal or not; if yes, then the condition becomes true.

(a == b) is not true.

!=

Checks whether the...