What is it?
- Ruby is high-level programming language
- It is an interpreted language
- It is a general purpose programming language
- Provides functional programming features (function closures - blocks and procs)
- Supports object-oriented programming (classes and inheritance)
- Strongly typed
- Inspired by Perl, Smalltalk, Lisp, Python
Installation
http://rubyinstaller.org/Documentation
Docs - http://www.ruby-doc.org/docs/ProgrammingRuby/Language Nuances
- Parenthesis are not required when calling methods
- Semicolons not required at the end of each line unless placing multiple statements on a single line
- No abstract classes
- No interfaces.
- Classes allow single class inheritance. However, using mixins, code from another module can be mixed-in and becomes part of the class using the include statement. All the module's instance methods are suddenly available as methods in the class as well.
- Modules define pieces of reusable code (cannot be instantiated)
- Modules have a namespace (to avoid name clashes)
- Variable declaration is not required
- All classes are derived from base class called Class
- No structs
- Supports symbols. :someValue is not a string but rather a symbol. If you are using a string over and over, use a symbol. Uses less memory.
- There is no main method. Ruby code is placed in a text file with extension .rb and is run as a script
- Code can be placed in separate files and included in the main script using require (require 'filename') or load (load 'filename.rb' ) directive. require loads the file once, load loads the file as many times as specified.
- require_relative complements the built-in method require by allowing you to load a file that is relative to the file containing the require_relative statement.
Reflection
- var.class - tells the class of variable (object)
- v.methods - tells the methods of an object
- puts "Type of self = #{self.type}"
- puts "Name of self = #{self.name}"
def who_am_i?
"#{self.class.name} (\##{self.object_id}): #{self.to_s}"
end
Naming
- localVariable
- @instanceVariable
- @@classVariable
- $globalVariable
- Constant
- ClassName
- method_name
- By convention, methods that return a boolean (or answer a question) have a '?' at the end of the method name
- By convention, methods that change the contents of passed in arguments have an '!' at the end of the method name
Comments
Single line start with #
Multiline comments
=begin
my comments
my comments
=end
Running Ruby
- To run interactive Ruby (console), enter irb at OS command prompt
- To run Ruby script, enter ruby filename.rb at at OS command prompt
puts
# add 2 and 3, get 5, apply to_s and print to screenputs 2 + 3 # outputs 5
put 1 > 2 # outputs false
gets
Retrieves a string from keyboard until enter key is pressedputs 'your name please'
name = gets.chomp # chomp removes the carriage return
puts 'hello ' + name
self
self is a special variable which points to whatever object you are in.# we generally omit self when writing puts
self.puts 'some string'
Variables
- All things in Ruby are objects, even puts and gets are part of an implicit class object
- A variable can point to any object
- First letter of var name must be lowercase
- someVar = "abc"
- someVar = 5 * (2 + 1) # holds 15
- var cannot point to other vars; when on variable is assigned to another, the variable being assigned to points to the value of the other variable (i.e. vars point to the value of the first var)
Literals
- even literals are objects. "AnyString".reverse
- "str" * 3 yields "strstrstr"
- 10.reverse yields an error
- "10".to_s.reverse yields "01"
Operators
- = for assignment
- == for testing equality
- != not equal
- > >=
- < <=
- For string comparison, uses lexicographical ordering (upcase or downcase before comparing)
- and
- or
- not
Strings
- buffer['stringtofind'] = 'newstringreplacement'
- buffer.lines.to_a.reverse - turns the buffer into a list of lines. lines decides what to split on and to_a puts the lines into an array. We can use byte and chars instead of lines.
- buffer.lines.to_a.reverse.join collates the array back into a single string
- buffer.include? "somestring" - returns bool whether "somestring" exists. By convention, methods that return a boolean have a '?' at the end
- x.upcase
- concatenation: someStringVar + 'string literal'
- "some string".reverse makes a reversed copy of a string
- "somestring".length
- upcase
- downcase
- capitalize - make first letter upper case
- swapcase - switch case of every letter
- center(lineWidth) - Center the given text within lineWidth
- ljust lineWidth - pad string on left
- rjust (lineWidth) - pad string on right
- to escape single-quote use \'
- variables can be used within quoted string to output their values
str = "Literal #{someVar} #{someConst} other literal #{@someClassInstanceVar}"
Arithematic
- ** exponentiation. 5**2 (five squared), 5**0.5 (square root of 5)
- % modulus
- abs
- rand - a float between 0.0 and 1.0
- rand(100) - an integer between 0 and 99
- to get same sequence of random numbers, seed with a certain value
seed = 400
srand seed
puts (rand(100))
seed = 0 # reset seed
Math object
- Math::PI
- Math::E
- Math.Cos
- Math.tan
- Math.log
- Math.sqrt
Conversion Functions
- to_s
- to_i
- to_f (to float)
- to_a // arrays example: (1..7).to_a returns an array of 1 through 7
var1=2
var2='10'
puts var1.to_s + var2 # 210
puts var1 + var2.to_i # 12
puts 'some string'.to_f # 0.0 since string is not valid float
Arrays
Ruby arrays are zero-based
[] # empty array
anArray = [1, 3, 5, 7]
puts anArray # puts all members
[] # empty array
anArray = [1, 3, 5, 7]
puts anArray # puts all members
[1, 3, 5, 7].min
someAr= [1, 9, 5, 7]
someAr.sort # yields sorted list
# arrays can contained mixed types and can contain other arrays
[1, 'New York', [true, false]]
# array iteration using iterator
cities = ['Chicago', 'New York', 'Los Angeles']
cities.each do |city|
puts 'City: ' + city
end
Array Methods
cities.join(', ') # flatten to string using comma as delimiter
cities.push ' San Diego' # add to city list, changes actual list
cities.pop # get and remove the first element in the array
citites.last # get the last element in the array
# map changes value of the array
str = ["AA", "BB"].map do |s|
s.downcase
end
puts str
#output
#aa
#bb
# does not change the value of original array str = ["AA", "BB"].each do |s|
s.downcase
end
puts str
#output
#AA
#BB
# changes the value of original array
str = ["AA", "BB"].each do |s|
s.downcase!
end
puts str
#output
#aa
#bb
# arrays can contained mixed types and can contain other arrays
[1, 'New York', [true, false]]
# array iteration using iterator
cities = ['Chicago', 'New York', 'Los Angeles']
cities.each do |city|
puts 'City: ' + city
end
Array Methods
- length
- reverse
- +
- *
- join
- sort
- push, pop, last
cities.join(', ') # flatten to string using comma as delimiter
cities.push ' San Diego' # add to city list, changes actual list
cities.pop # get and remove the first element in the array
citites.last # get the last element in the array
# map changes value of the array
str = ["AA", "BB"].map do |s|
s.downcase
end
puts str
#output
#aa
#bb
# does not change the value of original array str = ["AA", "BB"].each do |s|
s.downcase
end
puts str
#output
#AA
#BB
# changes the value of original array
str = ["AA", "BB"].each do |s|
s.downcase!
end
puts str
#output
#aa
#bb
Hash
Can use any object to refer to a slot
aCityDict = {} # same as Hash.new
aCityDict["Chicago"] = "Illinois"
aCityDict["Los Angeles"] = "California"
# iterating through hash
aCityDict.each do |city, state|
puts city + ' is located in the state of ' + state
end
We can even use symbols as keys
We can even use symbols as keys
- dictionary["key"] = :someValue# note the colon before someValue, which is a symbol
- dictionary.length
- dictionary.keys
# creating a hash with multiple entries
fred = {:name => "Fred", :age => 76, : occupation => :janitor }
fred = {:name => "Fred", :age => 76, : occupation => :janitor }
Conditionals
if condition # parenthesis not required in condition# statements
else
# statements
end
# Executes code if conditional is false. If the conditional is true,
# code specified in the else clause is executed.
unless conditional [then]
code
[else
code ]
end
Loops
3.times do
# statements
end
5.times { <statements to execute 5 times> }
5.times do
<statements to execute 5 times>
end
# statements
end
5.times { <statements to execute 5 times> }
5.times do
<statements to execute 5 times>
end
dictionary.values.each {<statements to execute> }
# %w(foo bar) is a shortcut for ["foo", "bar"]
names= %w(Fred Bert Laura Gus Waldo)
names.each { |name| puts name}
# same as above
names.each do |name|
puts name
end
1.upto(8) do |i|
puts i
end
[1, 2, 3, 4, 5].map do |number|
number *2
end
=> [2,4,6,8,10]
[1, 2, 3, 4, 5].map do |number|
number.to_s * 2
end
=> ["11","22","33","44","55"]
while <condition>
# statements
end
while <condition>
# statements
end
Methods
# declaring a method
# method is still associated with an
# object (the entire program object)
def method_name <args>
<local vars>
# statements
# will return nil
# OR whatever is the last line of the method
"some value" # this is returned as the value of the method call
aVar # or return a value held by the variable
end
# invoking
aMethodName <arg1> <arg2>
Method names start with lower case except for operator methods (e.g. +, ==)
def load_data(path)
# method is still associated with an
# object (the entire program object)
def method_name <args>
<local vars>
# statements
# will return nil
# OR whatever is the last line of the method
"some value" # this is returned as the value of the method call
aVar # or return a value held by the variable
end
# invoking
aMethodName <arg1> <arg2>
Method names start with lower case except for operator methods (e.g. +, ==)
def load_data(path)
city_dict = {}
File.foreach(path) do |line|
city, state = line.split(': ')
city_dict [:city] = city
city_dict [:state] = state
city_dict [:state] = state
end
lines
end
# call method
city_dict = load_data(path)
- Method calls can be chained
- Method call with exclamation mark at the end changes the object (i.e. the content of the object) it is applied to
- Method with a ? at the end returns a boolean or answer to a question
Object Orientation
Operators are object methods
# Fixnum is derived from Integer class
class Fixnum < Integer
def + numeric
# + operator for Fixnum can be redefined
end
end
Existing classes can be extended
# Add a new methods square and cube to Numeric class
class Numeric
def square
return self ** 2
end
alias :sqr :square # define another name (alias) for square
def cube
return self ** 3
end
end
2.sqr # 4
2.sqr # 4
Class
- The :: is a unary operator that allows: constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module.
anArray = Array.new # or anArray = []
aString = String.new # or aString =''
aTime = Time.new
someTime = Time.makeTime(2013, 8, 8)
# declare a class
class <classname> < <superclass>
# attr_accessor is method to define attributes of a class
attr_accessor :title, :time, :fulltext, :mood
def initialize( title, mood, fulltext )
# use @ to access instance vars
@time = Time.now
@title, @mood, @fulltext = title, mood, fulltext
end
end
# using a class
class_instance= <classname>.new
# use with initialize method
class_instance= <class_name>.new(<args>")
# Extending an existing class
class Integer
def to_BinaryStr
# Convert to binary representation given an integer
# logic to calculate binStr
puts self # self refers to the integer object
binStr # return value
end
end
# overriding methods
can redefine to_s to do different formatting for Integer class
# create our own class
class MyClass < <superclass>
CONST = "some const"
# getter and #setter
attr_accessor :accVar1, : accVar2
# getter only
attr_reader : accVar3
#setter only
attr_writer :accVar4
# instance variable get accessor (old school)
def ClassIntanceVariableAccessor
@myClassInstanceVariable
end
# instance variable setter (old school)
def accVar5= accVar5
@accVar5 = accVar5
end
def initialize
# Initialize state of the object
end
def classMethod
# statements
@myClassInstanceVariable = someValue
exit # exit/return immediately
end
# invoked using MyCall.class_method
def MyClass.class_method # class method
# code for class method
end
# cannot be called with an explicit receiver. Because you cannot
# specify an object when using them, private methods can be
# called only in the defining class and by direct
# descendents within that same object.
private
def privateClassMethod
# statements
@myClassInstanceVariable = someValue
end
# Can be invoked only by objects of the
# defining class and its subclasses.
# Access is kept within the family.
protected
end
# passing a block into a method for execution without have to assign to a variable
class Array
def eachNonNil(blockOfCodeToExecute)
# iterate through all members
self.each do |object|
if (object != nil)
blockOfCodeToExecute.call object
end
end
end
end # class
print = Proc.new do |x|
puts x.to_s
end
# print out non-nil members
x = [1, nil, 2, 3, nil]
x.eachNonNil print
# Code profiling, &codeBlock accepts a do..end code block
def profileCode codeBlockName, &codeBlock
startTime = Time.now
codeBlock.call
duration = Time.now - startTime
puts codeBlockName+': '+duration.to_s+' seconds'
end
profileCode "Factorial of 6" do 6.downto(1).inject(:*) end
module Mycompany
module AppName
module LibName
def LibName.MethodName arg
# code
end
class <classname>
#code
end
end
end
end
To use:
include Mycompany::AppName
LibName.MethodName arg
Example:
### citymodule.rb
module CityModule
def CityModule.load_city_data
# code
puts 'hello from module'
end
end
### main
require_relative 'CityModule'
city_dict = CityModule.load_city_data
class Integer
def to_BinaryStr
# Convert to binary representation given an integer
# logic to calculate binStr
puts self # self refers to the integer object
binStr # return value
end
end
# overriding methods
can redefine to_s to do different formatting for Integer class
# create our own class
class MyClass < <superclass>
CONST = "some const"
# getter and #setter
attr_accessor :accVar1, : accVar2
# getter only
attr_reader : accVar3
#setter only
attr_writer :accVar4
# instance variable get accessor (old school)
def ClassIntanceVariableAccessor
@myClassInstanceVariable
end
# instance variable setter (old school)
def accVar5= accVar5
@accVar5 = accVar5
end
def initialize
# Initialize state of the object
end
def classMethod
# statements
@myClassInstanceVariable = someValue
exit # exit/return immediately
end
# invoked using MyCall.class_method
def MyClass.class_method # class method
# code for class method
end
# cannot be called with an explicit receiver. Because you cannot
# specify an object when using them, private methods can be
# called only in the defining class and by direct
# descendents within that same object.
private
def privateClassMethod
# statements
@myClassInstanceVariable = someValue
end
# Can be invoked only by objects of the
# defining class and its subclasses.
# Access is kept within the family.
protected
end
Closures - Blocks and Procs
- Given a block of code (do.. end)
- Wrap it in a proc object
- Can stored into a variable or passed as method argument
- Execute proc object at will
- Block of code is an object
- Method cannot be passed to another method but proc can be passed as an argument
- Methods cannot be returned from another method but proc can be
aVar = Proc.new do |arg|
# statements
end
# to execute
aVar.call <arg>
# passing proc into a method
def receiverMethod aProc
# statements
aProc.call
#statements
end
# define the proc
aProc = Proc.new do
# statements
puts 'hello'
puts 'hello'
end
# execute the receiver method
receiverMethod aProc
# currying - using proc returned to compose methods
# proc that composes the passed in methods on the argument supplied
def compose p1, p2
# return a proc (i.e. do not execute the code below immediately)
# lazy evaluation
Proc.new do |x| # the returned proc will accept on arg
p2.call(p1.call(x))
end
end
# first proc
p1 = Proc.new do |x|
x - 100
end
# second proc
p2 = Proc.new do |x|
x.abs
end
# variable to store the composed proc
composeProc = compose p1 p2
# execute the proc
composeProc.call 50
# passing a block into a method for execution without have to assign to a variable
class Array
def eachNonNil(blockOfCodeToExecute)
# iterate through all members
self.each do |object|
if (object != nil)
blockOfCodeToExecute.call object
end
end
end
end # class
print = Proc.new do |x|
puts x.to_s
end
# print out non-nil members
x = [1, nil, 2, 3, nil]
x.eachNonNil print
# Code profiling, &codeBlock accepts a do..end code block
def profileCode codeBlockName, &codeBlock
startTime = Time.now
codeBlock.call
duration = Time.now - startTime
puts codeBlockName+': '+duration.to_s+' seconds'
end
profileCode "Factorial of 6" do 6.downto(1).inject(:*) end
Modules
- Act as namespaces
- Allow sharing of code amongst classes
module Mycompany
module AppName
module LibName
def LibName.MethodName arg
# code
end
class <classname>
#code
end
end
end
end
To use:
include Mycompany::AppName
LibName.MethodName arg
Example:
### citymodule.rb
module CityModule
def CityModule.load_city_data
# code
puts 'hello from module'
end
end
### main
require_relative 'CityModule'
city_dict = CityModule.load_city_data
Mixins
- Include a module within a class definition
- All the module's instance methods are suddenly available as methods in the class as well
- Mixed-in modules effectively behave as superclasses
- Include takes the name of a module, in the form of a constant, include method accepts any number of Module objects to mix
class <class_name>
include modulename
# ...
end
File System
Dir.entries "/"
"/" is an argument to the method; in Ruby argument is called an attachment
List only text files ([ ] below is like entries method above)
Dir["/*.txt"]
print File.read("/data/x.txt")
FileUtils.cp('/data/x.txt', '/Home/x.txt')
# open file in append mode
File.open("/Home/data.txt", "a") do |f|
# add data to file
f << "News http://cnn.com/"
# read file content
print File.read("/Home/data.txt")
# file change time
File.mtime("/Home/data.txt")
File.mtime("/Home/data.txt").hour