Get last output in console
# Get last output in console
irb(main):001:0> a = 1
=> 1
irb(main):002:0> b = _
=> 1
Private attr_reader
# Private attr_reader
require 'httparty'
class ExampleUserConnector
  URL = "https://jsonplaceholder.typicode.com/users"
  def initialize(adapter: HTTParty)
    @adapter = adapter
  end
  def call
    adapter.get(URL).body
  end
  private
  attr_reader :adapter
end
Writing large Integers
# Writing large Integers
123_456_789
# => 123456789
Here documents
# Here documents
string = <<-FIN
a long string with
a lot of text
FIN
# => "a long string with\na lot of text\n"
strings = [<<END, "short", "strings"]
another long string
with a lot of text 
END
# => ["another long string\nwith a lot of text \n", "short", "strings"]
Enumerable#find ifnone
# Enumerable#find ifnone
enum = [{a: 1, b:2}, {a:2, b:3}]
enum.find{ |e| e[:a] == 1 } # => {:a=>2, :b=>3}
enum.find{ |e| e[:a] == 3 } # => nil
# ifnone is called if no object matches:
# find(ifnone = nil) { |obj| block } → obj or nil
enum.find( proc{'default'} ) { |e| e[:a] == 1 } # => {:a=>2, :b=>3}
enum.find( proc{'default'} ) { |e| e[:a] == 3 } # => "default"
# and you can pass a proc or a lambda
enum.find( -> (){'default'} ) { |e| e[:a] == 3 } # => "default"
Enumerable#partition
# Enumerable#partition
(1..6).partition {|v| v.even? }  
#=> [[2, 4, 6], [1, 3, 5]]
Unescaping text
# Unescaping text
"\"WTF is this \\n \\u2202 text \\u{1F9D0}\\u{1F914}\"".undump
# => "WTF is this \n ∂ text 🧐🤔"
String spliting
# String spliting
"This is amazing".split 
# => ["This", "is", "amazing"]
"This is amazing".split(' ', 2)
# => ["This", "is amazing"]
# wrap the matcher in parentheses to include it in the output
"This is amazing".split(/(\s)/) 
# => ["This", " ", "is", " ", "amazing"]
"This is amazing".partition(' ')
# => ["This", " ", "is amazing"]
"This is amazing".rpartition(' ')
# => ["This is", " ", "amazing"]
String#strip
# String#strip
user_input = "  John    "
user_input.strip  # => "John"
user_input.lstrip # => "John    "
user_input.rstrip # => "  John"
user_input.strip! # => "John"
user_input = "John"
user_input.strip! # => nil
String#center
# String#center
'Foo'.center(20)
# => "        Foo         "
def puts_title(title, size:20, decoration:"#")
  puts "".center(size, decoration)
  puts " #{title} ".center(size, decoration)
  puts "".center(size, decoration)
end
puts_title("Hello!")
####################
###### Hello! ######
####################
String#casecmp?
# String#casecmp?
"aBcDeF".casecmp?("abcde")     #=> false
"aBcDeF".casecmp?("abcdef")    #=> true
"aBcDeF".casecmp?("abcdefg")   #=> false
"abcdef".casecmp?("ABCDEF")    #=> true
"\u{e4 f6 fc}".casecmp?("\u{c4 d6 dc}")   #=> true
Reduce
# Reduce
# Sum some numbers
(5..10).reduce(:+)                             #=> 45
# Same using a block and inject
(5..10).inject { |sum, n| sum + n }            #=> 45
# Multiply some numbers
(5..10).reduce(1, :*)                          #=> 151200
# Same using a block
(5..10).inject(1) { |product, n| product * n } #=> 151200
# find the longest word
longest = %w{ cat sheep bear }.inject do |memo, word|
   memo.length > word.length ? memo : word
end
longest                                        #=> "sheep"
The inject and reduce methods are aliases.
Example from ruby doc
OpenStruct
# OpenStruct
require 'ostruct'
address = OpenStruct.new(country: "France")
# => #<OpenStruct country="France">
address.city = "Paris"
# => #<OpenStruct country="France", city="Paris">
# OpenStruct VS Struct
Address = Struct.new(:country)
address2 = Address.new(country = "France")
# => #<struct Address country="France">
address2.city = "Paris"
# NoMethodError: undefined method `city=' for #<struct Address country="France">
Struct
# Struct
class User
  Address = Struct.new(:city, :contry)
  
  attr_accessor :name, :address
  def initialize(name, address)
    @name = name
    @address = Address.new(address[:city], address[:country])
  end
end
u = User.new("Rob Halford", {city: "Phoenix", country:"USA"})
u.address
# => #<struct User::Address city="Phoenix", contry="USA">
u.address.city = 'San Diego'
u.address
# => #<struct User::Address city="San Diego", contry="USA">
Time tips
# Time tips
t = Time.new(2018, 8, 28, 22, 40, 01, "+02:00")
# => 2018-08-27 22:40:01 +0200
t.monday?
# => true
t.wday # monday = 1, tuesday = 2,...
# => 1
t.yday # Returns the day of the year, 1..366.
# => 239
respond_to?
# respond_to?
class User
  def name; end
  private
  def registered?; end
end
user = User.new
user.respond_to? :name               # => true
user.respond_to? :registered?        # => false
user.respond_to? :registered?, true  # => true
itself and occurence count
# itself and occurence count
array = [1,2,3,4,5,1,2,2,3]
array.itself
# => [1, 2, 3, 4, 5, 1, 2, 2, 3]
# Real worl exemple: occurence count 
array.each_with_object(Hash.new(0)) { |item, count| count[item] = count[item] + 1 }
# => {1=>2, 2=>3, 3=>2, 4=>1, 5=>1}
array.group_by{|e| e}
# => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}
array.group_by(&:itself)
# => {1=>[1, 1], 2=>[2, 2, 2], 3=>[3, 3], 4=>[4], 5=>[5]}
array.group_by(&:itself).transform_values(&:count)
# => {1=>2, 2=>3, 3=>2, 4=>1, 5=>1}
You should also look at this long thread about this feature
gsub: retrieve the matched string
# gsub: retrieve the matched string 
"The Force will be with you. Always.".gsub(/[ae]/){"*#{$&}*"}
# => "Th*e* Forc*e* will b*e* with you. Alw*a*ys."
"The Force will be with you. Always.".gsub(/[ae]/, '*\0*')
# => "Th*e* Forc*e* will b*e* with you. Alw*a*ys."
Imagine we’re in the context of a rails app with the following model:
# Imagine we're in the context of a rails app with the following model:
class Restaurant < ApplicationRecord
  scope :best, -> { where(stars: 3) }
end
# You suddenly feel the urge to understand how a `scope` gets defined by ActiveRecord.
# You know that `scope`, used as it is in the context of the `Restaurant` class,
# must be a class-level method.
Restaurant.method(:scope)
# => #<Method: Restaurant.scope>
Restaurant.method(:scope).source_location
# => ["/Users/nicolasfilzi/.rbenv/versions/2.4.4/lib/ruby/gems/2.4.0/gems/activerecord-5.2.1/lib/active_record/scoping/named.rb", 163]
 # Now you know where to start your code spelunking session! Enjoy!
by @n_filzi
Map with index
# Map with index
%w[foo bar baz].map.with_index { |w, i| "#{i}:#{w}" }
# => ["0:foo", "1:bar", "2:baz"]
Enumerator#next and peek
# Enumerator#next and peek
e = [1,2,3].each   # returns an enumerator object.
e.next   # => 1
e.next   # => 2
e.peek   # => 3
e.next   # => 3
e.next   # raises StopIteration
e.rewind
e.peek   # => 1
Infinitely nested Hash
# Infinitely nested Hash
h = Hash.new
h[:this][:is][:really] = 'Amazing!'
# => NoMethodError: undefined method `[]' for nil:NilClass
h = Hash.new {|h, k| h[k] = Hash.new(&h.default_proc) }
h[:this][:is][:really] = 'Amazing!'
h
# => {:this=>{:is=>{:really=>"Amazing!"}}}
gsub with hash
# gsub with hash
"The Force will be with you. Always.".gsub(/[eo]/, 'e' => 3, 'o' => '0')
# => "Th3 F0rc3 will b3 with y0u. Always."
gsub with blocks
# gsub with blocks
"The Force will be with you. Always.".gsub(/[aeiou]/) {|s| s.upcase}
# => "ThE FOrcE wIll bE wIth yOU. AlwAys."
"The Force will be with you. Always.".gsub(/[aeiou]/) {$&.upcase}
# => "ThE FOrcE wIll bE wIth yOU. AlwAys."
Custom setter
# Custom setter
class User
  attr_reader :name
  def name=(name)
    @name = name.capitalize
  end
end
user = User.new
user.name = 'john'
user # => #<User:0x0000000111638a00 @name="John">
Struct subclasses aren’t triple-equal to themselves
# Struct subclasses aren't triple-equal to themselves
klass = Struct.new(:foo)
klass === klass            #=> false
Class === klass            #=> true
Class === Struct           #=> true
Class === Struct.new(:baz) #=> true
each_slice
# each_slice
(1..10).each_slice(3) {|a| p a}
# => [1, 2, 3]
# => [4, 5, 6]
# => [7, 8, 9]
# => [10]
assoc and rassoc
# assoc and rassoc
a  = [ 
       [ "colors", "red", "blue", "green" ],
       [ "letters", "a", "b", "c" ],
       "foo"
     ]
a.assoc("letters")  #=> [ "letters", "a", "b", "c" ]
a.assoc("foo")      #=> nil
#-----------------------------------------------
a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
a.rassoc("two")    #=> [2, "two"]
a.rassoc("four")   #=> nil
Negative Array indices
# Negative Array indices
array = [:a, :b, :c, :d, :e]
array[-1]    # => :e
array[0..-3] # => [:a, :b, :c]
array[1..-1] # => [:b, :c, :d, :e]
Benchmark-ips
# Benchmark-ips
# gem install benchmark-ips
require 'benchmark/ips'
array = Array(1..100)
Benchmark.ips do |x|
  x.report("sample:")  { array.sample }
  x.report("shuffle.first:")  { array.shuffle.first }
end
# Warming up --------------------------------------
#              sample:   258.402k i/100ms
#       shuffle.first:    41.862k i/100ms
# Calculating -------------------------------------
#              sample:      8.141M (± 2.7%) i/s -     40.828M in   5.018541s
#       shuffle.first:    480.061k (± 2.8%) i/s -      2.428M in   5.061688s
More about Benchmark on Fast-Ruby
Pathname
# Pathname
require 'pathname'
pn = Pathname.new("/usr/bin/ruby")
pn.size        # => 52016
pn.directory?  # => false
pn.dirname     # => Pathname:/usr/bin
pn.basename    # => Pathname:ruby
pn.to_s        # => "/usr/bin/ruby"
Pathname.new('foo.rb').extname # => '.rb'
Pathname.new("/usr/").children 
# => [#<Pathname:/usr/bin>,
 #<Pathname:/usr/standalone>,
 #... ]
Super
# Super
class Base
  def bar
    puts "Base#bar"
  end
end
class Foo < Base
  def bar(baz)
    # By default super sends all arguments from Foo#bar to Base#bar
    # Call super() to send no arguments to Base#bar and to avoid 
    # "ArgumentError: wrong number of arguments (given 1, expected 0)""
    super()
    puts "#{baz} Foo#bar"
  end
end
Foo.new.bar('Hello')
# => Base#bar
# => Hello Foo#bar
Tap method
# Tap method
class User
  def get_band_from_api
    @band = "Metallica" #example code
  end
end
user = User.new
user.get_band_from_api # => "Metallica"
user
# => #<User:0x000000010c366773 @band="Metallica">
user = User.new.tap(&:get_band_from_api)
# => #<User:0x000000010c366778 @band="Metallica">
Round to the nearest ten
# Round to the nearest ten
# instead of
15.7.round * 10 # => 160
# you can use
157.round(-1)   # => 160
# In Ruby 2.5 and above
155.round(-1, half: :up)     # => 160
155.round(-1, half: :down)   # => 150
The Spaceship Operator
# The Spaceship Operator
1 <=> 5 # => -1
5 <=> 5 # => 0
6 <=> 5 # => 1
numbers = Array(1..10)
numbers.group_by { |n| n <=> 5 }
# => {-1=>[1, 2, 3, 4], 0=>[5], 1=>[6, 7, 8, 9, 10]}
How to Use The Spaceship Operator in Ruby
Symbol vs String
# Symbol vs String
'foo'.__id__ == 'foo'.__id__ # => false
:foo.__id__  == :foo.__id__  # => true
Two strings with the same contents are two different objects, but for any given name there is only one Symbol object More
clone vs dup
# clone vs dup
class Book
  attr_accessor :title, :read
  def initialize(title:)
    self.title = title
    self.read = false
  end
end
book = Book.new(title: 'The Hobbit')
def book.read!; read = true; end
book_clone = book.clone
book_dup = book.dup
book_clone.read! # => true
book_dup.read! # => NoMethodError: undefined method `read!'
book.title << ' by Tolkien'
book_clone.title # => "The Hobbit by Tolkien"
book_dup.title   # => "The Hobbit by Tolkien"
book.freeze.clone.frozen? # => true
book.freeze.dup.frozen? # => false
Frozen object and object id
# Frozen object and object id
class Book
  attr_accessor :title
  def initialize(title:)
    self.title = title
  end
end
book = Book.new(title: 'The Hobbit')
book.title.__id__ # => 70172975062580
book.title << ' by Tolkien'
book.title.__id__ # => 70172975062580 => ⚠️ the same
book.title = 'The Return of the King'
book.title.__id__ # => 70172979274460 => ⚠️ different
book.freeze
book.frozen?       # => true
book.title.frozen? # => false
book.title << ' by Tolkien'     # => "The Return of the King by Tolkien"
book.title = 'The Silmarillion' # => RuntimeError: can't modify frozen Book
Object equality test
# Object equality test
class Book
  attr_reader :author, :title
  def initialize(author:, title:)
    @author = author
    @title = title
  end
  def ==(other)
    self.class === other &&
      other.author == @author &&
      other.title == @title
  end
end
book1 = Book.new(title: 'The Hobbit', author: 'Tolkien')
book2 = Book.new(title: 'The Hobbit', author: 'Tolkien')
book1 == book2 # => true
Dig
# Dig
john = {
  name: "John Doe",
  address: {
    city: "Paris"
  }
}
jeanne = { name: "Jeanne"}
john.dig(:address, :city)   # => "Paris"
jeanne[:address][:city]  # => NoMethodError: undefined method `[]' for nil:NilClass
jeanne.dig(:address, :city) #=> nil
Metaprogramming basics #1
# Metaprogramming basics #1
class Foo
  ["hello", "bye"].each do |method|
    define_method "say_#{method}" do
      "I say " + method.to_s
    end
  end
end
Foo.new.say_hello # => I say hello"
Foo.new.say_bye   # => I say bye"
# Real world exemple:
class Post
  STATUS = %w(to_moderate published planned done hidden)
  def initialize(status:)
    @status = status
  end
  STATUS.each do |status|
    define_method("#{status}?") do
      @status == status
    end
  end
end
post = Post.new(status: "published")
post.published? # => true
post.done?      # => false
Return the name of the current called method
# Return the name of the current called method
class Foo
  def bar
    [__method__, __callee__]
  end
  alias_method :hello, :bar 
end
Foo.new.bar # => [:bar, :bar]
Foo.new.hello # => [:bar, :hello]
Private class methods
# Private class methods
class Example
  def self.foo; end
  private
  # private_foo will not be private as it will be a singleton method
  def self.private_foo; end
  class << self
    def bar; end
    private
    def private_bar; end
  end
end
Example.methods(false)          # => [:foo, :private_foo, :bar]
Example.private_methods(false)  # => [:private_bar, :initialize, :inherited]
More: Class Methods In Ruby: a Thorough Review & Why I Define Them Using class « self
Singleton Methods
# Singleton Methods
class Foo
  def bar; "bar!"; end
end
foo = Foo.new
foo.bar # => "bar!"
def foo.bar
  "This is the new bar"
end
foo.define_singleton_method(:hi) {'hi!'}
foo.singleton_methods # => [:bar, :hi]
foo.bar               # => "This is the new bar"
foo.hi                # => "hi!"
Safe navigation operator (&.)
# Safe navigation operator (&.)
class Foo
  attr_accessor :bar
  def initialize(bar: Bar.new)
    @bar = bar
  end
end
class Bar
  def hello
    "hello"
  end
end
Foo.new.bar.hello # "hello"
Foo.new(bar: nil).bar # nil
Foo.new(bar: nil).bar.hello # NoMethodError: undefined method `hello' for nil:NilClass
Foo.new(bar: nil).bar&.hello # nil
Foo.new(bar: false).bar&.hello # NoMethodError: undefined method `hello' for false:FalseClass
Foo.new(bar: false).bar && Foo.new(bar: false).bar.hello # false
Convert value to boolean
# Convert value to boolean
!!(true) # true
!!(1)    # true
!!(nil)  # false
# Usage:
def foo?
  !!foo
end
# Bonus: Cast to boolean with ActiveModel in Rails
ActiveModel::Type::Boolean.new.cast(0)        # false
ActiveModel::Type::Boolean.new.cast('false')  # false
ActiveModel::Type::Boolean.new.cast('true')   # true
ActiveModel::Type::Boolean.new.cast(1)        # true
General Delimited Input, %w and %W
# General Delimited Input, %w and %W
%w(hello world)
# ["hello", "world"]
%w-hello world-
# ["hello", "world"]
%w$hello world$
# ["hello", "world"]
hello = 'hi'
%w(#{hello} world)
# ["\#{hello}", "world"]
%W(#{hello} world)
# ["hi", "world"]
more info about Q, q, W, w, x, r, s
The “method” method
# The "method" method
# Passing a method taking a block to another method or object
%w[Hello World].each &method(:puts)
# Hello
# World
Splat operator
# Splat operator
first, *others, last = ['a', 'b', 'c', 'd']
{first: first, others: others, last: last}
#=> {:first=>"a", :others=>["b", "c"], :last=>"d"}
def foo(*args, **opts)
  puts 'args: ' + args.to_s
  puts 'opts: ' + opts.to_s
  puts '"a" opts: ' + opts[:a].to_s
end
foo(1, 2, 3, a: 4, b: 5)
# args: [1, 2, 3]
# opts: {:a=>4, :b=>5}
# "a" opts: 4