Ruby
Homepage / Notes / Computer Science / Programming Languages / Ruby
Language Features
Strings
Can use both single quotes ' or double quotes ".
String interpolation
/!\ Must use double quotes
name = 'world'
str = "hello #{name}"hello world
Append to string
str = 'hello '
str << 'world'hello world
Freezing strings
str = 'hello'.freeze
str.frozen?true
str = 'hello'.freeze
str << ' world'=can't modify frozen String: "hello" (FrozenError)=
Frozen string literals
# frozen_string_literal: true This line placed at the beginning of a file will freeze all strings in the file.
See also: https://docs.ruby-lang.org/en/3.0.0/doc/syntax/comments_rdoc.html#label-Magic+Comments
String to chars
"Damien".chars["D", "a", "m", "i", "e", "n"]
Split
"String to be split".split["String", "to", "be", "split"]
"String,to,be,split".split(',')["String", "to", "be", "split"]
Arrays
https://docs.ruby-lang.org/en/3.0.0/Array.html
Concatenation
a = [1, 2, 3]
b = [4, 5, 6]
a.push(*b)[1, 2, 3, 4, 5, 6]
Appending
list = []
(1..5).each {|i| list << i}
list[1, 2, 3, 4, 5]
Destructuring / Pattern Matching
[1, 2, 3] => [a, b, c]
c3
Symbols
Symbols are immutable, unique identifiers represented by a name preceded by a colon (:).
:hello:hello
You can easily convert a string to a symbol and vice-versa:
:name.to_sname
"name".to_sym:name
Hashes
https://ruby-doc.org/core-3.0.0/Hash.html Older syntax, "hash rocket":
h = {:foo => 0, :bar => 1}{:foo=>0, :bar=>1}
Newer JSON-like syntax
h = {foo: 0, bar: 1}{:foo=>0, :bar=>1}
Getting value from key
Using array-like notation
h = {foo: 0, bar: 1}
h[:foo]0
Using fetch
h = {foo: 0, bar: 1}
h.fetch(:foo)0
Can provide a default:
h = {foo: 0, bar: 1}
h.fetch(:baz, "Oops")Oops
"Deep" nested value
h = {foo: {deepfoo: {nested: 'deep_nested_value'}}, bar: 1}
h.dig(:foo, :deepfoo, :nested)deep_nested_value
Delete Key
h = {foo: 0, bar: 1}
h.delete(:foo) # this returns the deleted key's value, so 0 in this case
h{:bar=>1}
Merging two hashes
a = {first: 'value'}
b = {second: 'another value'}
a.merge(b){:first=>"value", :second=>"another value"}
Using Double Splat Operator
a = {first: 'value'}
b = {**a, second: 'another value'}{:first=>"value", :second=>"another value"}
Getting Keys Only
h = {foo: 0, bar: 1}
h.keys[:foo, :bar]
Getting Values Only
h = {foo: 0, bar: 1}
h.values[0, 1]
Omitting values
Starting from Ruby 3.1
x = 8
y = 9
{x:, y:}{:x=>8, :y=>9}
Slice
user = { name: 'Damien', age: 28, role: 'CEO' }
user.slice(:name, :age){:name=>"Damien", :age=>28}
Except
user = { name: 'Damien', age: 28, role: 'CEO' }
user.except(:role){:name=>"Damien", :age=>28}
Transform Values
{a: true, b: false}.transform_values(&:!){:a=>false, :b=>true}
Iterate Over Hash
h = {foo: 0, bar: 1}
h.each do |key, value|
  puts "#{key}: #{value}"
endfoo: 0
bar: 1
Any?
h = {foo: 0, bar: 1}
h.any? { |key, value| value > 0 }true
Compact
Removes any null values
h = {foo: 0, bar: nil}
h.compact{:foo=>0}
Empty?
h = {foo: 0, bar: nil}
puts h.empty?
h = {}
puts h.empty?false
true
Functions
def say_hello(name)
  puts "hello #{name}"
end
say_hello('Damien')hello Damien
Optional Arguments
def greet_name(name = 'John Doe')
  puts "hello #{name}"
end
greet_name
greet_name('Damien')hello John Doe
hello Damien
Keyword Arguments
def greet_name(greeting:, name:)
  puts "#{greeting}, #{name}"
end
greet_name(name: 'Damien', greeting: 'hi')hi, Damien
Starting from Ruby 3.1
def greet_name(greeting:, name:)
  puts "#{greeting}, #{name}"
end
greeting = 'hi'
name = 'Damien'
greet_name(name:, greeting:)hi, Damien
One-liner
Starting from Ruby 3.0
def increment(x) = x + 1
increment(42)43
Iterators
https://docs.ruby-lang.org/en/3.0.0/doc/syntax/control_expressions_rdoc.html
While
x = 0
while x < 5
  puts x
  x += 1
end
0
1
2
3
4
Until
x = 0
until x == 5
  puts x
  x += 1
end0
1
2
3
4
For
x = [1, 2, 3, 4, 5]
for i in x do
  puts i
end1
2
3
4
5
Each
names = ['Bob', 'Joe', 'Steve', 'Janice', 'Susan', 'Helen']
names.each { |name| puts name }Bob
Joe
Steve
Janice
Susan
Helen
Enumerables
https://docs.ruby-lang.org/en/3.0.0/Enumerable.html
Any?
x = ['a', 'b', 'c']
x.any?('a')true
x.any?('d')false
Min
[1, 2, 3].min0
Max
[1, 2, 3].max3
minmax
[1, 2, 3].minmax[1, 3]
Sort
[3, 2, 1].sort[1, 2, 3]
Filter
[1, 2, 3, 4, 5].filter {|i| i >= 3}[3, 4, 5]
Each With Index
hash = Hash.new
['a', 'b', 'c'].each_with_index {|item, index|
  hash[index] = item
}
hash{0=>"a", 1=>"b", 2=>"c"}
Each With Object
(1..10).each_with_object([]) {|i, a| a << i*2}[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Map
[1, 2, 3, 4, 5].map {|i| i * 2}[2, 4, 6, 8, 10]
Reduce
[1, 2, 3, 4, 5].reduce(:+)15
Blocks, Procs and Lambdas
Blocks
A block of code that can be passed to a method.
Single-line syntax
[1, 2, 3].each { |num| puts num }1
2
3
Since Ruby 3.4, a default it variable is available:
[1, 2, 3].each { puts it }Multi-line syntax
[1, 2, 3].each do |num|
  puts num
end1
2
3
Procs
double = Proc.new { |num| num * 2 }
double.call(5)10
Lambdas
l = lambda { |x| x * 3 }
l.call(3)9
A shorter syntax is available using ->:
l = ->(x) { x * 3 }
l.call(5)15
Pattern Matching
Starting from Ruby 3.1
[1, 2] => _, x
x2
{ name: 'Damien', age: 28 } => {name:}
nameDamien
Classes
https://docs.ruby-lang.org/en/3.0.0/Class.html
class Greeter
  def initialize(name)
    @name = name.capitalize
  end
  def salute
    return "Hello #{@name}!"
  end
end
# Create a new object
g = Greeter.new("world")
g.saluteHello World!
What is @foobar?
The variable which name begins which the character `@', is an instance variable of self. Instance variables are belong to the certain object. Non-initialized instance variables has value nil.
attr_reader
To avoid having to call @name with the @, attr_reader can be used:
class Greeter
  attr_reader :name
  def initialize(name)
    @name = name.capitalize
  end
  def salute
    return "Hello #{name}!"
  end
end
# Create a new object
g = Greeter.new("world")
g.saluteHello World!
Methods
Greeter.instance_methods(false)| :salute | :name | 
Modules
https://docs.ruby-lang.org/en/3.0.0/Module.html
module Greeter
  def self.salute
    return "Hello World!"
  end
end
# Output "Hello World!"
Greeter.saluteHello World!
What is ::?
Allow to access items in modules or class-level items in classes. Example:
module SomeModule
    module InnerModule
        class MyClass
            CONSTANT = 4
        end
    end
end
SomeModule::InnerModule::MyClass::CONSTANT4
You could access CONSTANT by: SomeModule::InnerModule::MyClass::CONSTANT
Time
Time.now2021-05-31 21:31:48.883643 -0400
UNIX Timestamp
Time.now.to_i1622511129
Fibers
https://noteflakes.com/articles/2021-10-20-explaining-ruby-fibers
https://brunosutic.com/blog/ruby-fiber-scheduler
Misc
Conditional Assignment Operator
a ||= b means: If a is undefined, nil or false, assign b to a. Otherwise, keep a intact.
IRB
Interactive Ruby Shell, the REPL of Ruby!
Gems
Rails
https://rubyonrails.org/ Web Framework
Cache
https://guides.rubyonrails.org/caching_with_rails.html To enable caching in dev: rails dev:cache
Low-Level Caching
https://guides.rubyonrails.org/caching_with_rails.html#low-level-caching Using Rails.cache.fetch, both reading and writing is taken care of.
reload!
reload! is a method to reload your application code in the current console session.
Sandbox
rails console --sandbox shortcut: rails c -s Any modifications will be rolled back on exit
Hanami
https://hanamirb.org/ Alternative to Rails
state_machines
https://github.com/state-machines/state_machines
Adds support for creating state machines for attributes on any Ruby class
https://blog.appsignal.com/2022/06/22/state-machines-in-ruby-an-introduction.html
Polars
https://github.com/ankane/polars-ruby
🔥 Blazingly fast DataFrames for Ruby, powered by Polars
Resources
https://github.com/seanlerner/ruby-and-rails-learning-plan
https://learnrubythehardway.org/book/ex13.html
Polished Ruby Programming: Build Better Software with More Intuitive, Maintainable, Scalable, and High-performance Ruby Code
by Jeremy Evans