Ruby snippets you can understand in 30 seconds or less.
Inspired by 30-seconds-of-knowledge.
[Element: hr]
Always wondered how to see Ruby's class hierarchy? Simply call ancestors
on aclass to see the ancestor chain.
The return array contains the following order:
- the calling class
- its included modules
- its parent class
- the included modules of its parents class
- the parent class of its parent class
Here is the ancestor chain of the String class:
irb> String.ancestors
=> [String, Comparable, Object, Kernel, BasicObject]
A Ruby interpreter is any program that parses the Ruby source code to imitate its behavioral execution. It converts the program line by line compared to a compiler which converts the whole program at once. Hence, a code change only requires an edit. Interpreters only throw an error if the program gets executed and reach the line that containes the error, whereas compilers will throw the error already before execution. There are multiple versions of Ruby interpreters to choose from, each with a different but very similar set of rules and options.
Common Ruby Interpreters:
- Ruby MRI
- JRuby
- YARV
- Rubinius
If you've ever wondering what methods are available for a specific object, just call .methods
on it:
irb> name = 'Bob'
=> "Bob"
irb> name.methods
=> [:include?, :%, :unicode_normalize, :*, :+, :to_c, ...]
This will return an array of symbols (names) of all publicly accessible methods of the object and its ancestors.
The BasicObject class is the top parent of all class. It is a blank instance of class class
with no superclass and contains a minimum of methods for object creation and comparison.
irb> class User
irb> end
=> nil
irb> User
=> User
irb> User.class
=> Class
irb> User.superclass
=> Object
irb> Object.ancestors
=> [Object, Kernel, BasicObject]
irb> BasicObject.class
=> Class
irb> BasicObject.superclass
=> nil
irb> BasicObject.ancestors
=> [BasicObject]
Ever wondered if there is a better way how you can traverse through multi-layer hashes or arrays to retrieve a specific value? Luckily Ruby 2.3 introduced a new method called dig
.
catalogue = {
drinks: {
apple_juice: {
stock: 8,
price_per_unit: 2.4
},
orange_juice: {
stock: 4,
price_per_unit: 2.2
}
}
}
Given the above hash, we would access the price per unit of the orange juice by the below line.
catalogue[:drinks][:carrot_juice][:price_per_unit]
=> NoMethodError: undefined method `[]' for nil:NilClass
To mitigate Rails to throw an error we need to check the existence of each key while navigating through the hash structure.
catalogue[:drinks] && catalogue[:drinks][:carrot_juice] && catalogue[:drinks][:carrot_juice][:price_per_unit]
By using dig
we follow DRY and retrieve the value of each key object by dealing smoothly with nil values.
catalogue.dig(:drinks, :carrot_juice, :price_per_unit)
=> nil
catalogue.dig(:drinks, :apple_juice, :price_per_unit)
=> 2.4
In Ruby there are two common naming conventions for methods. Either you end a method name with a ! or ?. Methods ended by a ! are called bang methods and often modifies the original object.
irb> book_title = "example book title"
=> "example book title"
irb> puts book_title.capitalize!
Example book title
=> nil
irb> puts book_title
Example book title
=> nil
irb>
A famous example is merge
vs merge!
when dealing with params, whereas the former method will return the params and the latest modifies the original params.
The question mark at the end of a method name indicates that we can expect a boolean as return value.
irb> array = []
=> []
irb> array.empty?
=> true
irb> user = { 'first_name' => 'Bob', 'last_name' => 'Carlton' }
irb> user.has_key?('first_name')
=> true
The Kernel module is included by class Object and provides methods that are globally available, hence every Ruby object has access to them. These methods are called without a receiver and only act on the passed arguments.
Famouse representative of the Kernel module are:
- Array
- Hash
- Integer
- Hash
- p, print and puts
Ever wondered how you can find out where exactly a method lives inside Ruby?
Ruby offers two helpful methods here. By passing the name of the method as a symbol to owner
will reveal where a method lives inside Ruby. If you curious about who receives s specific method, just pass the name again as a symbol to receiver
.
irb> method(:initialize).owner
=> BasicObject
irb> method(:initialize).receiver
=> main
The ruby
command is mostly known for running a ruby app or script. But it also has a number of interesting options to offer.
Execute a single line code snippet just by using the -e flag:
ruby -e '[1, 2, 3].each do |e| puts e end'
Calling digits
on an integer returns the array including the digits extracted by place-value notation with radix base of int.
irb> 123.digits
=> [3, 2, 1]
irb> 14.digits(7)
=> [0, 2]
Using values_at
to retrieve multiple non-sequential values of arrays and hashes.
For a given array it will return an array of the values associated with the index position.
irb> programming_languages = ['Ruby', 'Python', 'Golang', 'C++', 'C', 'D']
=> ["Ruby", "Python", "Golang", "C++", "C", "D"]
irb> programming_languages.values_at(0, 2, 4)
=> ["Ruby", "Golang", "C"]
For a given hash it will return an array of the values associated with the given keys.
irb> fruits = { 'orange' => '$2.00', 'apple' => '$3.00', 'grapes' => '$2.50' }
=> => {"orange"=>"$2.00", "apple"=>"$3.00", "grapes"=>"$2.50"}
irb> fruits.values_at('orange')
=> ["$2.00"]
The *splat operator has almost endless uses. But the main idea is that whenever you don’t want to specify the number of arguments you have, you would use a splat operator. The simplest example would be something like this:
irb> def foo(*args)
irb> args
irb> end
=> :foo
irb> foo(1,5,9)
[1, 5, 9]
=> [1, 5, 9]
You can also use the splat operator to grab any segment of an array:
irb> first, second, *last = ["x", "y", "w", "z"]
=> ["x", "y", "w", "z"]
irb> first
=> "x"
irb> second
=> "y"
irb> last
=> ["w", "z"]
to_s
is an explicit casting helper and is used to transform a value from one type to another. to_str
is an implicit casting helper
with the same purpose. The difference is that the former will always return a string whereas the later will result in an error or data loss
if the value it acts on does not act like the type we are casting. Ruby will only return a value when objects act like the type.
Ruby is very strict when using an implicit casting helper to ensure that the value acts like the type we want.
irb> [1, 2].to_s
=> "[1, 2]"
irb> [1, 2].to_str
NoMethodError: undefined method `to_str` for [1, 2]:Array
Did you mean? to_s
irb> :name.to_s
=> "name"
irb> :name.to_str
NoMethodError: undefined method `to_str` for :name:Symbol
Did you mean? to_s
to_i
is an explicit casting helper and is used to transform a value from one type to another. to_int
is an implicit casting helper
with the same purpose. The difference is that the former will always return a string whereas the later will result in an error or data loss
if the value it acts on does not act like the type we are casting. Ruby will only return a value when objects act like the type.
Ruby is very strict when using an implicit casting helper to ensure that the value acts like the type we want.
irb> 19.99.to_i
=> 19
irb> 19.99.to_int
=> 19
irb> '19.99'.to_i
=> 19
irb> '19.99'.to_int
NoMethodError: undefined method `to_int` for "String":String
Did you mean? to_i
to_str
A lambda is a way to define a block & its parameters with some special syntax. You can save this lambda into a variable for later use.
The syntax for defining a Ruby lambda looks like this:
irb > say_something = -> { puts "This is a lambda" }
=> #<Proc:0x0000556829fa2fa8@(lambda)>
Defining a lambda won’t run the code inside it, just like defining a method won’t run the method, you need to use the call method for that.
irb > say_something = -> { puts "This is a lambda" }
=> #<Proc:0x0000556829fa2fa8@(lambda)>
irb > say_something.call
This is a lambda
=> nil
Procs are a very similar concept. But one of the differences is how you create them.
irb > my_proc = Proc.new { |x| puts x }
=> #<Proc:0x0000556829f8ad68@>
There is no dedicated Lambda class. A lambda is just a special Proc object. If you take a look at the instance methods from Proc, you will notice there is a lambda?
method.
irb > my_proc = Proc.new { |x| puts x }
=> #<Proc:0x0000556829f8ad68@>
irb > my_proc.lambda?
=> false
irb > my_lambda = -> { puts "This is a lambda" }
=> #<Proc:0x0000556829f59a60@(lambda)>
irb > my_lambda.lambda?
=> true
A proc behaves differently than a lambda, specially when it comes to arguments. Procs don’t care about the correct number of arguments, while lambdas will raise an exception.
irb > my_proc = Proc.new { |x,y| puts "I do not care about arguments!" }
=> #<Proc:0x0000556829f8ad68@>
irb > my_proc.call
I do not care about arguments!
=> nil
irb > my_lambda = -> x { "x = #{x}" }
=> #<Proc:0x000056145b4325e0@(lambda)>
irb > my_lambda.call
ArgumentError (wrong number of arguments (given 0, expected 1))
irb > my_lambda.call(10)
=> "x = 10"
to_a
is an explicit casting helper and is used to transform a value from one type to another. to_ary
is an implicit casting helper
with the same purpose. The difference is that the former will always return a string whereas the later will result in an error or data loss
if the value it acts on does not act like the type we are casting. Ruby will only return a value when objects act like the type.
Ruby is very strict when using an implicit casting helper to ensure that the value acts like the type we want.
irb > { key: :value }.to_a
=> [[:key, :value]]
irb > { key: :value }.to_ary
NoMethodError: undefined method `to_ary` for {:key=>:value}:Hash
Did you mean? to_a
The way the map
method works in Ruby is, it takes an enumerable object, (i.e. the object you call it on), and a block.
Then, for each of the elements in the enumerable, it executes the block, passing it the current element as an argument. The result of evaluating the block is then used to construct the resulting array.
In other words:
Applying map on an array returns a new array where each element is the result of evaluating the block with the element as an argument.
irb> a = [1, 2, 3]
=> [1, 2, 3]
irb> b = a.map { |n| n * 2 }
=> [2, 4, 6]
irb> b
=> [2, 4, 6]
each
is just another method on an object. That means that if you want to iterate over an array with each
, you’re calling the each
method on that array object.
It takes a list as it’s first argument and a block as the second argument. For every element in the list, it runs the block passing it the current element as a parameter.
You should use each
when you want iteration but don’t care about what it returns.
[1, 2, 3].each { |n| puts "Current number is: #{n}" }
irb> [1, 2, 3].each { |n| puts "Current number is: #{n}" }
Current number is: 1
Current number is: 2
Current number is: 3
=> [1, 2, 3]
irb> a = [1, 2, 3]
=> [1, 2, 3]
irb> b = a.each { |n| n * 2 }
=> [1, 2, 3]
irb> b
=> [1, 2, 3]
Ruby's Enumerable#cycle
offers an easy way to either repeat a certain pattern n times or just to switch between two predefined states.
Repeating a certain pattern:
irb> array = [1, 2, 3]
=> [1, 2, 3]
irb> array.cycle(3).to_a
=> [1, 2, 3, 1, 2, 3, 1, 2, 3]
Switching between two states:
irb> button = ['on', 'off'].cycle
=> #<Enumerator: ["on", "off"]:cycle>
irb> button.next
=> "on"
irb> button.next
=> "off"
Passes each element of the collection to the given block. The method returns true if the block never returns false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj }
which will cause all?
to return true when none of the collection members are false or nil.
irb> a = [1, 2, 3]
=> [1, 2, 3]
irb> a.all?(&:integer?)
=> true
irb> a.all?(&:odd?)
=> false
irb> a.all?
=> true
irb> a = [1, 2, nil]
=> [1, 2, nil]
a.all?
=> false
Passes each element of the collection to the given block. The method returns true if the block never returns true for all elements. If the block is not given, none?
will return true only if none of the collection members is true.
irb> a = []
=> []
irb> a.none?
=> true
irb> a = ['a', 'bb', 'c']
=> ["a", "bb", "c"]
irb> a.none? { |e| e.length > 1 }
=> false
irb> (1..10).none?(&:nil?)
=> true
Passes each element of the collection to the given block. The method returns true if the block ever returns a value other than false or nil. If the block is not given, Ruby adds an implicit block of { |obj| obj }
that will cause any?
to return true if at least one of the collection members is not false or nil.
irb> a = []
=> []
irb> a.any?
=> false
irb> a = [1, 'a']
=> [1, "a"]
irb> a.any? { |e| e.class == String }
=> true
irb> h = { a: 1, b: 2 }
=> {:a=>1, :b=>2}
irb> h.any? { |k, v| v.odd? }
=> true
Passes each element of the collection to the given block. The method returns true if the block returns true exactly once. If the block is not given, one?
will return true only if exactly one of the collection members is true.
irb> a = [500]
=> [500]
irb> a.one?
=> true
irb> a.one? { |e| e < 100 }
=> false
irb> (1..4).one? { |n| n % 2 == 0 }
=> false
Ever wondered how much power Ruby's count
method has? Besides counting the elements of an array, it can do pretty awesome things. So lets' start with the most common use case counting the elements of an array.
irb> numbers = [1,2,5,3,6,2,5,3]
=> [1, 2, 5, 3, 6, 2, 5, 3]
irb> numbers.count
=> 8
Let's say you want to count how often the number 3 is represented in the above array. The thought would be to use a loop an iterate over the array and increment a counter every time you see the number 3. But there is a better way. Just pass the object you looking for to the count
method.
irb> numbers.count(3)
=> 2
Finally, you can also pass a block to do more complicated counts.
irb> numbers.count(&:even?)
=> 3
Both methods are used to produce a shallow copy of obj—the instance variables of obj are copied, but not the objects they reference. clone
copies the frozen and tainted state of obj whereas dup
copies the tainted state of obj.
In general, clone and dup may have different semantics in the descendant classes. While clone is used to duplicate an object, including its internal state, dup typically uses the class of the descendant object to create the new instance. When using dup, any modules that the object has been extended with will not be copied.
irb> array = ['a','b','c']
=> ["a", "b", "c"]
irb> array.freeze
=> ["a", "b", "c"]
irb> array_clone = array.clone
=> ["a", "b", "c"]
irb> a_clone << "d"
RuntimeError: cant modify frozen Array
irb> array_dup = array.dup
=> ["a", "b", "c"]
irb> a_dup << "d"
=> ["a", "b", "c", "d"]
Returns a value from the hash for the given key. If the key can't be found, there are several options:
- will raise a KeyError exception when no arguments given
- if a default is given, then that will be returned
- if the optional code block is specified, then that will be run and its result returned.
irb> user = {'first_name': 'Dummy', 'last_name': 'User'}
=> {:first_name=>"Dummy", :last_name=>"User"}
irb> user.fetch(:first_name)
=> "Dummy"
irb> user.fetch(:email)
KeyError: key not found: :email
from (irb):5:in `fetch'
irb> user.fetch(:email, 'no email added')
=> "no email added"
irb> user.fetch(:email){ |e| "no #{e} added"}
=> "no email added"
Converts any arguments to arrays, then merges elements of self with corresponding elements from each argument.
This generates a sequence of ary.size n-element arrays, where n is one more than the count of arguments.
If the size of any argument is less than the size of the initial array, nil values are supplied.
If a block is given, it is invoked for each output array, otherwise an array of arrays is returned.
irb> first_names = ['George', 'Marcus', 'Brian']
=> ["George", "Marcus", "Brian"]
irb> last_names = ['Massy', 'Windmil']
=> ["Massy", "Windmil"]
irb> first_names.zip(last_names)
=> [["George", "Massy"], ["Marcus", "Windmil"], ["Brian", nil]]
Let's say we wanna add a new element to an array but we want to make sure to keep each element uniq. One way to achive this would be:
irb> alphabet = ['a','b','c']
=> ["a", "b", "c"]
irb> alphabet << 'c'
=> ["a", "b", "c", "c"]
irb> alphabet.uniq
=> ["a", "b", "c"]
Luckily Ruby offers Bitwise OR operator:
x |= y
is shorthand for:
x = x | y
So our example from above would become:
irb> alphabet = ['a','b','c']
=> ["a", "b", "c"]
irb> alphabet | ['c']
=> ["a", "b", "c"]
We can also assign more than one element at the same time:
irb> alphabet = ['a','b','c']
=> ["a", "b", "c"]
irb> alphabet | ['c','d']
=> ["a", "b", "c", "d"]
The Benchmark module provides methods to measure and report the time used to execute Ruby code. This report shows the user CPU time, system CPU time, the sum of the user and system CPU times, and the elapsed real time. The unit of time is seconds. Consider the following example:
require 'benchmark'
N = 1_000_000
puts RUBY_DESCRIPTION
Benchmark.bm(15, "concat/append") do |bm|
concat_report = bm.report("concat") { N.times { 'Hello' + ' ' + 'World' } }
append_report = bm.report("append") { N.times { 'Hello' << ' ' << 'World' } }
[concat_report / append_report]
end
~/: ruby concat_append_benchmark.rb
ruby 2.4.4p296 (2018-03-28 revision 63013) [x86_64-darwin17]
user system total real
concat 0.290000 0.000000 0.290000 ( 0.608981)
append 0.260000 0.000000 0.260000 ( 0.362523)
rescue/condition 1.115385 NaN NaN ( 1.679841)
The Ruby Logger class gives you a way to generate logs with a default output format & different levels of importance.
logger = Logger.new("my_log_file.txt")
For logging to the terminal just pass STDOUT
.
logger = Logger.new(STDOUT)
Logger levels are:
-
UNKNOWN: An unknown message that should always be logged.
-
FATAL: An unhandleable error that results in a program crash.
-
ERROR: A handleable error condition.
-
WARN: A warning.
-
INFO: Generic (useful) information about system operation.
-
DEBUG: Low-level information for developers.
Default log format is:
SeverityID, [DateTime pid] SeverityLabel -- ProgName: message
For instance:
I, [1999-03-03T02:34:24.895701 19074] INFO -- Main: info.
to_h
is an explicit casting helper and is used to transform a value from one type to another. to_hash
is an implicit casting helper
with the same purpose. The difference is that the former will always return a string whereas the later will result in an error or data loss
if the value it acts on does not act like the type we are casting. Ruby will only return a value when objects act like the type.
Ruby is very strict when using an implicit casting helper to ensure that the value acts like the type we want.
irb > rue.to_s
=> "true"
irb > true.to_str
=> NoMethodError: undefined method `to_str' for true:TrueClass
Did you mean? to_s
Ever wondered how you can use ruby code in the command line?
Running a ruby file from CMD:upcase
~/: ruby myprogram.rb
You can pass in code as a command-line argument to the ruby command...
~/: ruby -e "puts 'Hello World!'"
~/: Hello World!
and you have accss to the ARGV array to process additional passed arguments.
~/: ruby -e 'puts ARGV.inspect' 1 2 3 4
["1", "2", "3", "4"]
It is also possible to use the pipe command to execute ruby code.
~/: echo "puts 'Hello World!'" | ruby
~/: Hello World!
You an call .uniq
on the array after appending all elements. This will remove all elemnts that occure more than once in the array.
irb> array = []
=> []
irb> array << 1
=> [1]
irb> array << 2
=> [1, 2]
irb> array << 1
=> [1, 2, 1]
irb> array.uniq
=> [1, 2]
An ohter way is to only append an element if the array does not contain it already by using the '|'.
irb> array = []
=> []
irb> array << 1
=> [1]
irb> array << 2
=> [1, 2]
irb> array | [1]
=> [1, 2]
irb> array
=> [1, 2]