Tips and Tricks to Code Ruby at a Higher Level

Ruby is an interesting language. But when it comes to comparing it to giant classic languages like C or Java, it’s actually quite new. For those who are familiar with these classic languages, it’s not so simple to approach Ruby’s syntax even though it’s language is so close to the verbal language. In addition, because of its flexibility, you may not know which symbol to use or you may not even know if it exists. Today, we’ll review some tips that Ruby ninjas use in order to optimize their code. After reviewing this, we’d recommend using them in your daily coding or at least not to be confused when reading Ruby code from Ruby experts. Shall we begin?

The Basics

Basic shortcuts

First, in Ruby, there are some succinct ways to create some kind of object like [] to create array or {} to create Hash (or block/proc). Other than that, we can:

String

%{} or %Q{} are different ways to represent a double quote string and they can store string interpolation. By using this way, you don’t need to care about the annoying double quote character () like working with a standard string and a double quotation:
irb(main):001:0> %{Hi! I am a string!}
=> "Hi! I am a string!"
irb(main):002:0> %Q{Me too! "_"}
=> "Me too! \"_\""
irb(main):003:0> %{You're 5. I am older than you 2 years old, so I am #{5+2} years old.}
=> "You're 5. I am older than you 2 years old, so I am 7 years old."
On the other hand, %q{} is equivalent to a single quote string. It means that you cannot use string interpolation when it comes to age calculation like the above example.
irb(main):004:0> %q{#{2 + 5} equals to?}
=> "\#{2 + 5} equals to?"

Array

%w and %W can be used as what String#split can do. It splits a string into words by spaces. If you want to escape some spaces, you can use \ character like escaping a quotation character from a string. The difference between %W and %w is that %W allows string interpolation.
irb(main):005:0> %w{Fruits\ I\ like: oranges apple banana}
=> ["Fruits I like:", "oranges", "apple", "banana"]
irb(main):006:0> %W{I\ ate #{1+8}\ apples\ today}
=> ["I ate", "9 apples today"]

Regex

Usually, // is used to express a Regular Expression but if you want to escape the / character, you can use %r as below:
irb(main):001:0> %r{%d/%d}
=> /%d\/%d/

Symbol

Similar to the above example, we can use %s to create symbols instead of : or :”” to escape special characters. One note, %s does not support string interpolation.
irb(main):002:0> %s{studyId}
=> :studyId
irb(main):003:0> %s{hi:man}
=> :"hi:man"
irb(main):004:0> %s{id#{1+2}}
=> :"id\#{1+2}"
irb(main):005:0> :"id#{1+2}"
=> :id3

Shelling out

When text is wrapped in backquotes (or backticks), the text inside of it is passed to a special function named Kernel.`. This function executes the content inside the quotes like in a shell command and returns a string of results. Instead of using backticks you can use %x instead. It supports string interpolation as well.
irb(main):006:0> `echo welcome 2019!`
=> "welcome 2019!\n"
irb(main):007:0> `echo welcome #{2018+1}!`
=> "welcome 2019!\n"
irb(main):010:0> %x{echo welcome #{2018+1}!}
=> "welcome 2019!\n"

Lambda literal

This is a simple way to define scope in Rails by using ->:
irb(main):013:0> add = -> (a, b) { a + b }
=> #<Proc:0x007f80028cce98@(irb):13 (lambda)>
irb(main):015:0> add.call(1, 2)
=> 3

Sneak Peek

Something more interesting

We will now give you a sneak peek into some Ruby tricks that you may not have come across yet if you haven’t been coding Ruby for very long. If you master these tricks, you will be sure to distinguish your Ruby abilities from the rest of the pack.

Parameter with *, ** prefix

Take a look at this function:
def my_func  a, *b, **c
   return a, b, c
end
In this function, a is a normal parameter, With b, all arguments get passed to the function except a, which will be stored in b as an array. And finally with c, if you pass arguments by key-value type at the end of the function calling, they will be stored in c:
irb(main):001:0> def my_func a, *b, **c
irb(main):002:1>   return a, b, c
irb(main):003:1> end
=> :my_func
irb(main):004:0> my_func 1, 2, 3, 4, a: 5, b: 6
=> [1, [2, 3, 4], {:a=>5, :b=>6}]
irb(main):005:0>

Handle objects like an array

Sometimes, you need to handle input data with flexible types, maybe it’s an object or it’s an array. Normally, you need to check if it’s an array or not. But by using this trick, you can treat your object like a normal array with [*object] or [*array] or Array(something).
irb(main):005:0> number = 1
=> 1
irb(main):006:0> array = [2, 3, 4]
=> [2, 3, 4]
irb(main):007:0> [*number].each { |s| s }
=> [1]
irb(main):008:0> [*array].each { |s| s }
=> [2, 3, 4]

Tap method

tap is an interesting method. It’s used to make manipulations on objects before returning them. tap was created for tapping into method chains, it just allows you to do something with an object inside of a block, and to always have that block returned to the object itself. So the code:
def something
 result = operation
 do_something_with result
 result
end
can be turned to:
def something
 operation.tap do |op|
   do_something_with op
 end
end

Copy Objects

Deep copy

When you copy an object, it means that you copy the reference to the copied object. As you can see:
irb(main):009:0> fruits = %w(apple banana orange)
=> ["apple", "banana", "orange"]
irb(main):010:0> new_fruits = fruits
=> ["apple", "banana", "orange"]
irb(main):011:0> fruits.map(&:object_id)
=> [70109297139200, 70109297139180, 70109297139160]
irb(main):012:0> new_fruits.map(&:object_id)
=> [70109297139200, 70109297139180, 70109297139160]
irb(main):013:0> fruits.object_id
=> 70109297139120
irb(main):014:0> new_fruits.object_id
=> 70109297139120
By using Marshall class, you can create an deep copy object:
irb(main):015:0> complete_new_fruits = Marshal.load Marshal.dump(fruits)
=> ["apple", "banana", "orange"]
irb(main):016:0> complete_new_fruits.object_id
=> 70109305512340
irb(main):017:0> complete_new_fruits.map &:object_id
=> [70109305512320, 70109305512280, 70109305512260]
For example, if I have an array of strings and I want to capitalize all the elements. Normally, you can write something like this:Using & to create procs
irb(main):018:0> fruits = ['banana', 'apple', 'orange']
=> ["banana", "apple", "orange"]
irb(main):019:0> fruits.map { |f| f.upcase }
=> ["BANANA", "APPLE", "ORANGE"]
With & operator, it’s more elegant:
irb(main):021:0> fruits.map &:upcase
=> ["BANANA", "APPLE", "ORANGE"]
The & operator takes the method caller (the fruits object), and call the to_proc method on that object. If that object is a symbol, the to_proc function will create a proc and call the method with the name corresponding to the symbol via send method. So the above example is equivalent to:
irb(main):023:0> fruits.map {|f| f.send(:upcase)}
=> ["BANANA", "APPLE", "ORANGE"]
Now, instead of calling the instance method, we can do something like:
def demo_method(word)
 word + ' - ' + 'demo'
end
# Instead of:
res = arr.map{|str| demo_method(str)}
# We can:
res = arr.map(&method(:demo_method))

Conclusion

So as you can see the Ruby language is similar and different in many ways. Like with many things, the more experience and practice you have working with Ruby, the more skilled of a Ruby developer you will become. So what are you waiting for? Get coding!
Share this article:
You may be interested in these articles