🍓 LanguagesRubyBasics

Naming

var_names # snake_case
CONSTANT_VAR # UPPERCASE
 
class ClassNames # PascalCase
  @protected_class_attribute # single underscore
  @@private_class_attribute # double underscore (for class vars in Ruby)
end

Printing

print "hi there" # hi there
puts "hi there" # hi there\n (newline)
p "hi there" # "hi there" (inspect)

Data types

name = "Alice"  # string (text)
age = 25         # integer (whole nums)
height = 5.5     # float (decimal nums)
is_true = true   # boolean (true/false)
fruits = ["apple", "banana"]  # array
person = { name: "Alice", age: 25 }  # hash

Type checking

x = 5
x.class # Integer
x.kind_of?(Integer) # true
x.is_a?(Numeric) # true

Arrays

fruits = ["apple", "banana"]
Array.new  # []
Array.new(2, "orange") # ["orange", "orange"]
 
fruits[0] # get
fruits[4] # error
fruits.dig(4) # safe get, nil
fruits.last(2) # select
 
fruits[-1] = "strawberry"  # set
fruits.push("cherry")  # add
fruits.delete("cherry")  # remove
 
fruits.each do |fruit|  # loop
  puts fruit
end
a = [1, 2, 3]
b = [3, 4, 5]
 
c = a + b # [1, 2, 3, 3, 4, 5]
c - [1, 3] # [2, 4, 5]

Hashes

Symbols are used as keys in hashes since they are more performant than strings

person2 = { "name" => "Alice", "age" => 25 } # => as keys are non-symbols
person = { name: "Alice", age: 25 } # : as keys are symbols
person[:name]  # get
shoes.fetch(:city, "Toronto") # get with default
person[:height] ||= 5.5  # if nil, assign
person[:city] = "New York"  # add
person.delete(:age)  # remove
 
person.keys # access keys
person.values # access values
 
hash1.merge(hash2) # combine
 
person.each do |key, value|  # loop
  puts "#{key}: #{value}"
end

Formatting

Concatenation

username = "Alex"
puts "Welcome " + username # Welcome Alex

String Interpolation

name = "Bob"
puts "Thanks #{name}" # Thanks Bob

Input

All input is returned as a string

puts "Name: "
name = gets.chomp
puts "Height: "
height = gets.chomp.to_i

Loops

For Loops

fruits = ["apple", "banana", "cherry"]
fruits.each do |fruit| # |fruit| block variable
  puts fruit # apple, banana, cherry
end
# or
fruits.each { |fruit| puts fruit }
 
5.times do |i|
  puts i  # 0, 1, 2, 3, 4
end
 
fruits.each_with_index do |fruit, index|
  puts "#{index}: #{fruit}" # 0: apple, 1: banana, 2: cherry
end

While Loops

while condition
  puts "condition is true"
end

Until Loops

until condition
  puts "condition is false"
end

Loop Control

10.times do |i|
  break if i == 5 # exits out of loop
  puts i  # 0, 1, 2, 3, 4
end
 
for i in 0..4
  next if i == 2 # skips to next iteration
  puts i  # 0, 1, 3, 4
end
 
5.times do |i|
  redo if i == 2 # restarts the current iteration
  puts i  # 0, 1, 2, 2, 3, 4
end
 
1.upto(2) { |i| print "#{i} " }     # 1 2
2.downto(1) { |i| print "#{i} " }   # 2 1

Ranges

(0..2) # 0, 1, 2 (inclusive)
(0...2) # 0, 1 (exclusive)
(0..10).step(2) # 0, 2, 4, 6, 8, 10
(a..z) # a, b, c, ..., z

Iterators

names = ["Charles", "Bob"]
 
names.each { |name| puts name } # "Charles", "Bob"
names.each do |name|
  puts name
end
 
names.each_with_index { |name, index| puts "#{index}: #{name}" } # 0: Charles, 1: Bob
names.map { |name| name.upcase } # ["CHARLES", "BOB"]
names.select { |name| name.length > 5 } # keep all matching condition "Charles"
names.reject { |name| name.length > 5 } # remove all matching condition "Bob"
names.reduce { |acc, name| acc + name } # "CharlesBob"
names.any? { |name| name.length > 5 } # true
names.all? { |name| name.length > 5 } # false

Boolean Logic

Comparison Operators

ℹ️

Only false and nil are falsey in Ruby. Everything else is truthy.

==  # equal to
!=  # not equal to
>   # greater than
<   # less than
>=  # greater or equal
<=  # less or equal
<=> # -1, 0, 1 (less, equal, greater)

Conditionals

Conditional statements include if and unless + elsif and else

if temperature > 75
  puts "Hot!"
elsif temperature < 60
  puts "Cold!"
else
  puts "Mild"
end
unless age < 18
  puts "You are an adult"
else
  puts "You are a minor"
end

Logical Operators

Logical operators include and/&&, or/||, and !

if x > 0 && x < 10 # same as x.between?(0, 10)
  puts "x is between 0 and 10"
end
 
if x < 0 || x > 10 # same as !x.between?(0, 10)
  puts "Outside range"
end
 
is_valid = !false

Case (Switch) Statements

name = case first_letter
  when 'A' then "Arthur"
  when 'B' then "Bobby"
  else "Sam"
end

Functions Methods

ℹ️

Ruby is a “pure OOP” language. Everything is an object, so every function is a method

def add(a, b)
  a + b
end
 
result = add(5, 3)
puts result # 8

Arguments

Different types of arguments include: positional, default, keyword, and splat arguments

def area(width, height) # positional args
  width * height # implicit return
end
 
puts area(5, 6)  # must be passed in order
 
def area(width: 5, height: 5) # keyword args with defaults
  return width * height # explicit return
  height # never reached
end
 
puts area  # default arg values 5, 5 are used
puts area(height: 6, width: 5)  # keyword args can be passed in any order
 
def area(*args)  # splat args
  args[0] * args[1]
end
 
puts area(5, 6)  # can pass any number of args
puts area(5, 6, 7, 8) # args[2] and args[3] are unused
 
def area(**kwargs)  # keyword splat args
  kwargs[:width] * kwargs[:height]
end
 
puts area(height: 6, width: 5)  # can pass any number of keyword args in any order
puts area(width: 5, potatos: 'round', height: 6) # potatoes is unused

Predicate Methods

Predicates are methods (ending in ?) that return a boolean value

puts 6.even?
puts 17.odd?

Bang Methods

Bang methods (ending in !) modify the object in place

greeting = "HI"
 
puts greeting.downcase # "hi"
puts greeting # "HI"
 
puts greeting.downcase! # "hi"
puts greeting # "hi"

Built-in Methods

View More

"Hello".length      # length
123.class           # type check
"42".to_i           # convert to int
"3.14".to_f         # convert to float
123.to_s            # convert to string
3.14159.round(2)    # round

Scope

Determines the accessibility of variables, includes: local, instance, class, and global

$x = 10  # global var
what_scope = "global"
 
class ScopeClass
  @@class_var = "class"
 
  def initialize
    @instance_var = "instance"
  end
 
  def outer
    enclosing_var = "enclosing"
 
    inner = lambda do
      local_var = "local"
      puts $x, @@class_var, @instance_var, enclosing_var, local_var  # can access higher scopes
    end
 
    inner.call
    puts $x, @@class_var, @instance_var, enclosing_var  # local_var doesn't exist here
  end
end
 
example = ScopeClass.new
example.outer
puts $x  # enclosing_var and local_var don't exist here

Importing Modules

require 'mathn'  # import a module
require 'securerandom'
 
module AModule  # create a module
  def my_method
    puts "Hello"
  end
end

Error Handling

begin
  # code that might raise an error
  raise "Error!"
rescue => e
  puts e.message
end

File I/O

w: write, r: read, a: append, w+: read/write, a+: read/append

File.open("file.txt", "w") do |file|
  file.write("Hello, world!")
  file.append "Another line"
  puts file.read
end