Skip to content

Latest commit

 

History

History
817 lines (591 loc) · 10.9 KB

File metadata and controls

817 lines (591 loc) · 10.9 KB

Ruby language notes

puts vs p

Print to console puts x prints x.to_s p x prints x.inspect (not exactly but essentially)

gets

Gets from console gets returns everything, including newline gets.chomp omits the return

Variables

Local Variables

Only available in the local scope

10.times do
    x = 10
end
# Not available here, will fail
p x

Global Variables

Available in the whole application scope, usually not a great idea

10.times do
    $x = 10
end

p $x

Instance Variables

Available in the object instance scope

class MyClass
  def initialize
    @x = 10
  end
  def x
    @x
  end
end

mc = MyClass.new

p mc.x

Class Variable

Available in the class scope, usually not a great idea

class MyClass
  @@x = 10
  def self.x
    @@x
  end
end

p MyClass.x

Constant

You shouldn't change it but ruby will let you

    CONSTANT_X = "Test"

Strings

A series of characters

String interpolation

animal = 'fox'
other_animal = 'dog'
p "The quick brown #{animal} jumped over the lazy #{other_animal}"
p 'The quick brown #{animal} jumped over the lazy #{other_animal}'

String manipulation

str = 'Testing'

p str.downcase
p str.upcase
p str.swapcase
p str.reverse

sub/gsub

sub replaces the first occurrence, gsub replaces everything

str = 'The quick brown fox jumped over the lazy dog'

p str.gsub 'quick', 'slow'
p str

p str.gsub! 'quick', 'slow'
p str

strip/split

str = '  The quick brown fox jumped over the lazy dog   '
p str.strip
str = 'The quick brown fox jumped over the lazy dog'
p str.split
p str.split.size

p str.split('')
p str.split('').size

Arithmetic

Basic operators

p 2 + 2
p 2 - 1
p 2 * 3
p 6 / 2
p 2 ** 5

Order of operation (PEMDAS)

Parenthesis, exponents, multiplication, division, addition, substraction

p 5 + 15 * 20 - 2 / 6**3 - (3 + 1)
# 5 + 15 * 20 - 2 / 6**3 - 4
# 5 + 15 * 20 - 2 / 216 - 4
# 5 + 300 - 2 / 216 - 4
# 5 + 300 - 0 - 4 (2/216 is 0 because this is integer arithmetic)
# 305 - 0 - 4
# 301

integer/float/decimal

Ruby floating points have fixed precision, decimals have arbitrary precision

require "bigdecimal"

# integer
p 2 / 216

#float
p 2.0 / 216, Float(2) / 216

#big decimal
p BigDecimal(2) / 216

Methods

You dont have to explicitely use the return clause unless it is needed for clarity or you are implementing an early return

  def player_list
    ['John', 'Juan', 'Joao']
  end

  p player_list

Early return

def player_list(gender)
  return ['Joanne', 'Juana'] if gender == 'F' 
  ['John', 'Juan', 'Joao']
end

p player_list('M'), player_list(''), player_list('F')

Class methods

class Invoice
  def self.description
    'This is the invoice class'
  end
end

i = Invoice.new

p Invoice.description

# This will raise an exception
#p i.description

Instance methods

class Invoice
  def initialize
    @id = 10
  end

  def description
    "This is the invoice with id=#{@id}"
  end
end

i = Invoice.new

# This will raise an exception
# p Invoice.description

p i.description

procs/lambdas

proc

  • doesnt count the args, ignores any extra args
  • return inside a proc shortcuts the whole method
full_name = Proc.new { |first, last| "#{first} #{last}" }

p full_name["John", "Doe"], full_name.call("John", "Doe")

lambdas

  • counts the args, raises exception for incorrect count
  • return inside a lambda allows the method to continue
full_name = -> (first, last) { "#{first} #{last}" }

p full_name["John", "Doe"], full_name.call("John", "Doe")

Arguments

def full_name(first, last)
  "#{first} #{last}"
end

p full_name('Juan', 'Perez')

Named args

def full_name(first:, last:)
  "#{first} #{last}"
end

# This will raise an exception
# p full_name('Juan', 'Perez')

p full_name(last: 'Perez', first: 'Juan')

Defaults

def full_name(first: "John", last: "Smith")
  "#{first} #{last}"
end

p full_name(first: 'Juan')

Splat args

def names(*people)
  "People: #{people}"
end

p names('Juan'), names('Juan', 'Pedro', 'Jose')

Keyword args

def register(email:, password:, **kwargs)
  p "Building account for #{email}"
  p "Assigning role: #{kwargs[:role]}" if kwargs[:role]
  p "With plan: #{kwargs[:plan]}" if kwargs[:plan]
end

register(email: 'test@test.net', password: 'password')
register(email: 'test@test.net', password: 'password', role: 'admin')
register(email: 'test@test.net', password: 'password', plan: 'premium')

Iterators and Loops

while

i = 0

while i < 10
  p i
  i += 1
end

each

arr = [23, 234, 455, 768, 838]

arr.each do |i|
  p i
end

arr.each { |i| p i }

for in

arr = [23, 234, 455, 768, 838]

for i in arr do
  p i
end

Nested iterators

teams = {
  'engineering' => {
    'dev' => 'John',
    'qa' => 'Maria',
    'manager' => 'George'
  },
  'sales' => {
    'salesperson' => 'Jenny',
    'manager' => 'Alex'
  }
}

teams.each do |team, members|
  puts team
  members.each do |role, name|
    puts "  #{role}: #{name}"
  end
end

select

p (1..10).to_a.select(&:even?), (1..10).to_a.select { |x| x > 0 }

map

arr = ["1", "23.0", "0", "4"]
p arr.map { |x| x.to_i }, arr.map(&:to_i), Hash[arr.map { |x| [x,x.to_i] }]

inject

arr = [1, 23.0, 0, 4]
p arr.inject(&:+)

Collections

Arrays

Create

arr = [1, 2, 3, 4, 4, 4, 4]
arr2 = Array.new
arr2[10] = 56
p arr, arr2

Delete

arr = [1, 2, 3, 4, 4, 4, 4]

arr.delete(4)
p arr

deleted = arr.delete_at(2)
not_found = arr.delete_at(10)
p arr, deleted, not_found

arr = [1, 2, 3, 4, 4, 4, 4]
arr.delete_if { |num| num < 3 }
p arr

Join

arr = [1, 2, 3, 4]

str = arr.join(", ")
p arr, str

Push/Pop

arr = Array.new

arr.push(1)
p arr

num = arr.pop
p arr, num

Hashes

Create

hsh = {first: 1, second: 2, third: 3, fourth: 4, fifth: 5}
p hsh, hsh[:third]

Delete

hsh = {first: 1, second: 2, third: 3, fourth: 4, fifth: 5}

#returns deleted value
deleted = hsh.delete(:third)
p hsh, hsh[:third], deleted

#returns hash
deleted = hsh.delete_if { |key, value| value % 2 == 0 }
p hsh, deleted

Iterate (see also Nested Iterators)

hsh.each_key do |key|
  p key
end

hsh.each_value do |value|
  p value
end

Useful Methods

hsh = {first: 1, second: 2, third: 3, fourth: 4, fifth: 5}

hsh[:sixth] = 6
p hsh

inverted = hsh.invert
p hsh, inverted

other_hsh = {sixth: 6, seventh: 7, eighth: 8, ninth: 9, tenth: 10}
merged = hsh.merge(other_hsh)
p hsh, other_hsh, merged

arr = hsh.to_a
p hsh, arr

keys = hsh.keys
values = hsh.values
p hsh, keys, values

Dig

teams = {
  'engineering' => {
    'dev' => 'John',
    'qa' => 'Maria',
    'manager' => 'George'
  },
  'sales' => {
    'salesperson' => 'Jenny',
    'manager' => 'Alex'
  }
}

p teams.dig('engineering', 'manager'), teams.dig('hr', 'manager')

Sets

set = Set.new

set.add(1)
set.add(2)
set.add(3)
p set

set.add(1)
p set

set.delete(1)
p set

Conditionals

If/Else

x = 10
y = 5

if x == y
  p 'x and y are the same'
else
  p 'x and y are different'
end

Unless

arr = [1, 2, 3, 4, 5]
empty_arr = []

p arr unless arr.empty?
p empty_arr unless empty_arr.empty?

Multiple if/else

x = 10
y = 5
z = 1

if x == y
  p 'x and y are the same'
elsif x > y
  p 'x is greater than y'
elsif x > z
  p 'x is greater than z' # this will never run
else
  p 'y is greater than x'
end

Compound conditionals

x = 10
y = 5
z = 10

p 'x is equal to y and z' if x == y && x == z
p 'x is equal to y or z' if x == y || x == z

OOP

Everything in Ruby is an object.

Setters, getters and methods

class Animal
  attr_accessor :name, :age

  def info
    "#{@name} is #{@age} years old"
  end
end

a = Animal.new
a.name = 'Dog'
a.age = 3
p a.info

Initializer method

class Animal
  attr_accessor :name, :age

  def initialize(name: 'unknown', age: 0)
    @name = name
    @age = age
  end

  def info
    "#{@name} is #{@age} years old"
  end
end

a = Animal.new
p a.info

a = Animal.new(name: 'dog', age: 3)
p a.info

Inheritance / polymorphism

class Animal
  attr_accessor :name, :age

  def initialize(name: 'unknown', age: 0)
    @name = name
    @age = age
  end

  def info
    "#{@name} is #{@age} years old"
  end

  def noise
    '...'
  end
end

class Dog < Animal
  def initialize(name: 'dog', age: 0)
    super(name: name, age: age)
  end

  def noise
    'Bow wow'
  end
end

class Cat < Animal
  def initialize(name: 'cat', age: 0)
    super(name: name, age: age)
  end

  def noise
    'Meow meow'
  end
end

a = Animal.new
p a.info, a.noise

a = Dog.new
p a.info, a.noise

a = Cat.new
p a.info, a.noise

Private methods

class Animal
  attr_accessor :name, :age

  def initialize(name: 'unknown', age: 0)
    @name = name
    @age = age
  end

  def info
    "#{@name} is #{@age} years old"
  end

  private
  def secret_method
    'secret message'
  end
end

a = Animal.new(name: 'Dog', age: 3)
p a.info
p a.secret_method # => Error

Modules

module Tools
  module StringTools
    class << self
      def count_words(string)
        split_words(string).size
      end

      private

      def split_words(string)
        string.split
      end
    end
  end
end

p Tools::StringTools.count_words('Hello world')

File system

  • r read
  • a append
  • w write
  • w+ read/write
  • a+ read/append
  • r+ read/write/append

Creating a file

File.open('test1.txt', 'w+') { |f| f.write('Testing tests...') }

file = File.open('test2.txt', 'w+')
file.puts('Testing tests...')
file.close

Reading files

txt = File.read('test1.txt')
p txt

Deleting files

File.delete('test2.txt')

Appending to a file

10.times do
  sleep 1
  p 'Record saved'
  File.open('test.txt', 'a') {|f| f.puts "Record saved at #{Time.now}"}
end

Error handling

begin
  p 8/0
rescue StandardError => e
  p "Error occurred: #{e}"
end

Regex

str = 'The quick 12 brown foxes jumped over the 10 lazy dogs'

# Case sensitive
p str =~ /z/ ? 'Contains z' : 'Does not contain z', str =~ /Z/ ? 'Contains z' : 'Does not contain z'

# Case insensitive
p str =~ /z/i ? 'Contains z' : 'Does not contain z'

p(str.to_enum(:scan, /\d+/).map { Regexp.last_match })

grep

arr = ['data.txt', 'example.rb', 'data2.txt', 'data3.txt.xlsx', 'hack.rb', 'data5.txt']
p arr.grep(/w*.rb/), arr.grep(/w*.txt/), arr.grep(/w*.xlsx/)

General notes

  • A method with a ! generally means the variable will be modified in place
  • Use symbols when you want to create an identifier, and use strings for data. Strings are mutable, symbols are inmutable.
  • HashWithIndifferentAccess is a special kind of hash that allows you to access its keys using either strings or symbols interchangeably