Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
64 views

Ruby - Fundamentals - Course - Transcript

Ruby is a dynamic, object-oriented programming language that focuses on developer productivity and happiness. It allows writing clean, readable code through features like dynamic typing, duck typing, and object orientation. The most popular implementations of Ruby are byte code interpreted, which can impact performance. To get started with Ruby, you install the Ruby interpreter and can begin experimenting interactively through IRB or by writing Ruby files.

Uploaded by

Teodora
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views

Ruby - Fundamentals - Course - Transcript

Ruby is a dynamic, object-oriented programming language that focuses on developer productivity and happiness. It allows writing clean, readable code through features like dynamic typing, duck typing, and object orientation. The most popular implementations of Ruby are byte code interpreted, which can impact performance. To get started with Ruby, you install the Ruby interpreter and can begin experimenting interactively through IRB or by writing Ruby files.

Uploaded by

Teodora
Copyright
© © All Rights Reserved
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 29

by Alex Korban

Transcript

An introduction to Ruby

Overview

Hi this is Alex Korban welcome to the Ruby Fundamentals course. The goal of this course is to be a
launch pad for your Ruby development. I'd like you to get a solid foundation for writing Ruby code.
I would also like to leave you with an appreciation of Ruby's expressiveness and power. You will
learn about setting up your environment to run Ruby programs. You will find out about the tools
you can use. I will show you one of the popular Ruby IDE and some its features such as an
integrated debugger. And of course you will learn about the features of the language and some of
the standard libraries which come with it. In this first module you will find out how to get up and
running and start experimenting with some code.

10,000ft View of Ruby

Before launching into installing Ruby tools let's take a step back and talk about what kind of
language Ruby is and therefore what kinds of problems it's suitable for. What initially attracted me
to Ruby was that its creator has a focus on helping developers be productive and happy. It was a
refreshing attitude. As I started using the language I found that Ruby allows me to write very clean
and readable code with minimal levels of syntactic and semantic noise. It also comes with a huge
amount of useful functionality built into its extended library. Ruby was first released in 1995 and
over the years a large ecosystem of third-party libraries and frameworks grew around, particularly
in the web development arena. The focus on productivity and developer happiness is awesome, but
let's also take a look at the other aspects of the language. How does Ruby compare to other
languages? Ruby is thoroughly object oriented as it was inspired by small talk. There are a few
primitives and many things in Ruby are expressed in terms of objects and methods. It is based on
dynamic typing and duck typing. Dynamic typing means that a variable can refer to objects of
different types during the course of program execution. Duck typing means that valid semantics
undetermined by the objects type, instead it's enough for the object to have the methods which the
operation uses. This allows you to have polymorphism without inheritance, so class hierarchies can
be a lot simpler. It also gives you the opportunity to write _____ code. The flip side is that it may
require more discipline from the programmers working on the code base. In addition to object
oriented style of programming, Ruby is flexible enough to allow functional and procedural styles of
programming as you will see in the examples during this course. Ruby has a lot of facilities for
reflection. It can get a lot of information at run time, such as class methods, inheritance hierarchies,
and so on. Another aspect of Ruby is that it provides rich opportunities for metaprogramming by
various hook methods, as well as the ability to create classes and methods dynamically. As this
course is about fundamentals I won't devote much time to metaprogramming, but I think it's
important for you to know that it's something that's available to you. The widely used
implementations of Ruby are byte code interpreted. This can put some limitations on performance.
The official implementation, which I'm going to use in this course, is called MRI, which stands for
Matz's Ruby Interpreter. Another popular implementation is JRuby, which is built on top of the Java
Virtual Machine. I should mention that on the Mac another Ruby implementation called MacRuby
can perform both just-in-time and ahead-of-time compilation of Ruby code.
Installing Ruby

Let's take a look at installing Ruby. On Windows the easiest way to install Ruby is to use the
prepackaged installer. Open rubyinstaller.org/downloads in your browser. Enter an installer for
Ruby 2.0 or later. The installer comes in both 32-bit and 64-bit flavors, I'm going to download the
64-bit version. Once the installer downloads, run it and follow the steps in the wizard. On the
installation destination page check the box to Add Ruby executables to your path and then click
Install. Now that the installation is complete let's check that Ruby's working properly. I'm going to
open a command prompt and type ruby --v which will output the version of the Ruby that's
currently installed. So it outputs the version and I can see that 2.0 is installed and available. You can
run Ruby programs by passing the name of a file to Ruby, so I can create a very small test file.
(typing) And then I can run it by passing its name to Ruby. So it outputs Hello. Know that files with
Ruby code typically have a .rb extension. If you use Linux the easiest way to install Ruby is to use
RVM, a Ruby Version Manager. Some versions of Linux come with Ruby packages, but they can
often be out-of-date, whereas RVM gets updated much quicker. Another benefit of using RVM is
that it allows you to switch between multiple versions of Ruby easily if you have the need to write
applications targeting different versions of the interpreter. Open rvm.io in your browser and on the
home page you will see a command to install RVM along with the latest version of Ruby. (typing)
Copy this command and paste it into the shell. When you run it, it will take a while, but after it's
done you should have a shiny new Ruby installed. Again you can check that it works by running
ruby --v. Mac OS X comes with a preinstalled version of Ruby, but it's also likely to be out-of-date.
Similarly to Linux, you can use RVM to install the latest version of Ruby if you're on a Mac.

Interactive Shell Demo

The easiest way to start playing with Ruby is to use the interactive shell that comes with it. It's
called IRB because I stands for Interactive and Ruby code file names normally have the .rb
extension. This kind of tool is also sometimes called REPL, which stands for read-eval-print loop. It
was pioneered by Lisp and it's a great tool for quick experiments and exploration. You can start it by
running the IRB command in the terminal. (typing) If you run it on Windows you might get a DL is
deprecated, please use Fiddle message like I did. It's just a deprecation message which is going to
be fixed in the future versions of Ruby and our _____ still works fine so nothing to worry about.
Now that we have this interactive environment let's dive in and look at some examples of what you
can do with Ruby. Variables don't have to be declared, you just assign a value to a new variable
when you need it. (typing) So now I have a variable called lander_count, which is equal to 10.
_____ that irb shows the result of evaluating the expression. As Ruby has dynamic typing you can
also assign values of different types to one variable. (typing) By the way you can use the up arrow
to go through the history of expressions that you typed, which is a great time saver. In going back to
our variable, now we can check the type of land account by using its method called class. (typing)
Irb reports that its class is String. The interesting thing is that the class method doesn't just return
the name of the class it returns the class itself. If you recall most things in Ruby are objects, in fact
even classes themselves are objects so I can examine their interfaces too. Objects have a method
called public_methods which returns an array of public methods an object has, let's try it out.
(typing) This method returns an array of method names. I've also sorted the array by taking on a call
to sort to make it easier to read. If I look through the method list I can spot the superclass method in
it. This method allows me to traverse the inheritance hierarchy. I can type String.superclass to find
out that string inherits from object. If I add one more superclass I can see that object is derived from
BasicObject, which is at the root of class hierarchy in Ruby. Remember that I said that even
numbers in Ruby are objects, it means that I can do things like this. So the class of this object is
Fixnum or I can do this. This kind of extensive object orientation provides consistency which
allows you to write cleaner code and makes your job as a programmer easier. IRB allows you to do
a lot more than defining variables and call in methods, you can also define new methods or even
classes. For example, I'm going to define the method called double. (typing) For convenience I've
written the whole method on one line. It takes one argument, multiplies it by 2, and returns the
result, let's try it out. The method returns 20 as expected. Now let's try something else. Something
interesting happens here, the method returns the string, which is the argument repeated twice.
Because of Duck type and the custom operating implementation in this string class, this method also
works on strings. I can even use it with an array. (typing) The result is similar to what happens with
strings, the result is an array repeated twice. A handy thing to know about IRB is that a special
variable referred to with underscores stores the result of the last evaluated expression. So you can
get access to that result even if you didn't store it in the variable. I can type double_, to double the
previously returned array. Finally when you're done type exit to get out of IRB. I encourage you to
do some more exploration in IRB on your own. To recap IRBs great for experimentation and
exploration. You start it from the command line using the irb command. It allows arbitrary Ruby
code, you can use the up arrow to go through the history of the expressions that you typed, and use
the underscore variable to access the previous result, which saves you some typing.

IDE Options and RubyMine Demo

When you start developing complex software in Ruby you might want the assistance of an IDE to
manage, debug, and test the code. I use and recommend RubyMine. It's cross platform and works
on Windows, Linux, and Mac OS. It's free for open-source projects, but costs some money if you're
developing commercial software. In my opinion, it's the most advanced Ruby IDE. It provides code
completion and navigation, it has an integrated debugger, it can run your test suite, and even has
convenient built-in source control clients. It also has extensive support for the Ruby on Rails
framework if that's your reason for learning Ruby. You can download it at jetbraines.com/ruby.
Another option is Aptana Studio, it's also cross platform and you can download it as a standalone
application or as an eclipse plug-in, it's available free of charge. Of course you can also
development without an IDE using your favorite text editor. Emacs and VIM have Ruby plug-ins
and there are other editors such as SciTE or Notepad++ which have at least some support for Ruby.
I'm going to use RubyMine throughout this course, so first let me show you how to create a Ruby
project in it. When you open RubyMine it'll show a quick start window. Click on Create new
project. Set the type to Empty project, enter a name for it, RubyMine will create the corresponding
directory, but know that you can change where the source files are placed by changing the path and
the location field. Press OK and RubyMine will create the project. After that I just need to add a file
(typing) and I can start writing code. I'll make the program say hello to begin with. Then I can Run
it and it outputs Hello! in the console window at the bottom. I'd like to dedicate the rest of the
module to a kind of a bootstrap process for your learning of Ruby. I'll go over the basics like name
and variables, code formatting, comments, defining methods, and so on. This will give you a
foundation and let you write simple programs. With that you should be ready to dive into the details
of various aspects of the language in the subsequent modules.

Variables, nil, Methods and Scope

Let's start with variables. I've already used variables when I showed you IRB. In Ruby defining the
variable is done with a minimum of fuss, when you need a new variable you just give it a name and
assign a value to it. You don't need to declare it beforehand and you don't need to specify its type.
Variable names start with a lowercase letter and the idiomatic style is to use underscores in variable
names to make them more readable as opposed CamelCase. What if you want to define a variable
but don't have a value for it yet? In that case you can assign nil to it. Nil isn't the primitive, it's a
special object that signifies null value. If I type nil.class irb tells me that its class is NilClass. I can
check if a variable is nil by using its nil method. Result.nil returns true because result is actually nil.
The question mark in this statement isn't special syntax it's simply part of the method name. In
Ruby method names can end with a question mark or an exclamation mark. The question mark is
normally used for methods which perform a true/false test. The exclamation mark is used in method
names which do something slightly unexpected or dangerous. An example of that would be
modifying the object in place instead of returning the modified copy. We can see this in the string
class. (typing) Here I have a string with some whitespace in it. The string class has a convenient
method called strip which removes the leading and trailing whitespace from a string, let's try it out.
You can see that it returns a string without whitespace, however, the method returned a new string
and A's still unchanged. If you want to modify A instead of creating a new string, you can call the
version of strip with an exclamation mark. In this case the string object A refers to has been
modified in place. Another situation where an exclamation mark could be used is if you have a
method to terminate some operation abruptly without firing the normal callbacks. Normally you
would only define such methods when they also have a safe count, but without the exclamation
mark. You've also seen how to define the method. I defined the method on a single line in IRB like
this, this isn't how you would write regular code. Semicolons are used to _____ statements on a
single line, but good Ruby style is to use them very sparingly outside of IRB. Normally methods are
defined on multiple lines like this. The method definition starts with the keyword def followed by
the method name and followed by an optional parameter list in brackets. The definition ends with
the keyword end. A method can return a value of any type, in fact it can even return values of
different types depending on the circumstances. Methods return the result of evaluating the last
expression so there's no need for an explicit return statement, unless you specifically want to use it
for flow control. Typically Ruby code is indented with two spaces. Whitespace is not significant
unless it's inside a string. When calling the method, for example like this, the brackets around the
arguments are actually optional, but they are normally used when you have an argument list and
omitted if you don't. There are some exceptions though and I'll note them throughout the course.
Some methods are used more like keywords in Ruby, with those methods is common to omit the
brackets. One example of this is the boots method, which I've used before. One more thing you
need to know about methods in Ruby is that they provide scope for variables. In this example
lander_count is a local variable so its visibility is limited to the scope it was created in. As it's
defined at the start of the file, it's going to be visible throughout the program. If I define a variable
within a method instead, then the variable is only going to be visible inside that method, but what
happens if I name my variable in an inner scope, the same as a variable in the outer scope? In this
example lander_count is first defined at the start of the program and then I've redefined it in the
report method. What happens here is that the second definition in inner scope shadows the variable
in the outer scope. I'm also calling the report method after defining it, note that there are no brackets
because it doesn't take any arguments. And I also output the lander_count value at the end. When I
run this program it first outputs 5 and then 10. This is because the lander_count in the report method
is a new variable which exists within the scope of the method. It doesn't affect the lander_count
from the outer scope, so when I print the variable after the report method, I see the value from the
original definition. In addition to local variables, you can also create a global variable by prefixing
its name with a dollar sign. The log_level variable is visible everywhere throughout the program.
Hopefully you won't have much need to create global variables as global state is generally a bad
idea and can cause subtle bugs and a lot of headaches.

Flow Control, Operators, Comments

So far you've seen how to create variables and methods, the next thing you're going to need is some
control structures. Ruby has some familiar looking control structures such as the if-else statement.
As you can see in this if statement it also has the usual operators such as greater than. However, an
interesting twist is that Ruby treats statements as expressions as much as possible. The if is actually
an expression which evaluates to the result of the last expression in the selected branch. So instead
of outputting a string in each branch, you can do something like this. (typing) Now the if returns
one of the strings depending on the value of lander_count. The result is a sign to message and then
the message is printed afterwards. This property of Ruby means that you can change the
assignments as well. This is because the assignment expression yields the value that was assigned.
Let's have a look at some of the operators Ruby provides. This isn't an exhaustive list, but it should
be enough for the purposes of our bootstrap process. I'll introduce a few more operators later on in
the course. Greater than has its friends less than, greater or equal, and less or equal. You can also
check whether objects are equal or not. There are other usual mathematical operators to add,
subtract, multiply, divide numbers, and take the modular. There is also an exponentiation operator
denoted with a double star. Ruby has the familiar logical operators representing not and as well as
or, but it also has an alternative syntax where these operators are written as words. The difference
with the second group is precedence. Here instead of the or operator having higher precedence, both
and or have the same precedence. The second group is normally used for flow control outside of
control structures such as if-else. The next group is bitwise integer operators. We have the usual
suspects here, bitwise and/or exclusive or complement as well as operators for shifting left and right
by a specified number of bits. Ruby also provided a bunch of convenient shorthand operators which
combine assignment with another operation. So for example, a+=10 is the same as a=a+10. Finally
code always requires a sprinkling of comments. In Ruby anything following the pound sign is a
comment. Comments continue until the end of the line.

Some Useful Methods

The last thing I'd like to demonstrate in this module is a few useful methods. The first thing you
might like your programs to do is to take some input and produce some output. Let's look at a small
example which does that. So here I use print which outputs a string. It's convenient when you need
a prompt for example. Then gets, waits for your keyboard input and returns it and the puts call
outputs a string combined with your input. Note that the puts method adds a new line to the string.
Let's try this program out. I'll input my name and the program outputs a greeting which includes my
name. Let's look at one more example. Ruby makes it very easy to execute a command in another
process and collect its result. I can use backticks to specify a command to execute. In this program
I'm asking for the time from the system. It'll be launched in a separate process and the Ruby process
will block until it's complete. The output of the command is then returned to Ruby so I can store it
in a variable and output it. Instead of backticks, you can also use %x. (typing) The system method is
similar, however instead of the command output it returns true if the command finished with 0
status and false for non 0 status. It returns nil if the command failed. The output of the command is
part of standard output which is why we see the time printed twice when I run this program.

Recap

Let's quickly recap what you've learned. Variables are named using snake_case not CamelCase.
Defining a variable is a simple assignment. Global variable names start with a dollar sign, but I
hope you won't need them. A variable in inner scope will shadow a variable of the same name
previously defined in outer scope. You can assign a variable the value of nil. Nil is a special object
which signifies null value. Methods are defined using the def keyword. Methods return the result of
the last expression. You don't need to use an explicit return statement. You should indent your code
with two spaces, it's not a hard requirement as Ruby doesn't care about whitespace, but it's very
common practice. You've seen that Ruby has familiar looking operators and control structures,
however, as Ruby treats most things as expressions, you get extra convenience. Comments start
with a pound sign and go on until the end of the line. Input and output can be done using the gets,
puts, and print methods. And finally you can easily call out to the system using either backticks or
the system method.

Summary

This is the end of module 1. In this module you've learned about the principles underlying the Ruby
language and its implementation. You've seen a demonstration of its interactive shell, IRB, and one
of the IDEs, RubyMine. You've also learned the basics of the Ruby language. You now know how
to define variables and methods and how to format and comment your code. You've seen some
examples of Ruby control structures and operators. And you've found out about some useful
methods.

Classes and Objects


Overview

Hi this is Alex Korban. In this module you will learn about Classes and Objects in Ruby. You will
find out how to create your own classes and how to instantiate objects from those classes. You will
learn how to add instance variables and methods to your classes. You will find out how to control
the visibility of these variables and methods. I'll show you how to initialize your objects. You will
see how to create class variables and methods. You'll also get the hang of leveraging inheritance to
re-use functionality. Finally I'll talk about self, which refers to the current context. I'll talk about
what it means to have executable class bodies in Ruby and object equality.

Creating Classes and Objects

To begin with let's look at how you can create classes and objects. Class definitions start with the
class keyword and end with the end keyword. Generally the end keyword is used to finish all blocks
of code. The way you capitalize identifiers in Ruby is significant. While variable names start with a
lowercase letter, class names start with an uppercase letter. Multiple words and class names are
delineated using CamelCase and acronyms are normally written in uppercase letters. To instantiate
an object from a class you use the new method of the class. Remember that in Ruby you typically
omit brackets when defining or calling methods without arguments. You can think of the new
method as a factory which converts the blueprint encoded in the class into a specific object. Let's
take a moment to talk about variables versus objects, it's important to understand the difference.
Although most things in Ruby are objects, variable aren't, instead variables are just labels for
objects. Suppose I assign a string to a variable. Now I have a variable called A which refers to an
instance of the string class. What happens when I create another variable like this. There is still only
one object, but now I have two different labels called B and A, which refer to it. Now let's check
that it's indeed the case. If I convert A to uppercase like this, this modifies the object in place. So if I
look at A the string is in uppercase. This is because I used the version of uppercase with an
exclamation mark. Now let's take a look at B. Well look at that, B has also changed, which means
that there is one object both variables referred to. We can also verify that both B and A refer to the
same object in another way, by checking the unique identifier of the object. For that I use the
method called object_id, so that's the id for A. And this is the id for B and we can see that it's the
same. When you pass arguments to a method the behavior is similar, the objects are passed by
reference without creating copies, but what if you really need to create a copy of an object? Then
you can use the clone method from the object class. This will create a new object. So when I modify
it (typing) I can see that A and B now refer to two different objects. You should be aware that clone
doesn't perform deep copy. If I had references to other objects within it, then B would refer to the
same objects. In practice, however, this isn't often a problem. So remember that neither assignment
nor passing parameters to methods creates new objects. If you want to create a copy of an object
you need to use its clone method.

Instance Variables and Methods

The spaceship class, I showed you before, couldn't do anything useful because it's empty. Let's give
it a little bit of functionality. I've added the method called launch which takes this destination as its
argument. Let's also make it store the argument in an instance variable for future use. Instance
variables in Ruby are denoted with @. They're called instance variables because each instance of
the spaceship class is going to have its own copy of destination. Note that the destination instance
variable is only created if I call the launch method. Before that it doesn't exist. So let's take this
method for a spin now. I've got the same class in a project in RubyMine. You can also see here that I
can freely mix class definitions with other code in the same file. Ruby is low on ceremony so it
doesn't dictate any particular code organization. Once I've set the destination via the launch method
I can take a look at the state of my ship object with the help of the inspect method. If I run this
program, I can see in the output pane at the bottom that destination has indeed been set. Instead of
inspect I can also use the method called simply P to print out information about the object. If I rerun
this program I see the same output as with inspect. What if I want to access the value of destination
later on? Let's try it. When I run this I get an error telling me that the destination is an undefined
method. This is because all instance variables in Ruby are not visible outside of the class. Instance
methods, on the other hand, are public by default. In order to exit destination I have to define a
method which returns it. When I run this program again it outputs Earth which is what I wanted. In
this demo you've seen that you can use the objects inspect method or the P method to take a look
inside the object. Instance variables of an object are private and can only be accessed via methods.
Methods are public by default.

Accessors and Virtual Attributes

A class can have many different instance variables and defining methods to set and get each one of
them would be quite tedious. For this reason Ruby provides a convenient alternative. You can use
attr_accessor to provide read and write accessors for an instance variable. Here I've added accessors
for the destination instance variable. The colon before the word destination indicates that it's a
symbol. We'll talk about symbols in the one of the next modules. For now just remember that this is
how you specify the name to access. With this in place I can now set and get the destination. Note
that invoking a setter created via attr_accessor looks like assigning a value to an attribute.
Sometimes you might want to provide read only accessors to a variable and in other situations you
might only want to allow to set the variable. You can do that as well. Here I provide read and write
access to the name variable via separate declarations. Attr_accessor actually combines attr_reader
and attr_writer together, but you can use them separately. The nice thing about accessors is that the
syntax for using them is very clean. You can also define multiple accessors at once by providing a
coma separated list of names. One last thing I'd like to say about accessors is that there is a bit of a
gotcha when you use accessors inside a class. In the cancel_launch method the first line isn't going
to call the accessor method, instead it's just going to create a local variable. So to make it clear to
Ruby that you want to call the accessor you need to qualify it with self. as I've done on the second
line. If we dig a little deeper it turns out that attr_accessor simply adds a pair of methods to the class
behind the scenes. The first class definition here is equivalent to the second. If you look at the
second destination method you'll see that it's got an equals sign at the end. Once again the equals
sign in the second method is just a part of its name, just like a question mark or an exclamation
mark. It simply signifies that it's a setter. What if instead of using these methods to manipulate the
destination variable, I do something else instead? For example, I can change this class definition so
it passes the destination value to the autopilot instead of storing it. Now destination has become a so
called virtual attribute. The interface of the class hasn't changed, I can still assign a string to
destination and get a string back. However, under the hood there is no instance variable called
destination anymore. This is another case where Ruby provides very useful consistency. I can start
out with regular attributes in my class, but as I develop it, it's very easy for me to replace simple
attribute access with more complex code and it doesn't affect the interface of my class.

Initialization and Cleanup

Most objects need to have some initial state. In order to initialize objects you need to add a method
called initialize to your class. You can then provide arguments when you call the new method and it
will invoked initialize with those arguments. Let's check that this actually works. When I run this
program I can see in the output pane that my ship object now has a bunch of instance variables. So
initialize has indeed been called. So what about destroying objects? In Ruby you don't need to do it
explicitly as it has a garbage collector. Ruby has a variation of a mark and sweep garbage collector
which runs periodically and cleans up the objects which are no longer referenced by your program.
Inheritance

Like most other object oriented languages, Ruby provides the ability for classes to inherit
functionality from other classes. A class can only inherit from a single class. Multiple inheritance is
impossible, but as we'll see in a later module, Ruby provides a great alternative through the concept
of modules. If not specified otherwise, classes in Ruby inherit from the object class, which provides
methods like clone, public underscore methods, and so on. Object in turn inherits from basic object
which is an explicit blank class. In some situations you might find it useful for your class to inherit
from basic object instead of object, for example if you want to avoid name clashes with methods
from the object class. When you call a method Ruby checks whether it exists in your objects class.
If it doesn't find it, it starts traversing the hierarchy of the classes ancestors looking for a method
with that name. If it finds it in one of the superclasses it calls it and all is good, if not you get an
error. For example, if I call clone on my spaceship instance Ruby has to keep looking for it until it
gets to the object class. Here is an example of inheritance. Continuing with the spaceship theme let's
suppose my spaceship can launch probes to explore things. I'm going to create a class called probe
to represent probes. This class inherits from objects inside unspecifyied ancestor. Now suppose I
would like to have two specialized probes, one for taking mineral samples from the soil and another
to sample the atmosphere. Both of them share most of the functionality with the regular probe, they
can be deployed and so on. However the way they take samples is specific to these probes. This is a
great opportunity to use inheritance. Inheritance is specified by adding a left angled bracket and a
superclass name after the class name. In my example MineralProbe inherits all of the methods from
the probe class. If you have an initialized method in the base class it's also inherited along with the
other methods. The next thing I need to do is override the methods which are going to behave
differently from the superclass, like take_sample. All I need to do is define a method with the same
name in my subclass. What if you need to call a method from your base class in your subclass? You
can use the super keyword for that. Let's look at an example. Suppose that for my MineralProbe I
need to perform some extra work before it's deployed, but after that the deployment process is
exactly the same as for a regular probe? I can override the deploy method, add my extra bit of code
at the start, I just output a string here, and then I call the probes deploy method using the super
keyword. Super behaves like a function call so it's going to return whatever the superclass method
returns. Note that I can actually change the number of parameters a method takes when I override it.
The only important thing is that the method name matches. Let's try to run this program. So Ruby
complains about their own number of arguments. What happens here is that because I used super
without any kind of parameter list, it passed MineralProbes deploy method arguments through to
probes deploy method. Please keep in mind that calling super with an empty argument list is
different. See if I add an empty argument list and try to run this program again, I get a different
error message. This time Ruby is complaining that there was zero arguments, not one argument.
Any argument list given to super, even an empty one, overrides its default behavior. What I really
need to do to make this work is pass through the deploy time and provide a value for return time,
which is required by the Probe class. I'm going to set return time to be two hours in the future.
(typing) When I run this again it works as expected. One more thing I'd like you to know is that
compared to other languages, such as Java or C++, the role of inheritance and Ruby is limited. Its
main purpose is to provide a mechanism to reuse functionality between classes, not to enforce
interfaces. Suppose my spaceship can launch both lenders and probes, when they return they can
dock with the ship under the ships control and then they are transported to the storage facility.
However, the internal details of the docking mechanism are quite different for lenders and probes.
To solve this problem in other languages perhaps you would make both classes implemented
dockable interface so the spaceship only needs to deal with one type. However, in Ruby it's
completely unnecessary thanks to duck typing. All you need to do is implement the dock method in
both the lender and the probe classes and the spaceship called will work with either without any
extra code. So for example I could have a capture method in the spaceship class which calls dock on
its unit argument and then I can call a capture method with either a probe or a lender argument. And
it will work fine as long as those classes implement the dock method. This is one of the advantages
of the dynamically typed languages and duck typing in particular. The class hierarchy can be greatly
simplified when you don't need to write classes which don't do anything other than specify an
interface.

Class Methods and Variables

The next thing I'd like to show you is class methods and class variables. A class method is called on
a class instead of an object. An example of a class method you've already seen is new, which is used
to instantiate objects. Sometimes you have functionality which is independent of object state and
this is where class methods are useful. For example, I might want to have a method to return the
number of thrusters in my spaceship class. Every spaceship is going to have the same number of
thrusters so this is a good candidate for a class method. Now you could make this method a regular
instance method as well, but a class method makes it clearer that this bit of functionality is not
reliant on object state. To define a class method you need to prefix its name with self.. The self
keyword is actually more than just a syntactic signpost for class methods and I'll talk about its
meaning a bit later in the module. You call the class method on the class rather than an object. If
you try to call it on an object you will get an error. While class methods don't use object state, they
might nevertheless have some state that needs to be preserved between calls. To keep track of it you
can define class variables. A class variable is denoted with a double @, there is only one copy of a
class variable per class and it's shared between all objects of that class. You define it in the body of
the class. The class variable isn't visible outside the class, so you have to provide accessor methods
for it if you need to access it from the outside. It turns out that in practice class variables aren't
actually used very often and that's because of a quirk in their behavior. Suppose you have different
types of spaceships and they can have a different number of thrusters, which you'll want to specify
using the thrust account class variable. Let's try this out and see what happens. In this example I
have two subclasses of spaceship. SpritelySpaceship has four thrusters so it can go really fast.
EconolineSpaceship has only one thruster so it cruses slowly but saves on fuel. Now let's check the
value of thrust account with SpritelySpaceship. Opps this program actually outputs 1 instead of 4.
What happened here? Well, it turns out that class variables are actually shared between all of the
subclasses. Spaceships, SpritelySpaceship, and EconolineSpaceship all have just one copy of thrust
account between them. This can lead to unexpected results as we have seen here. Unless this is the
behavior you actually want it's probably better to avoid class variables. Fortunately Ruby does have
a different trick up its sleeve to allow you to store class level data. In addition to instance variables
and class variables, Ruby has another kind of variables, class instance variables. Check out this bit
of code. I'm certain what looks like an instance variable right in the body of the class here and I'm
also using this variable in a class method instead of an instance method. Instance variables, which
are set in the class body or in the class method, become variables on the class rather than an object.
Let's revisit our example of using a class variable and see how this kind of variable behaves instead.
This example is just like the example you've seen before for class variables except now I'm using a
class instance variable to store thrust account. When I run this program it outputs the correct value
for each class. What happens with class instance variables is that the parent class and each of the
subclasses get its own copy of the variable, but only one per class.

Method Visibility

So far all the methods I've added to classes have been public because that's the default. However,
Ruby does allow you to control the visibility of methods, although the rules for it aren't quite the
same as in other languages. Other than leaving all methods public, you have two other options. You
can make a method private or you can make it protected. You tell Ruby that a method is private by
adding a private declaration after you define the method. For example I can make the
batten_hatches method private like this. The other option is to use the private declaration without a
method name. So in this example I want to make both batten_hatches and light_seatbelt_sign
private. So I can put a private declaration before these methods and all the methods fall in the
declaration will be private, either until the end of the class or until there is another visibility
declaration. This is probably the most used variation of the syntax. You can mix and match visibility
declarations throughout the class. Finally you can supply multiple method names to the private
declaration. This is similar to how attr_accessor works. Now let's try to run some code that uses
private. I've got a Spaceship class with a private batten_hatches method. Let's try to call it from
outside the class. When I run this program I get an error as expected. You should be aware that in
Ruby the visibility isn't enforced very strongly. If instead of calling batten_hatches directly I use the
send method from the object class to invoke it Ruby will happily comply. Now on this program
there is no error anymore. This is in line with Ruby's philosophy of leaving the programmer in
charge. The other important thing to know about private methods is that they can be called from
subclasses. In this example, I have SpritelySpaceship which is a subclass of Spaceship. Since it
needs to go fast it comes with pre batten_hatches. Batten_hatches is still a private method in the
Spaceship class, however when I run this program I can see that it's called from SpritelySpaceships
initialize method. That might be a bit surprising if you've been programming in another language,
but there's a simple rule to remember how private works in Ruby. The rule is that a private method
can be called with an explicit object receiver. This makes it clear that you can't write
ship.battonhatches, it also explains why you can call a private based class method from a subclass.
The private method is inherited by the subclass along with all the other methods. As you are calling
it from the context of the subclass you don't need to provide an explicit receiver and that's why it
works. A word of caution, there is a separate mechanism for making class methods private. If you
tried to use the regular private declaration you won't get an error, but your class method will remain
public. The right way to do it is to use private_class_method, you can pass it one name or a coma
separated list of names but you can't use it without arguments as it doesn't work on a group of class
methods. Let's examine the behavior of protected methods next. It might also be a bit of a surprise.
The protected method can be called on another object by an object of the same class or an object
with the same ancestor if the method was defined in that ancestor. In this example I want to be able
to compare ships call signs. However I don't want to make getting the call sign part of the public
interface. To achieve that I've set up a protected attribute reader called call_sign. The call_sign is set
in the initialized method of this Spaceship class. I also have a method called call_sign_matches?
which takes an object as an argument and checks if it's call sign matches the call sign of my
spaceship. To do that it has to access the protected attribute reader call sign. I also have on a
subclass, called SpritelySpaceship, which is a specialization of spaceship. Next I create two objects,
one is a spaceship and another one is a SpritelySpaceship. When I run this program I don't get an
error, instead it outputs false. However, if I tried to invoke call_sign directly I do get an error
because it's a protected attribute. To summarize, methods are public by default. Private means can
be called with an explicit receiver, which does allow subclasses to use private methods.
Private_class_method is used to make class methods private. Protected means allow other objects of
the same class to use the method. Because of this definition protected class methods don't make
sense, so they don't exist in Ruby. On a final note, private and protected methods aren't used all that
much in Ruby, in keeping with the philosophy of leaving the programer in charge, lots of methods
are left public.

Executable Class Bodies and self

By now you've seen most of the features of Ruby classes, there is one more thing I'd like to show
you and this one is perhaps the most interesting. It turns out that the class bodies in Ruby are
expressions just like most other things, which means they are executed like other code. The
consequence of this is that you can put pretty much any code into the class definition. In this
example I have a class called Spaceship which contains a local variable definition, it has a boot
statement, and I even have a method call in it. When I run this program I can see that the code
inside the class declaration is executed. Since the class declaration is an expression I can even
assign its result to a variable. The last line of output confirms that I've also managed to define the
Spaceship class in the process. In a way you can think of classes as a way of providing a context for
execution of code. A method defined inside a class context is assigned to that class. What about the
attr family of declarations and method visibility declarations such as public and protected? Well,
they are just methods which can be called with or without arguments. The example I've shown you
should give you a hint as to how that's possible. These methods are normally called without
brackets, which makes them look more like keywords. You've already seen the keyword self a few
times, let's find out exactly what this keyword means. Now that you know that classes provide a
context for execution, it's easy to explain what self is. Self simply refers to the current execution
context, whatever that happens to be. You can use self at any point in a Ruby program. Inside a
class definition self refers to the class. This is why you need to prefix methods with self. to turn
them into class methods instead of instance methods. It's also why you end up with a class instance
variable when you assign a value to an instance variable in the class body. An instance variable is
always set on the self and inside the class body self is the class itself. The value of self keeps
changing as the program executes. When you call a method on an object that object becomes self
inside the method. So when I call ship.cancel_launch inside the cancel launch method, self refers to
my ship object. Finally any method which you call without an explicit object reference is called on
self. For this reason when I call seatbelt_sign, inside cancel_launch, it's also called on my ship
object.

Open Classes and Monkey Patching

Now that you know that classes are an execution context and that they can contain regular
executable code, hopefully you'll find it easy to understand the concept of open classes in Ruby.
You can see class Spaceship twice in this bit of code. That's perfectly legal code in Ruby. So what's
up with the second class declaration? I'm not redefining the class, but rather I'm reopening it to add
another method. Afterwards all the objects of this class are able to use the new method, even the
objects which were created beforehand. However, if I tried to call ship.launch before the second
class declaration I would have gotten an error. This leads us to monkey patching which exploits the
concept of open classes. Monkey patching is a term used for _____ or modifying functionality
particularly third-party functionality at runtime. As you have seen you can reopen a class and add a
method to it, it turns out that you can also override an existing method. When Ruby encounters
another definition of a method with a name that already exists, it simply overrides the previous
definition. So in this example I've reopened the class Spaceship and I over road the method called
batten_hatches. When our underscored I get the output from the second method definition. Keep in
mind that if your original method was private or protected, the _____ definition will not preserve
visibility restrictions. If I make the first definition of batten_hatches private and rerun this program I
can see that it still works. That's because the second definition is public. So I have to explicitly
make it private and then when I run this program I get an error as I should. You can even use
monkey patching to modify classes in distended library. Here I've added a new method to class
string. My new method space_out adds a space between each character so it doesn't look so
cramped when printed. I've also redefined the size method so that instead of returning the number of
characters, it returns a rather useless string. When I run this program you can see that I've got new
functionality in the string class. Monkey patching is sometimes used to fix bugs in third-party
libraries. While it is useful you should use it judiciously because it changes the behavior of the code
other users make expect, or it can introduce new and potentially surprising methods. It can also
make your code more brittle because, for example, when you upgrade a library the assumptions you
made when patching it may no longer be valid and your code will no longer work.

Equality

The final thing I'd like to discuss in relation to classes and objects is equality. At the start of the
module you've seen that if you assign one variable to another, both will refer to the same object.
Sometimes you'll need to find out if two variables point to the same object. You can use the equal
method to test if two variables in fact point to the same object. I made A and B equal to 1. If I use
the equal method it returns true. If I make B equal 2 instead then equal will return false, as these
variables now refer to different objects. That's fine but it's not the end of the story. What if I have
two instances of an object representing the same thing? For example, what if I have several
instances of Spaceship created throughout my program and sometimes I need to check if two
instances really represent the same Spaceship. Obviously if I tried to use the equal method it's not
going to work. Equal predictably returns false. Spaceship should really have unique names, so if I
check the name in both objects and it matches then it means they both represent the same
Spaceship. So I could write ship1.name == ship2.name and that will give me true, but that's a bit
un-_____. What else can I do? One option is to override the equal method to do what I want, but
then I won't really have the ability to check if two variables refer to the same object. Another option
is to provide a method in the Spaceship class to perform this comparison for me, but let's look at
that name comparison again. When I create two string objects in Ruby (typing) and then write a ==
b I get true, but if I write a.equal?(b) I get false. So Rubys showing the ability to compare two
different objects here. Well it turns out that I can provide a custom implementation of the double
equals operator in my class which gives me a nice bit of syntactic sugar. The default
implementation does the same thing as the equal method, which is why I need to override it. So here
my operator is simply comparing the names of the two Spaceships. So now instead of writing
ship1.name == ship2.name I can simply write ship1 == ship2 and when I run this I get true. I'll
come back to operate overload and then discuss it in more detail later, but for now when I try this
comparison it works and lets me make testing for equality clear and concise.

Summary

This is the end of module 2. In this module you've become familiar with objects and classes in
Ruby. You've learned how to add class and instance variables and methods to your classes. You
have found out how to use inheritance to specialize classes and how to limit method visibility.
You've also learned about self, the concept of open classes, monkey patching, and object equality.

Flow Control

Overview

Hi this is Alex Korban in this module you will learn about Flow Control in Ruby. I will start with
branching via if-else and the case statement. I will then show you the various looping constructs and
talk a little bit about blocks. I will tell you about exception handling. Finally you will see what
throw and catch do in Ruby, which is probably not quite what you expect.

Branching

As you've seen before Ruby has a pretty _____ if-else statement, however, it also works as an
expression, so you can assign its result to a variable. If you do that it may be convenient to keep it
on one line. Note the optional then keyword which is used to separate the condition from the next
statement. You would normally use it when writing an if statement on one line, but not for a
multiline if statement. Ruby also has a so called modify version of the if statement, this version
can't have an else clause and works best for a short statement followed by a short condition. If you
want to test multiple conditions you can use multiple elsif clauses, which can be supplemented by a
catchall else clause. Note that elsif is one word. In Ruby there are only two things which evaluate to
false in conditions. These things are nil and a literal false. Everything else, such as number 0, empty
string, empty array, and so on evaluates to true. If has a count part called unless in Ruby. Unless has
the opposite effect so if not condition is equivalent to unless condition. Using unless instead of
negated conditions can make your code a bit more readable. Unless can actually have an else clause,
but my advice is not to use it because it gets rather confusing. Like if, unless has a modifier version
which can be tagged onto a statement. As a more succinct alternative to if-else Ruby has the ternary
operator. If the first operand evaluates to true, then the second operand is evaluated by Ruby.
Otherwise it evaluates the third operand. The result is returned same as with the regular if. This
works well for single line conditional statements. I'd advise against nesting ternary operators as it
makes the code hard to understand.

Conditional Initialization

You've already seen the shortcut assignment operators which combine assignment with another
operation, such as += or *=. Ruby also has two other shortcut assignment operators or= and &=.
The &&= operator isn't used a whole lot, but the ||= operators is very very common because it can
be used for conditional initialization of variables. This line of code will call Spaceship.new and
assign it to the ship variable, but only if the ship variable evaluates to false or doesn't exist. If the
ship variable already has a value which evaluates to true, then the operator won't do anything. You
could also write the statement using unless, but it would be more verbose. This double pipe equals
idiom relies on two aspects of Ruby behavior. First, these two shortcut assignments behave in a
different way from the rest of the operators. The behavior of ship ||= Spaceship.new can best be
modeled as ship or ship = Spaceship.new. So if ship evaluates to true then the second operand
doesn't need to be evaluated. However, this conditional assignment works if the ship variable didn't
exist at all beforehand. And this is the second quirk of Ruby required for this idiom to work. If I try
to run a statement a or a = 10 I get an error because a's undefined, but if I run a || = 10 instead it
works. So what kind of magic allows this? It turns out that in Ruby if an assignment appears in a
statement the variable is created and set to nil even if the assignment isn't actually executed. Let's
try this. B now exists and is set to nil. It even works if I do this. The double pipe assignment works
in a similar way. Ruby passes it as an assignment and creates the variable behind the scenes. The
only caveat for this conditional initialization is that it doesn't work for Boolean values. Suppose I
wanted to initialize a Boolean flag. (typing) When I first run this it looks good, the flag is set but
what if I now set the flag to false and then do the conditional assignment again? Hey my flag has
been changed to true. This is not what I wanted. The issues that this idiom relies on nil being
evaluated as false. Of course false is the only other object that evaluates to false, so when I have a
Boolean flag set to false the idiom breaks down.

Flow Control Using and/or

I've already mentioned that Ruby has two forms of and and or operators. They are superficially
similar so you may be tempted to use the word forms of the operators in conditions. That wouldn't
be a good idea because there are two important differences between these operators. One and and or
have a much lower precedence than double ampersand and double pipe operators. Two ampersand
has higher precedence then double pipe, which is common in other languages as well, but and and
or have the same precedence. In the absence of copiers bracket ___ your conditions these
differences can lead to surprising results, for example if you tried to put an assignment into your
condition. For this reason the accepted practice in Ruby is to use the double ampersand and double
pipe in conditional statements, but and and or aren't just a _____ bit of functionality, they do have a
purpose. The role of these operators is to provide flow control, let's see how it works. You can use
and to chain operations together until one of them returns nil or false. This works due to short
circuiting in the and operator. It doesn't evaluate any more operands than it has to. In this example
lender.recall will only be executed if the lender is located successfully and isn't nil. Instead you
could write this code using if, but the first version is shorter and perhaps clearer as long as you're
used to seeing this sort of flow control. You can use or to construct a series of fallback operations. If
the first operation returns nil or false try the second one and so on. In this second example if the
engine cuts out we try to restart it. If restarting fails we switch to emergency power. The assumption
is that engine restart returns true if it succeeds. Using or here is an alternative to using unless. So we
enable_emergency_power unless engine.restart succeeds.

Case Statement

The next flow control structure I'd like to discuss is the case statement. It allows to choose one of
several alternatives based on comparing an object with values. The case statement is quite versatile.
In this example I'm performing different actions based on lenders distance from dock. Note that this
is a bit contrived and I'm not advocating the use of string values to represent distance. Each of the
when clauses is evaluated in turn. There is no fall through between them. Just like the if statement,
the case statement can be used as an expression. Here I'm using it to choose a value for thrust power
based on distance. This statement can also be written a bit more concisely. Similarly to if I've used
the optional keyword then in this example to separate the value compared against from the value
being returned. The case statement uses the triple equals operator to compare the values. This fact
can be used to dispatch based on an objects class because a class uses the triple equals operator to
determine if an object is an instance of that class. By default the triple equals operator does the
same thing as the double equals operator. However, it can be overridden to do something else,
which is how classes can be compared with objects. In this example I'm performing different
actions based on the class of the object given to the case statement. You can also see another feature
of the case statement here, the else clause. It gives you the ability to provide a catchall clause when
none of the when clauses match. It's particularly useful when you're using the return value of the
case statement to assign to a variable, because without else it would return nil if nothing matched.
Else gives you a chance to provide some other value. Finally you can use the case statement without
providing an object. In this situation you simply specify conditions in each of the when clauses.

Looping Constructs

Loops are one of the fundamental constructs in programming so Ruby provides a number of them.
However the use of explicit loops in Ruby code is fairly limited. This is because two of the main
users of loops are to iterate over collections and to iterate a particular number of times. Both of
these can be better done with the help of iterators. I'm going to explain what iterators are, but first
let's talk about regular loops as you're still going to use them occasionally. The first loop construct is
while. Now this is a pretty familiar looking while loop. If you have a very short loop you can also
write the whole thing on one line. The do keyword will help you separate the loop condition from
the body of the loop. It works just like the then keyword and if statements. You'd normally use it in
single line loops, but not in multiline loops. Ruby has one more trick up its sleeve. Just like with if
and unless, while has a modifier form which you can tag onto a statement. Much like if has a
counterpart called unless, while has a counterpart called until, which allows you to invert the
condition. In this example the ship will continue accelerating until it reaches cruising velocity. Keep
in mind, however, that the condition is still evaluated at the start of the loop so the loop body may
not execute at all if the condition is true to start with. Until has the same forms as the while loop, it
can be written on a single line or as a statement modifier. Finally while and until can be tacked onto
the end of a begin/end block as modifiers. The begin/end block is a way of grouping multiple
expressions into one expression. It yields the result of the last expression in the group. So end and
while and until is almost the same as applying them as modifiers to loop over a single expression,
but there's one crucial difference. If you use a begin/end block it will execute at least once even if
your condition is false from the start. Ruby provides a for loop as well, but it's not used all that
much. Most people prefer to use the each method for iteration. The for loop happens to be syntactic
sugar over the each method, which I'll discuss in a minute, but in case you do encounter the for
loop, this is a syntax. I is the loop variable and it takes on subsequent values from the collection. A
somewhat more common use of the for loop is to iterate over a range. The 1..10 in brackets is a
range literal representing the numbers from 1 to 10, which this loop is going to iterate over and print
out each number. I'll talk more about ranges along with other standard types in the following
module.

Looping with Iterators and Blocks

As I mentioned, the for loop uses the each method under the hood. If you call each directly it looks
like this. This might look a bit unusual, to understand what's going on here I need to tell you a little
bit about blocks. These blocks aren't the same as begin/end blocks you've seen earlier, instead these
blocks are a piece of code between two end keywords or between curly braces. And the only way to
use them is to pass them as an argument to a method. Some methods like each can take a block as a
special kind of argument which comes after any regular arguments. These methods are able to
execute the block once or multiple times. By convention the do end keywords I usually used for
multiline blocks and the curly braces I used for single line blocks. In going back to the example, I'm
giving the each method a block which it will execute once for each element of the array. Methods
like this are called iterators in Ruby. In this example I'm using an array but it could just as well be
another kind of collection. The result of executing this code will be that the string, This is Serenity,
please respond, will be printed three times because there are three elements in the array. The
method, which is executing a block, also has the ability to pass one or more arguments into the
block every time it's executed. Block arguments are specified between vertical bars at the start of
the block. So for example, if I have a method called all in the Spaceship class which returns all
instances of Spaceships, I can call each on the ships array and provide it with a block argument,
which outputs each ships name. I'll talk about blocks in more detail later in the course. Here is
another example of a method that takes a block. If you need an infinite loop instead of while/true
you can simply call the method called loop and give it a block to execute. As numbers are objects
they can be quite helpful when you need to iterate a particular number of times or work with a range
of numbers. For example, you can print numbers from 10 to 20 using the upto method from the
integer class. Or you could print the same numbers in reverse using the downto method. The times
method repeats the block according to the number it's called on, so this line of code will output the
line, This is Serenity, please respond, three times. Finally the step method allows you to loop over a
range with a custom increment. This loop will print the odd numbers in the range from 1 to 10.

Controlling Loop Flow

Sometimes it's necessary to terminate the loop early, skip a few iterations, or repeat an iteration.
Ruby has three different keywords which let you alter the control flow within a loop. There's a
break next and redo. They work in explicit loops like while and then implicit iterator loops like
each. Let's start with next. Next starts the next iteration of the loop without finishing the current
iteration. In this bit of code I'm skipping messages with the type sync. If the current message has a
type sync, then next transfers the control flow to the start of the loop and kicks off the next iteration,
and message.process isn't executed. Break is a bit like the return statement in methods, it terminates
the loop. In this example, the loop is going to process messages until it encounters a message with
type voice. When that happens the loop will be terminated. As loops are expressions in Ruby they
produce a value. For this reason you can pass one or more arguments to break and they become the
result of the loop or the return value of an iterator method. In my second example the loop is going
to process messages until it encounters a message with type voice and to that point break will
execute and terminate the loop. The message text will be assigned to the text variable. Redo is used
to repeat the iteration of the loop. It moves the execution point to the start of the loop without
revaluating the loop condition. Obviously it's very easy to create an infinite loop this way, so you
want to make sure that execution moves to the next iteration eventually. In the example here, the
loop is used to get three positive numbers from the user. The reduce statement is used to deal with
invalid input. If the user enters a number which is negative or zero or an invalid value such as a
string, the prompt is simply repeated.

Handling Exceptions

Whenever you write software you are going to encounter the need to handle errors. The preferred
mechanism for error handling in Ruby is to raise and handle exceptions. This is the approach
employed by the standard library methods. Exceptions are encapsulated in an object of class
exception or one of its subclasses. In order to handle exceptions you need to delineate the segment
of code you want to handle exceptions from. Ruby gives you two options for that. One option is to
reuse the begin/end block, which you've already encountered when I talked about loops. You can
add a rescue clause to this block in order to intercept exceptions. In this example I want to intercept
exceptions raised by the batten_hatches method. If an exception is raised the code outputs a
message and returns false. By the way this is one of the situations where an explicit return keyword
is required. This is so that subsequent lines in the method aren't executed. When an exception is
raised Ruby starts unwinding the call stick until it finds an appropriate handler. If it doesn't find one
the program is terminated. This is well and good, but in all probability light_seatbelt_sign can also
raise exceptions. This is where the other option to define a code segment comes in handy. The
rescue clause can be applied to the whole method definition instead of a begin/end block. Here I've
added a rescue clause at the end of the method definition. Whether you use a begin/end block or add
a rescue clause at the end of method definition, the rescue clause is exactly the same. If an
exception from either batten_hatches or light_seatbelt_sign is intercepted, this launch method will
return false. If everything goes normally it will return true. When I simply write rescue without
supplying any additional details about what I want to intercept, the clause will handle any
exceptions derived from the standard error class. Ruby defines quite a few standard exception
classes, but these three are the most prominent. Standard error derives from exception and runtime
error derives from standard error. So now I can handle exceptions from both methods called by
launch, but the message I output is generic. In order to get some details from the exception object, I
can give it a name in the rescue clause and then I can output its message attribute. Another useful
attribute is called backtrace, it provides the call stick for the point where the exception was raised.
What if I want to do something different for different types of exceptions? That's easy, I just need to
provide multiple exception clauses. I've added a clause to handle errors from the lighting system
specifically. If a seatbelt sign doesn't come on it's not a show stopper for the launch, but I want to
output a message about it. Note that I can specify the type of exception without naming the
exception object. If you had multiple exception clauses, keep in mind that they are evaluated in
order and that subclasses are successfully matched against super classes. This means that you need
to put more specific exception types first. Assuming LightError derives from StandardError, if I
wrote the StandardError rescue clause first the LigthError clause would never be triggered as light
errors would be handled by the more general clause. Since the exception hierarchy starts with the
class called exception, you might be tempted to provide a generic exception handler that catches
instances of exception, but in most cases it's going to be a bad idea. Such an exception handler is
very broad and it will catch things like signal exception or syntax error. Catching single exception,
for example, means that the user won't be able to terminate the program using Ctrl C or the kill
command and will have to resort to kill-9 or -kill/F if you're on Windows to terminate it.

Raising Exceptions

Let's turn to the other side of the equation now. You'll need to raise exceptions in your own code
when something unexpected happens. To raise an exception you use the raise method from the
object class or its synonym fail. Raise gives you a couple of options. If you use a string as an
argument it will raise a runtime error and set the message to the string you pass. You can also
specify another exception class to raise in which case the message becomes the second argument. If
you need to provide additional information in the exception object you can write your own
exception class. If you go down that path it's a good idea to derive your class from standard error to
make sure that it's code by default. Raise also has another use. If you use it without arguments
within the rescue clause, it will raise the exceptions stored in the special global variable called
dollar exclamation mark. This variable refers to the last raised exception. This allows you to do
things like log in exceptions and passing them on to be handled by other handlers further up the call
stack. You can also decide whether you can handle an exception and if not pass it on to a more
generic handler by calling raise.

Exceptions: ensure and else Clauses

I added a little bit of exception raising code to the batten_hatches method before. Now suppose I'm
dealing with a fairly old model of spaceship with a list of doors and other entry points as kept in a
plain text file. So this method needs to read the file and go through the records in it to look
everything up. Now our batten_hatches method can raise exceptions and the file needs to be closed
whether an exception is raised or not. I could add a call to close the file at every exit point in this
function, either via a return or via an exception, but it would get messy very quickly. Ruby provides
a better solution in the form of the ensure clause. This clause will be executed in every case whether
the function exits normally via a rescue clause or via an unhandled exception. The reason I'm
checking whether hatch_file has a value in the ensure clause is because file.open can itself throw
exceptions and if it does hatch_file won't have a value. The ensure clause has to come after the
rescue clauses. Make sure you don't put a return statement in the ensure clause as that will cause
any exceptions thrown from the method to be silently swallowed and the return statement will
execute instead. As they say in infomercials, but wait there's more. Before the ensure clause you can
add an else clause, which will be executed if the section of code you'd intercept an exceptions from
didn't throw any exceptions. This section has to come after the rescue clauses but before the ensure
clause. The ensure clause is always executed regardless of whether you have an else clause.

Exceptions: Retrying and Rescue Modifier

Generally speaking, using exceptions for control flow is a bad idea, but sometimes you can't get
around the fact that exceptions will affect your control flow. Here is a somewhat realistic example.
Imagine that the antiquated file with a list of hatches, from the previous example, has been replaced
with a snazzy restful API which provides this list. The only problem with this is that the API server
fails to respond from time to time. In those situations I get an exception from the API. So I'd like to
retry the request a few times before propagating the exception out of the batten_hatches method, as
it dramatically reduces the number of failures in this method. I could use a loop to do it, but the
code is fairly messy. I've got a loop count in request attempts and I also have a begin/end block
inside it to intercept exceptions. If the last attempt fails I re-raise the exception so it propagates
outside of the method. Instead I could rewrite this code using the retry statement. In this case I no
longer have the loop and instead I keep track of the request attempts in the rescue clause. The retry
statement is used within the rescue clause and it transfers the execution point back to the beginning
of the begin/end block or the beginning of the method. This version of the code has less nesting so it
is easier to follow. The discussion of exceptions in Ruby wouldn't be complete without mentioning
the rescue modifier which is similar to if and while modifiers. If you add a rescue modifier to a
statement it will catch any exceptions raised by that statement which are instances of standard error
or its subclasses. If an exception is caught, then the result of the whole expression is the result of the
statement following rescue. In my example, if batten_hatches raises an exception the rescue clause
will kick in and return false instead. This might seem convenient, but as it catches all sorts of things
and quietly provides a value instead, it can _____ errors and make debugging harder. So it's
probably a good idea to write your code without this modifier.

Throw and Catch

In addition to exceptions, Ruby has a separate throw/catch mechanism. In many other languages
throw and catch are keywords used for raising and handling exceptions. However in Ruby this pair
is a different flow control mechanism, although its behavior is somewhat similar to exceptions. The
way it works is that you put some code, which contains a throw statement, into a catch block. By
the way, catch is a method that takes a block as a special argument, same as iterator methods like
each. If the throw statement is triggered the corresponding catch block is terminated. The argument
of catch and the first argument of throw must match in order for it to work. I'm using a symbol
called abort here, but I could use an arbitrary object instead as long as it matches between throw and
catch. Getting out of nested loops is the sort of use case where throw and catch may result in clearer
code. Catch returns the second argument of throw if it was provided, or nil if it wasn't. If a throw
statement isn't triggered then catch returns the result of the last expression in its block. This is why I
provided a string saying all samples processed at the end. The result of this program is that if all
samples are processed correctly it says All samples processed. If one of the samples failed to
process then it outputs the reason for the failure, which was provided as the second argument to
throw. Throw/catch even works across method calls. I can extract the contents of the inner loop into
a method without any other modifications and this code will still work. At this point you may be
wondering whether throw/catch should be considered harmful along with go/to and whether all it
does is facilitates spagetti code. The difference between go/to and catch/throw is that catch/throw
unwinds the stack properly and then the process triggers ensure blocks so that resources are cleaned
up. Granted it isn't something I would recommend to use often, however it might come in handy
occasionally when you need exception like nonlinear flow control, but aren't actually handling
errors. Also while my example could be refactored so that the inner loop wasn't a separate method
and would work fine that way, throw/catch provides an alternative for getting out of nested loops
quickly. Finally I should note that catch calls can be nested.

Scope

Before I wrap up this module I'd like to draw your attention to scope as the rules in Ruby may be
different from what you're used to. While classes and methods in Ruby introduce scope, other
constructs such as if/else, loops, and begin/end blocks don't. Any variables you define within these
constructs will still be in scope afterwards. However, blocks do introduce scope, so any variables
you define within a block won't be visible outside it.

Summary

This is the end of module 3. In this module you've become familiar with the variety of constructs
for flow control available in Ruby. You've learned how to use various constructs for conditional
execution. You've seen how to write loops and how to alter execution flow within them. You found
out how to raise and handle exceptions. You've also seen another nonlinear flow control mechanism
provided by throw and catch.

Standard Types

Overview

Hi this is Alex Korban in this module you will learn about some of the types in the Ruby standard
library. The Ruby standard library is quite extensive, so this module is only going to scratch the
surface of the available functionality. I will tell you about the types you will use in almost any Ruby
program you write. Most of these types are also integrated into the language through special syntax
_____. I'm going to talk about Booleans, types for representing integer and floating point numbers,
regular expressions, strings, symbols, arrays and hashes, and finally ranges. I will also show you
how to do parallel assignment.

Booleans

Okay the first thing you need to know is that Ruby doesn't have a Boolean type, but you've already
seen true and false in the previous module, so what are they? Well true is an instance of true class
and false is an instance of false class. They are singleton instances which means that you can't
create any other instances of these classes. As I mentioned before, only false and nil evaluate to
false in a Boolean context and everything else, including true, zero, empty string, empty array, and
so on, evaluates to true. Both true class and false class derive from object. So each of these literals
come equipped with a bunch of useful methods. For example, you can convert a Boolean value to a
string or check whether it's nil.

Numbers

As you've seen before numbers in Ruby are represented by objects. In fact you can think of each
number as a label for a corresponding object. You can call methods on both integer and floating
point numbers. You're already familiar with methods which help with iterating over a range of
numbers, such as times, up to, and down to. I'll talk about integer numbers first. Ruby has two
classes to represent integers, they are called fixnum and bignum. Both of them inherit from the
integer class. The range of integers represented by fixnum is limited by the machine word size and
by the Ruby build that you have. Bignum objects are used for larger integers and are only limited by
the available memory. Ruby manages the conversion between these two types automatically. If the
result of an operation on two fixnums is outside the fixnum range, then it's converted into a bignum
and vice versa. There is a variety of ways to write integer literals, hex numbers start with 0X, octal
literals start with a O or a O0, decimal literals start with OD or no prefix, and binary literals start
with OB. Negative numbers have a minus in front of them, no surprises there. You can also use
underscores to separate groups of digits to make numbers easier to read. Ruby will just ignore the
underscores. Let's turn to floating point numbers now. They are represented by objects of the float
class and typically have 15 digits of precision. Internally they map to the machine double type.
There are two ways to write floating point literal, either simply as a number with a floating point or
you can additionally tack an exponent on the end as well. Note that there must be at least one digit
before the decimal point and one after. This is required to avoid ambiguity with method calls. You
can also use underscores as a separator for groups of digits before and after the decimal point, same
as with integers. If you mix floats with integers then Ruby will return a float. There is one aspect of
numeric classes which can cause a bit of confusion. Suppose I want to have a function which takes
a numeric object and modifies it in some way, I could try something like this. (typing) If I have a
variable A, which is an integer, and I pass A to F the function returns a new value, however A itself
is unchanged. The reason for it is that objects representing numbers are read-only. Incidentally, this
is why Ruby doesn't have increment and decrement operators. So a function like F really doesn't
make sense in Ruby, instead you should return the new number and assign it to your variable.
Numbers are special in this regard and other objects such as strings and arrays are mutable.

Strings

The next type I'm going to talk about is strings. Strings in Ruby are an extremely versatile tool. The
string class contains around 100 methods and Ruby also provides several ways of writing string
literals. This makes sense if you consider how much programming revolves around processing
strings. If we get down to the basics a string is just a sequence of characters with an associated
encoding. The characters don't have to be readable, Ruby strings can also be used to represent
binary sequences. A string has an associated encoding which is defined by the encoding of the
source file it's in. The default encoding is UTF-8, but it can be changed by placing a special
comment at the start of the file. The encoding method outputs the encoding of a given string. If I
don't specify any encoding then Ruby reports that the string is encoded in UTF-8. I can specify an
encoding explicitly by placing the specially formatted comment at the start of the file, if I run this
program again, Ruby now reports that the string is encoded in USS key. The comment has to appear
on the first line of the file or on the second line if the first line is a shebang. Ruby has several
different forms of string literals. Whenever you assign a literal or pass it as an argument, a new
object of class string is created. The first option to write a string literal is to use single quotes.
Single quotes only allow two escape sequences, if you need to include a single quote in this string
proceed it with a backslash. You can also include a backslash by proceeding it with another
backslash. Instead of single quotes you can use %q followed by a delimiter. The Q stands for quote,
the delimiter can be any known alphanumeric character. If you use delimiters that come in pairs,
such as square brackets, then you need to use appropriate opening and closing delimiters. Otherwise
Ruby will look for the second occurrence of the same delimiter to indicate the end of the string.
This is useful, for example, when you want to insert a number of single quotes in your string,
because when you use %q you don't need to escape the quotes. Another option is to use double
quotes, they support a what more escape sequences. For example, backslash N inserts a new line,
backslash D inserts a tab, and backslash double quote inserts a double quote. Additionally you can
insert characters using either their octal code or a hex code. The octal code is preceded by a
backslash and the hex code is prefixed with backslash X. You can also insert Unicode, code points,
using backslash U. Note that the leading zero's can be omitted. If you need to insert multiple code
points you can combine them using curly braces. Double quoted strings also allow interpolation
which is a way of embedding results of Ruby expressions into a string. If you look at the strings in
this bit of code you'll see that they contain examples of interpolated expressions. Interpolated code
is marked with a hash and curly braces. In the first string I insert the value of lander_count via
interpolation. In the second string I insert the sum of lander and probe counts. For the most part
interpolation is used for single variables or simple expressions, but in theory you can even
interpolate multiple statements, although of course that will quickly lead to unreadable code.
Interpolation is used a lot in Ruby code as it's cleaner then concatenating strings and will perform
better as well because it doesn't require the creation of multiple string objects. It will also
automatically convert interpolated results into strings by calling the __S method on them. Instead of
double quotes you can use percent capital Q or simply percent followed by a delimiter. The
delimiters follow the same rules as when using percent lower case Q. When you use either single or
double quotes, multiple literals following one another get concatenated into a single string, so if I
type, for example, abc and def, both of the strings are concatenated into one. Literals can also
stretch over multiple lines, in this case both new lines and indentation are included in the string. So
here I have hello and then I'll insert a few spaces and the resulting string contains both the new line
and the spaces. Finally Ruby supports the so called heredoc syntax for strings. This may be useful if
you have a multiline string with multiple codes in, for example. The heredoc is denoted with a
double less then followed by the terminator. In my example EOS is the terminator. The string ends
when Ruby sees the terminator again. The terminator has to be at column one, unless you include a
dash after the double less then. With the dash present you can indent the terminator, but in both
cases if the contents of the string are indented the indentation is preserved.

String Operators and Methods

Let me show you a few interesting string operators and methods. There are a lot more methods
available in the string class then I can show here of course, I just want to give you a few examples
of the string capabilities. The square brackets operator can be used in a few ways on a string. You
can use it to get a character at a particular position, you can also use it to get a substring. In this case
the first argument is the index of the start of the substring and the second argument is the length of
the substring. Another handy thing you can do is check whether a substring appears in the string, in
that case you use the substring as the argument to the square brackets operator. If the string contains
the substring then the substring is returned and if it doesn't you get a nil. You can even use this
operator to replace the substring with another substring. So for example if I have a string which says
Hello Alex, I can replace Alex with George like this. I can go a You can use the multiplication
operator to duplicate the content of a string a number of times. The percent operator allows you to
produce formatted output. For example you can format numbers to have leading zeroes like this.
The first argument to the string is a format specify and the second is the number. So this produces a
string representing a number pattern to 5 digits with zeroes. You can also use this operator to limit
the total number of digits, so I can type a formatting string like this and pass it a number with a lot
of digits. And it's limited to eight digits total. There are tons of other formatting options available as
well. The plus operator allows you to concatenate strings, but often interpolation is used instead.
Let's look at a few methods now. The string class has methods which return different
representations of the contents of a string. For example if I have a string which contains some
Unicode like this, I can get an array of characters in this string. I can also get an array of code points
representing the string. And finally I can obtain an array of bytes which are used to represent this
string. Note that the Unicode code point uses three bytes. The string class also has corresponding
iterators called each_byte, each_char, and each_codepoint. You can convert a string to uppercase or
lowercase using upcase and downcase methods. (typing) I'll type upcase and then downcase. Like
many other methods they have two versions, the exclamation mark version modifies the string
object in place and the version without an exclamation mark returns the modified string as a new
object. As an aside it's typical for a lot of methods in the standard library to return either the new
object or in the case of exclamation mark methods the object they were called on. This allows you
to chain method calls which can be very convenient. For example if I have a string with some
leading and trailing whitespace I can call strip on this string which will remove the leading and
trailing whitespace. And then in the same expression I can call capitalize on it to capitalize the first
letter. Another really useful method in the string class is called gsub, it replaces all occurrences of a
substring within a string. For example if I have a string containing a bit of HTML I can use a gsub
method to replace all the angled brackets with square brackets. Again I'm going to chain it because I
need two different replacements. This method becomes a lot more powerful when combined with
regular expressions. I'll show you a couple of examples in a minute when I talk about the regular
expression class. The last method from the string class I'd like to show you is called split. Split
allows you to break a string into an array of substrings based on the separator. So if I have a bunch
of numbers in a string separated by spaces, I can call split and it returns an array of substrings
because by default it considers space to be a separator. You can also specify a custom separator if
you want, so for example if I have no numbers separated by arrows I can call split and give it an
arrow as the argument. And again it returns an array of substrings.

Regular Expressions

The next thing I'd like to talk about is Ruby's support for regular expressions. Regular expressions
are a powerful mini language for analyzing and manipulating strings. The regular expression class
is one of the standard types built into Ruby. I'm not going to go over all of the regular expressions
syntax as that will probably require a good couple of hours. Instead I'll focus on using them in Ruby
code. For a reference on regular expressions syntax you can look up the Ruby documentation for
the Regexp class. It's succinct but thorough. Another useful thing is Ruby Mines built-in test tool
for regular expressions which you can use to check your regular expressions against input strings.
When editing a file in Ruby Mine you can put the cursor on the regular expression literal, hit Alt +
Enter, and choose Check RegExp from the menu that pops up. You can then enter sample strings to
test your regular expressions. If the sample string doesn't match the regular expression the field is
highlighted in red. If it does match then the field is highlighted in green. You can also use an online
regular expression test tool at rubular.com. Regular expressions are represented by the Regexp
class. You can pass a string containing a pattern to regexp.new. Ruby also allows regular expression
literals denoted with slashes. Alternatively you can use %r followed by a delimiter of your choice
similarly to %q for strings. The patterns behave similarly to double quoted string literals. They
allow interpolation of Ruby expressions the same as cape sequences as well as Unicode characters
and sequences. To test for a match between a regular expression and a string you can use the equals
tilde operator. The regular expression can appear either on the left or on the right. If a substring of
the string operand matches the pattern the operator yields the starting position of the match in the
string. Otherwise it yields nil. The exclamation mark tilde operator checks for a lack of a match
instead. Instead of a position it only yields true or false. In addition to these operators you can also
use the match method to check for matches, which is useful if you want to get more detailed
information about the match in the form of an object. This method is a part of the interface of both
the string and the Regexp classes. It returns a match data object. Let's look at an example. (typing)
M refers to a match data object now, this object has methods called pre-match and post-match
which allow you to retrieve the portions of the string before and after the match. You can use the
square brackets operators with an index to retrieve the match and any sub-matches defined via
capture groups. An index of zero gives you the whole match. And one to three and so on give you
the sub-matches. This is best illustrated with a diagram. Given this line of code the match will be
12:13 and m return this substring. m.pre_match and m.post_match will refer to the parts of the
string before and after the match. Lastly m in the regular expression. When you use either the match
method or the equals tilde operator Ruby also sets a few global variables. Dollar back tick is the
fragment of the string before the match. Dollar quote is the post-match fragment. Dollar ampersand
contains the match and dollar 1, dollar 2, and so on contain the sub-matches. What if you need to
match multiple instances of a pattern within a string? You can apply the scan method from the string
class to this job. This call to scan will return an array of matched substrings. You can see in the
output that it returns an array containing 12 and 13. The gsub method you've seen before becomes
more powerful if combined with regular expressions, particularly because you can refer to capture
groups in the replacement string. This line of code is going to return a string with the first and last
name swapped and the coma placed after the last name. The \\2 and \\1 in the replacement string
refer to sub-matches in the input string. Note that because of the escaping and double quoted strings
I had to write backslash, backslash 2 and backslash, backslash 1. I could have used the single
quoted string and in that case it would be enough to use one backslash. When I run this you can see
that the first and last names are swapped. Gsub can also take a block argument, which is convenient
for more complex transformations. For example, if I have a log lines with passwords I might want
to replace the passwords with stars. I can do it like this. So here I'm looking for instances of a
password in the input string and then I pass a block to gsub, which is going to construct an output
string containing the first sub-match, which is the word password, plus a number of stars
corresponding to the length of the second match, which is a password itself. When I run this I can
see that the password has been replaced with asterisks. Let's move onto the next type now.

Symbols

You've already seen a few examples of symbols in the previous modules. For example symbols are
used to add attribute accessor methods to classes and to make methods private. Symbols are very
convenient once you get used to them and feel very natural to use. So what are they? They are
simply a special kind of object, you can think of them a mix between a constant and string. In some
other languages enums are used as an alternative to symbols. Each symbol is an instance of class
symbol. Symbol instances are only created via literals. A symbol literal is a colon followed by an
identifier. Alternatively you can use a colon followed by a string literal. This string literal can
include interpolated code just like a regular string. Ruby ensures that symbols are globally unique
and immutable. The first time you use a symbol an object is created behind the scenes. Whenever
you refer to the same symbol in your program afterwards it's referring to the same object. Symbols
are a good substitute for strings when strings are used as labels. An example of this is passing
method names to attr_accessor or passing a symbol to a catch block. Symbols are a better option
because if you use string literals there's a new string object created every time. Also comparing
symbols is simply a matter of comparing object ids, whereas if you have two different string objects
their contents need to be compared, which requires more computation. So symbols are more
efficient in terms of memory use and performance. They also work great as hash keys as you'll see a
bit later. One way to use them is as function parameters where a parameter can be one of a small set
of values like sort order or a color from a predefined set or some kind of mode. It's easy to go from
a symbol to a string and back. The __s method converts a symbol into a corresponding string. The
__sym method of the string class performs the reverse conversion.

Arrays

Next up I'm going to talk about another indispensable tool, arrays. Arrays are instances of the array
class. An array literal is a sequence of comma separated elements in square brackets. An array
stores references to objects and can contain objects of different types. As it stores references you
have to be careful when cloning arrays. If you need a deep copy you'll need to implement it
yourself. If you simply want to create an empty array typically you would just use an empty array
literal rather than array.new. Array.new is used for more complex initialization. You can create an
array containing a specified number of elements by passing element count to array.new. All the
elements are set to nil, if you want something other than nil, then you can also add the default value
as the second argument. However, this only works if the elements are read-only, because each
element refers to the same object. Let me show you what I mean. If I create an array with a string as
a default value and then I try to convert the first element to uppercase, which I can refer to using the
first method by the way. What happens is that every element of the array is converted to uppercase
because every element refers to the same object, but don't worry there is a way around this. If I use
the block form of new like this, (typing) then every element will be a different object. So now when
I modify the last element the other elements remain unchanged. This form of new is also handy
when constructing multi-dimensional arrays. With this line of code I've constructed an array
containing three arrays of three elements each, in other words, a two-dimensional array. There are
convenient shortcuts if you want to create an array of words or an array of symbols. %w creates an
array of strings from a string of space separated words. You can use backslash to insert a literal
space. Otherwise the available escape sequences are the same as for single quoted string literals. To
get the behavior of double quoted string literals, including interpolation, you can use a capital W.
Opps let me remove the extra square bracket. So now I have an array containing elements with a tab
and you can see that 2+2 is interpolated into 4. There is a similar shortcut for arrays of symbols. For
that I need to use %i. (typing) Alright so when you've created an array what can you do with it? It
has methods like size and empty. You've already seen that first and last methods X has the ______
elements of the array. You can also access any element using a zero based index and square
brackets. Not only that you can also use a -1 based index to access elements in reverse order. This is
what I have in the array, -1 is the index of the last element so this returns right. -2 is the index of the
second to last element and so on. You can also slice the array using square brackets. This returns a
slice of the array starting from index 1 and ending at index 3. This also works if you use a reverse
index for either the start or the end of the slice. (typing) The square brackets operator can also be
used to set elements of the array. Negative indexes work here as well. In addition you can replace a
section of the array. So this is what my array contains now, I'm going to replace the third and fourth
elements, so for that I need to type array 2…3 and assign the new elements to it. So now array
contains east and west instead of 3 and 4. You can also append elements to an array like this. As you
add and remove elements they are able to grow and shrink as necessary. You can join two arrays
using the plus operator. You can duplicate the elements using the multiplication operator. If you use
a string as a second argument the array will be converted to a string with the second argument used
as a separator. The minus operator allows you to delete one or more elements by value. So if I have
an array containing 1, 2, 3, 2, 5, and I say minus 2 and 5, then any elements appearing in the second
array will be removed from the first array. There are a whole lot more methods available to delete
elements, sort the array, and iterate in various ways. It's also easy to use the array as a stack or as a
queue.

Enumerable

A large portion of these methods comes from the enumerable module which is part of the array
interface. In one sentence modules are a way to package a set of methods and constants. I'll talk
about how modules work in later videos. For now let's take a look at a couple of examples of what
an enumerable provides. In total it has close to 50 methods and this is what turns Ruby collections
into power tools. One of these methods is map, which allows you to apply a transformation to each
element of the collection. Here I have an array and I'm calling map on it, I'm passing it a block
where I multiply each element by 10. The method returns a transformed array. Another interesting
method is reduce, which you can use to derive a value from the elements. This line of code sums the
elements of the array and returns the result. Map and reduce are a staple of functional programming.
Enumerable also includes methods like sort to sort collections and select. (typing) Select returns a
portion of the collection containing elements which match the criteria defined by the selects block
argument. So with this line of code I'm extracting the elements of the array which are even and that
is 2 and 4. Enumerable allows you to iterate over subsets of elements in a few different ways. One
of them is using each _cons. So if I have an array like this, I can call each cons with an argument of
2 and print the results. So this bit of code iterates over each block of two consecutive elements in
the array. So the first block is 1, 2 then it shifts by 1 and goes over to 2, 3, then 3, 4, and so on.

Hashes

Ruby's arrays and hashes are very versatile tools which is partly due to the dynamic nature of the
language. Because of this Ruby programmers can use them to represent all sorts of data and don't
often need to look beyond these two classes. A hash in Ruby is an ordered collection of key value
pairs represented by the hash class. Both keys and values can be arbitrary objects. Keys have to be
unique within a hash. A hash literal is marked by curly braces, so this statement assigns an empty
hash to h. Inside the braces commas separate each key value pair and arrows point from keys to
values. In this hash the string min is the key for value zero and the string max is the key for value
100. As it's extremely common to use symbols as hash keys there's a special shortcut syntax for
that. The colon migrates from the start of the symbol name to the end and replaces the arrow. If you
have a hash you can access its elements by a key using the square brackets operator. You can think
of hashes as arrays with arbitrary object indexes instead of integers. You can also replace a value
this way. This is also how you add elements, so if you use a key which is not already in the hash a
new element will be added. Now if you use a key that isn't in the hash to get an element, like this,
by default you will get a nil. However, similarly to the array instantiation you can specify a different
default value when constructing the hash using hash.new. So if I type h=hash.new0 and try to get an
element that isn't there, instead of a nil I get zero. Same as with arrays, this means the same object
reference is returned every time. If you want different objects to be created every time you can use
the block version of the new method. You can iterate over the elements of a hash using each. It
looks like this. Let me just put some elements into this hash and when I try this again you can see
that it iterates over two element arrays consistent of a key and a value. You can also separate the key
and the value out if you list two arguments in the block. So if I list k and v, I can output them
separately. As I mentioned, hashes are ordered so each lists the elements in the order they were
added to the hash. Like array, the hash class includes the enumerable module so all the methods
available for arrays are available to hashes as well, although in this case they will operate on two
element arrays instead of single values.

Ranges

The last type I'd like to talk about is ranges. The range class objects can be created via literals. A
literal is two objects separate by either two dots or three dots. Two dots indicate an inclusive range
with the upper boundary included and three dots means that the range is exclusive and the upper
boundary isn't part of it. If you want to call methods on the range literal you need to enclose it in
brackets so that all the dots don't confuse Ruby. The range class doesn't have a whole lot of its own
methods, it's got methods like begin and end, which allow you to get its boundaries. And it also has
include which allows you to test if a particular value is part of the range. There are a few other
methods as well, however, the range class also includes the enumerable module so it does end up
providing the reach interface and allows you to do things like this. (typing) As you can see when
you call map on a range, map iterates over the array representation of the range and returns an array
of 10 elements. You aren't limited to just integer ranges, you can create ranges of string values, you
can also create ranges of floats, however in this case you won't be able to iterate over them. I also
want to mention that ranges can be used in a case statement. This works in the same way as dispatch
and waste on the class of an object in a case statement. The range class has a custom
implementation of the triple equals operator, which checks whether the supplied values within the
range. In my example the case statement will check whether sample reading falls within either of
the ranges and outputs a string correspondingly.

Parallel Assignment

Parallel assignment and the splat operator are related to the standard collection types, so let's give
them some attention in this module as well. Parallel assignment allows you to assign to multiple
variables in a single statement. The result of this statement is that a is equal to 1 and b is equal to 2.
If the right side of the assignment is a comma separated list, it's converted into an array and then its
elements are assigned to variables on the left. A side effect of parallel assignment is that if you
assign a comma separated list to a single variable, that list is converted into an array. The right side
of parallel assignment can be an actual array. This works especially well when you have a function
returning multiple values in an array. You don't need to create a temporary array if you assign the
elements to variables directly. Because the function returns an array with 1 and 2 as the first
elements, once again a is assigned 1 and b is assigned 2. The rest of the elements are discarded.
What if you want to assign only some of the returned elements to variables? For example, I might
only want to assign the first and last elements from the returned array. What about the other two
elements? There's no way to skip them, so I have to use a dummy variable. Instead of coming up
with a dummy name, you can use underscore. Underscore is mostly a normal variable except it's
treated in a slightly special way by the interpreter. If you run the Ruby interpreter with a -w
argument it will output warnings, including warning you about unused variables. If you use
underscore or any variable name starting with an underscore in your parallel assignment, the unused
variable warning will be suppressed. Parallel assignment can be combined with a splat operator
which is represented by an asterisk. One of the values on the left can have the splat applied to it.
This value will accumulate as many elements as possible in the form of an array. If the last variable
on the left has a splat, then it will accumulate the remainder of the elements from the right. If it's not
last, it will behave in a greedy manner leaving just enough elements for the following variables. So
in this case a will be assigned 1, b will contain an array with 2 and 3, and c will be assigned 4. The
splat can also appear on the right-hand of the assignment. In this case the object it's supplied to are
converted into arrays which have their elements expanded in line. For example, you can use a range
to assign elements from a sequence to variables. So, for this line of code a, b, and c are assigned 1,
2, and 3. You can also make an array a part of the sequence. In fact, you can simplify the last
assignment by using a splat by itself instead of the dummy variables. As you can also see in this
example, the splat can appear both on the left and right sides of one assignment. The splat operator
has another use outside of parallel assignment. If I use the splat operator on the range inside an
array literal, the range is converted into a series of elements which are inserted into the array. It also
works on hashes. If I use a splat on a hash inside an array literal I get an array containing two arrays
representing keys and values. In fact, the splat operator will work on any class that implements a
__a method. To illustrate this I've written a __a method in the Probe class which returns an array of
all its attribute values, such as name, type, and size. I then use the splat operator to convert the
instance of the Probe class into an array. When I run this you can see that the result is the series of
elements returned by __a.

Summary

This is the end of module 4. In this module I've shown you the most common standard types and
some of their methods and operators. I talked about Boolean values, numbers, and strings. I showed
you regular expressions and symbols. I also discussed collection types, arrays and hashes, as well as
ranges and the enumerable module which makes this collection so powerful. Finally I explained
how parallel assignment works in combination with the splat operator.

Methods in Depth

{{clip.title}}

Hi, this is Alex Korban in this module we'll have an in-depth look at writing and using methods in
Ruby. You've already seen a lot of methods in the previous modules, however, they are really
simple, taking just one or two arguments. Ruby has a lot more method features and in this module
I'd like to get into the intricacies of defining and calling methods. I will show you how you can
provide default values for method parameters. You will find out how to write methods which take a
variable number of arguments. I will explain how you can add named arguments to your methods.
I'll talk about creating method aliases and overriding methods. You'll see how operators and
operator overload work in Ruby. I'll explain the method calls as messages model Ruby employs.
Finally, we'll delve a little bit into metaprogramming when I talk about the method missing method.

{{clip.title}}

Ruby doesn't allow you to define two methods which have the same name, but different parameter
lists. When you need to provide a flexible interface that doesn't require specifying all the arguments
every time, you can use default arguments instead. Suppose I have an in orbit spaceship factory
which can produce spaceships to order. I can have a produced spaceship method which looks like
this. The default values for parameters are specified in the function definition with an equals sign
and an expression after the parameter name. The expression isn't limited to a simple value and can
include preceding parameters, method calls, or even conditional logic. The default values are
calculated at the point of method call, not at the point of method definition. The optional parameters
don't have to be at the end of the parameter list. If there are required parameters following a group
of optional parameters, Ruby will correctly use default values if you pass fewer than the maximum
number of arguments in. In this example, engine_count is a required parameter, which falls to
optional parameters. When I call produce spaceship with one argument, that argument is used as the
value of engine_count. However, you can't intermingle required and optional arguments arbitrarily.
You'll get a syntax error from the interpreter if you do.

{{clip.title}}

Sometimes you will need more than just a couple of optional arguments. For some methods its
useful if they can take an arbitrary number of arguments. You could always just pass in an array, but
Ruby has nice built-in syntax for methods taking a variable number of arguments courtesy of the
splat operator. For example, if I want my spaceship factory class to have a method which produces a
whole fleet containing different types of spaceships, I can write it like this. The first argument will
be assigned two days to complete and the rest will become elements of the array assigned to types.
When I call this method, days to complete will be set to 10 and types will be an array containing
symbols freighter, freighter, and explorer. The array argument doesn't have to come last in the
parameter list, in fact the parameter list with a splat works in the same way as a list of variables on
the left-hand side of a parallel assignment. I talked about parallel assignment in detail in module 4.
The array parameter collects arguments in a greedy manner leaving just enough elements to assign
to the following regular parameters. An array parameter can be combined with default parameter
values. Optional parameters have to come before the array parameter. The arguments passed to the
method are first used to provide values for optional parameters and after that any remaining
arguments are assigned to the array parameter. So here I have a method which has a default value
for the first parameter and the second parameter is an array parameter. You can call this method
without arguments or you can explicitly provide a value for the first parameter, followed by any
values for the array parameter. However, you can't just omit the first argument, as days to complete
will always be set to whatever you pass as the first argument. You can also use the splat operator
when calling the method. Its effect is to convert the argument it's applied to into an array by calling
the arguments two underscore A method. After that the elements of the array are inserted into the
argument list. As a result, the first call to produce fleet is equivalent to the second call. The
mechanics of the splat operator in method calls are the same as when you use a splat on the right-
hand side of a parallel assignment.

{{clip.title}}

When method parameters start to multiply the code can easily become hard to understand. When
there's more than one argument it's not exactly obvious what each one of them represents. To
improve this situation Ruby has keyword arguments. When calling the method with keyword
arguments you don't just provide a value, instead you need to include the argument name followed
by a colon and then the value. The definition of a method with keyword parameters looks quite
similar. The parameters are required to have default values. If any of the arguments aren't passed to
the method the default values are used instead. As keyword arguments can be distinguished by
name, they can be supplied to a method in a different order from how they are initially defined.
They can also coexist with regular parameters as long as regular parameters come first. In this
example, the first parameter is just a regular parameter with a default value, while size and
engine_count are keyword arguments. Normally if you tried to pass a method some keyword
arguments which aren't in its definition, you'll get an error. However, if you add a double splat
parameter to the end of the parameter list in method definition, it will collect any keyword
arguments which weren't explicitly listed in the definition. The double splat parameter will be
assigned a hash of these arguments. I can use this, for example, to allow my method to take an
optional speck of custom components. In the implementation of this method I have the standard
component speck in the components hash. I then merge this hash with custom components. The
merge method works in such a way that values with duplicate keys will be overridden by values
from custom components. As a result, I can call this method and specify any components I want to
deviate from the standard speck. In this call I specified engine upgrades and nice leather seats for
my yacht. Instead of specifying all the keyword arguments directly in the method call, you can first
construct a hash and then pass it to the method. Similarly to using a splat operator to splice array
elements into the argument list. You can use the double splat operators so that Ruby creates the
variable it's applied to as a hash and combines it with any other keyword arguments. This about
covers it for method definitions.

{{clip.title}}

The next feature I'd like to talk about is method aliasing. It's useful when you're overriding a
method, but want to be able to access the old version. If you're overriding a superclass method you
can use super to call the superclass method, but if you're monkey patching a class you need aliasing.
The method called alias_method allows you to create a copy of a method with another name. For
example, if I modify this string class to print strings with extra _____, I might also want to override
the size method so it reports the new size. However, I want the new size method to refer to the
original size. To achieve this I can call alias_method to create a copy of the size method called
original_size. Alias_method can take either symbol or string arguments. I can then override the size
method and have it call original size. So alias_method allows me to override a method while
retaining access to the original version. Let me run this just to check that it works correctly and you
can see that it reports 5 as the string size.

{{clip.title}}

I'd like to bring your attention to operators now. It's no accident that I'm talking about operators in
this module. As you've already seen in previous modules, Ruby allows you to define your own
versions of some operators when writing a class. The reason for it is that most operators are in fact
methods they just have a little bit of syntactic sugar on top, so using them doesn't look like calling
methods. The exceptions to these are the logical operators, &&, ||, and, or, not, and the ?: operator.
The assignment operators aren't methods either. Everything else, such as the square brackets
operators, comparison operators, mathematical and bitwise operators are methods and as such you
can either add your own implementations of them or override standard implementations. Let's look
at few examples. I'm going to go back to my trusty Spaceship class and add a few operators to it.
First I'm going to add the index operator. (typing) I'm going use it to get and set different types of
vessels stored within the spaceship, these include landers and probes. There are actually two parts to
this operator, the square brackets operator returns a value based on an index object. My
implementation passes the type to the vessels hash and returns whatever is stored at that key. The
second part is the square brackets equals operator. This operator returns a value which can appear
on the left side of an assignment. It takes an index and a value to set as its arguments. My
implementation takes the vessel type and an array as its arguments. The array goes into the vessels
hash at type key. I can now use these operators like this. So I can use it to add some lenders and
then I can have a look at the lenders on board the spaceship. So when I run it I can see that two
lenders have been added to the vessels hash. I can also add an append operator to my spaceship to
allow me to put cargo on board easily. This operator simply adds the cargo object to the cargo array
instance variable. I can use it like this. So here I have a dummy class called CargoPod, I'm going to
create an instance and then I'm going to add that to the cargo bay of the spaceship. Let's just check
that it works, so in the output I can see that there's now a new item in the cargo instance variable.
Another interesting operator I'd like to show you is coincidently called the spaceship operator
sometimes. This operator is used to make objects sortable. This operator compares two objects and
returns zero if they are equal, -1 if the first is less than the second, and 1 if the first is greater than
the second. In my case I want to sort spaceships by name so I can delegate to the string operator.
Now that I have this operator in place, I can sort an array of spaceships. Let me just add a couple
more spaceship instances and then I'll put them in an array, sort them, and output the names. Let's
run this and see what happens. You can see that they are sorted by names now. While I'm at it I'm
also going to show you how to implement unary plus and minus operators. In order to distinguish
them from the binary versions they have @ added to their name and of course they don't take any
arguments. By the way, binary operators such as plus or less than only take one argument as self if
the implicit left-hand side argument. Going back to my unary plus and minus I'm going to use them
to increment and decrement the ships speed. And then I can use these operators like this. Let's run
this, you can see that speed was first increased to 10 and then reduced back to zero. The last
operator I'm going to add to the Spaceship class is the not operator. I'm going to use it to initiate the
self-destruct sequence as I'm going to have no ship after invoking this operator, there is some logic
to this. Obviously I can no longer use the operator in a Boolean context as it does something
completely unrelated now. This is how I can use it, it's no longer going to work in a Boolean
context. When I run this I can see that the operator output self-destruct sequence initiated. The
plus/minus and not operators in my Spaceship class actually illustrate an important point. It's easy
to get carried away and get to clever with operator overload at the expense of clarity. The code with
custom operators can look quite cryptic to someone who's not familiar with the exact semantics of
operators in your class and can even behave contrary to normal expectations as in the case of the not
operator that I've added. For this reason my advice is to use operator overload in sparingly and only
in those cases where it makes the code more readable.

{{clip.title}}

Now that we've explored all the syntactic nooks and crannies related to methods, let's focus on the
semantics for a bit. Using an idea borrowed from small-talk calling a method in Ruby is done by
sending a message with the method name and parameters to an object. The object then looks up the
corresponding method and if it finds it, it executes it. So you can also think of methods as message
handlers. For this reason the object you call a method on is sometimes called the receiver. This
aspect of object semantics is actually visible. The object class has a method called send which
allows you to send a message as a symbol along with any parameters. I've already mentioned this
method when I showed you that you can call a private method using send. This can be really
convenient and can cut down on boiler plate code. For example, if you have methods which are
executed in response to user input, instead of writing a potentially unwieldy case statement to
decide which method to call. You can create a hash, associate an input with a method, and your
dispatch code will be reduced to a single statement. If you happen to implement a method called
send for your own purposes in your class, you can also use sends alias called __send__ to send
messages instead. This can be handy as send is a common method name. We've established that
method calls need a receiver, but what about methods I was defining at the start of the course which
weren't even a part of any class like double. I'll clear this up in a minute. First, let's recall that you
can make method calls without an explicit receiver. When I call batten_hatches inside the launch
method it's called on self which is the implicit receiver. It turns out that a similar thing happens to
methods which are defined outside of any class. Every Ruby program has a default object called
main. Outside of any other context, self refers to main. The class of self is object. When you add a
method like double it's added to the object class, which makes

{{module.title}}

{{module.title}}

You might also like