- GUI
- Windows API tutorial
- Introduction to Windows API
- Windows API main functions
- System functions in Windows API
- Strings in Windows API
- Date & time in Windows API
- A window in Windows API
- First steps in UI
- Windows API menus
- Windows API dialogs
- Windows API controls I
- Windows API controls II
- Windows API controls III
- Advanced controls in Windows API
- Custom controls in Windows API
- The GDI in Windows API
- PyQt4 tutorial
- PyQt5 tutorial
- Qt4 tutorial
- Introduction to Qt4 toolkit
- Qt4 utility classes
- Strings in Qt4
- Date and time in Qt4
- Working with files and directories in Qt4
- First programs in Qt4
- Menus and toolbars in Qt4
- Layout management in Qt4
- Events and signals in Qt4
- Qt4 Widgets
- Qt4 Widgets II
- Painting in Qt4
- Custom widget in Qt4
- The Breakout game in Qt4
- Qt5 tutorial
- Introduction to Qt5 toolkit
- Strings in Qt5
- Date and time in Qt5
- Containers in Qt5
- Working with files and directories in Qt5
- First programs in Qt5
- Menus and toolbars in Qt5
- Layout management in Qt5
- Events and signals in Qt5
- Qt5 Widgets
- Qt5 Widgets II
- Painting in Qt5
- Custom widget in Qt5
- Snake in Qt5
- The Breakout game in Qt5
- PySide tutorial
- Tkinter tutorial
- Tcl/Tk tutorial
- Qt Quick tutorial
- Java Swing tutorial
- JavaFX tutorial
- Java SWT tutorial
- wxWidgets tutorial
- Introduction to wxWidgets
- wxWidgets helper classes
- First programs in wxWidgets
- Menus and toolbars in wxWidgets
- Layout management in wxWidgets
- Events in wxWidgets
- Dialogs in wxWidgets
- wxWidgets widgets
- wxWidgets widgets II
- Drag and Drop in wxWidgets
- Device Contexts in wxWidgets
- Custom widgets in wxWidgets
- The Tetris game in wxWidgets
- wxPython tutorial
- Introduction to wxPython
- First Steps
- Menus and toolbars
- Layout management in wxPython
- Events in wxPython
- wxPython dialogs
- Widgets
- Advanced widgets in wxPython
- Drag and drop in wxPython
- Internationalisation
- Application skeletons in wxPython
- The GDI
- Mapping modes
- Creating custom widgets
- Tips and Tricks
- wxPython Gripts
- The Tetris game in wxPython
- C# Winforms Mono tutorial
- Java Gnome tutorial
- Introduction to Java Gnome
- First steps in Java Gnome
- Layout management in Java Gnome
- Layout management II in Java Gnome
- Menus in Java Gnome
- Toolbars in Java Gnome
- Events in Java Gnome
- Widgets in Java Gnome
- Widgets II in Java Gnome
- Advanced widgets in Java Gnome
- Dialogs in Java Gnome
- Pango in Java Gnome
- Drawing with Cairo in Java Gnome
- Drawing with Cairo II
- Nibbles in Java Gnome
- QtJambi tutorial
- GTK+ tutorial
- Ruby GTK tutorial
- GTK# tutorial
- Visual Basic GTK# tutorial
- PyGTK tutorial
- Introduction to PyGTK
- First steps in PyGTK
- Layout management in PyGTK
- Menus in PyGTK
- Toolbars in PyGTK
- Signals & events in PyGTK
- Widgets in PyGTK
- Widgets II in PyGTK
- Advanced widgets in PyGTK
- Dialogs in PyGTK
- Pango
- Pango II
- Drawing with Cairo in PyGTK
- Drawing with Cairo II
- Snake game in PyGTK
- Custom widget in PyGTK
- PHP GTK tutorial
- C# Qyoto tutorial
- Ruby Qt tutorial
- Visual Basic Qyoto tutorial
- Mono IronPython Winforms tutorial
- Introduction
- First steps in IronPython Mono Winforms
- Layout management
- Menus and toolbars
- Basic Controls in Mono Winforms
- Basic Controls II in Mono Winforms
- Advanced Controls in Mono Winforms
- Dialogs
- Drag & drop in Mono Winforms
- Painting
- Painting II in IronPython Mono Winforms
- Snake in IronPython Mono Winforms
- The Tetris game in IronPython Mono Winforms
- FreeBASIC GTK tutorial
- Jython Swing tutorial
- JRuby Swing tutorial
- Visual Basic Winforms tutorial
- JavaScript GTK tutorial
- Ruby HTTPClient tutorial
- Ruby Faraday tutorial
- Ruby Net::HTTP tutorial
- Java 2D games tutorial
- Java 2D tutorial
- Cairo graphics tutorial
- PyCairo tutorial
- HTML5 canvas tutorial
- Python tutorial
- Python language
- Interactive Python
- Python lexical structure
- Python data types
- Strings in Python
- Python lists
- Python dictionaries
- Python operators
- Keywords in Python
- Functions in Python
- Files in Python
- Object-oriented programming in Python
- Modules
- Packages in Python
- Exceptions in Python
- Iterators and Generators
- Introspection in Python
- Ruby tutorial
- PHP tutorial
- Visual Basic tutorial
- Visual Basic
- Visual Basic lexical structure
- Basics
- Visual Basic data types
- Strings in Visual Basic
- Operators
- Flow control
- Visual Basic arrays
- Procedures & functions in Visual Basic
- Organizing code in Visual Basic
- Object-oriented programming
- Object-oriented programming II in Visual Basic
- Collections in Visual Basic
- Input & output
- Tcl tutorial
- C# tutorial
- Java tutorial
- AWK tutorial
- Jetty tutorial
- Tomcat Derby tutorial
- Jtwig tutorial
- Android tutorial
- Introduction to Android development
- First Android application
- Android Button widgets
- Android Intents
- Layout management in Android
- Android Spinner widget
- SeekBar widget
- Android ProgressBar widget
- Android ListView widget
- Android Pickers
- Android menus
- Dialogs
- Drawing in Android
- Java EE 5 tutorials
- Introduction
- Installing Java
- Installing NetBeans 6
- Java Application Servers
- Resin CGIServlet
- JavaServer Pages, (JSPs)
- Implicit objects in JSPs
- Shopping cart
- JSP & MySQL Database
- Java Servlets
- Sending email in a Servlet
- Creating a captcha in a Servlet
- DataSource & DriverManager
- Java Beans
- Custom JSP tags
- Object relational mapping with iBATIS
- Jsoup tutorial
- MySQL tutorial
- MySQL quick tutorial
- MySQL storage engines
- MySQL data types
- Creating, altering and dropping tables in MySQL
- MySQL expressions
- Inserting, updating, and deleting data in MySQL
- The SELECT statement in MySQL
- MySQL subqueries
- MySQL constraints
- Exporting and importing data in MySQL
- Joining tables in MySQL
- MySQL functions
- Views in MySQL
- Transactions in MySQL
- MySQL stored routines
- MySQL Python tutorial
- MySQL Perl tutorial
- MySQL C API programming tutorial
- MySQL Visual Basic tutorial
- MySQL PHP tutorial
- MySQL Java tutorial
- MySQL Ruby tutorial
- MySQL C# tutorial
- SQLite tutorial
- SQLite C tutorial
- SQLite PHP tutorial
- SQLite Python tutorial
- SQLite Perl tutorial
- SQLite Ruby tutorial
- SQLite C# tutorial
- SQLite Visual Basic tutorial
- PostgreSQL C tutorial
- PostgreSQL Python tutorial
- PostgreSQL Ruby tutorial
- PostgreSQL PHP tutorial
- PostgreSQL Java tutorial
- Apache Derby tutorial
- SQLAlchemy tutorial
- MongoDB PHP tutorial
- MongoDB Java tutorial
- MongoDB JavaScript tutorial
- MongoDB Ruby tutorial
- Spring JdbcTemplate tutorial
- JDBI tutorial
Object-oriented programming II in Ruby
In this part of the Ruby tutorial, we will continue talking about object-oriented programming in Ruby.
We start with attribute accessors. We will cover class constants, class methods and operator overloading. We will define polymorphism and will show how it is used in Ruby. We will also mention modules and exceptions.
Attribute accessors
All Ruby variables are private. It is possible to access them only via methods. These methods are often called setters and getters. Creating a setter and a getter method is a very common task. Therefore Ruby has convenient methods to create both types of methods. They are attr_reader
, attr_writer
and attr_accessor
.
The attr_reader
creates getter methods. The attr_writer
method creates setter methods and instance variables for this setters. The attr_accessor
method creates both getter, setter methods and their instance variables.
#!/usr/bin/ruby class Car attr_reader :name, :price attr_writer :name, :price def to_s "#{@name}: #{@price}" end end c1 = Car.new c2 = Car.new c1.name = "Porsche" c1.price = 23500 c2.name = "Volkswagen" c2.price = 9500 puts "The #{c1.name} costs #{c1.price}" p c1 p c2
We have a Car class. In the definition of the class, we use the attr_reader
and attr_writer
to create two getter and setter methods for the Car class.
attr_reader :name, :price
Here we create two instance methods named name and price. Note that the attr_reader
takes symbols of methods as parameters.
attr_writer :name, :price
The attr_writer
creates two setter methods named name and price and two instance variables, @name
and @price
.
c1.name = "Porsche" c1.price = 23500
In this context, two setter methods are called to fill instance variables with some data.
puts "The #{c1.name} costs #{c1.price}"
Here two getter methods are called to get data from the instance variables of the c1
object.
$ ./arw.rb The Porsche costs 23500 Porsche: 23500 Volkswagen: 9500
This is the output of the example.
As we already stated above, the attr_accessor
method creates getter, setter methods and their instance variables.
#!/usr/bin/ruby class Book attr_accessor :title, :pages end b1 = Book.new b1.title = "Hidden motives" b1.pages = 255 p "The book #{b1.title} has #{b1.pages} pages"
We have a Book
class in which the attr_accessor
creates two pairs of methods and two instance variables.
class Book attr_accessor :title, :pages end
The attr_accessor
method that sets up title and pages methods and @title
and @pages
instance variables.
b1 = Book.new b1.title = "Hidden motives" b1.pages = 255
An object of a Book
class is created. Two setter methods fill the instance variables of the object.
p "The book #{b1.title} has #{b1.pages} pages"
In this code line we use two getter methods to read the values of the instance variables.
$ ./accessor.rb "The book Hidden motives has 255 pages"
This is example output.
Class constants
Ruby enables you to create class constants. These constants do not belong to a concrete object. They belong to the class. By convention, constants are written in uppercase letters.
#!/usr/bin/ruby class MMath PI = 3.141592 end puts MMath::PI
We have a MMath
class with a PI
constant.
PI = 3.141592
We create a PI
constant. Remember that constants in Ruby are not enforced.
puts MMath::PI
We access the PI
constant using the ::
operator.
$ ./classconstant.rb 3.141592
Running the example we see this output.
The to_s method
Each object has a to_s
method. It returns a string representation of the object. Note that when the puts
method takes an object as a parameter, the to_s
of the object is being called.
#!/usr/bin/ruby class Being def to_s "This is Being class" end end b = Being.new puts b.to_s puts b
We have a Being class in which we override the default implementation of the to_s
method.
def to_s "This is Being class" end
Each class created inherits from the base Object
. The to_s
method belongs to this class. We overwrite the to_s
method and create a new implementation. We provide a human-readable description of our object.
b = Being.new puts b.to_s puts b
We create a Being class and call the to_s
method twice. The first time explicitly, the second time implicitly.
$ ./tostring.rb This is Being class This is Being class
This is what we get when we run the example.
Operator overloading
Operator overloading is a situation where different operators have different implementations depending on their arguments.
In Ruby there is only a slight distinction between an operator and a method.
#!/usr/bin/ruby class Circle attr_accessor :radius def initialize r @radius = r end def +(other) Circle.new @radius + other.radius end def to_s "Circle with radius: #{@radius}" end end c1 = Circle.new 5 c2 = Circle.new 6 c3 = c1 + c2 p c3
In the example, we have a Circle
class. We overload the +
operator in the class. We use it to add two circle objects.
def +(other) Circle.new @radius + other.radius end
We define a method with a +
name. The method adds the radiuses of two circle objects.
c1 = Circle.new 5 c2 = Circle.new 6 c3 = c1 + c2
We create two circle objects. In the third line, we add these two objects to create a new one.
$ ./operatoroverloading.rb Circle with radius: 11
Adding these two circle objects creates a third with a radius of 11.
Class methods
Ruby methods can be divided into class methods and instance methods. Class methods are called on a class. They cannot be called on an instance of a class.
Class methods cannot access instance variables.
#!/usr/bin/ruby class Circle def initialize x @r = x end def self.info "This is a Circle class" end def area @r * @r * 3.141592 end end p Circle.info c = Circle.new 3 p c.area
The above code example presents a Circle
class. Apart from a constructor method, it has one class and one instance method.
def self.info "This is a Circle class" end
Methods that start with a self
keyword are class methods.
def area "Circle, radius: #{@r}" end
Instance methods do not start with the self keyword.
p Circle.info
We call a class method. Note that we call the method on a class name.
c = Circle.new 3 p c.area
To call an instance method, we must first create an object. Instance methods are always called on an object. In our case, the c
variable holds the object and we call the area method on the circle object. We utilize a dot operator.
$ ./classmethods.rb "This is a Circle class" 28.274328
Output of the code example describing class methods in Ruby.
There are three ways to create a class method in Ruby.
#!/usr/bin/ruby class Wood def self.info "This is a Wood class" end end class Brick class << self def info "This is a Brick class" end end end class Rock end def Rock.info "This is a Rock class" end p Wood.info p Brick.info p Rock.info
The example has three classes. Each of them has one class method.
def self.info "This is a Wood class" end
Class methods may start with a self
keyword.
class << self def info "This is a Brick class" end end
Another way is to put a method definition after the class << self
construct.
def Rock.info "This is a Rock class" end
This is the third way to define a class method in Ruby.
$ ./classmethods2.rb "This is a Wood class" "This is a Brick class" "This is a Rock class"
We see the output of calling all three class methods on a Wood
, Brick
, and Rock
classes.
Three ways to create an instance method
Ruby has three basic ways to create instance methods. Instance methods belong to an instance of an object. They are called on an object using a dot operator.
#!/usr/bin/ruby class Wood def info "This is a wood object" end end wood = Wood.new p wood.info class Brick attr_accessor :info end brick = Brick.new brick.info = "This is a brick object" p brick.info class Rock end rock = Rock.new def rock.info "This is a rock object" end p rock.info
In the example we create three instance objects from a Wood, a Brick
and a Rock
class. Each object has one instance method defined.
class Wood def info "This is a wood object" end end wood = Wood.new p wood.info
This is probably the most common way to define and call an instance method. The info method is defined inside the Wood
class. Later, the object is created and we call the info method on the object instance.
class Brick attr_accessor :info end brick = Brick.new brick.info = "This is a brick object" p brick.info
Another way is to create a method using the attribute accessors. This is a convenient way which saves some typing for the programmer. The attr_accessor
creates two methods, the getter and the setter method It also creates an instance variable which stores the data. The brick object is created and the data is stored in the @info
variable using the info setter method. Finally, the message is read by the info getter method.
class Rock end rock = Rock.new def rock.info "This is a rock object" end p rock.info
In the third way we create an empty Rock
class. The object is instantiated. Later, a method is dynamically created and placed into the object.
$ ./threeways.rb "This is a wood object" "This is a brick object" "This is a rock object"
Example output.
Polymorphism
Polymorphism is the process of using an operator or function in different ways for different data input. In practical terms, polymorphism means that if class B inherits from class A, it doesn't have to inherit everything about class A; it can do some of the things that class A does differently. (Wikipedia)
In general, polymorphism is the ability to appear in different forms. Technically, it is the ability to redefine methods for derived classes. Polymorphism is concerned with the application of specific implementations to an interface or a more generic base class.
Note that there is some difference in the definition of the polymorphism in statically typed languages like C++, Java or C# and dynamically typed languages like Python or Ruby. In statically typed languages it is important when the compilers determine the method definition, at compile time or at run time. In dynamically typed languages we concentrate on the fact that methods with the same name do different things.
#!/usr/bin/ruby class Animal def make_noise "Some noise" end def sleep puts "#{self.class.name} is sleeping." end end class Dog < Animal def make_noise 'Woof!' end end class Cat < Animal def make_noise 'Meow!' end end [Animal.new, Dog.new, Cat.new].each do |animal| puts animal.make_noise animal.sleep end
We have a simple inheritance hierarchy. There is an Animal
base class and two descendants, a Cat
and a Dog
. Each of these three classes has its own implementation of the make_noise
method. The implementation of the method of the descendants replaces the definition of a method in the Animal
class.
class Dog < Animal def make_noise 'Woof!' end end
The implementation of the make_noise method
in the Dog
class replaces the implementation of the make_noise
of the Animal
class.
[Animal.new, Dog.new, Cat.new].each do |animal| puts animal.make_noise animal.sleep end
We create an instance of each class. We call make_noise
and sleep
methods on the objects.
$ ./polymorhism.rb Some noise Animal is sleeping. Woof! Dog is sleeping. Meow! Cat is sleeping.
This is the output of the polymorhism.rb
script.
Modules
A Ruby Module
is a collection of methods, classes, and constants. Modules are similar to classes with a few differences. Modules cannot have instances and cannot subclasses.
Modules are used to group related classes, methods and constants can be put into separate modules. This also prevents name clashes, because modules encapsulate the objects they contain. In this regard, Ruby modules are similar to C# namespaces and Java packages.
Modules also support the use of mixins in Ruby. A mixin is a Ruby facility to create multiple inheritance. If a class inherits functionality from more than one class, we speak of multiple inheritance.
#!/usr/bin/ruby puts Math::PI puts Math.sin 2
Ruby has a built-in Math
module. It has multiple methods and a constant. We access the PI constant by using the :: operator. Methods are accessed by a dot operator as in classes.
#!/usr/bin/ruby include Math puts PI puts sin 2
If we include a module in our script, we can refer to the Math objects directly, omitting the Math name. Modules are added to a script using the include
keyword.
$ ./modules.rb 3.141592653589793 0.9092974268256817
Output of the program.
In the following example, we show how modules can be used to organize code.
#!/usr/bin/ruby module Forest class Rock ; end class Tree ; end class Animal ; end end module Town class Pool ; end class Cinema ; end class Square ; end class Animal ; end end p Forest::Tree.new p Forest::Rock.new p Town::Cinema.new p Forest::Animal.new p Town::Animal.new
Ruby code can be grouped semantically. Rocks and trees belong to a forest. Pools, cinemas, squares belong to a town. By using modules our code has some order. Animals can be in a forest and in a town too. In a single script, we cannot define two animal classes. They would clash. Putting them in different modules we solve the issue.
p Forest::Tree.new p Forest::Rock.new p Town::Cinema.new
We are creating objects that belong to a forest and to a town. To access an object in a module, we use the :: operator.
p Forest::Animal.new p Town::Animal.new
Two different animal objects are created. The Ruby interpreter can tell between them. It identifies them by their module name.
$ ./modules3.rb #<Forest::Tree:0x97f35ec> #<Forest::Rock:0x97f35b0> #<Town::Cinema:0x97f3588> #<Forest::Animal:0x97f3560> #<Town::Animal:0x97f3538>
This is the output of the modules3.rb program.
The final code example of this section will demonstrate multiple inheritance using Ruby modules. In this context the modules are called mixins.
#!/usr/bin/ruby module Device def switch_on ; puts "on" end def switch_off ; puts "off" end end module Volume def volume_up ; puts "volume up" end def vodule_down ; puts "volume down" end end module Pluggable def plug_in ; puts "plug in" end def plug_out ; puts "plug out" end end class CellPhone include Device, Volume, Pluggable def ring puts "ringing" end end cph = CellPhone.new cph.switch_on cph.volume_up cph.ring
We have three modules and one class. The modules represent some functionality. A device can be swiched on and off. Many objects can share this functionality, including televisions, mobile phones, computers or refrigerators. Rather than creating this ability to be swiched on/off for each object class, we separate it in one module, which can be included in each object if necessary. This way the code is better organized and more compact.
module Volume def volume_up ; puts "volume up" end def vodule_down ; puts "volume down" end end
A Volume module organizes methods that are responsible for controlling the volume level. If a device needs these methods, it simply includes the module to its class.
class CellPhone include Device, Volume, Pluggable def ring puts "ringing" end end
A cell phone adds all three modules with the include
method. The methods of the modules are mixed in the CellPhone
class. And are available for the instances of the class. The CellPhone
class has also its own ring method that is specific to it.
cph = CellPhone.new cph.switch_on cph.volume_up cph.ring
A CellPhone
object is created and we call three methods upon the object.
$ ./mixins.rb on volume up ringing
Running the example gives this output.
Exceptions
Exceptions are objects that signal deviations from the normal flow of program execution. Exceptions are raised, thrown or initiated.
During the execution of our application, many things might go wrong. A disk might get full and we cannot save our file. An Internet connection might go down and our application tries to connect to a site. All these might result in a crash of our application. To prevent this from happening, we should anticipate and respond to errors in expected program operation. For this, we can use the exception handling.
Exceptions are objects. They are descendants of a built-in Exception
class. Exception objects carry information about the exception. Its type (the exception’s class name), an optional descriptive string, and optional traceback information. Programs may subclass Exception
, or more often StandardError
, to obtain custom Exception objects that provide additional information about operational anomalies.
#!/usr/bin/ruby x = 35 y = 0 begin z = x / y puts z rescue => e puts e p e end
In the above program, we intentionally divide a number by zero. This leads to an error.
begin z = x / y puts z
Statements that can fail are placed after the begin
keyword.
rescue => e puts e p e end
In the code following the rescue
keyword, we deal with an exception. In this case, we print the error message to the console. The e is an exception object that is created when the error occurs.
$ ./zerodivision.rb divided by 0 #<ZeroDivisionError: divided by 0>
In the output of the example, we see the message of the exception. The last line shows the exception object called ZeroDivisionError
.
A programmer may raise exceptions himself using the raise
keyword.
#!/usr/bin/ruby age = 17 begin if age < 18 raise "Person is a minor" end puts "Entry allowed" rescue => e puts e p e exit 1 end
The entrance to a club is not allowed for people younger than 18 years. We simulate this situation in our Ruby script.
begin if age < 18 raise "Person is a minor" end puts "Entry allowed"
If the person is a minor, an exception is raised. If the raise
keyword does not have a specific exception as a parameter, a RuntimeError
exception is raised setting its message to the given string. The code does not reach the puts "Entry allowed"
line. The execution of the code is interrupted and it continues at the rescue block.
rescue => e puts e p e exit 1 end
In the rescue block, we print the error message and the string representation of the RuntimeError
object. We also call the exit
method to inform the environment that the execution of the script ended in error.
$ ./raise_exception.rb Person is a minor #<RuntimeError: Person is a minor> $ echo $? 1
The person, a minor, was not allowed to enter the club. The bash $?
variable is set to the exit error of the script.
Ruby's ensure
clause creates a block of code that always executes, whether there is an exception or not.
#!/usr/bin/ruby begin f = File.open("stones", "r") while line = f.gets do puts line end rescue => e puts e p e ensure f.close if f end
In the code example, we try to open and read the stones file. I/O operations are error prone. We could easily have an exception.
ensure f.close if f end
In the ensure block we close the file handler. We check if the handler exists because it might not have been created. Allocated resources are often placed in the ensure block.
We can create our own custom exceptions if we want. Custom exceptions in Ruby should inherit from the StandardError
class.
#!/usr/bin/ruby class BigValueError < StandardError ; end LIMIT = 333 x = 3_432_453 begin if x > LIMIT raise BigValueError, "Exceeded the maximum value" end puts "Script continues" rescue => e puts e p e exit 1 end
Let's say we have a situation in which we cannot deal with big numbers.
class BigValueError < StandardError ; end
We have a BigValueError
class. This class derives from the built-in StandardError
class.
LIMIT = 333
Numbers which exceed this constant are considered to be "big" by our program.
if x > LIMIT raise BigValueError, "Exceeded the maximum value" end
If the value is bigger than the limit, we throw our custom exception. We give the exception a message "Exceeded the maximum value".
$ ./custom_exception.rb Exceeded the maximum value #<BigValueError: Exceeded the maximum value>
Running the program.
In this chapter we finished talking about object-oriented programming in Ruby language.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论