© Stefan Wintermeyer 2018
Stefan WintermeyerLearn Rails 5.2https://doi.org/10.1007/978-1-4842-3489-1_1

1. Ruby Introduction

Stefan Wintermeyer1 
(1)
Bochum, Germany
 

This chapter is a tightrope walk between oversimplification and a degree of detail that is unnecessary for a Rails newbie. After all, the objective is not to become a Ruby guru but to understand Ruby on Rails. I will elaborate on the most important points, and the rest is then up to you. If you would like to know more about Ruby, I recommend the book The Ruby Programming Language by David Flanagan and Yukihiro Matsumoto.

“It is easy to program in Ruby, but Ruby is not a simple language.”

—Yukihiro Matsumoto

Ruby 2.5

I’m going to use Ruby 2.5, but for most part of this book you can use older versions too. Ruby 2.5 is just a bit faster. You can check the installed Ruby version by running the command ruby -v, as shown here:

$ ruby -v
ruby 2.5.0p0 (2017-12-25 revision 61468) [x86_64-darwin17]
$

../images/460214_1_En_1_Chapter/460214_1_En_1_Figa_HTML.gif If your system is running an older version and you want to upgrade it, take a look at https://rvm.io , which is my preferred way of installing and using different Ruby versions.

Basics

Ruby is a scripting language. So, it is not compiled and then executed; instead, it is read by an interpreter and then processed line by line.

Hello World

A simple hello-world.rb program consists of one line of code, as shown in Listing 1-1.

puts 'Hello World!'
Listing 1-1

hello-world.rb

Use your favorite editor to open a new file with the filename hello-world.rb and insert the previous line into it. You can then execute this Ruby program at the command line as follows:

$ ruby hello-world.rb
Hello World!
$

../images/460214_1_En_1_Chapter/460214_1_En_1_Figb_HTML.gif A program line in a Ruby program does not have to end with a semicolon. The Ruby interpreter is even so intelligent that it recognizes if a program line was split over two or more lines for the sake of readability. Indenting code is also not necessary. But it does make it much easier to read for human beings!

puts and print

If you look for examples on Ruby on the Internet, you will find two typical ways of printing text on the screen.
  • puts prints a string, followed by a newline.

  • print prints a string (without a newline).

Listing 1-2 shows an example program (an extension of the program hello-world.rb).

puts 'Hello World!'
puts
puts 'zzz'
print 'Hello World!'
print
puts 'zzz'
Listing 1-2

hello-world.rb

On the screen, you will see this:

$ ruby hello-world.rb
Hello World!
zzz
Hello World!zzz

Comments

A comment in a Ruby program starts with a # sign and ends with a newline. As an example, I added a comment to the earlier hello-world.rb program; see Listing 1-3.

# Program for displaying "Hello World!"
# by Stefan Wintermeyer
puts 'Hello World!'
Listing 1-3

hello-world.rb

A comment can also follow a program line, as shown in Listing 1-4.

puts 'Hello World!'  # Example comment
Listing 1-4

hello-world.rb

A # sign within strings in a single quote mark is not treated as the start of a comment, as shown in Listing 1-5.

# Example program
# by Stefan Wintermeyer
puts 'Hello World!'
puts '############'
puts
puts '1#2#3#4#5#6#'  # Comment on this
Listing 1-5

hello-world.rb

Help via ri

When programming , you do not always have a Ruby handbook available. Fortunately, the Ruby developers thought of this and provided a built-in help feature in form of the program ri.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figc_HTML.gif Of course, you must have installed the documentation, which is the default. If you used rvm to install Ruby, you can run rvm docs generate to generate the documentation.

This is a typical chicken-and-egg situation. How can I explain the Ruby help feature if you are only just getting started with Ruby? So, I am going to jump ahead a little and show you how you can search for information on the class String.

$ ri String
  [...]
$

../images/460214_1_En_1_Chapter/460214_1_En_1_Figd_HTML.gif Many times it is easier and more informative to use Google instead of ri.

irb

irb stands for “Interactive Ruby ” and is a kind of sandbox where you can play around with Ruby at your leisure. You can launch irb by entering irb on the shell and end it by entering exit.

An example is worth a thousand words.

$ irb
irb(main):001:0> puts 'Hello World!'
Hello World!
=> nil
irb(main):002:0> exit
$

../images/460214_1_En_1_Chapter/460214_1_En_1_Fige_HTML.gif In future examples, I use IRB.conf[:PROMPT_MODE] = :SIMPLE in my .irbrc config file to generate shorter irb output (without the irb(main):001:0> part). You can do the same by using irb --simple-prompt.

Ruby Is Object-Oriented

Ruby only knows objects. Everything is an object (sounds almost like Zen). Every object is an instance of a class. You can find out the class of an object via the method .class.

An object in Ruby is encapsulated and can be reached from the outside only via the methods of the corresponding object. What does this mean? You cannot change any property of an object directly from the outside. The corresponding object has to offer a method with which you can do so.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figf_HTML.gif Please do not panic if you have no idea what a class or an object is. I won’t tell anyone, and you can still work with them just fine without worrying too much. This topic alone could fill whole volumes. Roughly speaking, an object is a container for something, and a method changes something in that container.

Please go on reading and take a look at the examples. The puzzle will gradually get clearer.

Methods

In other programming languages , the terms you would use for Ruby methods would be functions, procedures, subroutines, and of course methods.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figg_HTML.gif Here I go with the oversimplification. You cannot compare non-object-oriented programming languages with object-oriented ones. Plus, there are two kinds of methods (class methods and instance methods). I do not want to make it too complicated. So, I simply ignore those “fine” distinctions.

At this point, you probably want to look at a good example, but all I can think of are silly ones. The problem is the assumption that you are only allowed to use knowledge that has already been described in this book .

So, let’s assume that you use the code sequence in Listing 1-6 repeatedly (for whatever reason).

puts 'Hello World!'
puts 'Hello World!'
puts 'Hello World!'
Listing 1-6

hello-worldx3a.rb

So, you want to output the string “Hello World!” three times in separate rows. As this makes your daily work routine much longer, you are now going to define a method (with the meaningless name three\_times), with which this can all be done in one go, as shown in Listing 1-7.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figh_HTML.gif Names of methods are always written in lowercase.

def three_times
  puts 'Hello World!'
  puts 'Hello World!'
  puts 'Hello World!'
end
Listing 1-7

hello-worldx3b.rb

Let’s test this by starting irb and loading the program with the command load './hello-worldx3b.rb'. After that, you have access to the three_times method.

$ irb
>> load './hello-worldx3b.rb'
=> true
>> three_times
Hello World!
Hello World!
Hello World!
=> nil
>> exit

When defining a method, you can define required parameters and use them within the method. This enables you to create a method to which you pass a string as a parameter, and you can then output it three times, as shown in Listing 1-8.

def three_times(value)
  puts value
  puts value
  puts value
end
$ irb
>> load './hello-worldx3c.rb'
=> true
>> three_times('Hello World!')
Hello World!
Hello World!
Hello World!
=> nil
Listing 1-8

hello-worldx3c.rb

Incidentally, you can omit the brackets when calling the method.

>> three_times 'Hello World!'
Hello World!
Hello World!
Hello World!
=> nil

../images/460214_1_En_1_Chapter/460214_1_En_1_Figi_HTML.gif Ruby gurus and would-be gurus are going to turn up their noses on the subject of “unnecessary” brackets in your programs and will probably pepper you with more or less stupid comments of comparisons to Java and other programming languages.

There is one simple rule in the Ruby community: the fewer brackets, the cooler you are!

But you won’t get a medal for using fewer brackets. Decide for yourself what makes you happy.

If you do not specify a parameter with the previous method, you will get this error message: wrong number of arguments (0 for 1).

>> three_times
ArgumentError: wrong number of arguments (given 0, expected 1)
    from /Users/.../hello-worldx3c.rb:1:in `three_times'
    from (irb):2
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>> exit

You can give the variable value a default value, and then you can also call the method without a parameter, as shown in Listing 1-9.

def three_times(value = 'blue')
  puts value
  puts value
  puts value
end
$ irb
>> load './hello-worldx3d.rb'
=> true
>> three_times('Example')
Example
Example
Example
=> nil
>> three_times
blue
blue
blue
=> nil
>> exit
Listing 1-9

hello-worldx3d.rb

Classes

For now you can think of a class as a collection of methods. The name of a class always starts with an uppercase letter. Let’s assume that the method belongs to the new class This_and_that. It would then be defined as shown in Listing 1-10 in a Ruby program.

class This_and_that
  def three_times
    puts 'Hello World!'
    puts 'Hello World!'
    puts 'Hello World!'
  end
end
Listing 1-10

hello-worldx3e.rb

Let’s play it through in irb.

$ irb
>> load './hello-worldx3e.rb'
=> true

Now you try to call the method three_times.

>> This_and_that.three_times
NoMethodError: undefined method `three_times' for This_and_that:Class
    from (irb):2
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>>

This results in an error message because This_and_that is a class and not an instance. As you are working with instance methods, it works only if you have first created a new object (a new instance) of the class This_and_that with the class method new. Let’s name it abc .

>> abc = This_and_that.new
=> #<This_and_that:0x007fb01b02dcd0>
>> abc.three_times
Hello World!
Hello World!
Hello World!
=> nil
>> exit

I will explain the difference between instance and class methods in more detail in the section “Class Methods and Instance Methods” (another chicken-and-egg problem).

Private Methods

Quite often it makes sense to only call a method within its own class or own instance. Such methods are referred to as private methods (as opposed to public methods), and they are listed after the keyword private within a class, as shown in Listing 1-11.

class Example
  def a
    puts 'a'
  end
  private
  def b
    puts 'b'
  end
end
Listing 1-11

pm-example.rb

You run this in irb, first the public and then the private method, which raises an error.

$ irb
>> load './pm-example.rb'
=> true
>> abc = Example.new
=> #<Example:0x007fa530037910>
>> abc.a
a
=> nil
>> abc.b
NoMethodError: private method `b' called for #<Example:0x007fa530037910>
    from (irb):4
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>> exit

Method initialize()

If a new instance is created (by calling the method new), the method that is processed first and automatically is the method initialize. The method is automatically a private method, even if it not listed explicitly under private, as shown in Listing 1-12.

class Room
  def initialize
    puts 'abc'
  end
end
Listing 1-12

pm-example-a.rb

Here is an irb test of it:

$ irb
>> load './initialize-example-a.rb'
=> true
>> kitchen = Room.new
abc
=> #<Room:0x007f830704edb8>
>> exit

The instance kitchen is created with Room.new, and the method initialize is processed automatically.

The method new accepts the parameters specified for the method initialize, as shown in Listing 1-13.

class Example
  def initialize(value)
    puts value
  end
end
$ irb
>> load './initialize-example-b.rb'
=> true
>> abc = Example.new('Hello World!')
Hello World!
=> #<Example:0x007fbb0b845f30>
>> exit
Listing 1-13

initialize-example-b.rb

return

puts is nice to demonstrate an example in this book, but normally you need a way to return the result of something. The return statement can be used for that, as shown in Listing 1-14.

def area_of_a_circle(radius)
  pi = 3.14
  area = pi * radius * radius
  return area
end
$ irb
>> load './circle-a.rb'
=> true
>> area_of_a_circle(10)
=> 314.0
>> exit
Listing 1-14

circle-a.rb

But it wouldn’t be Ruby if you couldn’t do it shorter, right? You can simply skip return, as shown in Listing 1-15.

def area_of_a_circle(radius)
  pi = 3.14
  area = pi * radius * radius
  area
end
Listing 1-15

circle-b.rb

You can actually even skip the last line because Ruby returns the value of the last expression as a default, as shown in Listing 1-16.

def area_of_a_circle(radius)
  pi = 3.14
  area = pi * radius * radius
end
Listing 1-16

circle-c.rb

Obviously you can go one step further with this code, as shown in Listing 1-17.

def area_of_a_circle(radius)
  pi = 3.14
  pi * radius * radius
end
Listing 1-17

circle-d.rb

return is sometimes useful to make a method easier to read. But you don’t have to use it if you feel more comfortable with out.

Inheritance

A class can inherit from another class . When defining the class, the parent class must be added with a less-than (<) sign.

class Example < ParentClass

Rails makes use of this approach frequently (otherwise I would not be bothering you with it).

In Listing 1-18, you define the class Abc that contains the methods a, b, and c. Then you define a class Abcd and let it inherit the class Abc and add a new method d. The new instances example1 and example2 are created with the class method new and show that example2 has access to the methods a, b, c, and d but example1 only to a, b, and c.

class Abc
  def a
    'a'
  end
  def b
    'b'
  end
  def c
    'c'
  end
end
class Abcd < Abc
  def d
    'd'
  end
end
Listing 1-18

inheritance-example-a.rb

Run it in irb.

$ irb
>> load './inheritance-example-a.rb'
=> true
>> example1 = Abc.new
=> #<Abc:0x007fac5a845630>
>> example2 = Abcd.new
=> #<Abcd:0x007fac5a836630>
>> example2.d
=> "d"
>> example2.a
=> "a"
>> example1.d
NoMethodError: undefined method `d' for #<Abc:0x007fac5a845630>
    from (irb):6
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>> example1.a
=> "a"
>> exit

../images/460214_1_En_1_Chapter/460214_1_En_1_Figj_HTML.gif It is important to read the error messages. They tell you what happened and where to search for the problem. In this example, Ruby says that there is an undefined method for #<Abc:0x007fac5a845630>. With that information you know that the class Abc is missing the method that you were trying to use.

Class Methods and Instance Methods

There are two important kinds of methods: class methods and instance methods.

You now already know what a class is. An instance of such a class is created via the class method new. A class method can only be called in connection with the class (for example, the method new is a class method). An instance method is a method that works only with an instance. So, you cannot apply the method new to an instance.

Let’s first try to call an instance method as a class method, as shown in Listing 1-19.

class Knowledge
  def pi
    3.14
  end
end
Listing 1-19

pi-a.rb

Run it in irb.

$ irb
>> load 'pi-a.rb'
=> true
>> Knowledge.pi
NoMethodError: undefined method `pi' for Knowledge:Class
    from (irb):2
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>>

So, that does not work. Well, then let’s create a new instance of the class and try again.

>> example = Knowledge.new
=> #<Knowledge:0x007fe620010938>
>> example.pi
=> 3.14
>> exit

Now you just need to find out how to define a class method. Hard-core Rails gurus would now whisk you away into the depths of the source code and pick out examples from ActiveRecord. I will spare you this and show an abstract example; see Listing 1-20.

class Knowledge
  def self.pi
    3.14
  end
end
$ irb
>> load './pi-b.rb'
=> true
>> Knowledge.pi
=> 3.14
>>
Listing 1-20

pi-b.rb

Here is the proof to the contrary:

>> example = Knowledge.new
=> #<Knowledge:0x007fa8da045198>
>> example.pi
NoMethodError: undefined method `pi' for #<Knowledge:0x007fa8da045198>
    from (irb):4
    from /Users/stefan/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
>> exit

There are different notations for defining class methods . The two most common ones are self.xyz and class << self.

# Variant 1
# with self.xyz
#
class Knowledge
  def self.pi
    3.14
  end
end
# Variant 2
# with class << self
#
class Knowledge
  class << self
    def pi
      3.14
    end
  end
end

The result is always the same.

Of course, you can use the same method name for a class and an instance method. Obviously that doesn’t make code easier to read. Listing 1-21 shows an example with pi as a class and an instance method .

class Knowledge
  def pi
    3.14
  end
  def self.pi
    3.14159265359
  end
end
$ irb
>> load './pi-c.rb'
=> true
>> Knowledge.pi
=> 3.14159265359
>> example = Knowledge.new
=> #<Knowledge:0x007f8379846f30>
>> example.pi
=> 3.14
>> exit
Listing 1-21

pi-c.rb

List of All Instance Methods

You can read all the defined methods for a class with the method instance_methods. Try it with the class Knowledge (first you create it once again in irb), as shown in Listing 1-22.

class Knowledge
  def pi
    3.14
  end
end
$ irb
>> load './pi-a.rb'
=> true
>> Knowledge.instance_methods
=> [:pi, :instance_of?, :kind_of?, :is_a?, :tap, :public_send,
:remove_instance_variable, :singleton_method, :instance_variable_set,
:define_singleton_method, :method, :public_method, :extend, :to_enum,
:enum_for, :<=>, :===, :=~, :!~, :eql?, :respond_to?, :freeze,
:inspect, :object_id, :send, :display, :to_s, :nil?, :hash, :class,
:singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint,
:untrust, :untrusted?, :trust, :frozen?, :methods, :singleton_methods,
:protected_methods, :private_methods, :public_methods,
:instance_variable_get, :instance_variables,
:instance_variable_defined?, :!, :==, :!=, :__send__, :equal?,
:instance_eval, :instance_exec, :__id__]
>>
Listing 1-22

pi-a.rb

But that is much more than you have defined! Why? It’s because Ruby gives every new class a basic set of methods by default. If you want to list only the methods that you have defined, then you can do it like this:

>> Knowledge.instance_methods(false)
=> [:pi]
>> exit

Basic Classes

Many predefined classes are available in Ruby. For a newbie, probably the most important ones handle numbers and strings.

Strings

Let’s experiment a little bit in irb. The method .class tells you which class you are dealing with.

$ irb
>> "First test"
=> "First test"
>> "First test".class
=> String

That was easy. As you can see, Ruby “automagically” creates an object of the class String. You can also do this by explicitly calling the method new.

>> String.new("Second test")
=> "Second test"
>> String.new("Second test").class
=> String

If you call String.new or String.new() without a parameter, this also creates an object of the class String. But it is an empty String.

>> String.new
=> ""
>> String.new.class
=> String
>> exit

Single and Double Quotations Marks

Strings can be defined either in single quotes or in double quotes .

There is a special feature for the double quotes: you can integrate expressions with the construct #{}. The result is then automatically inserted in the corresponding place in the string.

To show this, you have to jump ahead and use variables in the example.

$ irb
>> a = "blue"
=> "blue"
>> b = "Color: #{a}"
=> "Color: blue"
>> exit

If the result of the expression is not a string, Ruby tries to apply the method to_s to convert the value of the object into a string. Let’s try that by integrating an Integer into a String.

$ irb
>> a = 1
=> 1
>> b = "A test: #{a}"
=> "A test: 1"
>> a.class
=> Integer
>> b.class
=> String
>> exit

../images/460214_1_En_1_Chapter/460214_1_En_1_Figk_HTML.gif If I mention single or double quotation marks in the context of strings, I do not mean typographically correct curly quotation marks (see wikipedia.org/wiki/Quotation_mark); instead, I mean the ASCII symbols referred to as apostrophe (') or quotation mark (").

Built-in Methods for String

Most classes already come with a bundle of useful methods. These methods are always written after the relevant object, separated by a dot.

Here are a few examples for methods of the class String:

$ irb
>> a = 'A dog'
=> "A dog"
>> a.class
=> String
>> a.size
=> 5
>> a.downcase
=> "a dog"
>> a.upcase
=> "A DOG"
>> a.reverse
=> "god A"
>> exit

With instance_methods(false), you can get a list of the built-in methods.

$ irb
>> String.instance_methods(false)
=> [:include?, :%, :*, :+, :to_c, :unicode_normalize, :unicode_normalize!,
:unicode_normalized?, :count, :partition, :unpack, :unpack1, :sum, :next,
:casecmp, :casecmp?, :insert, :bytesize, :match, :match?, :succ!, :+@,
:-@, :index, :rindex, :<=>, :replace, :clear, :upto, :getbyte, :==, :===,
:setbyte, :=~, :scrub, :[], :[]=, :chr, :scrub!, :dump, :byteslice,
:upcase, :next!, :empty?, :eql?, :downcase, :capitalize, :swapcase,
:upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split,
:lines, :reverse, :chars, :codepoints, :prepend, :bytes, :concat, :<<,
:freeze, :inspect, :intern, :end_with?, :crypt, :ljust, :reverse!, :chop,
:scan, :gsub, :ord, :start_with?, :length, :size, :rstrip, :succ, :center,
:sub, :chomp!, :sub!, :chomp, :rjust, :lstrip!, :gsub!, :chop!, :strip,
:to_str, :to_sym, :rstrip!, :tr, :tr_s, :delete, :to_s, :to_i, :tr_s!,
:delete!, :squeeze!, :each_line, :squeeze, :strip!, :each_codepoint,
:lstrip, :slice!, :rpartition, :each_byte, :each_char, :to_f, :slice,
:ascii_only?, :encoding, :force_encoding, :b, :valid_encoding?, :tr!,
:encode, :encode!, :hash, :to_r]
>> exit

Numbers

Let’s discuss numbers.

Integers

Ruby used to have different types of integers depending on the length of the number. Since Ruby version 2.4, things are easier; you just deal with Integer.

$ irb
>> 23.class
=> Integer
>> 230000000000000000000.class
=> Integer
>> (23*10000).class
=> Integer
>> exit

Floats

Float is a class for real numbers (“floating-point numbers”). The decimal separator is a dot.

$ irb
>> a = 20.424
=> 20.424
>> a.class
=> Float
>> exit

Mixed Class Calculations

Adding two integers will result in an integer . Adding an integer and a float will result in a float.

$ irb
>> a = 10
=> 10
>> b = 23
=> 23
>> (a + b).class
=> Integer
>> (a + 3.13).class
=> Float
>> exit

Boolean Values and nil

For Boolean values (true and false) and for nil (no value), there are separate classes.

$ irb
>> true.class
=> TrueClass
>> false.class
=> FalseClass
>> nil.class
=> NilClass
>> exit

nil (no value) is, by the way, the contraction of the Latin word nihil (nothing); or if you look at it in terms of programming history , the term derives from “not in list” from the legacy of the programming language Lisp (the name is an acronym of “list processing”).

Variables

Let’s discuss variables .

Naming Conventions

Normal variables are written in lowercase. Please use snake_case. The same goes for symbols and methods.

$ irb
>> pi = 3.14
=> 3.14
>> exit

Constants

Constants start with an uppercase letter.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figl_HTML.gif A constant can also be overwritten with a new value since Ruby 2.3 (but you will get a warning message). So, please do not rely on the constancy of a constant.

$ irb
>> Pi = 3.14
=> 3.14
>> Pi = 123
(irb):2: warning: already initialized constant Pi
(irb):1: warning: previous definition of Pi was here
=> 123
>> puts Pi
123
=> nil
>> exit

You are on the safe side if you are using only ASCII symbols. But with Ruby 2.5 and the right encoding, you could also use special characters (for example, the German umlaut) more or less without any problems in a variable name. But if you want to be polite toward other programmers who probably do not have those characters directly available on their keyboards, it is better to stick to pure ASCII.

Scope of Variables

Variables have a different scope (or “reach”) within the Ruby application and therefore also within a Ruby on Rails application .

../images/460214_1_En_1_Chapter/460214_1_En_1_Figm_HTML.gif You need to keep this scope in mind while programming. Otherwise, you can end up with odd effects.

Local Variables (aaa or _aaa)

Local variables start with either a lowercase letter or an underscore (_). Their scope is limited to the current environment (for example, the current method). Listing 1-23 defines two methods that use the same local variable radius. Because they are local, they don’t interact with each other.

def area(radius)
  3.14 * radius * radius
end
def circumference(radius)
  2 * 3.14 * radius
end
$ irb
>> load './variable-a.rb'
=> true
>> area(10)
=> 314.0
>> circumference(1)
=> 6.28
>> exit
Listing 1-23

variable-a.rb

Global Variables ($aaa)

A global variable starts with a $ sign and is accessible in the entire program. Listing 1-24 shows an example program.

$value = 10
def example
  $value = 20
end
puts $value
example
puts $value
$ ruby variable-b.rb
10
20
Listing 1-24

variable-b.rb

Global variables are used rarely! You wouldn’t harm yourself by forgetting that they exist right now.

Instance Variables (@aaa)

Instance variables (“attributes,” which is why there’s an @ sign) apply only within a class, but they apply everywhere in it—they’re mini versions of global variables, so to speak. Unlike global variables, you will find instance variables all over the place in a Rails application. Let’s tackle them in form of an example program with the name color.rb, as shown in Listing 1-25.

class Wall
  def initialize
    @color = 'white'
  end
  def color
    @color
  end
  def paint_it(value)
    @color = value
  end
end
my_wall = Wall.new
puts my_wall.color
my_wall.paint_it('red')
puts my_wall.color
Listing 1-25

color.rb

If you start this program, you will see the following output:

$ ruby color.rb
white
red
$

In the method initialize, you set the instance variable @color to the value white. The method paint_it(value) changes this instance variable.

With the method color you can access the value of @color outside of the instance. This kind of method is called a setter method.

Methods Once Again

To keep the amount of chicken-and-egg problems in this chapter at a manageable level, you need to go back to the topic of methods and combine what you have learned so far.

Method Chaining

You may not think of it straightaway, but once you have gotten used to working with Ruby, then it makes perfect sense (and is perfectly logical) to chain different methods.

$ irb
>> a = 'a blue car'
=> "a blue car"
>> a.upcase
=> "A BLUE CAR"
>> a.upcase.reverse
=> "RAC EULB A"
>> exit

Getters and Setters

As instance variables (attributes) exist only within the relevant instance, you always need to write a “getter” method for exporting such a variable. If you define a class Room that has the instance variables @doors and @windows (for the number of doors and windows in the room), then you can create the getter methods doors and windows. Listing 1-26 shows an example program called room.rb.

class Room
  def initialize
    @doors  = 1
    @windows = 1
  end
  def doors
    @doors
  end
  def windows
    @windows
  end
end
kitchen = Room.new
puts "D: #{kitchen.doors}"
puts "W: #{kitchen.windows}"
Listing 1-26

room.rb

Here is the output from the execution of the program:

$ ruby room.rb
D: 1
W: 1
$

Because this scenario—wanting to simply return a value in identical form—is so common, there is already a ready-made getter method for it with the name attr_reader, which you would apply as follows in the program room.rb, as shown in Listing 1-27.

class Room
  def initialize
    @doors  = 1
    @windows = 1
  end
  attr_reader :doors, :windows
end
kitchen = Room.new
puts "D: #{kitchen.doors}"
puts "W: #{kitchen.windows}"
Listing 1-27

room.rb

attr_reader is a method called on the Room class. That is the reason why you use symbols (e.g., :doors and :windows) instead of variables (e.g., @doors and @windows) as parameters.

../images/460214_1_En_1_Chapter/460214_1_En_1_Fign_HTML.gifattr_reader is a good example for metaprogramming in Ruby. When working with Rails, you will frequently come across metaprogramming and be grateful for how it works “automagically.”

If you want to change the number of doors or windows from the outside, you need a setter method. It can be implemented as shown in Listing 1-28.

class Room
  def initialize
    @doors  = 1
    @windows = 1
  end
  attr_reader :doors, :windows
  def doors=(value)
    @doors = value
  end
  def windows=(value)
    @windows = value
  end
end
kitchen = Room.new
kitchen.windows = 2
puts "D: #{kitchen.doors}"
puts "W: #{kitchen.windows}"
Listing 1-28

room.rb

The corresponding output is as follows:

$ **ruby room.rb**
D: 1
W: 2
$

As you can probably imagine , there is also a ready-made and easier way of doing this. Via the setter method attr_writer, you can simplify the code of room.rb as shown in Listing 1-29.

class Room
  def initialize
    @doors  = 1
    @windows = 1
  end
  attr_reader :doors, :windows
  attr_writer :doors, :windows
end
kitchen = Room.new
kitchen.windows = 2
puts "D: #{kitchen.doors}"
puts "W: #{kitchen.windows}"
Listing 1-29

room.rb

And (who would have thought?) there is even a method attr_accessor that combines getters and setters. The code for room.rb would then look like Listing 1-30.

class Room
  def initialize
    @doors  = 1
    @windows = 1
  end
  attr_accessor :doors, :windows
end
kitchen = Room.new
kitchen.windows = 2
puts "D: #{kitchen.doors}"
puts "W: #{kitchen.windows}"
Listing 1-30

room.rb

Converting from One to the Other: Casting

There is a whole range of useful instance methods for converting (casting) objects from one class to another. First, let’s use the method .to_s to convert a Fixnum to a String.

$ irb
>> a = 10
=> 10
>> a.class
=> Integer
>> b = a.to_s
=> "10"
>> b.class
=> String
>> exit

../images/460214_1_En_1_Chapter/460214_1_En_1_Figo_HTML.gif Incidentally, that is exactly what puts does if you use puts to output a Fixnum or a Float (for nonstrings, it simply implicitly adds the method .to_s and outputs the result).

Now you use the method .to_i to change a Float to a Fixnum.

irb
>> c = 10.0
=> 10.0
>> c.class
=> Float
>> d = c.to_i
=> 10
>> d.class
=> Integer
>> exit

Method to_s for Your Own Classes

Integrating a to_s method is often useful. Then you can simply output a corresponding object via puts (puts automatically outputs an object via the method to_s).

Listing 1-31 shows an example.

class Person
  def initialize(first_name, last_name)
    @first_name = first_name
    @last_name = last_name
  end
  def to_s
    "#{@first_name} #{@last_name}"
  end
end
$ irb
>> load './person-a.rb'
=> true
>> sw = Person.new('Stefan', 'Wintermeyer')
=> #<Person:0x007fa95d030558 @first_name="Stefan", @last_name="Wintermeyer">
>> puts sw
Stefan Wintermeyer
=> nil
>> exit
Listing 1-31

person-a.rb

Is + a Method?

Why is there also a plus symbol in the list of methods for String? Let’s find out by looking it up in ri.

$ ri -T String.+
String.+
(from ruby site)
---------------------------------------------------------------------------
  str + other_str   -> new_str
---------------------------------------------------------------------------
Concatenation---Returns a new String containing other_str
concatenated to str.
  "Hello from " + self.to_s   #=> "Hello from main"

Let’s see what it says for Integer.

$ ri -T Integer.+
Integer.+
(from ruby site)
---------------------------------------------------------------------------
  int + numeric  ->  numeric_result
---------------------------------------------------------------------------
Performs addition: the class of the resulting object depends on the class of
numeric and on the magnitude of the result. It may return a Bignum.

Let’s play around with this in irb. You should be able to add the + to an object, just as any other method, separated by a dot and then add the second number in brackets as a parameter.

$ irb
>> 10 + 10
=> 20
>> 10+10
=> 20
>> 10.+10
=> 20
>> 10.+(10)
=> 20
>> exit

Aha! The plus symbol is indeed a method, and this method takes the next value as a parameter. Really, you should put this value in brackets, but thanks to Ruby’s well-thought-out syntax, this is not necessary.

Can You Overwrite the Method +?

Yes, you can overwrite any method. Logically, this does not make much sense for methods such as +, unless you want to drive your fellow programmers mad. I am going to show you a little demo in irb so you will believe me.

The aim is overwriting the method + for Fixnum. You want the result of every addition to be the number 42. You can write a so-called monkey patch , as shown in Listing 1-32.

class Integer
  def +(name, *args, &blk)
    42
  end
end
Listing 1-32

monkey-patch-a.rb

Now you use the + method before and after that monkey patch.

irb
>> 10 + 10
=> 20
>> load './monkey-patch-a.rb'
=> true
>> 10 + 10
=> 42
>> exit

First you perform a normal addition . Then you redefine the method + for the class Integer, and after that you do the calculation again. But this time, you get different results.

if Condition

An abstract if condition looks like this:

if expression
  program
end

The program between the expression and end is executed if the result of the expression is not false and not nil.

../images/460214_1_En_1_Chapter/460214_1_En_1_Figp_HTML.gif You can also use a then after the expression, as shown here:

if expression then
  program
end

The construct for a simple if branch in a Ruby program looks like the following example program:

a = 10
if a == 10
  puts 'a is 10'
end

../images/460214_1_En_1_Chapter/460214_1_En_1_Figq_HTML.gif The == is used to compare two values. Please don’t mix it up with the single =.

You can test an expression really well in irb .

$ irb
>> a = 10
=> 10
>> a == 10
=> true
>> exit
$

Shorthand

The following code shows a frequently used shorthand notation of an if condition:

a = 10
# long version
#
if a == 10
  puts 'a is 10'
end
# short version
#
puts 'a is 10' if a == 10

else

You can probably imagine how this works, but for the sake of completeness, here is a little example :

a = 10
if a == 10
  puts 'a is 10'
else
  puts 'a is not 10'
end

elsif

Again, most programmers will know what this is all about. Here’s an example:

a = 10
if a == 10
  puts 'a is 10'
elsif a == 20
  puts 'a is 20'
end

Loops

There are different ways of implementing loops in Ruby. The iterator variation is used particularly often in the Rails environment.

while and until

An abstract while loop looks like this:

while expression do
  program
end

../images/460214_1_En_1_Chapter/460214_1_En_1_Figr_HTML.gif The do that follows expression is optional. Often you will also see this:

while expression
  program
end

Here is an irb example:

$ irb
>> i = 0
=> 0
>> while i < 3 do
?>   puts i
>>   i = i + 1
>> end
0
1
2
=> nil
>> exit

You build until loops similarly.

until expression
  program
ends

Again, here is the corresponding irb example:

$ irb
>> i = 5
=> 5
>> until i == 0
>>   i = i - 1
>>   puts i
>> end
4
3
2
1
0
=> nil
>> exit

Blocks and Iterators

Block and iterator are some of the favorite words of many Ruby programmers. Now I am going to show you why.

In the following loop, i is the iterator, and puts i is the block.

5.times { |i| puts i }

You can also express the whole thing in the following syntax:

5.times do |i|
  puts i
end

Iterators

Iterators are just a specific type of method. As you probably know, the word iterate means to repeat something. For example, the class Integer has the iterator times(). Let’s see what help ri Integer.times offers:

$ ri -T Integer.times
Integer.times
(from ruby site)
---------------------------------------------------------------------------
  int.times {|i| block }  ->  self
  int.times               ->  an_enumerator
---------------------------------------------------------------------------
Iterates the given block int times, passing in values from zero to int - 1.
If no block is given, an Enumerator is returned instead.
  5.times do |i|
    print i, " "
  end
  #=> 0 1 2 3 4

It also gives a nice example that you can try in irb.

$ irb
>> 5.times do |i|
?>   puts i
>> end
0
1
2
3
4
=> 5
>> exit

There is also a single-line notation for small blocks.

$ irb
>> 5.times { |i| puts i }
0
1
2
3
4
=> 5
>> exit

By the way, an iterator does not necessarily have to pass a variable to the block.

$ irb
>> 5.times { puts 'example' }
example
example
example
example
example
=> 5
>> exit

Blocks

A block is the code that is triggered by an iterator . In the block, you have access to the local variable (or variables) passed by the iterator.

Method upto

In addition to times, there is also the method upto for easily implementing a loop. ri offers a nice example for this, too.

$ ri -T Integer.upto
Integer.upto
(from ruby site)
---------------------------------------------------------------------------
  int.upto(limit) {|i| block }  ->  self
  int.upto(limit)               ->  an_enumerator
---------------------------------------------------------------------------
Iterates the given block, passing in integer values from int up to and
including limit.
If no block is given, an Enumerator is returned instead.
For example:
  5.upto(10) { |i| print i, " " }
  #=> 5 6 7 8 9 10

Arrays and Hashes

As in many programming languages , arrays and hashes are popular structures in Ruby for storing data.

Arrays

An array is a list of objects. Let’s play around in irb.

$ irb
>> a = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
>> a.class
=> Array
>> exit

That is simple and easy to understand.

Let’s see if it also works with strings in the array.

$ irb
>> a = ['Test', 'Banana', 'blue']
=> ["Test", "Banana", "blue"]
>> a.class
=> Array
>> a[1]
=> "Banana"
>> a[1].class
=> String
>> exit

That also works.

So, all that’s missing now is an array with a mixture of both. Obviously that will work, too, because the array stores objects , and it does not matter which kind of objects they are (i.e., String, Integer, Float, …). But a little test can’t hurt.

$ irb
>> a = [1, 2.2, 'House', nil]
=> [1, 2.2, "House", nil]
>> a.class
=> Array
>> a[0]
=> 1
>> a[0].class
=> Integer
>> a[1].class
=> Float
>> a[2].class
=> String
>> a[3].class
=> NilClass
>> exit

Arrays can also be created via the method new (like any class). Individual new elements can then be added at the end of an array via the method <<. Here is the corresponding example:

$ irb
>> a = Array.new
=> []
>> a << 'first item'
=> ["first item"]
>> a << 'second item'
=> ["first item", "second item"]
>> exit

Iterator each

You can work your way through an array piece by piece via the method each. Here’s an example:

$ irb
>> cart = ['eggs', 'butter']
=> ["eggs", "butter"]
>> cart.each do |item|
?>   puts item
>> end
eggs
butter
=> ["eggs", "butter"]
>> exit

ri Array.each provides help and an example in case you forget how to use each.

Hashes

A hash is a list of key-value pairs. Here is an example with strings as keys :

$ irb
>> prices = { 'egg' => 0.1, 'butter' => 0.99 }
=> {"egg"=>0.1, "butter"=>0.99}
>> prices['egg']
=> 0.1
>> prices.count
=> 2
>> exit

Of course, hashes can store not just strings as objects in the values but, as with arrays, also classes that you define yourself (see the section “Arrays”).

Symbols

Symbols are a strange concept and difficult to explain. But they are useful and used frequently with hashes, among others.

Normally, variables always create new objects.

$ irb
>> a = 'Example 1'
=> "Example 1"
>> a.object_id
=> 70124141350360
>> a = 'Example 2'
=> "Example 2"
>> a.object_id
=> 70124141316700
>> exit

In both cases, you have the variable a, but object_id is different. You could carry on in this way indefinitely. Each time, it would generate a different object ID and therefore a new object. In principle, this is no big deal and entirely logical in terms of object orientation. But it is also rather a waste of memory space .

A symbol is defined by a colon before the name and cannot store any values itself, but it always has the same object ID, so it is very well suited to be a key.

$ irb
>> :a.class
=> Symbol
>> :a.object_id
=> 702428
>> exit

Let’s do another little experiment to make the difference clearer. Use a string object with the content white three times in a row and then the symbol :white three times in a row. For white, a new object is created each time. For the symbol :white, it’s created only the first time.

$ irb
>> 'white'.object_id
=> 70342874305700
>> 'white'.object_id
=> 70342874300640
>> 'white'.object_id
=> 70342874271720
>> :white.object_id
=> 1088668
>> :white.object_id
=> 1088668
>> :white.object_id
=> 1088668
>> exit

Using symbols as key for hashes is much more memory efficient.

$ irb
>> colors = { black: '#000000', white: '#FFFFFF' }
=> {:black=>"#000000", :white=>"#FFFFFF"}
>> puts colors[:white]
#FFFFFF
=> nil
>> exit

You will frequently see symbols in Rails . If you want to find out more about symbols, go to the help page about the class Symbol via ri Symbol.

Iterator each

With the method each you can work your way through a Hash step-by-step. Here’s an example:

$ irb
>> colors = {black: '#000000', white: '#FFFFFF' }
=> {:black=>"#000000", :white=>"#FFFFFF"}
>> colors.each do |key, value|
?>   puts "#{key} #{value}"
>> end
black #000000
white #FFFFFF
=> {:black=>"#000000", :white=>"#FFFFFF"}
>> exit

Again, ri Hash.each offers help and an example in case you cannot remember one day how to use each.

Range

The class Range represents an interval. The starting and ending points of the interval are defined enclosed in normal brackets and separated by two dots in between them. Here is an example in which you use a range like an iterator with each:

$ irb
>> (0..3)
=> 0..3
>> (0..3).class
=> Range
>> (0..3).each do |i|
?>   puts i
>> end
0
1
2
3
=> 0..3
>>

Via the method to_a, you can generate an array from a range.

>> (0..3).to_a
=> [0, 1, 2, 3]
>>

A range can be generated from objects of any type. It’s only important that the objects can be compared via <, >, == and can use the method succ for counting on to the next value. So, you can also use Range to represent letters.

>> ('a'..'h').to_a
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
>>

As alternative notation, you may sometimes come across Range.new(). In this case, the starting and ending points are not separated by two dots but by a comma. This is what it looks like:

>> (0..3) == Range.new(0,3)
=> true
>> exit
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.144.217