Ruby is a general-purpose language; it can’t properly be called a web language at all. Even so, web applications and web tools in general are among the most common uses of Ruby.
Not only can you write your own SMTP server, FTP daemon, or Web server in Ruby, but you can also use Ruby for more usual tasks such as CGI programming or as a replacement for PHP.
Please spend few minutes with CGI Programming Tutorial for more detail on CGI Programming.
Writing CGI Scripts
The most basic Ruby CGI script looks like this −
#!/usr/bin/ruby
puts "HTTP/1.0 200 OK"
puts "Content-type: text/html\n\n"
puts "<html><body>This is a test</body></html>"
If you call this script test.cgi and uploaded it to a Unix-based Web hosting provider with the right permissions, you could use it as a CGI script.
For example, if you have the Web site https://www.example.com/ hosted with a Linux Web hosting provider and you upload test.cgi to the main directory and give it execute permissions, then visiting https://www.example.com/test.cgi should return an HTML page saying This is a test.
Here when test.cgi is requested from a Web browser, the Web server looks for test.cgi on the Web site, and then executes it using the Ruby interpreter. The Ruby script returns a basic HTTP header and then returns a basic HTML document.
Using cgi.rb
Ruby comes with a special library called cgi that enables more sophisticated interactions than those with the preceding CGI script.
Let’s create a basic CGI script that uses cgi −
#!/usr/bin/rubyrequire'cgi'
cgi =CGI.new
puts cgi.header
puts "<html><body>This is a test</body></html>"
Here, you created a CGI object and used it to print the header line for you.
Form Processing
Using class CGI gives you access to HTML query parameters in two ways. Suppose we are given a URL of /cgi-bin/test.cgi?FirstName = Zara&LastName = Ali.
You can access the parameters FirstName and LastName using CGI#[] directly as follows −
If a form contains multiple fields with the same name, the corresponding values will be returned to the script as an array. The [] accessor returns just the first of these.index the result of the params method to get them all.
In this example, assume the form has three fields called “name” and we entered three names “Zara”, “Huma” and “Nuha” −
Note − Ruby will take care of GET and POST methods automatically. There is no separate treatment for these two different methods.
An associated, but basic, form that could send the correct data would have the HTML code like so −
<html><body><form method ="POST" action ="http://www.example.com/test.cgi">FirstName:<input type ="text" name ="FirstName" value =""/><br />LastName:<input type ="text" name ="LastName" value =""/><input type ="submit" value ="Submit Data"/></form></body></html>
Creating Forms and HTML
CGI contains a huge number of methods used to create HTML. You will find one method per tag. In order to enable these methods, you must create a CGI object by calling CGI.new.
To make tag nesting easier, these methods take their content as code blocks. The code blocks should return a String, which will be used as the content for the tag. For example −
cgi.head {"\n"&plus;cgi.title{"This Is a Test"}}&plus;
cgi.body {"\n"&plus;
cgi.form {"\n"&plus;
cgi.hr &plus;
cgi.h1 {"A Form: "}&plus;"\n"&plus;
cgi.textarea("get_text")&plus;"\n"+
cgi.br +
cgi.submit
}}}}</pre>
NOTE − The form method of the CGI class can accept a method parameter, which will set the HTTP method ( GET, POST, and so on...) to be used on form submittal. The default, used in this example, is POST.
This will produce the following result −
Content-Type: text/html
Content-Length: 302
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Final//EN">
<HTML>
<HEAD>
When dealing with URLs and HTML code, you must be careful to quote certain characters. For instance, a slash character ( / ) has special meaning in a URL, so it must be escaped if it's not part of the pathname.
For example, any / in the query portion of the URL will be translated to the string %2F and must be translated back to a / for you to use it. Space and ampersand are also special characters. To handle this, CGI provides the routines CGI.escape and CGI.unescape.
This chapter teaches you how to access a database using Ruby. The Ruby DBI module provides a database-independent interface for Ruby scripts similar to that of the Perl DBI module.
DBI stands for Database Independent Interface for Ruby, which means DBI provides an abstraction layer between the Ruby code and the underlying database, allowing you to switch database implementations really easily. It defines a set of methods, variables, and conventions that provide a consistent database interface, independent of the actual database being used.
DBI can interface with the following −
ADO (ActiveX Data Objects)
DB2
Frontbase
mSQL
MySQL
ODBC
Oracle
OCI8 (Oracle)
PostgreSQL
Proxy/Server
SQLite
SQLRelay
Architecture of a DBI Application
DBI is independent of any database available in the backend. You can use DBI whether you are working with Oracle, MySQL or Informix, etc. This is clear from the following architecture diagram.
The general architecture for Ruby DBI uses two layers −
The database interface (DBI) layer. This layer is database independent and provides a set of common access methods that are used the same way regardless of the type of database server with which you’re communicating.
The database driver (DBD) layer. This layer is database dependent; different drivers provide access to different database engines. There is one driver for MySQL, another for PostgreSQL, another for InterBase, another for Oracle, and so forth. Each driver interprets requests from the DBI layer and maps them onto requests appropriate for a given type of database server.
Prerequisites
If you want to write Ruby scripts to access MySQL databases, you’ll need to have the Ruby MySQL module installed.
You can install ruby DBI using the Ruby Gems packaging manager:
gem install dbi
Before starting this installation make sure you have the root privilege. Now, follow the steps given below −
Step 1
$ tar zxf dbi-0.2.0.tar.gz
Step 2
Go in distribution directory dbi-0.2.0 nd configure it using the setup.rb script in that directory. The most general configuration command looks like this, with no arguments following the config argument. This command configures the distribution to install all drivers by default.
$ ruby setup.rb config
To be more specific, provide a –with option that lists the particular parts of the distribution you want to use. For example, to configure only the main DBI module and the MySQL DBD-level driver, issue the following command −
$ ruby setup.rb config --with = dbi,dbd_mysql
Step 3
Final step is to build the driver and install it using the following commands −
$ ruby setup.rb setup
$ ruby setup.rb install
Database Connection
Assuming we are going to work with MySQL database, before connecting to a database make sure of the following −
You have created a database TESTDB.
You have created EMPLOYEE in TESTDB.
This table is having fields FIRST_NAME, LAST_NAME, AGE, SEX, and INCOME.
User ID “testuser” and password “test123” are set to access TESTDB.
Ruby Module DBI is installed properly on your machine.
You have gone through MySQL tutorial to understand MySQL Basics.
Following is the example of connecting with MySQL database “TESTDB”
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")# get server version string and display it
row = dbh.select_one("SELECT VERSION()")
puts "Server version: "+ row[0]rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"ensure# disconnect from server
dbh.disconnect if dbh
end
While running this script, it produces the following result at our Linux machine.
Server version: 5.0.45
If a connection is established with the data source, then a Database Handle is returned and saved into dbh for further use otherwise dbh is set to nil value and e.err and e::errstr return error code and an error string respectively.
Finally, before coming out it, ensure that database connection is closed and resources are released.
INSERT Operation
INSERT operation is required when you want to create your records into a database table.
Once a database connection is established, we are ready to create tables or records into the database tables using do method or prepare and execute method.
Using do Statement
Statements that do not return rows can be issued by invoking the do database handle method. This method takes a statement string argument and returns a count of the number of rows affected by the statement.
dbh.do("DROP TABLE IF EXISTS EMPLOYEE")
dbh.do("CREATETABLEEMPLOYEE(FIRST_NAMECHAR(20)NOTNULL,LAST_NAMECHAR(20),AGEINT,SEXCHAR(1),INCOMEFLOAT)" );
Similarly, you can execute the SQL INSERT statement to create a record into the EMPLOYEE table.
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
dbh.do( "INSERTINTOEMPLOYEE(FIRST_NAME,LAST_NAME,AGE,SEX,INCOME)VALUES('Mac','Mohan',20,'M',2000)" )
puts "Record has been created"
dbh.commit
rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure# disconnect from server
dbh.disconnect if dbh
end
Using prepare and execute
You can use prepare and execute methods of DBI class to execute the SQL statement through Ruby code.
Record creation takes the following steps −
Preparing SQL statement with INSERT statement. This will be done using the prepare method.
Executing SQL query to select all the results from the database. This will be done using the execute method.
Releasing Statement handle. This will be done using finish API
If everything goes fine, then commit this operation otherwise you can rollback the complete transaction.
Following is the syntax to use these two methods −
sth = dbh.prepare(statement)
sth.execute
... zero or more SQL operations ...
sth.finish
These two methods can be used to pass bind values to SQL statements. There may be a case when values to be entered is not given in advance. In such a case, binding values are used. A question mark (?) is used in place of actual values and then actual values are passed through execute() API.
Following is the example to create two records in the EMPLOYEE table −
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
sth = dbh.prepare( "INSERTINTOEMPLOYEE(FIRST_NAME,LAST_NAME,AGE,SEX,INCOME)VALUES(?,?,?,?,?)" )
sth.execute('John','Poul',25,'M',2300)
sth.execute('Zara','Ali',17,'F',1000)
sth.finish
dbh.commit
puts "Record has been created"rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure# disconnect from server
dbh.disconnect if dbh
end
If there are multiple INSERTs at a time, then preparing a statement first and then executing it multiple times within a loop is more efficient than invoking do each time through the loop.
READ Operation
READ Operation on any database means to fetch some useful information from the database.
Once our database connection is established, we are ready to make a query into this database. We can use either do method or prepare and execute methods to fetch values from a database table.
Record fetching takes following steps −
Preparing SQL query based on required conditions. This will be done using the prepare method.
Executing SQL query to select all the results from the database. This will be done using the execute method.
Fetching all the results one by one and printing those results. This will be done using the fetch method.
Releasing Statement handle. This will be done using the finish method.
Following is the procedure to query all the records from EMPLOYEE table having salary more than 1000.
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
sth = dbh.prepare("SELECT * FROM EMPLOYEE WHERE INCOME > ?")
sth.execute(1000)
sth.fetch do|row|
printf "First Name: %s, Last Name : %s\n", row[0], row[1]
printf "Age: %d, Sex : %s\n", row[2], row[3]
printf "Salary :%d \n\n", row[4]end
sth.finish
rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"ensure# disconnect from server
dbh.disconnect if dbh
end
This will produce the following result −
First Name: Mac, Last Name : Mohan
Age: 20, Sex : M
Salary :2000
First Name: John, Last Name : Poul
Age: 25, Sex : M
Salary :2300
There are more short cut methods to fetch records from the database. If you are interested then go through the Fetching the Result otherwise proceed to the next section.
Update Operation
UPDATE Operation on any database means to update one or more records, which are already available in the database. Following is the procedure to update all the records having SEX as ‘M’. Here, we will increase AGE of all the males by one year. This will take three steps −
Preparing SQL query based on required conditions. This will be done using the prepare method.
Executing SQL query to select all the results from the database. This will be done using the execute method.
Releasing Statement handle. This will be done using the finish method.
If everything goes fine then commit this operation otherwise you can rollback the complete transaction.
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
sth = dbh.prepare("UPDATE EMPLOYEE SET AGE = AGE + 1 WHERE SEX = ?")
sth.execute('M')
sth.finish
dbh.commit
rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure# disconnect from server
dbh.disconnect if dbh
end
DELETE Operation
DELETE operation is required when you want to delete some records from your database. Following is the procedure to delete all the records from EMPLOYEE where AGE is more than 20. This operation will take following steps.
Preparing SQL query based on required conditions. This will be done using the prepare method.
Executing SQL query to delete required records from the database. This will be done using the execute method.
Releasing Statement handle. This will be done using the finish method.
If everything goes fine then commit this operation otherwise you can rollback the complete transaction.
#!/usr/bin/ruby -wrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
sth = dbh.prepare("DELETE FROM EMPLOYEE WHERE AGE > ?")
sth.execute(20)
sth.finish
dbh.commit
rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure# disconnect from server
dbh.disconnect if dbh
end
Performing Transactions
Transactions are a mechanism that ensures data consistency. Transactions should have the following four properties −
Atomicity − Either a transaction completes or nothing happens at all.
Consistency − A transaction must start in a consistent state and leave the system is a consistent state.
Isolation − Intermediate results of a transaction are not visible outside the current transaction.
Durability − Once a transaction was committed, the effects are persistent, even after a system failure.
The DBI provides two methods to either commit or rollback a transaction. There is one more method called transaction which can be used to implement transactions. There are two simple approaches to implement transactions −
Approach I
The first approach uses DBI’s commit and rollback methods to explicitly commit or cancel the transaction −
dbh['AutoCommit']=false# Set auto commit to false.begin
dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")
dbh.commit
rescue
puts "transaction failed"
dbh.rollback
end
dbh['AutoCommit']=true
Approach II
The second approach uses the transaction method. This is simpler, because it takes a code block containing the statements that make up the transaction. The transaction method executes the block, then invokes commit or rollback automatically, depending on whether the block succeeds or fails −
dbh['AutoCommit']=false# Set auto commit to false.
dbh.transaction do|dbh|
dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'John'")
dbh.do("UPDATE EMPLOYEE SET AGE = AGE+1 WHERE FIRST_NAME = 'Zara'")end
dbh['AutoCommit']=true
COMMIT Operation
Commit is the operation, which gives a green signal to database to finalize the changes, and after this operation, no change can be reverted back.
Here is a simple example to call the commit method.
dbh.commit
ROLLBACK Operation
If you are not satisfied with one or more of the changes and you want to revert back those changes completely, then use the rollback method.
Here is a simple example to call the rollback method.
dbh.rollback
Disconnecting Database
To disconnect Database connection, use disconnect API.
dbh.disconnect
If the connection to a database is closed by the user with the disconnect method, any outstanding transactions are rolled back by the DBI. However, instead of depending on any of DBI’s implementation details, your application would be better off calling the commit or rollback explicitly.
Handling Errors
There are many sources of errors. A few examples are a syntax error in an executed SQL statement, a connection failure, or calling the fetch method for an already canceled or finished statement handle.
If a DBI method fails, DBI raises an exception. DBI methods may raise any of several types of exception but the two most important exception classes are DBI::InterfaceError and DBI::DatabaseError.
Exception objects of these classes have three attributes named err, errstr, and state, which represent the error number, a descriptive error string, and a standard error code. The attributes are explained below −
err − Returns an integer representation of the occurred error or nil if this is not supported by the DBD.The Oracle DBD for example returns the numerical part of an ORA-XXXX error message.
errstr − Returns a string representation of the occurred error.
state − Returns the SQLSTATE code of the occurred error.The SQLSTATE is a five-character-long string. Most DBDs do not support this and return nil instead.
You have seen following code above in most of the examples −
rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"
dbh.rollback
ensure# disconnect from server
dbh.disconnect if dbh
end
To get debugging information about what your script is doing as it executes, you can enable tracing. To do this, you must first load the dbi/trace module and then call the trace method that controls the trace mode and output destination −
The mode value may be 0 (off), 1, 2, or 3, and the destination should be an IO object. The default values are 2 and STDERR, respectively.
Code Blocks with Methods
There are some methods that create handles. These methods can be invoked with a code block. The advantage of using code block along with methods is that they provide the handle to the code block as its parameter and automatically cleans up the handle when the block terminates. There are few examples to understand the concept.
DBI.connect − This method generates a database handle and it is recommended to call disconnect at the end of the block to disconnect the database.
dbh.prepare − This method generates a statement handle and it is recommended to finish at the end of the block. Within the block, you must invoke execute method to execute the statement.
dbh.execute − This method is similar except we don’t need to invoke execute within the block. The statement handle is automatically executed.
Example 1
DBI.connect can take a code block, passes the database handle to it, and automatically disconnects the handle at the end of the block as follows.
DBI transaction method also takes a code block which has been described in above.
Driver-specific Functions and Attributes
The DBI lets the database drivers provide additional database-specific functions, which can be called by the user through the func method of any Handle object.
Driver-specific attributes are supported and can be set or gotten using the []= or [] methods.DBD::Mysql implements the following driver-specific functions −
Example
#!/usr/bin/rubyrequire"dbi"begin# connect to the MySQL server
dbh =DBI.connect("DBI:Mysql:TESTDB:localhost","testuser","test123")
puts dbh.func(:client_info)
puts dbh.func(:client_version)
puts dbh.func(:host_info)
puts dbh.func(:proto_info)
puts dbh.func(:server_info)
puts dbh.func(:thread_id)
puts dbh.func(:stat)rescueDBI::DatabaseError=> e
puts "An error occurred"
puts "Error code: #{e.err}"
puts "Error message: #{e.errstr}"ensure
dbh.disconnect if dbh
end
This will produce the following result −
5.0.45
50045
Localhost via UNIX socket
10
5.0.45
150621
Uptime: 384981 Threads: 1 Questions: 1101078 Slow queries: 4 \
Opens: 324 Flush tables: 1 Open tables: 64 \
Queries per second avg: 2.860
A regular expression is a special sequence of characters that helps you match or find other strings or sets of strings using a specialized syntax held in a pattern.
A regular expression literal is a pattern between slashes or between arbitrary delimiters followed by %r as follows −
Syntax
/pattern/
/pattern/im # option can be specified
%r!/usr/local! # general delimited regular expression
Example
#!/usr/bin/ruby
line1 ="Cats are smarter than dogs";
line2 ="Dogs also like meat";if( line1 =~/Cats(.*)/)
puts "Line1 contains Cats"endif( line2 =~/Cats(.*)/)
puts "Line2 contains Dogs"end
This will produce the following result −
Line1 contains Cats
Regular-Expression Modifiers
Regular expression literals may include an optional modifier to control various aspects of matching. The modifier is specified after the second slash character, as shown previously and may be represented by one of these characters −
Sr.No.
Modifier & Description
1
iIgnores case when matching text.
2
oPerforms #{} interpolations only once, the first time the regexp literal is evaluated.
3
xIgnores whitespace and allows comments in regular expressions.
4
mMatches multiple lines, recognizing newlines as normal characters.
5
u,e,s,nInterprets the regexp as Unicode (UTF-8), EUC, SJIS, or ASCII. If none of these modifiers is specified, the regular expression is assumed to use the source encoding.
Like string literals delimited with %Q, Ruby allows you to begin your regular expressions with %r followed by a delimiter of your choice. This is useful when the pattern you are describing contains a lot of forward slash characters that you don’t want to escape −
# Following matches a single slash character, no escape required
%r|/|
# Flag characters are allowed with this syntax, too
%r[</(.*)>]i
Regular-Expression Patterns
Except for control characters, (+ ? . * ^ $ ( ) [ ] { } | \), all characters match themselves. You can escape a control character by preceding it with a backslash.Following table lists the regular expression syntax that is available in Ruby.
Regular-Expression Examples
Literal CharactersCharacter ClassesSpecial Character ClassesRepetition CasesNon-greedy RepetitionGrouping with ParenthesesBack ReferencesAlternativesAnchorsSpecial Syntax with Parentheses
Search and Replace
Some of the most important String methods that use regular expressions are sub and gsub, and their in-place variants sub! and gsub!.
All of these methods perform a search-and-replace operation using a Regexp pattern. The sub & sub! replaces the first occurrence of the pattern and gsub & gsub! replaces all occurrences.
The sub and gsub returns a new string, leaving the original unmodified where as sub! and gsub! modify the string on which they are called.
Following is the example −
#!/usr/bin/ruby
phone ="2004-959-559 #This is Phone Number"# Delete Ruby-style comments
phone = phone.sub!(/#.*$/,"")
puts "Phone Num : #{phone}"# Remove anything other than digits
phone = phone.gsub!(/\D/,"")
puts "Phone Num : #{phone}"
This will produce the following result −
Phone Num : 2004-959-559
Phone Num : 2004959559
Following is another example −
#!/usr/bin/ruby
text ="rails are rails, really good Ruby on Rails"# Change "rails" to "Rails" throughout
text.gsub!("rails","Rails")# Capitalize the word "Rails" throughout
text.gsub!(/\brails\b/,"Rails")
puts "#{text}"
Ruby is a pure object-oriented language and everything appears to Ruby as an object. Every value in Ruby is an object, even the most primitive things: strings, numbers and even true and false. Even a class itself is an object that is an instance of the Class class. This chapter will take you through all the major functionalities related to Object Oriented Ruby.
A class is used to specify the form of an object and it combines data representation and methods for manipulating that data into one neat package. The data and methods within a class are called members of the class.
Ruby Class Definition
When you define a class, you define a blueprint for a data type. This doesn’t actually define any data, but it does define what the class name means, that is, what an object of the class will consist of and what operations can be performed on such an object.
A class definition starts with the keyword class followed by the class name and is delimited with an end. For example, we defined the Box class using the keyword class as follows −
class Box
code
end
The name must begin with a capital letter and by convention names that contain more than one word are run together with each word capitalized and no separating characters (CamelCase).
Define Ruby Objects
A class provides the blueprints for objects, so basically an object is created from a class. We declare objects of a class using new keyword. Following statements declare two objects of class Box −
box1 = Box.new
box2 = Box.new
The initialize Method
The initialize method is a standard Ruby class method and works almost same way as constructor works in other object oriented programming languages. The initialize method is useful when you want to initialize some class variables at the time of object creation. This method may take a list of parameters and like any other ruby method it would be preceded by def keyword as shown below −
classBoxdefinitialize(w,h)@width,@height = w, h
endend
The instance Variables
The instance variables are kind of class attributes and they become properties of objects once objects are created using the class. Every object’s attributes are assigned individually and share no value with other objects. They are accessed using the @ operator within the class but to access them outside of the class we use public methods, which are called accessor methods. If we take the above defined class Box then @width and @height are instance variables for the class Box.
classBoxdefinitialize(w,h)# assign instance variables@width,@height = w, h
endend
The accessor & setter Methods
To make the variables available from outside the class, they must be defined within accessor methods, these accessor methods are also known as a getter methods. Following example shows the usage of accessor methods −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# accessor methodsdefprintWidth@width
enddefprintHeight@height
endend# create an object
box =Box.new(10,20)# use accessor methods
x = box.printWidth()
y = box.printHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
When the above code is executed, it produces the following result −
Width of the box is : 10
Height of the box is : 20
Similar to accessor methods, which are used to access the value of the variables, Ruby provides a way to set the values of those variables from outside of the class using setter methods, which are defined as below −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height= w, h
end# accessor methodsdefgetWidth@widthenddefgetHeight@heightend# setter methodsdefsetWidth=(value)@width= value
enddefsetHeight=(value)@height= value
endend# create an object
box =Box.new(10,20)# use setter methods
box.setWidth =30
box.setHeight =50# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
When the above code is executed, it produces the following result −
Width of the box is : 30
Height of the box is : 50
The instance Methods
The instance methods are also defined in the same way as we define any other method using def keyword and they can be used using a class instance only as shown below. Their functionality is not limited to access the instance variables, but also they can do a lot more as per your requirement.
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance methoddefgetArea@width *@height
endend# create an object
box =Box.new(10,20)# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
When the above code is executed, it produces the following result −
Area of the box is : 200
The class Methods and Variables
The class variables is a variable, which is shared between all instances of a class. In other words, there is one instance of the variable and it is accessed by object instances. Class variables are prefixed with two @ characters (@@). A class variable must be initialized within the class definition as shown below.
A class method is defined using def self.methodname(), which ends with end delimiter and would be called using the class name as classname.methodname as shown in the following example −
#!/usr/bin/ruby -wclassBox# Initialize our class variables@@count =0definitialize(w,h)# assign instance avriables@width,@height = w, h
&commat;&commat;count +=1enddefself.printCount()
puts "Box count is : #&commat;&commat;count"endend# create two object
box1 =Box.new(10,20)
box2 =Box.new(30,100)# call class method to print box countBox.printCount()
When the above code is executed, it produces the following result −
Box count is : 2
The to_s Method
Any class you define should have a to_s instance method to return a string representation of the object. Following is a simple example to represent a Box object in terms of width and height −
#!/usr/bin/ruby -wclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# define to_s methoddefto_s"(w:#@width,h:#@height)"# string formatting of the object.endend# create an object
box =Box.new(10,20)# to_s method will be called in reference of string automatically.
puts "String representation of box is : #{box}"
When the above code is executed, it produces the following result −
String representation of box is : (w:10,h:20)
Access Control
Ruby gives you three levels of protection at instance methods level, which may be public, private, or protected. Ruby does not apply any access control over instance and class variables.
Public Methods − Public methods can be called by anyone. Methods are public by default except for initialize, which is always private.
Private Methods − Private methods cannot be accessed, or even viewed from outside the class. Only the class methods can access private members.
Protected Methods − A protected method can be invoked only by objects of the defining class and its subclasses. Access is kept within the family.
Following is a simple example to show the syntax of all the three access modifiers −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance method by default it is publicdefgetArea
getWidth()* getHeight
end# define private accessor methodsdefgetWidth@width
enddefgetHeight@height
end# make them privateprivate:getWidth,:getHeight# instance method to print areadefprintArea@area = getWidth()* getHeight
puts "Big box area is : #&commat;area"end# make it protectedprotected:printAreaend# create an object
box =Box.new(10,20)# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"# try to call protected or methods
box.printArea()
When the above code is executed, it produces the following result. Here, first method is called successfully but second method gave a problem.
Area of the box is : 200
test.rb:42: protected method `printArea' called for #
<Box:0xb7f11280 @height = 20, @width = 10> (NoMethodError)
Class Inheritance
One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to create and maintain an application.
Inheritance also provides an opportunity to reuse the code functionality and fast implementation time but unfortunately Ruby does not support multiple levels of inheritances but Ruby supports mixins. A mixin is like a specialized implementation of multiple inheritance in which only the interface portion is inherited.
When creating a class, instead of writing completely new data members and member functions, the programmer can designate that the new class should inherit the members of an existing class. This existing class is called the base class or superclass, and the new class is referred to as the derived class or sub-class.
Ruby also supports the concept of subclassing, i.e., inheritance and following example explains the concept. The syntax for extending a class is simple. Just add a < character and the name of the superclass to your class statement. For example, following define a class BigBox as a subclass of Box −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance methoddefgetArea@width *@height
endend# define a subclassclassBigBox<Box# add a new instance methoddefprintArea@area =@width *@height
puts "Big box area is : #&commat;area"endend# create an object
box =BigBox.new(10,20)# print the area
box.printArea()
When the above code is executed, it produces the following result −
Big box area is : 200
Methods Overriding
Though you can add new functionality in a derived class, but sometimes you would like to change the behavior of already defined method in a parent class. You can do so simply by keeping the method name same and overriding the functionality of the method as shown below in the example −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance methoddefgetArea@width *@height
endend# define a subclassclassBigBox<Box# change existing getArea method as followsdefgetArea@area =@width *@height
puts "Big box area is : #&commat;area"endend# create an object
box =BigBox.new(10,20)# print the area using overriden method.
box.getArea()
Operator Overloading
We’d like the + operator to perform vector addition of two Box objects using +, the * operator to multiply a Box width and height by a scalar, and the unary – operator to do negate the width and height of the Box. Here is a version of the Box class with mathematical operators defined −
classBoxdefinitialize(w,h)# Initialize the width and height@width,@height = w, h
enddef+(other)# Define + to do vector additionBox.new(@width + other.width,@height + other.height)enddef-@# Define unary minus to negate width and heightBox.new(-@width,-@height)enddef*(scalar)# To perform scalar multiplicationBox.new(@width*scalar,@height*scalar)endend
Freezing Objects
Sometimes, we want to prevent an object from being changed. The freeze method in Object allows us to do this, effectively turning an object into a constant. Any object can be frozen by invoking Object.freeze. A frozen object may not be modified: you can’t change its instance variables.
You can check if a given object is already frozen or not using Object.frozen? method, which returns true in case the object is frozen otherwise a false value is return. Following example clears the concept −
#!/usr/bin/ruby -w# define a classclassBox# constructor methoddefinitialize(w,h)@width,@height= w, h
end# accessor methodsdefgetWidth@widthenddefgetHeight@heightend# setter methodsdefsetWidth=(value)@width= value
enddefsetHeight=(value)@height= value
endend# create an object
box =Box.new(10,20)# let us freez this object
box.freeze
if( box.frozen?)
puts "Box object is frozen object"else
puts "Box object is normal object"end# now try using setter methods
box.setWidth =30
box.setHeight =50# use accessor methods
x = box.getWidth()
y = box.getHeight()
puts "Width of the box is : #{x}"
puts "Height of the box is : #{y}"
When the above code is executed, it produces the following result −
Box object is frozen object
test.rb:20:in `setWidth=': can't modify frozen object (TypeError)
from test.rb:39
Class Constants
You can define a constant inside a class by assigning a direct numeric or string value to a variable, which is defined without using either @ or @@. By convention, we keep constant names in upper case.
Once a constant is defined, you cannot change its value but you can access a constant directly inside a class much like a variable but if you want to access a constant outside of the class then you would have to use classname::constant as shown in the below example.
#!/usr/bin/ruby -w# define a classclassBoxBOX_COMPANY="TATA Inc"BOXWEIGHT=10# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance methoddefgetArea@width *@height
endend# create an object
box =Box.new(10,20)# call instance methods
a = box.getArea()
puts "Area of the box is : #{a}"
puts Box::BOX_COMPANY
puts "Box weight is: #{Box::BOXWEIGHT}"
When the above code is executed, it produces the following result −
Area of the box is : 200
TATA Inc
Box weight is: 10
Class constants are inherited and can be overridden like instance methods.
Create Object Using Allocate
There may be a situation when you want to create an object without calling its constructor initialize i.e. using new method, in such case you can call allocate, which will create an uninitialized object for you as in the following example −
#!/usr/bin/ruby -w# define a classclassBox
attr_accessor :width,:height# constructor methoddefinitialize(w,h)@width,@height = w, h
end# instance methoddefgetArea@width *@height
endend# create an object using new
box1 =Box.new(10,20)# create another object using allocate
box2 =Box.allocate
# call instance method using box1
a = box1.getArea()
puts "Area of the box is : #{a}"# call instance method using box2
a = box2.getArea()
puts "Area of the box is : #{a}"
When the above code is executed, it produces the following result −
Area of the box is : 200
test.rb:14: warning: instance variable @width not initialized
test.rb:14: warning: instance variable @height not initialized
test.rb:14:in getArea': undefined method *'
for nil:NilClass (NoMethodError) from test.rb:29
Class Information
If class definitions are executable code, this implies that they execute in the context of some object: self must reference something. Let’s find out what it is.
#!/usr/bin/ruby -wclassBox# print class information
puts "Type of self = #{self.type}"
puts "Name of self = #{self.name}"end
When the above code is executed, it produces the following result −
Type of self = Class
Name of self = Box
This means that a class definition is executed with that class as the current object. This means that methods in the metaclass and its superclasses will be available during the execution of the method definition.
The execution and the exception always go together. If you are opening a file, which does not exist, then if you did not handle this situation properly, then your program is considered to be of bad quality.
The program stops if an exception occurs. So exceptions are used to handle various type of errors, which may occur during a program execution and take appropriate action instead of halting program completely.
Ruby provide a nice mechanism to handle exceptions. We enclose the code that could raise an exception in a begin/end block and use rescue clauses to tell Ruby the types of exceptions we want to handle.
Syntax
begin
# -
rescue OneTypeOfException
# -
rescue AnotherTypeOfException
# -
else
# Other exceptions
ensure
# Always will be executed
end
Everything from begin to rescue is protected. If an exception occurs during the execution of this block of code, control is passed to the block between rescue and end.
For each rescue clause in the begin block, Ruby compares the raised Exception against each of the parameters in turn. The match will succeed if the exception named in the rescue clause is the same as the type of the currently thrown exception, or is a superclass of that exception.
In an event that an exception does not match any of the error types specified, we are allowed to use an else clause after all the rescue clauses.
puts "File opened successfully"endrescue
file =STDINend
print file,"==",STDIN,"\n"
This will produce the following result. You can see that STDIN is substituted to file because open failed.
#<IO:0xb7d16f84>==#<IO:0xb7d16f84>
Using retry Statement
You can capture an exception using rescue block and then use retry statement to execute begin block from the beginning.
Syntax
begin
# Exceptions raised by this code will
# be caught by the following rescue clause
rescue
# This block will capture all types of exceptions
retry # This will move control to the beginning of begin
end
NOTE − Notice that if the file of re-substituted name does not exist this example code retries infinitely. Be careful if you use retry for an exception process.
Using raise Statement
You can use raise statement to raise an exception. The following method raises an exception whenever it’s called. It’s second message will be printed.
Syntax
raise
OR
raise "Error Message"
OR
raise ExceptionType, "Error Message"
OR
raise ExceptionType, "Error Message" condition
The first form simply re-raises the current exception (or a RuntimeError if there is no current exception). This is used in exception handlers that need to intercept an exception before passing it on.
The second form creates a new RuntimeError exception, setting its message to the given string. This exception is then raised up the call stack.
The third form uses the first argument to create an exception and then sets the associated message to the second argument.
The fourth form is similar to the third form but you can add any conditional statement like unless to raise an exception.
Example
#!/usr/bin/rubybegin
puts 'I am before the raise.'raise'An error has occurred.'
puts 'I am after the raise.'rescue
puts 'I am rescued.'end
puts 'I am after the begin block.'
This will produce the following result −
I am before the raise.
I am rescued.
I am after the begin block.
One more example showing the usage of raise −
#!/usr/bin/rubybeginraise'A test exception.'rescueException=> e
puts e.message
puts e.backtrace.inspect
end
This will produce the following result −
A test exception.
["main.rb:4"]
Using ensure Statement
Sometimes, you need to guarantee that some processing is done at the end of a block of code, regardless of whether an exception was raised. For example, you may have a file open on entry to the block and you need to make sure it gets closed as the block exits.
The ensure clause does just this. ensure goes after the last rescue clause and contains a chunk of code that will always be executed as the block terminates. It doesn’t matter if the block exits normally, if it raises and rescues an exception, or if it is terminated by an uncaught exception, the ensure block will get run.
Syntax
begin
#.. process
#..raise exception
rescue
#.. handle error
ensure
#.. finally ensure execution
#.. This will always execute.
end
Example
beginraise'A test exception.'rescueException=> e
puts e.message
puts e.backtrace.inspect
ensure
puts "Ensuring execution"end
This will produce the following result −
A test exception.
["main.rb:4"]
Ensuring execution
Using else Statement
If the else clause is present, it goes after the rescue clauses and before any ensure.
The body of an else clause is executed only if no exceptions are raised by the main body of code.
Syntax
begin
#.. process
#..raise exception
rescue
# .. handle error
else
#.. executes if there is no exception
ensure
#.. finally ensure execution
#.. This will always execute.
end
Example
begin# raise 'A test exception.'
puts "I'm not raising exception"rescueException=> e
puts e.message
puts e.backtrace.inspect
else
puts "Congratulations-- no errors!"ensure
puts "Ensuring execution"end
This will produce the following result −
I'm not raising exception
Congratulations-- no errors!
Ensuring execution
Raised error message can be captured using $! variable.
Catch and Throw
While the exception mechanism of raise and rescue is great for abandoning the execution when things go wrong, it’s sometimes nice to be able to jump out of some deeply nested construct during normal processing. This is where catch and throw come in handy.
The catch defines a block that is labeled with the given name (which may be a Symbol or a String). The block is executed normally until a throw is encountered.
Syntax
throw :lablename
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
OR
throw :lablename condition
#.. this will not be executed
catch :lablename do
#.. matching catch will be executed after a throw is encountered.
end
Example
The following example uses a throw to terminate interaction with the user if ‘!’ is typed in response to any prompt.
defpromptAndGet(prompt)
print prompt
res = readline.chomp
throw:quitRequestedif res =="!"return res
end
catch :quitRequesteddo
name = promptAndGet("Name: ")
age = promptAndGet("Age: ")
sex = promptAndGet("Sex: ")# ..# process informationend
promptAndGet("Name:")
You should try the above program on your machine because it needs manual interaction. This will produce the following result −
Name: Ruby on Rails
Age: 3
Sex: !
Name:Just Ruby
Class Exception
Ruby’s standard classes and modules raise exceptions. All the exception classes form a hierarchy, with the class Exception at the top. The next level contains seven different types −
Interrupt
NoMemoryError
SignalException
ScriptError
StandardError
SystemExit
There is one other exception at this level, Fatal, but the Ruby interpreter only uses this internally.
Both ScriptError and StandardError have a number of subclasses, but we do not need to go into the details here. The important thing is that if we create our own exception classes, they need to be subclasses of either class Exception or one of its descendants.
Now, look at the following example, which will use this exception −
File.open(path,"w")do|file|begin# Write out the data ...rescue# Something went wrong!raiseFileSaveError.new($!)endend
The important line here is raise FileSaveError.new($!). We call raise to signal that an exception has occurred, passing it a new instance of FileSaveError, with the reason being that specific exception caused the writing of the data to fail.
Ruby provides a whole set of I/O-related methods implemented in the Kernel module. All the I/O methods are derived from the class IO.
The class IO provides all the basic methods, such as read, write, gets, puts, readline, getc, and printf.
This chapter will cover all the basic I/O functions available in Ruby. For more functions, please refer to Ruby Class IO.
The puts Statement
In the previous chapters, you have assigned values to variables and then printed the output using puts statement.
The puts statement instructs the program to display the value stored in the variable. This will add a new line at the end of each line it writes.
Example
#!/usr/bin/ruby
val1 ="This is variable one"
val2 ="This is variable two"
puts val1
puts val2
This will produce the following result −
This is variable one
This is variable two
The gets Statement
The gets statement can be used to take any input from the user from standard screen called STDIN.
Example
The following code shows you how to use the gets statement. This code will prompt the user to enter a value, which will be stored in a variable val and finally will be printed on STDOUT.
#!/usr/bin/ruby
puts "Enter a value :"
val = gets
puts val
This will produce the following result −
Enter a value :
This is entered value
This is entered value
The putc Statement
Unlike the puts statement, which outputs the entire string onto the screen, the putc statement can be used to output one character at a time.
Example
The output of the following code is just the character H −
#!/usr/bin/ruby
str ="Hello Ruby!"
putc str
This will produce the following result −
H
The print Statement
The print statement is similar to the puts statement. The only difference is that the puts statement goes to the next line after printing the contents, whereas with the print statement the cursor is positioned on the same line.
Until now, you have been reading and writing to the standard input and output. Now, we will see how to play with actual data files.
The File.new Method
You can create a File object using File.new method for reading, writing, or both, according to the mode string. Finally, you can use File.close method to close that file.
Syntax
aFile = File.new("filename", "mode")
# ... process the file
aFile.close
The File.open Method
You can use File.open method to create a new file object and assign that file object to a file. However, there is one difference in between File.open and File.new methods. The difference is that the File.open method can be associated with a block, whereas you cannot do the same using the File.new method.
File.open("filename","mode")do|aFile|# ... process the fileend
Here is a list of The Different Modes of opening a File −
Reading and Writing Files
The same methods that we’ve been using for ‘simple’ I/O are available for all file objects. So, gets reads a line from standard input, and aFile.gets reads a line from the file object aFile.
However, I/O objects provides additional set of access methods to make our lives easier.
The sysread Method
You can use the method sysread to read the contents of a file. You can open the file in any of the modes when using the method sysread. For example −
Following is the input text file −
This is a simple text file for testing purpose.
Now let’s try to read this file −
#!/usr/bin/ruby
aFile =File.new("input.txt","r")if aFile
content = aFile.sysread(20)
puts content
else
puts "Unable to open file!"end
This statement will output the first 20 characters of the file. The file pointer will now be placed at the 21st character in the file.
The syswrite Method
You can use the method syswrite to write the contents into a file. You need to open the file in write mode when using the method syswrite. For example −
#!/usr/bin/ruby
aFile =File.new("input.txt","r+")if aFile
aFile.syswrite("ABCDEF")else
puts "Unable to open file!"end
This statement will write “ABCDEF” into the file.
The each_byte Method
This method belongs to the class File. The method each_byte is always associated with a block. Consider the following code sample −
#!/usr/bin/ruby
aFile =File.new("input.txt","r+")if aFile
aFile.syswrite("ABCDEF")
aFile.each_byte {|ch| putc ch; putc ?.}else
puts "Unable to open file!"end
Characters are passed one by one to the variable ch and then displayed on the screen as follows −
s. .a. .s.i.m.p.l.e. .t.e.x.t. .f.i.l.e. .f.o.r. .t.e.s.t.i.n.g. .p.u.r.p.o.s.e...
.
.
The IO.readlines Method
The class File is a subclass of the class IO. The class IO also has some methods, which can be used to manipulate files.
One of the IO class methods is IO.readlines. This method returns the contents of the file line by line. The following code displays the use of the method IO.readlines −
In this code, the variable arr is an array. Each line of the file input.txt will be an element in the array arr. Therefore, arr[0] will contain the first line, whereas arr[1] will contain the second line of the file.
The IO.foreach Method
This method also returns output line by line. The difference between the method foreach and the method readlines is that the method foreach is associated with a block. However, unlike the method readlines, the method foreach does not return an array. For example −
The following command finds whether the file has zero size or not −
#!/usr/bin/rubyFile.zero?("test.txt")# => true
The following command returns size of the file −
#!/usr/bin/rubyFile.size?("text.txt")# => 1002
The following command can be used to find out a type of file −
#!/usr/bin/rubyFile::ftype("test.txt")# => file
The ftype method identifies the type of the file by returning one of the following − file, directory, characterSpecial, blockSpecial, fifo, link, socket, or unknown.
The following command can be used to find when a file was created, modified, or last accessed −
#!/usr/bin/rubyFile::ctime("test.txt")# => Fri May 09 10:06:37 -0700 2008File::mtime("text.txt")# => Fri May 09 10:44:44 -0700 2008File::atime("text.txt")# => Fri May 09 10:45:01 -0700 2008
Directories in Ruby
All files are contained within various directories, and Ruby has no problem handling these too. Whereas the File class handles files, directories are handled with the Dir class.
Navigating Through Directories
To change directory within a Ruby program, use Dir.chdir as follows. This example changes the current directory to /usr/bin.
Dir.chdir("/usr/bin")
You can find out what the current directory is with Dir.pwd −
puts Dir.pwd # This will return something like /usr/bin
You can get a list of the files and directories within a specific directory using Dir.entries −
puts Dir.entries("/usr/bin").join(' ')
Dir.entries returns an array with all the entries within the specified directory. Dir.foreach provides the same feature −
Dir.foreach("/usr/bin")do|entry|
puts entry
end
An even more concise way of getting directory listings is by using Dir’s class array method −
Dir["/usr/bin/*"]
Creating a Directory
The Dir.mkdir can be used to create directories −
Dir.mkdir("mynewdir")
You can also set permissions on a new directory (not one that already exists) with mkdir −
NOTE − The mask 755 sets permissions owner, group, world [anyone] to rwxr-xr-x where r = read, w = write, and x = execute.
Dir.mkdir("mynewdir",755)
Deleting a Directory
The Dir.delete can be used to delete a directory. The Dir.unlink and Dir.rmdir performs exactly the same function and are provided for convenience.
Dir.delete("testdir")
Creating Files & Temporary Directories
Temporary files are those that might be created briefly during a program’s execution but aren’t a permanent store of information.
Dir.tmpdir provides the path to the temporary directory on the current system, although the method is not available by default. To make Dir.tmpdir available it’s necessary to use require ‘tmpdir’.
You can use Dir.tmpdir with File.join to create a platform-independent temporary file −
require'tmpdir'
tempfilename =File.join(Dir.tmpdir,"tingtong")
tempfile =File.new(tempfilename,"w")
tempfile.puts "This is a temporary file"
tempfile.close
File.delete(tempfilename)
This code creates a temporary file, writes data to it, and deletes it. Ruby’s standard library also includes a library called Tempfile that can create temporary files for you −
require'tempfile'
f =Tempfile.new('tingtong')
f.puts "Hello"
puts f.path
f.close
Built-in Functions
Here are the ruby built-in functions to process files and directories −
Iterators are nothing but methods supported by collections. Objects that store a group of data members are called collections. In Ruby, arrays and hashes can be termed collections.
Iterators return all the elements of a collection, one after the other. We will be discussing two iterators here, each and collect. Let’s look at these in detail.
Ruby each Iterator
The each iterator returns all the elements of an array or a hash.
Syntax
collection.each do |variable|
code
end
Executes code for each element in collection. Here, collection could be an array or a ruby hash.
Example
#!/usr/bin/ruby
ary =[1,2,3,4,5]
ary.eachdo|i|
puts i
end
This will produce the following result −
1
2
3
4
5
You always associate the each iterator with a block. It returns each value of the array, one by one, to the block. The value is stored in the variable i and then displayed on the screen.
Ruby collect Iterator
The collect iterator returns all the elements of a collection.
Syntax
collection = collection.collect
The collect method need not always be associated with a block. The collect method returns the entire collection, regardless of whether it is an array or a hash.
Example
#!/usr/bin/ruby
a =[1,2,3,4,5]
b =Array.new
b = a.collect
puts b
This will produce the following result −
1
2
3
4
5
NOTE − The collect method is not the right way to do copying between arrays. There is another method called a clone, which should be used to copy one array into another array.
You normally use the collect method when you want to do something with each of the values to get the new array. For example, this code produces an array b containing 10 times each value in a.
#!/usr/bin/ruby
a =[1,2,3,4,5]
b = a.collect{|x|10*x}
puts b
Ranges occur everywhere: January to December, 0 to 9, lines 50 through 67, and so on. Ruby supports ranges and allows us to use ranges in a variety of ways −
Ranges as Sequences
Ranges as Conditions
Ranges as Intervals
Ranges as Sequences
The first and perhaps the most natural use of ranges is to express a sequence. Sequences have a start point, an end point, and a way to produce successive values in the sequence.
Ruby creates these sequences using the ”..” and ”…” range operators. The two-dot form creates an inclusive range, while the three-dot form creates a range that excludes the specified high value.
The sequence 1..100 is held as a Range object containing references to two Fixnum objects. If you need to, you can convert a range to a list using the to_a method. Try the following example −
Ranges implement methods that let you iterate over them and test their contents in a variety of ways −
#!/usr/bin/ruby# Assume a range
digits =0..9
puts digits.include?(5)
ret = digits.min
puts "Min value is #{ret}"
ret = digits.max
puts "Max value is #{ret}"
ret = digits.reject {|i| i <5}
puts "Rejected values are #{ret}"
digits.eachdo|digit|
puts "In Loop #{digit}"end
This will produce the following result −
true
Min value is 0
Max value is 9
Rejected values are 5, 6, 7, 8, 9
In Loop 0
In Loop 1
In Loop 2
In Loop 3
In Loop 4
In Loop 5
In Loop 6
In Loop 7
In Loop 8
In Loop 9
Ranges as Conditions
Ranges may also be used as conditional expressions. For example, the following code fragment prints sets of lines from the standard input, where the first line in each set contains the word start and the last line the word ends −
while gets
print if/start/../end/end
Ranges can be used in case statements −
#!/usr/bin/ruby
score =70
result =case score
when0..40then"Fail"when41..60then"Pass"when61..70then"Pass with Merit"when71..100then"Pass with Distinction"else"Invalid Score"end
puts result
This will produce the following result −
Pass with Merit
Ranges as Intervals
A final use of the versatile range is as an interval test: seeing if some value falls within the interval represented by the range. This is done using ===, the case equality operator.
#!/usr/bin/rubyif((1..10)===5)
puts "5 lies in (1..10)"endif(('a'..'j')==='c')
puts "c lies in ('a'..'j')"endif(('a'..'j')==='z')
puts "z lies in ('a'..'j')"end
The Time class represents dates and times in Ruby. It is a thin layer over the system date and time functionality provided by the operating system. This class may be unable on your system to represent dates before 1970 or after 2038.
This chapter makes you familiar with all the most wanted concepts of date and time.
Getting Current Date and Time
Following is the simple example to get current date and time −
#!/usr/bin/ruby -w
time1 =Time.new
puts "Current Time : "+ time1.inspect
# Time.now is a synonym:
time2 =Time.now
puts "Current Time : "+ time2.inspect
This will produce the following result −
Current Time : Mon Jun 02 12:02:39 -0700 2008
Current Time : Mon Jun 02 12:02:39 -0700 2008
Getting Components of a Date & Time
We can use Time object to get various components of date and time. Following is the example showing the same −
#!/usr/bin/ruby -w
time =Time.new# Components of a Time
puts "Current Time : "+ time.inspect
puts time.year # => Year of the date
puts time.month # => Month of the date (1 to 12)
puts time.day # => Day of the date (1 to 31 )
puts time.wday # => 0: Day of week: 0 is Sunday
puts time.yday # => 365: Day of year
puts time.hour # => 23: 24-hour clock
puts time.min # => 59
puts time.sec # => 59
puts time.usec # => 999999: microseconds
puts time.zone # => "UTC": timezone name
This will produce the following result −
Current Time : Mon Jun 02 12:03:08 -0700 2008
2008
6
2
1
154
12
3
8
247476
UTC
Time.utc, Time.gm and Time.local Functions
These two functions can be used to format date in a standard format as follows −
# July 8, 2008Time.local(2008,7,8)# July 8, 2008, 09:10am, local timeTime.local(2008,7,8,9,10)# July 8, 2008, 09:10 UTCTime.utc(2008,7,8,9,10)# July 8, 2008, 09:10:11 GMT (same as UTC)Time.gm(2008,7,8,9,10,11)
Following is the example to get all the components in an array in the following format −
#!/usr/bin/ruby -w
time =Time.new
values = time.to_a
p values
This will generate the following result −
[26, 10, 12, 2, 6, 2008, 1, 154, false, "MST"]
This array could be passed to Time.utc or Time.local functions to get different format of dates as follows −
#!/usr/bin/ruby -w
time =Time.new
values = time.to_a
puts Time.utc(*values)
This will generate the following result −
Mon Jun 02 12:15:36 UTC 2008
Following is the way to get time represented internally as seconds since the (platform-dependent) epoch −
# Returns number of seconds since epoch
time =Time.now.to_i
# Convert number of seconds into Time object.Time.at(time)# Returns second since epoch which includes microseconds
time =Time.now.to_f
Timezones and Daylight Savings Time
You can use a Time object to get all the information related to Timezones and daylight savings as follows −
time =Time.new# Here is the interpretation
time.zone # => "UTC": return the timezone
time.utc_offset # => 0: UTC is 0 seconds offset from UTC
time.zone # => "PST" (or whatever your timezone is)
time.isdst # => false: If UTC does not have DST.
time.utc?# => true: if t is in UTC time zone
time.localtime # Convert to local timezone.
time.gmtime # Convert back to UTC.
time.getlocal # Return a new Time object in local zone
time.getutc # Return a new Time object in UTC
Formatting Times and Dates
There are various ways to format date and time. Here is one example showing a few −
Mon Jun 02 12:35:19 -0700 2008
Mon Jun 2 12:35:19 2008
Mon Jun 02 12:35:19 -0700 2008
2008-06-02 12:35:19
Time Formatting Directives
These directives in the following table are used with the method Time.strftime.
Sr.No.
Directive & Description
1
%aThe abbreviated weekday name (Sun).
2
%AThe full weekday name (Sunday).
3
%bThe abbreviated month name (Jan).
4
%BThe full month name (January).
5
%cThe preferred local date and time representation.
6
%dDay of the month (01 to 31).
7
%HHour of the day, 24-hour clock (00 to 23).
8
%IHour of the day, 12-hour clock (01 to 12).
9
%jDay of the year (001 to 366).
10
%mMonth of the year (01 to 12).
11
%MMinute of the hour (00 to 59).
12
%pMeridian indicator (AM or PM).
13
%SSecond of the minute (00 to 60).
14
%UWeek number of the current year, starting with the first Sunday as the first day of the first week (00 to 53).
15
%WWeek number of the current year, starting with the first Monday as the first day of the first week (00 to 53).
16
%wDay of the week (Sunday is 0, 0 to 6).
17
%xPreferred representation for the date alone, no time.
18
%XPreferred representation for the time alone, no date.
19
%yYear without a century (00 to 99).
20
%YYear with century.
21
%ZTime zone name.
22
%%Literal % character.
Time Arithmetic
You can perform simple arithmetic with time as follows −
now =Time.now # Current time
puts now
past = now -10# 10 seconds ago. Time - number => Time
puts past
future = now +10# 10 seconds from now Time + number => Time
puts future
diff = future - past # => 10 Time - Time => number of seconds
puts diff
This will produce the following result −
Thu Aug 01 20:57:05 -0700 2013
Thu Aug 01 20:56:55 -0700 2013
Thu Aug 01 20:57:15 -0700 2013
20.0
A Hash is a collection of key-value pairs like this: “employee” = > “salary”. It is similar to an Array, except that indexing is done via arbitrary keys of any object type, not an integer index.
The order in which you traverse a hash by either key or value may seem arbitrary and will generally not be in the insertion order. If you attempt to access a hash with a key that does not exist, the method will return nil.
Creating Hashes
As with arrays, there is a variety of ways to create hashes. You can create an empty hash with the new class method −
months = Hash.new
You can also use new to create a hash with a default value, which is otherwise just nil −
months = Hash.new( "month" )
or
months = Hash.new "month"
When you access any key in a hash that has a default value, if the key or value doesn’t exist, accessing the hash will return the default value −
Following are the public hash methods (assuming hash is an array object) −
Sr.No.
Methods & Description
1
hash == other_hashTests whether two hashes are equal, based on whether they have the same number of key-value pairs, and whether the key-value pairs match the corresponding pair in each hash.
2
hash.[key]Using a key, references a value from hash. If the key is not found, returns a default value.
3
hash.[key] = valueAssociates the value given by value with the key given by key.
4
hash.clearRemoves all key-value pairs from hash.
5
hash.default(key = nil)Returns the default value for hash, nil if not set by default=. ([] returns a default value if the key does not exist in hash.)
6
hash.default = objSets a default value for hash.
7
hash.default_procReturns a block if hash was created by a block.
8
hash.delete(key) [or]array.delete(key) { |key| block }Deletes a key-value pair from hash by key. If block is used, returns the result of a block if pair is not found. Compare delete_if.
9
hash.delete_if { |key,value| block }Deletes a key-value pair from hash for every pair the block evaluates to true.
10
hash.each { |key,value| block }Iterates over hash, calling the block once for each key, passing the key-value as a two-element array.
11
hash.each_key { |key| block }Iterates over hash, calling the block once for each key, passing key as a parameter.
12
hash.each_key { |key_value_array| block }Iterates over hash, calling the block once for each key, passing the key and value as parameters.
13
hash.each_key { |value| block }Iterates over hash, calling the block once for each key, passing value as a parameter.
14
hash.empty?Tests whether hash is empty (contains no key-value pairs), returning true or false.
15
hash.fetch(key [, default] ) [or]hash.fetch(key) { | key | block }Returns a value from hash for the given key. If the key can’t be found, and there are no other arguments, it raises an IndexError exception; if default is given, it is returned; if the optional block is specified, its result is returned.
16
hash.has_key?(key) [or] hash.include?(key) [or]hash.key?(key) [or] hash.member?(key)Tests whether a given key is present in hash, returning true or false.
17
hash.has_value?(value)Tests whether hash contains the given value.
18
hash.index(value)Returns the key for the given value in hash, nil if no matching value is found.
19
hash.indexes(keys)Returns a new array consisting of values for the given key(s). Will insert the default value for keys that are not found. This method is deprecated. Use select.
20
hash.indices(keys)Returns a new array consisting of values for the given key(s). Will insert the default value for keys that are not found. This method is deprecated. Use select.
21
hash.inspectReturns a pretty print string version of hash.
22
hash.invertCreates a new hash, inverting keys and values from hash; that is, in the new hash, the keys from hash become values and values become keys.
23
hash.keysCreates a new array with keys from hash.
24
hash.lengthReturns the size or length of hash as an integer.
25
hash.merge(other_hash) [or]hash.merge(other_hash) { |key, oldval, newval| block }Returns a new hash containing the contents of hash and other_hash, overwriting pairs in hash with duplicate keys with those from other_hash.
26
hash.merge!(other_hash) [or]hash.merge!(other_hash) { |key, oldval, newval| block }Same as merge, but changes are done in place.
27
hash.rehashRebuilds hash based on the current values for each key. If values have changed since they were inserted, this method reindexes hash.
28
hash.reject { |key, value| block }Creates a new hash for every pair the block evaluates to true
29
hash.reject! { |key, value| block }Same as reject, but changes are made in place.
30
hash.replace(other_hash)Replaces the contents of hash with the contents of other_hash.
31
hash.select { |key, value| block }Returns a new array consisting of key-value pairs from hash for which the block returns true.
32
hash.shiftRemoves a key-value pair from hash, returning it as a two-element array.
33
hash.sizeReturns the size or length of hash as an integer.
34
hash.sortConverts hash to a two-dimensional array containing arrays of key-value pairs, then sorts it as an array.
35
hash.store(key, value)Stores a key-value pair in hash.
36
hash.to_aCreates a two-dimensional array from hash. Each key/value pair is converted to an array, and all these arrays are stored in a containing array.
37
hash.to_hashReturns hash (self).
38
hash.to_sConverts hash to an array, then converts that array to a string.
39
hash.update(other_hash) [or]hash.update(other_hash) {|key, oldval, newval| block}Returns a new hash containing the contents of hash and other_hash, overwriting pairs in hash with duplicate keys with those from other_hash.
40
hash.value?(value)Tests whether hash contains the given value.
41
hash.valuesReturns a new array containing all the values of hash.
42
hash.values_at(obj, …)Returns a new array containing the values from hash that are associated with the given key or keys.