4.1.
Class Principles
4.2. Method Visibility
4.3. Subclassing and Inheritance
4.4. Modules
4.5. Exceptions
4.6. Conclusion
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We have said many times that Ruby is an Object Oriented
programming language.
This means that any value is an object and any object has its own
class (it is an instance of that class).
A class defines what an object will look like, i.e. the set of methods
that the object accepts.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
This course does not cover object oriented principles and software
development techniques.
We will cover constructors and statements without going deep into
OO theory and programming styles.
Therefore if you do not know OO paradigms, we suggest you read
up on it.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Moreover we will mainly use the pry interpreter to explain classes,
module and exceptions.
But again, sometimes having the code in a real Ruby script is
required.
Therefore when you see a script, remember that it is available in
your Members Area. You can download and test any script without
rewriting it.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Before continuing with the study of the course, be sure to
know the answers to the following questions:
• What is a class ?
• What is an object ?
• What is an instance of a class ?
• What is a method ?
• What is a subclass ?
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us now see how to define a class. We can use the following
syntax :
class <Name>
…<class body>…
end
Where <Name> must begin with a capital letter. This holds
because Ruby silently creates the constant <Name> to refer the
class, so the capital letter is required.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following is a very simple example of a class named MyClass
which implements a simple method named hello.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In order to instantiate an object we can use the new construct
provided by all classes.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
To invoke an object method, simply
call it throughout your object. In other
words, we can use the object
instantiated followed by a dot (.)
and the method name.
object.method_name
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You should find the previous example very simple.
During the course, we have already used objects and methods
because we used a straightforward OO perspective about Ruby.
The only new concepts are class creation and object instantiation
but they are very simple.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Now we can move to study classes and objects deeply. You should
have all the prerequisites to learn them easily, especially if you are
familiar with the OO programming paradigm.
For further information on classes, please take a look at the
references here.
http://ruby-doc.org/core-1.9.3/Class.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Instance variables are variables available only to each instance of
the class, meaning that they change from object to object.
Since instance variables are encapsulated in any object of the class,
they are not visible outside of it.
Note they are defined within class definition using the special
character @.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Instance variables are only accessible via the instance’s public
methods. So you have to define accessors methods to read them
and setters methods to set them.
To initialize them, the default constructor method in Ruby is
initialize.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the following example, we can see all of
these methods.
All instances of MyClass (defined in
MyClass.rb file) have their own instance
variable (@a) which is accessible thanks to
the getter and the setter method a.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The example shows how to load a
ruby file using pry or irb and how
to use the previous defined
constructor, getter and setter of
MyClass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see from the previous example, each object has its
instance variable @a that is visible within the method of the
object.
NB: with OO methodology it is not a best practice to provide a
getter/setter for each instance variable. Use them only if they are
necessary.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Remember that instances variables can only
be accessed by the instance methods of the
object of that class.
Therefore the instruction @a = 4000 in the
following example would not compute as
expected.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the previous example, the first @a is an instance variable that
belongs to the class object (WrongClass) while the others are
instance variables that belong to instances of WrongClass.
It is a substantial difference; instances variables are resolved in the
context of self. When we invoke a method, self refers to an
instance of a Class. Otherwise inside a class but outside any
method, self is the object that represents the class.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see the new does not
initialize the instance variable @a of
wobj.
It is created when we call the setter
(wobj.a = 100).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
But where is the @a of the class definition? It belongs to the class
object WrongClass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We suggest you get familiar with this concept in order to avoid
bugs or wrong code in your scripts.
A pentester should know the pragmatics of the languages that they
use.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Another powerful feature of Ruby is the ability to define
getter/setter using Metaprogramming. Metaprogramming allows
you to write, manipulate or generate programs (and their data) at
runtime.
We will not cover Metaprogramming in details but you should
know that it extends Ruby syntax to make programming easier.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
For example, with the attr_accessor
keyword, Ruby silently defines a getter
and a setter for us.
NB: It requires a symbol notation but it
defines real instance variables @x, @y.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
With the attr_reader keyword, Ruby
silently defines (only) a getter for us.
Note that the setter has not been
defined; if we try to set x, we get
“undefined method”.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Attr is another useful keyword.
If used alone, it defines a getter
while with true it defines a setter
too.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Ruby allows you to define methods that are called on the class
object instead of an instance object.
We have already said that self keyword always refers the current
object.
So we can define methods that belong to the class object using it.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see, the say method
belongs to the C1 object (we have
defined it with self). Available if we use C1,
but not if we
instantiate a C1 object
(obj).
Instances of C1 class do not have
such a method.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Since a Class is an object, we can define Class object instance
variables with getter and setter too.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In this example, the ClassObject
definition obscures two different scopes
for @a instance variable.
Try to find them by yourself before
continuing.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
There are two @a instance variables. One belongs to the class
object.
The second belongs to an arbitrary instance of ClassObject.
There are also getter/setter/constructor for each of them.
Can you find them?
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Now everything should be clear.
The next slide will better clarify this
concept.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see, there are two
different @a.
One belongs to the ClassObject
object and one belongs to an
instance of ClassObject (obj
object).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Class methods may be defined in a few other ways:
• Using the class name instead of self keyword
• Using the << notation
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following is an example of the method definition.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The << notation is useful when you work with classes that have
been already defined. In the following example, we are adding the
method sub to the class object instance we created.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the previous examples, the class object instance variable @a is
not shared among the class instances (objects created with new).
A class variable must start with special characters @@ and it is
shared among all class instances.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
It is accessible from instance methods, class methods and by the
class definition itself.
They are encapsulated in the object that represent the class; the
user of a class cannot access them from outside without
getter/setter.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
MyClass defines an instance variable @a
accessible through getter/setter created
thanks to attr and a class variable @@a
accessible through class_a getter/setter.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Loading the previous file, we can use MyClass and see what are
the differences of the two types of variables (instance and class).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You may find it useful to define
constants in your classes.
They are accessible from outside using
:: notation.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Constants can also be defined outside of a
class definition.
In the following example, we define a new
constant (C3) in the class named MyClass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Classes are very flexible in Ruby. The following are some concepts
that a good Ruby programmer needs to known:
• Open Classes
• Operator methods
• Mutable / Immutable Objects and Methods
Let us inspect them one by one.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Generally in conventional OO languages, when you close the class
definition you cannot add anything else in it (generally methods,
variables,…) unless you use some advanced technique and tools
like reflection.
Ruby instead allows you to open a defined class in order to add
other methods, constants and so on.
https://en.wikipedia.org/wiki/Reflection_(computer_programming)
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Opening a class in Ruby is very simple; it is the same as defining a
new class. Ruby silently adds methods to the already defined class.
The following example shows how to add a method to obtain the
double if its size in the String class.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As we can see, it is very easy. The syntax
is the same as defining a class. Since the
String class already exists, the method
dsize is added to it.
This is a very powerful feature. Try it by
yourself. You can extend classes as much
as you want.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Classes are often used to define new user data types.
When you define new data types, you want to define operations
and operators for that type too, and you may want to use pre-
defined and easy syntax operator like +, -, *, etc.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The easiest example you may find in books and references is the
Point data type example. We use it too because we can show
better how to use operator methods.
Point class represent a simple point in Euclidean geometry. For
example: p1(1,2) – p2(10,20).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We want an operation that sums two points. The standard
operator for sum is +. We want that if
p1(10,20) and p2(2,3)
than
p1 + p2 = > (10+2), (20+3) => p3(12,23)
The sum of two points will return a new point that contains the
sum of the coordinates x and y.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
This is our Point Class. As you can
see, a point has two coordinates
(x,y). Each of them has a getter.
Initialize creates a Point with
immutable x and y (there is no setter
or other method to change them).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The operator method is +. It returns a
new Point with the sum of the two
points.
Defining + as operator allows us to use
‘+’ in the traditional way (other is the
argument of the + method). You can
see this in the next slide.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
What will happen if we run the command p1 + p2?
The method ‘+’ of the object p1 will be called, meaning that @x
contains the x coordinate of p1 and other.x contains the x
coordinate of p2.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the following example p1,p2,p3 are three instances of Point.
Note that p3 is automatically created.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You can define a lot of operator methods for your data type (for
example comparison operators such as ‘==’ ).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the previous Point example, we used
Point as immutable values.
As you can see, there is no way to
change an object’s coordinate values
once it is initialized.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
This new Point class creates mutable object
value. Each coordinate has its own setter.
This time, the plus operator changes the first
object and returns it as a result. A Point value
can change its coordinate values using both the
setters and plus operation.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As expected, the sum modifies p1
object.
Moreover, p1 and p3 are two
variables that reference the same
object.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We show mutable and immutable objects because Ruby has a lot
of operators and methods that act as immutable or mutable
operators/methods.
Do you remember bang methods (methods that ends with
exclamation mark !)?
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
They allow you to treat an object as a mutable or immutable one.
Without an exclamation mark, the method returns a new value; in
the other case, it modifies the original object.
This is a feature that Ruby programmers must know and use
(properly) in their scripts.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Do not use mutable objects if they are not necessary. You may
introduce bugs or something not expected.
The use of immutable object is more of a programming philosophy
than a feature. Use it in an appropriate manner.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the previous examples, we used only public methods (since they
are public by default) but Ruby allows you to define protected and
private methods too.
If you are familiar with protected/private concepts in Java (and
other programming languages), you should be aware that Ruby has
some differences.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You can define both private instance methods and private class
methods.
Private instance methods can only be called by other instance
methods of the class (and subclass). You cannot call them from
outside an object.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
A famous Ruby private instance method is initialize. You cannot
call it from outside:
obj.initialize -> it is not possible
Note: initialize is an exception because in Ruby all methods are
public by default.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Private instance methods are defined using
the private keyword.
If used without arguments (like in the
example), all the methods below this
keyword are private.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
There is another way to define private
methods. You can use the private
keyword with arguments. This allows
you to specify which of the methods to
treat as private.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In both cases, instances of Aclass can
access only getName Only the class
object (Aclass) can access the method
privateName.
In this code, getName calls privateName.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Sometimes it may be useful to specify class methods as private.
For example, if you want to use particular design patterns that
must use this feature.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
To do this, you can use the
private_class_method keyword.
Remember that with the self
keyword, we are setting methods
for the Aclass class object (not for
instances of Aclass).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see from the class object,
only getName can be called.
Once again, it is a method of the object
that represents the class (it is not a
“AClass” instance).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Protected methods work as private methods but protected
methods may be called by any instance of the defining class or its
subclasses.
We know that this definition may be unclear. The following
example explain its meaning.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see, we can explicitly call a
protected method if its caller is an
instance of the defining class.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
When you define a complex class with
private/protected methods (instance and
class), it should look like the following
screenshot.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Visibility keyword does not apply to constants, instance or class
variables.
Constants are public while instance/class variables are private.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You can use private/protected methods as key for a good
programming style.
Do not think that private methods is a secure way to hide
something private. A different technique such as meta-
programming (via send method) or reflection API allows to bypass
private/protected methods.
https://en.wikipedia.org/wiki/Reflection_(computer_programming)
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We encourage you to use them in order to avoid something not
desirable in your program and as an index of good programming
capabilities.
Remember that scripts with meta-programming or (not required)
reflection are not welcome. A good programming style is always
appreciated.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Ruby provides a mechanism to extend a class in order to modify its
behavior or add new functionalities.
This is what is called (in all other languages) subclassing.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
A class may have multiple subclasses but classes in general can
only extend one class (a class has only one superclass).
When you define a new class, if nothing is specified, it
automatically extends the Object Class.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
This means that any class is a descendant of Objects and
respectively any class has Objects in its ancestors.
Curiosity: Object Class extends another Ruby utility Class:
BasicObject.
Therefore the root class in ruby is BasicObject.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Extending a class is very simple, just use the < operator. A class
inherits all superclass methods.
As we can see in the example, Italian extends Person, therefore it
can use Person methods.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Italian class has inherited all Person methods and the initialize
constructor too. This may be strange if you come from an OO
language like Java.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can imagine, we can specialize a class in Ruby in order to
define new methods or override existing methods.
You can override all methods: public, protected and private
(initialize constructor too).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Pay attention; subclassing in Ruby is strongly discouraged if you do
not properly know the superclass that you want to extend.
You might override some private methods that are fundamental
for the class to work properly.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Note: in Java you can use a superclass as an API, without taking
into account the implementation and what are the
private/protected methods.
Do not use this style of programming in Ruby. You may introduce
bugs extending classes that you do not yet know well.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
To override a method, simply define it in the subclass. Ruby will do
the rest.
A very common overridden method is to_s (the same as toString in
Java).
Remember that by default, a class extends the Object class and
that to_s is a method that Object class hold.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
So let us suppose that a generic class named Person (defined
without < ) extends the Object method to_s as follows.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following code shows how the Italian subclass overrides the
to_s method of Person.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Often when you extend a class, you want to specialize the
behaviors of some methods.
The super keyword helps us avoid the complete redefinition of
method behavior.
With super, you can call the method of the superclass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You can use super with or without arguments according to the
superclass method called.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see how the previous classes
work.
As you can see, both initialize and
to_s of Car class use the super
version of those methods (I am a
#{@type} vehicle is printed).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Ruby allows you to specialize both instance methods (like the
previous examples) and class methods.
Just use the proper notation (explained earlier) to define a class
method.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Inheritance does not affect instance variables.
This holds because an instance variable by definition is created by
the methods that first initialize it; it belongs to the scope of self.
In Ruby, a class does not define the set of fields for its object
instances like Java or other OO languages.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following code (same of the previous example) is perfectly
legal. Car initialization defines instance variable @type . Therefore
@type is not inherited.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Inheritance does not affect instance variables. Remember this.
Therefore if you use an instance variable defined in a superclass,
you must pay attention because other superclass methods can use
the same variables and you might introduce bugs or change the
superclass method behavior.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Do you remember? Class variables are shared and visible from
instance methods, class methods and by the class definition itself.
These rules apply to both classes and its subclasses.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Therefore if a class A defines a global variable @@a and B is an
subclass of A, B and its instances can use the same @@a variable:
• @@a is shared among A and B (class and instances). Any @@a
changes affect all the objects that may use it.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following is a simple example:
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Constants have a particular behavior when used with inheritance.
They are inherited and they can be overridden.
What if when you try to override an inherited constant? Ruby
creates a new one with the same name but available only for the
subclass.
The redefinition does not affect the superclass and its object.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following is a simple example.
As you can see, each class has its own
constant CONST.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can imagine, if you do not
override a constant in the subclass then
it is simply inherited and usable by the
subclass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Note there is another strange behavior when we use inherited
constants.
Ruby first looks up a class constant in its lexical scope rather then
in the inherited chain. An inherited method (not overridden)
always uses the superclass constant even if it is overridden in the
subclass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see, inherited getCONST uses the superclass CONST.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Do you remember the private keyword? We saw that it can be
used to hide a method from the outside.
When you work with inheritance, you must know that private
keyword works in a similar way as the protected Java keyword.
This means that private methods can be used inside inherited
classes.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Private methods are inherited.
This code may seem incorrect for a Java
programmer.
It is perfectly legal in Ruby.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
As you can see, the subclass can use
private methods of the superclass.
Attention: superPrivate is a subclass
public method that use a superclass
private method.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In Ruby, protected methods work like private methods. They are
inherited and can be used similar to private methods.
The only difference is that you have to use them in an explicit way
(object.method notation) when used inside (and not outside) a
class or subclass.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The easiest way to understand protected
behavior is with an example.
Inside a class or a subclass, you can use
obj.method notation (obj.getA).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see the previous code at work.
As you can see, protected method getA
cannot be used outside classes; getAB uses
it internally with obj.getA notation.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
So what happens if we change the
previous example’s protected keyword
with private keyword?
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The main difference between protected and private is that we
cannot use the explicit notation obj.getAB notation inside the A
class or any of its subclasses (B).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Now you should be able to manage classes, subclasses and objects
in a proper way.
You have all the prerequisites to go further in your study of Ruby.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
A module is used in Ruby to define namespaces and mixins. We
will explain both of them soon.
A module is essentially a collection of methods, constants and class
variables with a name.
Module official references are available here.
http://ruby-doc.org/core-1.9.3/Module.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The main differences between classes and modules are:
• Modules cannot be instantiated
• They cannot be subclassed, therefore there is not a
module hierarchy
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Semantically, a module object is an instance of the Module class.
Class is a subclass of Module, therefore all classes are modules too
but not vice versa.
These concepts are simply a curiosity for a standard programmer
but they may be useful for fully understand Ruby pragmatics.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Modules can be used to define a new custom namespace for
methods and constants.
A namespace is a way to collect and bind related methods and
constants, giving them a name that helps you to use them.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Math is the most suitable example of modules used as namespace.
It is a collection of mathematical constants (PI and E) and methods,
especially for basic trigonometric and transcendental functions.
http://ruby-doc.org/core-2.1.0/Math.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
For example, let us write our own Math namespace - MyMath. In
the following example, we are defining two constants (PI and E)
and a function (exp).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Modules and namespaces allow you to define custom Libraries:
collection of constants, methods, classes, other modules and so
on.
Note that modules and classes are handled by Ruby by looking at
their name. These names are constants so you can define classes
and modules inside a module and create hierarchies of libraries.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
This strategy is often used by third-party libraries.
You use them by including the third party custom module and they
provide you a hierarchy of methods, constants, classes and more.
This avoids collisions between their function and yours. It is an
appropriate style of code architecture management.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Mixin is a powerful feature implemented in Ruby.
Mixin means that if a module defines instance methods (instead of
class methods), those instance methods can be mixed into another
class; the implementation of the class and the module are joined.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In other words, any instance of the destination class includes
module methods as their instance methods.
To mix a module into a class, simply use the include keyword.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see a simple example. Module B is mixed with A class. The
method hello is available inside instances of A class as a simply
instance method.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Two useful Ruby modules designed for mixin are Comparable and
Enumerable.
If your class defines the operator <=>, you can include Comparable
to get for free operation like <, <=, ==, >, >= and between?.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Same thing with Enumerable. If it is mixed with your class, it gives
you sort, find, min, max, etc.. without the need to implement
them.
The Ruby platform provides other usable classes as well. Each one
requires that your target class implements some methods in order
to work correctly. For example, Enumerable requires the method
each and <=> for some operations.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Nothing prevents the use of a module both as a namespace and as
a mixin; just provide both instance and class methods to the
module.
Math is a classical example of a module that can be used both as
namespace and as a mixin.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see how to use Math as a
namespace and as a mixin.
Once we include Math, we do not need
to specify Math:: to access its constants,
methods and so on.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Another very important class that you need to know is Exception.
Sometimes, something can go wrong in a program. Imagine a
division by 0; it will generate an error.
A good programmer should know if a program may go to
unwanted states. We should provide some code to execute when
these errors happen in order to retrieve a correct execution flow.
http://ruby-doc.org/core-1.9.3/Exception.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Exceptions are used for this type of situation.
We have already seen a lot of Exceptions during this course. If you
have experience with OO languages (like Java or PHP), you have
already identified them.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
An exception will be generated if we divide a number by 0 or if we
use undefined constants, undefined objects and much more.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
When any of the previous errors occur, Ruby raises an exception.
Normally when an exception is raised, the program terminates its
execution.
But as with almost all OO languages. Ruby allows you to handle the
error and execute some arbitrary code.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Exception in Ruby are object instances of the Exception class (or
one of its subclasses).
Usually subclasses of Exception are used to add information about
the type of Exception raised or to distinguish different exceptions.
Please refer to references to see the full Ruby Exception hierarchy.
http://ruby-doc.org/core-1.9.3/Exception.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Exceptions are objects but they are usually created with the
method raise (instead of new). Nothing prevents you from creating
them with new but good programming styles suggests avoiding it.
Raise alone creates a
RuntimeError.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
RuntimeError objects can be created using raise. Note that you can
specify a string argument to associate them.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
With raise, you can specify the Error type too. Just use the name of
the Exception Class and the message to display.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The following is a simple example that uses ArgumentError. In this
case, if a or b are not integer an ArgumentError occurs.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
ArgumentError, RuntimeError, ZeroDivisionError are subclasses of
StandardError.
If you want to use a custom error and non pre-defined errors are
ideal, it is best practice to create your Error class that is inherited
from StandardError.
Please consult the following reference for the full hierarchy of pre-
defined Error classes.
http://ruby-doc.org/core-1.9.3/Exception.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see now how to define a custom NoIntError.
It is useful to handle the ArgumentError seen in the previous
example.
First, we shall define the new class NoIntError that is inherited
from StandardError. It is our custom error class. It is really simple.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Then we can use it to raise a more specific exception when we
have found an argument that is not an integer.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Attention: in our examples, we used the interpreter. Remember
that if an exception is not handled, the program terminates.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
In the previous example, the second int_sum invocation cause an
Exception because the first argument is not an integer. Therefore
the program terminates its execution without executing the last
int_sum invocation.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
If you want to handle an exception and execute some arbitrary
code when it happens, you can use rescue.
References defines rescue as a clause that can be attached to
other statements (begin is the most common).
http://ruby-doc.org/core-1.9.3/Exception.html
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Attaching rescue to begin gives us the easiest
way to explain how rescue works. In Ruby, $!
refers the last Exception object.
If you call the fact method with an integer less
than 0, it is executed infinite times because
return statements are always
false. Therefore at some point, the script
spends all its memory.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
At some point, an exception is raised by Ruby because the stack is
full. Rescue catches the exception object and global variable $!
stores it.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You have seen that $! Refers to the last Exception object. You can
also use a personal variable with rescue. In the example, we use
exc instead of $!.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
You can use different rescue clauses and handle exceptions by their type.
In the example, the ARGV[0] is used to call int_sum method with wrong
arguments.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Rescue can follow any statement. If an exception occurs, the body of
rescue is executed. In the example, the last int_sum causes an exception.
Therefore the rescue body is executed, printing 0 to stdout.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Raise and rescue are not the only exception clauses available in
Ruby. Let us see :
• retry
• else
• ensure
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Retry is a clause that can be used inside a rescue clause to re-
execute the block of code that has caused the exception.
It is a very useful feature. Imagine that you want to update a
database and an exception occurs (a network error, a DB error,
etc.). You may simply try it again (the network may be available
now). With retry you can do that.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Let us see a very simple example. When b is 0, a ZeroDivisionError
occurs. Rescue captures it, changes b to 1 and then retry the begin
block.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Attention: with retry, you might introduce an infinite loop of retry
block execution. It is a feature that you should use carefully.
Usually programmers use retry with an appropriate strategy based
on their needs. For example, using an ' exponential backoff '
between retry attempts.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Else is another clause provided by Ruby. It is used to execute some
arbitrary code when rescue does not catch any exception.
Using else is similar to putting the else block at the end of the
begin clause. Note that any exception raised in the else block will
not be handled by the rescue clause!
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Else may be put after a rescue clause. It is not a very used feature
but you should know it exists.
begin
# code You may need it when
rescue
# code you become a Ruby
else
# code guru.
end
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Ensure is another clause that is used to specify some code that is
always executed at the end of the begin flow.
The code is always executed even if an exception occurs inside the
main control flow.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Ensure may be inserted after all rescue and else clauses. A
complete view is:
begin
# normal flow
rescue
# exception handling
else
# no exception occur
ensure
# always executed
end
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
For simplicity, in the previous example, we saw exception handling
using the begin statement.
You can use all the previous concepts and clauses with methods,
classes and modules as well without the need of begin keyword.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
For example, you can write a method like the following one:
def my_method(a,b,c)
# normal flow
rescue
# exception handling
else
# no exception occur
ensure
# always executed
end
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The same holds for classes and modules.
Exceptions are a very powerful Ruby feature. You can write elegant
and semantically correct code that are able to handle all type of
errors and exceptions.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We have reached the end of the basic Ruby course.
Now you should be able to understand how Ruby works and you
should be able to write simple and rich Ruby program.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
We have seen Data types, control flows (basic statement and
methods), variables, classes, objects, modules and much more.
You have everything you need to start programming with Ruby
using an OO style and a correct programming structure
methodology (readable, manageable and semantically correct
code).
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The next step is to learn how to use Ruby in real penetration
testing environments.
Therefore in the next sections, you will learn system and network
programming with Ruby.
You will also see how to use Ruby in order to write a custom
Metasploit module and much more.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Note that there also are many other statements, techniques and
features that we have not seen in this module. Some of them are:
• Proc and Lamba abstraction
• Closures
• Functional programming and higher order function
• Reflection
• Metaprogramming
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
To fully understand them, some high knowledge of programming
paradigms in general are required.
Therefore we have decided to skip them. Usually a pentester does
not use them. If you are interested, they are explained in one of
the best Ruby books:
“The Ruby Programming Language”.
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
Penetration Testing Professional 5.0 – Caendra Inc. © 2018
The Ruby Programming Language Ruby Language Official References
https://www.amazon.com/Ruby-
Programming-Language-David- http://ruby-doc.org/
Flanagan/dp/0596516177
Ruby Essentials Ruby Programming Wikibook
https://www.techotopia.com/index.php/Rub https://en.wikibooks.org/wiki/Ruby_Program
y_Essentials ming
Penetration Testing Professional 5.0 – Caendra Inc. © 2018