Buy @ Amazon

Search This Blog

May 29, 2014

Exploiting tap in Ruby

The instance method tap is available as part of Object class from Ruby 1.9.x onwards. Rubyists exploit it to different use cases for fun and fashion. This blog post is to share my thoughts on what I think tap is best for.

Stackoverflow, the life-saver for many developers has one instance where the accepted correct answer to the use of tap is more misleading. This prompted me to write this blog post. To reproduce the accepted answer, it goes like below:

When readers encounters the code like below, they would have to follow all the three lines and then recognize that is is just creating an instance named user.
user = User.new
user.username = "foobar"
user.password = "mypassword"
user.age = 15
The above code can be re-written as below to make the code immediately clear. A reader would not have to read what is inside the block to know that an instance user is created.
user = User.new.tap do |u|
  u.username = "foobar"
  u.password = "mypassword"
  u.age = 15
end
Based on my experience, in the context of real-world code, there should be many instances of code patterns like above. In such cases, it is much ideal to create an instance method of User like, say build, that is something like below than utilising tap.
class User
  attr_accessor :username, :password, :age
  def build(h)
    h.each do |k,v|
      sym = "#{k}=".to_sym
      self.send(sym, v) if self.respond_to?(sym)
    end
    self
  end
end

u = User.new.build :username => "ganesh", "password" => "mypass!!!", :age => 12, :sex => 'm'
p u

There is another example that states that tap can be used to contain related set methods within its block. I'd much rather build a composite method that contains all these methods within it than using method. It is this way I make my code more readable and concise.

Now you should be wondering, "What on earth can I use the "tap" method for? I'm so vying to exploit its potential."

I'd say the best use of tap method is for debugging and hardly anything else. To be specific, use tap to watch the value of an intermediate expression like below:
(1..10)              .tap {|x| puts "original: #{x.inspect}"}
.to_a                .tap {|x| puts "array: #{x.inspect}"}
.select {|x| x%2==0} .tap {|x| puts "evens: #{x.inspect}"}
.map { |x| x*x }     .tap {|x| puts "squares: #{x.inspect}"}
All the tap calls are meant for debugging the intermediate state of the expression in the chain-calls. Isn't this a lot better?

How tap works?

tap{|x|...} → obj
Yields x to the block, and then returns x. The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.

And for your information, the example and explanation is shamelessly reproduced from Ruby doc.

ProTip: The best way to learn and digest Ruby phrases is to get into the habit of reading Ruby Doc.

More examples of how tap is used in intermediate expressions for debugging purposes
myobject.methods.sort.tap {|arr| p arr}.grep(/taint/)

(a + b) (p - q) / (a - b).tap {|denominator| puts denominator}

def meth
  return (some complex expression).tap {|result| puts result}
end

References

Ruby API Doc for Object#tap
MenTaLguY's blog titled, "Eavesdropping on expression"