amber tunnell

puts 'my thoughts on the magic that is code'

Ruby magic

| Comments

I’ve been learning Ruby for about 2-3 months now, and I’ve already fallen in love. Hard. The language is so intuitive that often I find myself trying methods in Ruby that I’ve never learned about just because I think there is a good chance they’ll work. And, often if they don’t do exactly what I thought they did, they still do something interesting that is awesome.

In this post, I plan to discuss hidden Ruby tricks that many beginning Rubyists might not know about (yet!) that I’ve discovered online or through playing around with Ruby. This is by no means a comprehensive list, but I hope it illustrates a few of Ruby’s awesome tricks. They are all included in the Ruby Documentation if you want to learn more. Also, shout out in the comments if you know of any other good ones to add to the list!

.collect.with_index

This one may seem obvious to most, but it was a happy discovery for me last week when I was trying to solve a problem. I had been familiar with the method .each.with_index for a while, and every time I needed to use indexes while iterating, I used it. However, I prefer .collect over .each in most cases, and was frustrated that I couldn’t use indexes with collect. I’m not sure why I thought it could only work with .each, but I did for a while. But then I tried it with .collect, and it worked! .collect.with_index is a real thing! So, the method .with_index can work on either .each or .collect.

In general, .collect is preferable to .each in any iteration where you are trying to collect data from a block into a new array. The code written with .collect will be cleaner and more concise, as shown in the example below.

each.with_index
1
2
3
4
5
array = [1,2,3,4]

new_array = Array.new
array.each.with_index {|num, index| new_array << num * index }
new_array #=> [0,2,6,12]
collect.with_index
1
2
3
4
array = [1,2,3,4]

new_array = array.collect.with_index {|num, index| num * index}
new_array #=> [0,2,6,12]

.freeze

Freeze! Because this is Ruby, the method .freeze does exactly what you think it does. It freezes the object from being altered in any way. And you can even check if an object is frozen by asking it if it’s frozen! This may be useful if you have a class that you want to alter in your program until a certain condition is met, then if you want the object to be immutable you can just .freeze it from that point on.

.freeze
1
2
3
4
5
6
array = [1,2,3]
array.freeze
array.collect! {|num| num * 27}
  #=> "RuntimeError: can't modify frozen Array"
array.frozen?
  #=> true 

.to_s(base)

This was a cool discovery for me. If you convert an integer to a string (using .to_s), it can take an argument that will convert it to a different base. It works up to base 36.

.to_s(base)
1
2
3
4
5
6
7
8
#2 in binary
2.to_s(2) #=> "10"

#converting to binary
5678437.to_s(2) #=> "10101101010010101100101"

#converting to base 23
5678437.to_s(23) #=> "k6g6d"

Splat * symbol

Splat(*) is very cool and powerful. Here’s a few splat tricks I’ve learned.

allows an array to take unspecified amount of arguments

It allows an array to take any number of arguments, and returns those values in a array. You can use it with other aguments, if you want to separate the first or last argument from the array.

splat_power
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#splat argument as the only arugment 
def splat_is_awesome(*a)
  a
end

splat_is_awesome("and","it","looks","cool","too")
 #=> ["and", "it", "looks", "cool", "too"] 

#splat as last argument
def splat_power(a,*b)
  [a,b]
end

splat_power("powerful","stuff","here")
 #=> ["powerful", ["stuff", "here"]] 

#splat as first argument
def splat_power_reversed(*a,b)
  [a,b]
end

splat_power_reversed("powerful","stuff","here")
 #=> [["powerful", "stuff"], "here"] 

converts 1D array to a hash

I think this is the kind of thing that doesn’t seem very useful until you get that one rare type of problem where it ends up being perfect for. If you use splat * on an array as the key in a new Hash, it will automatically split the array into key-value pairs and then create the new hash. Note that it only works when you have an array with an even number of elements.

array to hash using splat
1
2
3
4
5
6
7
animals = ["cat","meow","snake","hiss"]
Hash[*animals] #=> {"cat"=>"meow", "snake"=>"hiss"} 

#It first splits the elements into pairs and then creates the Hash: 
# ["cat","meow","snake","hiss"] ==> 
# ["cat"=>"meow","snake"=>"hiss"] ==> 
# {"cat"=>"meow", "snake"=>"hiss"}  

Comments