Ruby Crash Course
In 2015, I created a web app using Ruby on Rails. My reasons are Ruby was fast and Rails was robust. Of course, there are other benefits such as the syntax being simple and easy to learn.
Today, many people think that Ruby is dead. For example, people like to start web applications with NodeJS or GoLang. Maybe I agree with that statement. But Ruby was in a lot of legacy projects. Sometimes, tweaking a feature is cheaper than revamping the entire system with the new language.
Let's simplify this course like Ruby. I hope this article can help you learn Ruby in no time or warm up your existing Ruby skills.
Installation
In development, the best way to install Ruby is by using a Ruby manager. There are a lot of Ruby managers out there but I recommend Ruby Version Manager (RVM). For Windows, you can try rbenv.
Ruby Version Manager (RVM)
-
gpg2 --keyserver keyserver.ubuntu.com --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
- In macOS, you can replace
gpg2
withgpg
. But make sure you install it first,brew install gnupg
. - If you failed at this command, I recommend you download and install GPG keys manually. Sorry, I didn't give the commands or clear instructions here because there are a lot of ways to do that. Maybe https://rvm.io/rvm/install can help.
- In macOS, you can replace
-
\curl -sSL https://get.rvm.io | bash -s stable
- We don't need
--rails
here. We can install Rails later by usinggem install rails
.
- We don't need
rvm list
is to list available Ruby.rvm install ruby-3.3.1
to install Ruby 3.3.1 for example. Now, you can install multiple versions of Ruby on your local.rvm use 3.3.1
to use it. You can add~/.rvm/gems/ruby-3.3.1/bin
to your path to make it permanent.
Variables
number = 9
decimal = 9.99
hello1 = "Hello!"
hello2 = 'Hello!'
is_active = false
not_is_active = !is_active
Variables in String
name = "John Doe"
hello = "Hello #{name}!"
Comments
# I am a comment.
=begin
We are comments.
We are comments.
We are comments.
=end
Operations
Arithmetic
puts 1 + 1 # 2
puts 2 - 1 # 1
puts 2 / 1 # 1
puts 2 * 2 # 4
puts 2 ** 3 # 8
puts 4 % 2 # 0
Bitwise
puts ~7 # 8
puts 5 & 3 # 1
puts 5 | 3 # 7
puts 5 ^ 3 # 6
puts 4 >> 1 # 2
puts 4 << 1 # 8
Control
if score >= 100
puts "Perfect!"
elsif score >= 80
puts "Good!"
elsif score >= 70
puts "Okay."
else
puts "Sad..."
end
puts score >= 70 ? "Passed!" : "Not qualified!"
puts "Congratulations!" if score >= 70
unless score >= 70
puts "Try again!"
end
There is unless
in Ruby. In the example above, unless the score is >= 70 then you can avoid "Try again!".
Case
case grade
when "A"
puts "Very good!"
when "B"
puts "Good!"
else
puts "Not qualified!"
end
The case
is just like the switch
in other programming languages.
Comparison
puts 1 > 2 # false
puts 1 < 2 # true
puts 2 >= 2 # true
puts 2 <= 2 # true
puts 1 == 2 # false
puts 1 <=> 2 # -1
puts 2 <=> 2 # 0
puts 3 <=> 2 # 1
The <=>
is the comparison syntax in Ruby. It returns the integer. It returns lower than 0 if the first operand is less than the second. It returns greater than 0 if the first operand exceeds the second. The syntax is useful when sorting.
Looping
for i in 1..3
print i # 123
end
i = 1
while i <= 3 do
print i # 123
i += 1
end
(1..3).each do |i|
print i # 123
end
i = 1
loop do
print i # 123
i += 1
break if i > 3
end
i = 1
until i == 3 do
print i # 12
i += 1
end
(1...3).each do |i|
print i # 12
end
3.times do
print "ha" # "hahaha"
end
As we can see, there is a lot of syntax in Ruby for looping.
- The
loop
will loop forever if we don'tbreak
it. - The
until
has the same result with1...3
. They will not print to 3. - The integer with
times
is looping until the integer times.
Next
for i in 1..8
next if i % 2 == 1
print i # 2468
end
The next
is just like the continue
in other programming languages. We skip the iteration when found the condition.
Collection
numbers = [1, 2, 3, 4, 5]
unrestricted = [1, 2.3, true, "Hello", 'World!']
number.push(6)
unrestricted << 6
Sorting
|
|
- On line 2, we already sorted the
numbers
, but thenumbers
are still the same. We can see the result on line 3. - On line 4, we sorted the
numbers
, then they are sorted. That is because of the!
syntax. That means we assigned the new value to the existing variable. We can see the result on line 5. - On line 6, we added a block to the
sort
method to sort in reversed order, using the<=>
syntax.
Hash
map = {
"a" => 1,
"b" => 2,
"c" => 3
}
set = {
1 => true,
2 => false,
3 => true
}
start = {}
same_start = Hash.new
That is called Hash in Ruby. We can make a Map or Set from Hash. To create an empty hash is with {}
or Hash.new
.
Default
m = Hash.new(9)
puts m["a"] # 9
The difference between {}
and Hash.new
is we can set the default with Hash.new
.
Symbol
map = {
:a => 1,
:b => 2,
:c => 3
}
It is better to use symbols for hashes. It can make your program faster.
Accessing
numbers = [1, 2, 3]
map = {
:a => 1,
:b => 2,
:c => 3
}
puts numbers[1] # 2
puts map[:b] # 2
We need brackets to access the element whether it is array or hash.
Key and Value
map = {
:a => 1,
:b => 2,
:c => 3
}
map.each { |k, v| puts "#{k}: #{v}" }
map.each_key { |k| print k } # abc
map.each_value { |v| print v } # 123
Select
map = {
:a => 1,
:b => 2,
:c => 3
}
puts map.select { |_, v| v % 2 == 0 } # {:b=>2}
We can filter the hash by using select
.
Method
def power(number, value)
return number ** value
end
def hello
"Hello, world!"
end
puts power(2, 3) # 8
puts hello # "Hello, world!"
The hello
function above was returning "Hello, world!"
even without return
.
Splat
def count(*numbers)
numbers.each { |number| puts number }
end
def single_count(numbers)
numbers.each { |number| puts number }
end
count(1, 2, 3)
single_count([1, 2, 3])
With Splat, *
, we can put many arguments to the method.
def count(*numbers)
a, b = *numbers
puts a, b
end
count(1, 2, 3)
But, with Splat, we also can take how many arguments we need.
Yield
def ac
print "a"
yield
print "c"
end
ac { print "b" } # abc
Proc vs Lambda
def proc_method
demo = Proc.new { return "Printed" }
demo.call
return "Not printed"
end
def lambda_method
demo = lambda { return "Not printed" }
demo.call
return "Printed"
end
puts proc_method
puts lambda_method
The results are the same. The difference is that proc_method
returns the result of the Proc, not the method, and lambda_method
returns the result of the method, not the Lambda.
Object-Oriented Programming
class Animal
def initialize(name, feets, has_paws)
@name = name
@feets = feets
@has_paws = has_paws
end
protected
attr_accessor :name
attr_accessor :feets
attr_accessor :has_paws
public
def print
puts "#{@name} has #{@feets} feets."
puts "#{@name} has paws." if @has_paws
end
end
class Monster < Animal
def initialize(name, feets, has_paws, abilities)
super(name, feets, has_paws)
@abilities = abilities
end
public
def print
puts "#{@name} is a monster!!!"
puts "#{@name} has:"
@abilities.each do |ability|
puts "- #{ability}"
end
end
end
monster = Monster.new("Dragon", 4, true, ["Nuclear blast", "Ice smoke"])
monster.print()
That is my common OOP example, Animal and Monster.
- Inheritance comes with
<
. - The
initialize
is to define the constructor. - Class variables are with
@
. attr_accessor
is to create a getter and setter. For example, we canyour_variable.name = "Whatever Name"
set it and putsyour_variable.name
to get it.
class Animal
@@counter = 0
def initialize(name, feets, has_paws)
@name = name
@feets = feets
@has_paws = has_paws
end
def print
@@counter += 1
puts "#{@name} has #{@feets} feets."
puts "#{@name} has paws." if @has_paws
end
def self.printed
@@counter
end
end
dog = Animal.new("Scooby", 4, true)
dog.print
puts Animal.printed
We can define a class variable with double @
. So, class variables are attached to entire classes, not just instances of classes. For example, take a look at the self.printed
, we tried to print the counter
and it was counted. We can call it by using Animal.printed
. The self.printed
is just like a static method in PHP.
Access Modifiers
Ruby has 4 access modifiers; default, private, protected, and public. That is similar to Java and PHP.
Module
module Environment
DEFAULT = "development"
end
puts Environment::DEFAULT # development
In that Environment
module, we have a constant (a variable that starts with an uppercase), called DEFAULT
.
Interface
module Interface
def print
raise "Not implemented"
end
end
class Animal
include Interface
end
animal = Animal.new
animal.print
With modules, we can include constants and methods in classes. We also can trick it into interfaces like in Java and PHP. Like an example above. To avoid an error, the Animal
class needs to override (or implement) the print
method.
In Ruby, everything is an object. Just like Java. So, they have methods. What methods are available? You can visit https://ruby-doc.org to look for help. Go to the documentation of your Ruby version.
Getting serious? You can visit Ruby Style Guide for more best practices.
Related Articles
- Object-Oriented Programming in C++
- C/C++ Crash Course
- Behavior-Driven Development with Go
- Server-Side Rendering with Next.js and TypeScript
- Install Go