Category Archives: Ruby

Ruby Tuesday – Symbol#to_proc

Today’s Ruby Tuesday is on Symbol#to_proc.

Symbol#to_proc returns a Proc object which corresponds to the method represented by the symbol it is called on.

First, we will create a new method foo which just puts the string Foo to output.

def foo
  puts "Foo"
end
# => :foo

Now let’s call Symbol#to_proc on a couple of different symbols, and see what their return values are.

:foo.to_proc
# => #<Proc:0x007ff08395d9b0>
:to_s.to_proc
# => #<Proc:0x007ff0829f42a8>
:keys.to_proc
# => #<Proc:0x007ff0828280f0>

And we will also capture the results of calling to_proc on the symbol :to_s, so that we can be assured that it is the same Proc object later on.

to_s_proc = :to_s.to_proc
# => #<Proc:0x007ff0829f42a8>

Now that we have seen that Procs are being returned, it’s time to call those Procs to see how they behave.

:to_s.to_proc.call(1)
# => "1"
:foo.to_proc.call(1)
# Foo
# => nil
:keys.to_proc.call({:a => 1, :b => 2, :c => 3})
# => [:a, :b, :c]
:foo.to_proc.call()
# ArgumentError: no receiver given
# from (pry):40:in `call'
:foo.to_proc.call(1, 2, 3)
# ArgumentError: wrong number of arguments (2 for 0)
# from (pry):1:in `foo'

When we call a Proc generated in this way at the Ruby shell, the first argument is the context for what the Proc will be called against.

If we pass no arguments, we get an error of no receiver given, telling us that the Proc doesn’t have anything to call the method on.

:foo.to_proc.call()
# ArgumentError: no receiver given
# from (pry):40:in `call'

And if we pass in extra arguments to a Proc that was generated from calling Symbol#to_proc, it will error out as it expects the right number of arguments to be passed to the Proc.

:foo.to_proc.call(1, 2, 3)
# ArgumentError: wrong number of arguments (2 for 0)
# from (pry):1:in `foo'

And finally, we will call the Proc we captured in a variable, to show that the same Proc will operate against multiple objects of different types.

to_s_proc.call(1)
# => "1"
to_s_proc.call({:a => 1, :b => 2, :c => 3})
# => "{:a=>1, :b=>2, :c=>3}"

So we can see that the Proc we got from calling :to_s.to_proc will work and call to_s on both and integer and a Hash.

–Proctor

Ruby Tuesday – Symbol#id2name

Today’s Ruby Tuesday is on Symbol#id2name.

`Symbol#id2name` returns the string value for a given symbol that is the name of the symbol.

:foo.id2name
# => "foo"
:'HelloWorld'.id2name
# => "HelloWorld"
:nil.id2name
# => "nil"
:''.id2name
# => ""

If we scroll down the documentation page for `Symbol` down to Symbol#to_s, we can see it is using `id2name` in the example.

So let’s see if we can quickly notice a difference in what is returned.

:foo.to_s
# => "foo"
:''.to_s
# => ""
:nil.to_s
# => "nil"

We can see the behavior appears to indeed be the same, so we will dig a little deeper.

If you go to the documentation page for both methods, and then toggle the source for both of the methods, you can see they both use the underlying procedure `rb_sym_to_s`, and are infact aliases for each other.

–Proctor

Ruby Tuesday – Hash#fetch

Today’s Ruby Tuesday is on Hash#fetch.

Hash#fetch is one of those methods that would have to go in my Top 10 of most underutilized methods in Ruby.

Why would Hash#fetch make that list? Because it makes explicit the results of a key lookup in a Hash.

If we have a Hash constructed using a hash literal, and do a key lookup using the square brackets, it will return a nil when a key is not found, as nil is the default default-value for Hashes.

hash1 = {:a => 1, :b => 2, :c => 3}
# => {:a=>1, :b=>2, :c=>3}
hash1[:a]
# => 1
hash1[:d]
# => nil

You might be thinking, “That’s not so bad, I can just check for nils”.

What happens when there is a key that references nil? Now you can’t know if nil was in there because it was “valid”, or just returned.

hash2 = {:a => 1, :b => 2, :c => 3, :d => nil}
# => {:a=>1, :b=>2, :c=>3, :d=>nil}
hash2[:d]
# => nil

Or what happens when you get a Hash that was not created with a Hash literal?

hash3 = Hash.new {|hash, key| "foo"}
# => {}
hash4 = Hash.new("foo")
# => {}
hash3[:a]
# => "foo"
hash4[:a]
# => "foo"

Oops. We no longer get a nil back that we can check against.

This is where Hash#fetch becomes nice and explicit.

If we call Hash#fetch and no key is found, it will raise an key not found exception.

hash2.fetch(:d)
# => nil
hash1.fetch(:d)
# KeyError: key not found: :d
# from (pry):8:in `fetch'

Why is this nice? Well, it means we encountered and error, and we stop execution at the point of the error, instead of propagating nils throughout the code base to crash at some later point.

If we don’t want an exception, we can also pass in a default value to Hash#fetch allowing us to control the default value when a key is not found.

hash1.fetch(:d, :key_not_found)
# => :key_not_found
hash2.fetch(:d, :key_not_found)
# => nil
hash3.fetch(:a, :key_not_found)
# => :key_not_found
hash4.fetch(:a, :key_not_found)
# => :key_not_found

It even works when the Hash fetch is being called on specifies different default behavior.

Even when that default behavior would try to add the key into the Hash with a default value.

hash5 = Hash.new {|hash, key| hash[key] = "foo"}
# => {}
hash5.fetch(:d)
# KeyError: key not found: :d
# from (pry):43:in `fetch'
hash5.fetch(:d, "bar")
# => "bar"

Hash#fetch can also take a block that will be called with the key as an argument, when the key is not found in the Hash.

hash1.fetch(:d) do |key|
  puts "no key found for key: `#{key}`"
  :no_key_found
end
# no key found for key: `d`
# => :no_key_found

I encourage you to play with it, and see if it doesn’t start to creep up into your list of favorite methods that are underutilized.

–Proctor

Ruby Tuesday – Array#to_h

Today’s Ruby Tuesday is on Array#to_h.

Array#to_h will turn an Array of two element Arrays into a Hash where each two element Array represents a key value pair in the new Hash.

[[1, :a], [2, :b]].to_h
# => {1=>:a, 2=>:b}
[["cat", "meow"], ["dog", "woof"], ["mouse", "squeak"]].to_h
# => {"cat"=>"meow", "dog"=>"woof", "mouse"=>"squeak"}

If called on an Array that is not an Array of Arrays, you get a TypeError.

[1, 2, 3, 4].to_h
# TypeError: wrong element type Fixnum at 0 (expected array)
# from (pry):4:in `to_h'

If called on an Array that is an Array of Arrays, but the nested Arrays are not of length two, an ArgumentError is raised.

[[1, 2, 3], [2, 3, 4]].to_h
# ArgumentError: wrong array length at 0 (expected 2, was 3)
# from (pry):5:in `to_h'

The items in the nested arrays can be anything, even more Arrays, but those arrays will just be used as is.

[[1, [2, 3]], [[:a, :b], [3, 4]]].to_h
# => {1=>[2, 3], [:a, :b]=>[3, 4]}

–Proctor

Ruby Tuesday – Hash#invert

Today’s Ruby Tuesday is on Hash#invert.

Hash#invert will make the key the value, and the value the key, for each key-value pair in the hash.

{a: 1, b: 2, c: 3}.invert
# => {1=>:a, 2=>:b, 3=>:c}
{}.invert
# => {}
{twos: [2, 4, 6, 8], threes: [3, 6, 9], fives: [5, 10]}.invert
# => {[2, 4, 6, 8]=>:twos, [3, 6, 9]=>:threes, [5, 10]=>:fives}

This might seem like a odd thing to need, but sometimes your hash is not just a hash, but represents a bi-directional relationship.

One might use this when looking up DNA neucleobase pairings, where Adenine and Thymine always go together, and Guanine and Cytosine always pair togther, and we can create the full mapping by merging the mapping with it’s inverse.

{:A => :T, :C => :G}.invert
# => {:T=>:A, :G=>:C}
nucleobase_pairs.merge(nucleobase_pairs.invert)
# => {:A=>:T, :C=>:G, :T=>:A, :G=>:C}

Or when we have a mapping between a government id and a person (in the theoretically ideal world without identity theft), where we can get the person by their id, or the id for the person.

govt_ids_to_names = {123456789 => "Violetta",
                     999999999 => "Dilbert",
                     987654321 => "Nonnie Moose"}
# => {123456789=>"Violetta", 999999999=>"Dilbert", 987654321=>"Nonnie Moose"}
govt_ids_to_names.fetch(999999999)
# => "Dilbert"
govt_ids_to_names.invert.fetch("Nonnie Moose")
# => 987654321

And if we invert an inverted hash, we have the hash we started with.

govt_ids_to_names.invert.invert.fetch(123456789)
# => "Violetta"
govt_ids_to_names == govt_ids_to_names.invert.invert
# => true

–Proctor

Ruby Tuesday – Enumerable#group_by

Today’s Ruby Tuesday is on Enumerable#group_by.

Enumerable#group_by takes a block and returns a hash whose keys are the distinct values returned from the block, and the values are a list of items for which the block returned the key they are associated with.

This sounds a lot more complex than if you see it in code, so we will do a group_by of the range of numbers from one to ten, and group them by the result of calling even? on them.

(1..10).group_by(&:even?)
# => {false=>[1, 3, 5, 7, 9], true=>[2, 4, 6, 8, 10]}

We can se we have a hash with the two keys false and true, and the value for the key of false is a list of all the odd numbers, and the value for true is the list of the even numbers.

As the keys are just the return value, we can pass an array of strings, and group them by their first letter.

["foo", "bar", "bazz"].group_by(&:chr)
# => {"f"=>["foo"], "b"=>["bar", "bazz"]}

Or we can group them by their length,

["foo", "bar", "bazz"].group_by(&:length)
# => {3=>["foo", "bar"], 4=>["bazz"]}

Or, if we want to find some anagrams, we can group the words by the result of sorting their characters.

["tar", "rat", "bar", "rob", "art", "orb"].group_by {|word| word.chars.sort}
# => {["a", "r", "t"]=>["tar", "rat", "art"],
#  ["a", "b", "r"]=>["bar"],
#  ["b", "o", "r"]=>["rob", "orb"]}

This is also useful for when you are trying to get the start of some data to plot in a graph or a histogram, such as the length example above, or if we wanted to get a hash to be able to plot the number of words in the system dictionary against their length.

File.readlines("/usr/share/dict/words").
     map(&:strip).
     group_by(&:length).
     reduce({}) {|accum, kv| word_length, words = kv; accum[word_length] = words.length; accum}
# => {1=>52,
#  2=>160,
#  3=>1420,
#  5=>10230,
#  4=>5272,
#  8=>29989,
#  7=>23869,
#  9=>32403,
#  6=>17706,
#  11=>26013,
#  10=>30878,
#  12=>20462,
#  14=>9765,
#  16=>3377,
#  15=>5925,
#  20=>198,
#  19=>428,
#  17=>1813,
#  13=>14939,
#  18=>842,
#  21=>82,
#  22=>41,
#  23=>17,
#  24=>5}

–Proctor

Ruby Tuesday – Enumerable#find

Today’s Ruby Tuesday is on Enumerable#find a.k.a. Enumerable#detect.

Enumerable#find takes a predicate as a block and returns the first item for which the predicate returns true. If the predicate doesn’t return true for any of the items in the enumeration, nil is returned.

[1, 2, 3, 4, 5, 6, 7, 8, 9].find {|x| x > 5}
# => 6
[1, 2, 3, 4, 5, 6, 7, 8, 9].find {|x| x > 15}
# => nil

Enumerable#find can also take a “callable” as an argument, which will be called to if no item matches the predicate, and use that result as the return value of Enumerable#find.

[1, 2, 3, 4, 5, 6, 7, 8, 9].find(-> {:oops}) {|x| x > 15}
# => :oops
[1, 2, 3, 4, 5, 6, 7, 8, 9].find(-> {:oops}) {|x| x > 5}
# => 6
[1, 2, 3, 4, 5, 6, 7, 8, 9].find(-> {[true, false].sample}) {|x| x > 15}
# => false
[1, 2, 3, 4, 5, 6, 7, 8, 9].find(-> {[true, false].sample}) {|x| x > 15}
# => true
[1, 2, 3, 4, 5, 6, 7, 8, 9].find(-> {[true, false].sample}) {|x| x > 15}
# => false

–Proctor

Ruby Tuesday – Enumerable#lazy

Today’s Ruby Tuesday in on Enumerable#lazy.

Enumerable#lazy makes an enumerable so that it will evaluate only as a value is needed.

If we take a benchmark of calculating the squares of the first ten numbers in the range of one to one-million, we can see the time difference.

Benchmark.realtime{(1..1_000_000).map{|x| x^2}.take(10) }
# => 0.187007
Benchmark.realtime{(1..1_000_000).lazy.map{|x| x^2}.take(10) }
# => 3.2e-05

As we only end up taking the first ten results, the timing difference shows that we are only performing the square on the items needed when the range was declared as lazy, as opposed to calculating the squares of all of the numbers and taking the first ten of that result.

We can also see the effect when we take two infinite sequences, and try to zip them together, and print the first ten items.

abcs = [:a, :b, :c].cycle
# => #<Enumerator: ...>
 nums = [1, 2, 3].cycle
# => #<Enumerator: ...>
abcs.zip(nums).take(10).each{|x| puts x.inspect}
# ^CInterrupt:
# from (pry):58:in `next'

You can sit there all day, and more likely, all your life, at your Ruby prompt waiting for it to return, but it has to do the zip of two infinite sequences before it can take the first ten items.

If we make those infinite sequences lazy, we will zip those items together until only for as long as we need the data to complete the pipeline of operations, and it returns the result seemingly instantaneously.

lazy_abcs = [:a, :b, :c].cycle.lazy
# => #<Enumerator::Lazy: ...>
lazy_nums = [1, 2, 3].cycle.lazy
# => #<Enumerator::Lazy: ...>
lazy_abcs.zip(lazy_nums).take(10).each{|x| puts x.inspect}
# [:a, 1]
# [:b, 2]
# [:c, 3]
# [:a, 1]
# [:b, 2]
# [:c, 3]
# [:a, 1]
# [:b, 2]
# [:c, 3]
# [:a, 1]
# => nil

By using lazy, it not only allows us to save computation cycles avoiding work that would never be needed, but it can also open up new possibilities to structuring problems in a way that would never be able to be finished without lazy enumerables.

–Proctor

Ruby Tuesday – SecureRandom::uuid

Today’s Ruby Tuesday is on SecureRandom::uuid.

Sometimes you just want a unique identifier, and the more guaranteed to be unique the identifier is, the better.

Enter SecureRandom::uuid.

SecureRandom::uuid generates a new 128 bit identifier, and according to the RFC for a UUID, a.k.a GUID, is “guaranteed to be unique across space and time”.

While the math and avanced physics to prove that guarantee is beyond me, I have found that they are unqiue enough for every case that I have encountered so far. If you find otherwise I would love for you to let me know how you “broke” that guarantee.

To use SecureRandom::uuid, we first have to require 'securerandom'. And yes, this is one of those Ruby requires that does not have the name snake cased, but all one word.

require 'securerandom'
# => true
SecureRandom.uuid
# => "fc804c3a-def2-4739-a723-605992f055cc"
SecureRandom.uuid
# => "67986323-afe9-41c9-81d8-c91d13593534"
SecureRandom.uuid
# => "2deabd2c-55a1-48b5-8b6e-6ee96d56036e"
SecureRandom.uuid.class
# => String

This returns a Version 4 UUID, as can be seen by the 4 following the second dash in the UUID.

SecureRandom.uuid.class
# => String

Be warned though, that this doesn’t generate an actual UUID object, but just the String representation of a UUID, so if you need access to the raw bits of the UUID generated, you will likely need to track down another gem for that use case.

–Proctor

Ruby Tuesday – String#codepoints

Today’s Ruby Tuesday is on String#codepoints.

String#codepoints returns an Array of Integers that represent the values of the characters in the string.

"Hello, World!".codepoints
# => [72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33]
"rn".codepoints
# => [13, 10]

For ASCII characters this is what we would expect when looking at an ASCII chart of characters to the decimal value that represents them, but it also works on extended character sets such as Unicode.

"こんにちは世界".codepoints
# => [12371, 12435, 12395, 12385, 12399, 19990, 30028]
"💾".codepoints
# => [128190]

As String#codepoints returns an Array, we can also use the standard methods from the Enumerable module to modify a String.

"HAL".codepoints.map{|codepoint| codepoint + 1}.reduce("", &:<<)
# => "IBM"

And it even works on Unicode characters as well.

"💾".codepoints.map{|codepoint| codepoint + 1}.reduce("", &:<<)
# => "💿"

–Proctor