Ruby: Learn Ruby in 1 Hour
This is a Ruby tutorial. I assume you already know a scripting language well. (e.g. Python, PHP, JavaScript, etc) This intro is designed to quickly get you started. After reading, you should be able to use standard documentation.
Ruby has a interactive command line. In terminal, type irb
.
To find your Ruby version, type ruby --version
This tutorial is based on Ruby 2. Version 2 is compatible with 1.9.x. But Ruby 1.9 is NOT compatible with Ruby 1.8.
[see Ruby Version Release Dates]
If you don't have Ruby installed, see:
Printing
Print Ruby Version
# -*- coding: utf-8 -*- # Ruby # print Ruby version from within Ruby script p RUBY_VERSION # "1.9.73"
Save the above in a file test.rb
. Run it in terminal like this: ruby test.rb
.
For emacs users, install this function to run Ruby file in emacs: Emacs Lisp: Execute/Compile Current File .
To print, use p
, puts
, print
.
# -*- coding: utf-8 -*- # ruby a = 5 b = "rabbit" p a, b, 3 # prints each on a new line. =begin this is a multi-line comment p a, b, 3 can be written as p(a, b, 3) parenthesis are often not necessary =end
What is the difference between {puts, print, p}?
puts
prints in a human readable form, and adds newline after each argument. For example, string is printed without quotes, array are printed without the brackets or separators.print
is similar to “puts” but does not add newline.p
prints in a technical form. For example, string will include the quotes. This is good for debugging.
What does newline or indentation mean in Ruby?
- Newline or Semicolon is used to separate expressions.
p(3);
is the same asp(3)
on a line by itself. - Indentation (tabs or spaces) has no meaning.
- Parentheses for function/method's arguments are often optional (similar to Perl). For example,
p(3)
is the same asp 3
.
Strings
Single Quote for Literal String
Use single quote to quote string exactly. (literal string). \n
has no special meaning inside single quote.
# -*- coding: utf-8 -*- # ruby aa = 'cat' # single quote for literal string p aa # prints 「"cat"」 bb = '4\n5' p bb # prints 「"4\\n5"」 in one single line. # single quoted string containing newline or tab will be printed as they are cc = '1 2' p cc # prints 「"1\n2"」
(Perl tip: Ruby's string quoting system is similar to Perl's. [see Perl: Quoting Strings])
Double Quote String to Evaluate Embedded Variable and Ruby Code
Use double quote for strings that contain newline escape \n
, or include variable values or Ruby code.
# -*- coding: utf-8 -*- # ruby mm = "cat\nsnake" puts mm # prints each word in separate line
You can use \n
for newline, and \t
for tab, etc.
To evaluate a variable or Ruby code within a string, use #{…}
.
# -*- coding: utf-8 -*- # ruby # put variable value inside a string aa = 4 bb = "there are #{aa} cats" p bb # prints “there are 4 cats” # eval Ruby code inside a string p "there are #{1+2} cats" # prints “there are 3 cats”
Quoting Chunk of Text
See: Ruby: Quote Long String, Heredoc .
String Length
Use method length
to get number of character in string.
# -*- coding: utf-8 -*- # ruby "2831".length # 4
Get Substring
Get substring.
# -*- coding: utf-8 -*- # ruby # get one character p "abcdefg"[2] # c # string can contain Unicode p "α♥β"[1] # ♥ # get substring, start at index 2, get 3 chars p "abcdefg"[2, 3] # cde
[see Ruby: Unicode Tutorial 💎]
String Manipulation
String join.
# -*- coding: utf-8 -*- # ruby # string join. Use + p "aa" + "bb" # aabb
Replacing substring.
# -*- coding: utf-8 -*- # ruby # replacing string xx = "0123456789" xx[1]= "a" p xx # "0a23456789" # start at index 1, replace 8 chars xx[1,8]= "what" p xx # "0what9"
Simple string matching.
# -*- coding: utf-8 -*- # ruby # get the start index of a substring p "in love?".index("love") # 3 p "in love?".index("456") # nil (not found)
Split a string into a array.
# -*- coding: utf-8 -*- # ruby p "once upon a time".split(" ") # ["once", "upon", "a", "time"]
Numbers and String Conversion
Ruby does not automatically convert between strings and integers.
Each string or number object has methods to convert to other types.
# -*- coding: utf-8 -*- # ruby # string to int p "3".to_i # 3 # string to float p "3".to_f # 3.0
# -*- coding: utf-8 -*- # ruby # int to string p 3.to_s # "3" # int to float p 3.to_f # 3.0
# -*- coding: utf-8 -*- # ruby # float to string p 3.0.to_s # "3.0" # float to int p 3.0.to_i # 3
WARNING: decimal number such as 3.
must be written with 0 at end, like this 3.0
, because dot is used for method call.
# -*- coding: utf-8 -*- # ruby # decimal number must end with dot and digit p 5/2 # 2 p 5/2.0 # 2.5 p 5/2. # syntax error, unexpected end-of-input, expecting '('
Everything is a Object; Finding Object's Methods
In Ruby, practically everything is a “Object” in the sense of Object Oriented programing (OOP). Even numbers and strings are objects. What this effective means is that for any “thing” in Ruby, you can append it with .name
where the name is a method (function).
For example, 3
is a thing in Ruby. So, it has many methods, for example: to_i
(convert to integer), to_s
(convert to string), and you can call it like this: 3.to_i
.
To find the methods of a thing, use the method methods
. Example:
# -*- coding: utf-8 -*- # ruby # methods for a integer object p 5.methods # [:to_s, :-@, :+, :-, :*, :/, :div, :%, :modulo, :divmod, :fdiv, :**, :abs, :magnitude, :==, :===, :<=>, :>, :>=, :<, :<=, :~, :&, :|, :^, :[], :<<, :>>, :to_f, :size, :zero?, :odd?, :even?, :succ, :integer?, :upto, :downto, :times, :next, :pred, :chr, :ord, :to_i, :to_int, :floor, :ceil, :truncate, :round, :gcd, :lcm, :gcdlcm, :numerator, :denominator, :to_r, :rationalize, :singleton_method_added, :coerce, :i, :+@, :eql?, :quo, :remainder, :real?, :nonzero?, :step, :to_c, :real, :imaginary, :imag, :abs2, :arg, :angle, :phase, :rectangular, :rect, :polar, :conjugate, :conj, :between?, :nil?, :=~, :!~, :hash, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
# -*- coding: utf-8 -*- # ruby # methods for a string object p "rabbit".methods # [:<=>, :==, :===, :eql?, :hash, :casecmp, :+, :*, :%, :[], :[]=, :insert, :length, :size, :bytesize, :empty?, :=~, :match, :succ, :succ!, :next, :next!, :upto, :index, :rindex, :replace, :clear, :chr, :getbyte, :setbyte, :byteslice, :to_i, :to_f, :to_s, :to_str, :inspect, :dump, :upcase, :downcase, :capitalize, :swapcase, :upcase!, :downcase!, :capitalize!, :swapcase!, :hex, :oct, :split, :lines, :bytes, :chars, :codepoints, :reverse, :reverse!, :concat, :<<, :prepend, :crypt, :intern, :to_sym, :ord, :include?, :start_with?, :end_with?, :scan, :ljust, :rjust, :center, :sub, :gsub, :chop, :chomp, :strip, :lstrip, :rstrip, :sub!, :gsub!, :chop!, :chomp!, :strip!, :lstrip!, :rstrip!, :tr, :tr_s, :delete, :squeeze, :count, :tr!, :tr_s!, :delete!, :squeeze!, :each_line, :each_byte, :each_char, :each_codepoint, :sum, :slice, :slice!, :partition, :rpartition, :encoding, :force_encoding, :valid_encoding?, :ascii_only?, :unpack, :encode, :encode!, :to_r, :to_c, :>, :>=, :<, :<=, :between?, :nil?, :!~, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
# -*- coding: utf-8 -*- # ruby xx = [3,4,5] # array # methods for a array object p xx.methods # [:inspect, :to_s, :to_a, :to_ary, :frozen?, :==, :eql?, :hash, :[], :[]=, :at, :fetch, :first, :last, :concat, :<<, :push, :pop, :shift, :unshift, :insert, :each, :each_index, :reverse_each, :length, :size, :empty?, :find_index, :index, :rindex, :join, :reverse, :reverse!, :rotate, :rotate!, :sort, :sort!, :sort_by!, :collect, :collect!, :map, :map!, :select, :select!, :keep_if, :values_at, :delete, :delete_at, :delete_if, :reject, :reject!, :zip, :transpose, :replace, :clear, :fill, :include?, :<=>, :slice, :slice!, :assoc, :rassoc, :+, :*, :-, :&, :|, :uniq, :uniq!, :compact, :compact!, :flatten, :flatten!, :count, :shuffle!, :shuffle, :sample, :cycle, :permutation, :combination, :repeated_permutation, :repeated_combination, :product, :take, :take_while, :drop, :drop_while, :pack, :entries, :sort_by, :grep, :find, :detect, :find_all, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :min, :max, :minmax, :min_by, :max_by, :minmax_by, :member?, :each_with_index, :each_entry, :each_slice, :each_cons, :each_with_object, :chunk, :slice_before, :nil?, :===, :=~, :!~, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
Method name ending in “!” means it changes the variable's value. For example,
myArray.reverse
returns a reversed array,
myArray.reverse!
also changes the variable myArray.
Methods ending in “?” means it returns true
or false
. (aka “predicate function”.)
Variables
In Ruby, variables do not need declaration. Variable does not have a type. Values do have type. The type is the class they belong to.
Finding the type of a value.
# -*- coding: utf-8 -*- # ruby p 5.kind_of?(Integer) # true. The “kind_of?” is a method. p 5.class # Fixnum p "5".class # String p [3,4,5].class # Array p true.class # TrueClass p false.class # FalseClass p nil.class # NilClass
Variable Name Prefix and Variable Scope
- Ruby has 4 variable scopes: {local, global, instance, class}.
- Variable name's first character determines its scope.
Starting Symbol | Explanation |
---|---|
a…z or _ | lower case = local variable |
A…Z | upper case = Constant |
$ | global variable |
@ | instance variable (of a class in OOP) |
@@ | class variable (of a class in OOP) |
# -*- coding: utf-8 -*- # ruby a = 3 $a = 4 @a = 5 @@a = 6 p defined?(a) # "local-variable" p defined?($a) # "global-variable" p defined?(@a) # "instance-variable" p defined?(@@a) # "class variable"
Constants starts with a capital letter. This is enforced by Ruby interpreter. However, Ruby actually allows you to redefine a constant. When you do so, it gives a warning.
# -*- coding: utf-8 -*- # ruby C2 = 5 # constant C2 = 6 # warning: already initialized constant C2 p C2 # prints 6
Predefined Global Variables
Variable Name | Variable Value |
---|---|
$0 | name of the Ruby script file currently executing |
$* | command line arguments used to invoke the script. (a array) |
$$ | Ruby process ID |
$? | exit status of last executed child process |
There are many more. For complete list, see: Ruby: List of Predefined Global Variables
True, False
true
and false
are builtin objects.
The following evaluates to false:
false
nil
Everything else evaluates to true
(including zero, empty string, empty array.).
Conditional: if then else
Simple “if then”.
# -*- coding: utf-8 -*- # ruby xx = 4 if xx > 0 then p 1 end # prints 1 # formatted in multiple lines if xx > 0 then p 1 end # prints 1
“if then else”.
# -*- coding: utf-8 -*- # ruby xx = 4 if xx > 0 then p 1 else p 0 end # prints 1
Multilpe “else”.
# -*- coding: utf-8 -*- # ruby xx = 4 # multiple “else if” if xx > 4 then p 1 elsif xx < 4 then p 0 elsif xx == 4 then p "yy" end # prints "yy" # formatted in another way if xx > 4 then p 1 elsif xx < 4 then p 0 elsif xx == 4 then p "yy" end # prints "yy" # formatted in one line if xx > 4 then p 1 elsif xx < 4 then p 0 elsif xx == 4 then p "yy" end # prints "yy"
“if” construct is also a expression. It returns the value of the last line of the block executed.
# -*- coding: utf-8 -*- # ruby xx = 4 p(if xx > 0 then 1 end) # prints 1 p(if xx > 0 then 1 else 0 end) # prints 1 p( if xx > 4 then 1 elsif xx < 4 then 0 elsif xx == 4 then "yes" end ) # prints "yes" # short form p( xx > 2 ? 1 : 0) # prints 1
“everything” in Ruby is a expression. They return a value.
Using “case”. (in other languages, it's also known as {which, switch, cond})
# -*- coding: utf-8 -*- # ruby xx = 3 myResult = case xx when 1 then "one" when 2 then "two" when 3 then "three" when 3 then "four" else "cat" end p myResult # “three”
“case” construct is also a expression. It returns a value.
Loop, Iteration
“for” loop.
# -*- coding: utf-8 -*- # ruby for ii in 0..4 do p ii end # prints 0 to 4
Nested “for” loop.
# -*- coding: utf-8 -*- # ruby for ii in 1..2 do for jj in 1..3 do puts "#{ii}, #{jj}" end end # prints # 1, 1 # 1, 2 # 1, 3 # 2, 1 # 2, 2 # 2, 3 # can also be written in one line. for ii in 1..2 do for jj in 1..3 do puts "#{ii}, #{jj}" end end
“while” loop.
# -*- coding: utf-8 -*- # ruby ii = 1 while ii < 9 do puts ii; if ii == 5 then break end ii += 1 end # prints 1 to 5
Semicolon can be replaced by newline.
Creating a range. Use (1..5).to_a
. This creates a array with elements 1 to 5.
# -*- coding: utf-8 -*- # ruby a = (1..5).to_a # “to_a” converts to array p a # [1, 2, 3, 4, 5]
# -*- coding: utf-8 -*- # ruby p (1..5).class # Range # methods for the range p (1..5).methods # [:==, :===, :eql?, :hash, :each, :step, :begin, :end, :first, :last, :min, :max, :to_s, :inspect, :exclude_end?, :member?, :include?, :cover?, :to_a, :entries, :sort, :sort_by, :grep, :count, :find, :detect, :find_index, :find_all, :select, :reject, :collect, :map, :flat_map, :collect_concat, :inject, :reduce, :partition, :group_by, :all?, :any?, :one?, :none?, :minmax, :min_by, :max_by, :minmax_by, :each_with_index, :reverse_each, :each_entry, :each_slice, :each_cons, :each_with_object, :zip, :take, :take_while, :drop, :drop_while, :cycle, :chunk, :slice_before, :nil?, :=~, :!~, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
List/Array
Creating a array.
# -*- coding: utf-8 -*- # ruby # creating a array aa = [3, "four",5] p aa # prints [3, "four", 5] # another way bb = Array.new(3) p bb # prints [nil, nil, nil] # create array of 3 elements, with value of 1 cc = Array.new(3,1) p cc # prints [1, 1, 1] # array can be nested aa = [0, 1, 2, ["8", 9], 3]
Counting elements:
# -*- coding: utf-8 -*- # ruby aa = [3, "four",5] p aa.length # 3
Getting a element.
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2, 3, "four", 5, [6, 8], 7] p aa[0] # 0 p aa[-1] # 7 p aa[6] # [6, 8] p aa[6][0] # 6
Finding the index of a element.
# -*- coding: utf-8 -*- # ruby aa = [3, "four",5] p aa.index("four") # 1 p aa.index("7") # nil
Extracting a sequences of elements.
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2, 3, "four", 5, 6, 7] # starting at index 3, get 2 elements p aa[3, 2] # [3, "four"]
Modify a element.
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2, 3, "four"] aa[1] = "one" p aa # [0, "one", 2, 3, "four"]
Adding element into array.
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2] p aa.insert(1,"b") # [0, "b", 1, 2] p aa # [0, "b", 1, 2]
Appending a element.
# -*- coding: utf-8 -*- # ruby # appending to array aa = [0, 1] aa << 2 p aa # [0, 1, 2] aa << [5, 6] p aa # [0, 1, 2, [5, 6]]
Removing Element.
# -*- coding: utf-8 -*- # ruby aa = [0, "b", 2] aa.delete_at(1) # "b" p aa # [0, 2]
push and pop. (append or remove a element from the end.)
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2] # add a element to the end p aa.push("a") # [0, 1, 2, "a"] # original array also changed p aa # [0, 1, 2, "a"] # pop removes the last element, and returns that p aa.pop # "a" p aa # [0, 1, 2]
Join 2 arrays.
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2, 3] bb = ["four", 5] p aa + bb # [0, 1, 2, 3, "four", 5]
Array Union, Intersection, Difference
# -*- coding: utf-8 -*- # ruby aa = [0, 8, 7, 3, 1] bb = [3, 4] # difference p aa - bb # [0, 8, 7, 1] # intersection p aa & bb # [3] # union p aa | bb # [0, 8, 7, 3, 1, 4]
Get uniq elements.
# -*- coding: utf-8 -*- # ruby aa = [0, 7, 3, 7] # uniq p aa.uniq # [0, 7, 3] # original array not modified p aa # [0, 7, 3, 7] # uniq, modify original array aa.uniq! p aa # [0, 7, 3]
Sorting array.
# -*- coding: utf-8 -*- # ruby aa = [0, 4, 2] aa.sort # [0, 2, 4] # original not changed p aa # [0, 4, 2] # change original aa.sort! # [0, 2, 4] p aa # [0, 2, 4]
Array Comparison
# -*- coding: utf-8 -*- # ruby aa = [0, 1, 2] bb = [0, 1, 2.0] cc = [0, 1, "2"] # check if 2 arrays are the same (ignores type.) p aa == bb # true p aa == cc # false # check if 2 arrays are the same, and each element has the same type p aa.eql?(bb) # false
Hash Table
(aka key/value list, Dictionary)
#-*- coding: utf-8 -*- # ruby # define a keyed list hh = {:john => 3, :mary => 4, :joe => 5, :vicky => 7} p hh # {:john=>3, :mary=>4, :joe=>5, :vicky=>7} # getting value from a key p hh[:mary] # 4 # add a entry hh[:pretty] = 99 p hh # {:john=>3, :mary=>4, :joe=>5, :vicky=>7, :pretty=>99} # delete a entry hh.delete :vicky p hh # {:john=>3, :mary=>4, :joe=>5, :pretty=>99} # get all keys p hh.keys # [:john, :mary, :joe, :pretty] # get all values p hh.values # [3, 4, 5, 99] # check if a key exists p hh.has_key? :mary # true p hh.has_value? :jenny # false
In Ruby, :something
is a “symbol”. It's similar to lisp's symbol. For practical purposes, you can think of it as a static string. Whenever you need to use a string as a label that doesn't change, you should use symbol instead, because it's more efficient.
In the above example, you could replace all symbols by string. example
#-*- coding: utf-8 -*- # ruby # hash, with keys as string aa = {'john' => 3, 'mary' => 4, 'joe' => 5} # hash, with keys as symbol. bb = {:john => 3, :mary => 4, :joe => 5} # using symbol is more efficient, because each string is a full object
In Ruby, “everything” is a object. So, creating a string creates a object, which often means it's slow. So, the “symbol” datatype is a solution for that.
Looping thru Array/Hash
…
Calling Unix Shell Command
Use backticks `…`
to call shell commands.
# -*- coding: utf-8 -*- # ruby # call unix commands puts `ls -Al ~` # list home dir =begin prints the following total 4786 -rw-------+ 1 h3 None 27264 Nov 30 15:48 .bash_history -rwx------+ 1 h3 None 403 Nov 30 15:48 .bashrc -rwx------+ 1 h3 None 285 Nov 18 22:57 .emacs … =end
Using Library
…
Defining a Function
The following is a example of defining a function.
# -*- coding: utf-8 -*- # ruby def f 3 end puts f
The keyword “return” can be used to return value and exit code. Else, the last expression of a function definition is its returned value.
# -*- coding: utf-8 -*- # ruby def f(x) x+1 end puts f(4) # prints 5
# -*- coding: utf-8 -*- # ruby # function with default value def f(x = 3) x+1 end puts f # prints 4
# -*- coding: utf-8 -*- # ruby # example of defining a function with unspecified number of parameters def ff(*xx) xx.each {|string| puts string} end ff(3,4,5)
Classes and Objects
Defining a class. Class name should start with a capital letter.
# -*- coding: utf-8 -*- # ruby # Object example class Xyz # initializer def initialize(ii) @xx = ii # @xx is a instance variable end # a method. Return the instance variable @xx def mm @xx end # a another method. def nn(aa) @xx + aa end end # create a object. myobj = Xyz.new(3) # call a method p myobj.mm # 3 # call another method with argument p myobj.nn(2) # 5
Instance variable must be accessed by methods only. You must define methods to get instance variable's value, or change it. (this is different from Java or Python.)
- “Instance Variable” are variables such that each object has a different copy. Changing one variable in one object doesn't change that variable's value in another object. Name of instance variables must start with
@
. - “Class Variable” are variables such that all objects share one single copy of the variable. Name of class variables must start with
@@
.
Writing a Module
# -*- coding: utf-8 -*- # ruby # Module name must start with Capital letter module Xyz # … end