After my last post on how Ruby initializes objects, Sagar shared with me following code.

class Abc
  attr_accessor :a, :b

  def self.new(a, b)
    @a = a
    @b = b
  end
end

o = Abc.new("a", "b")
puts o.a
puts o.b
>> o.a
=> NoMethodError

>> o.b
=> "b"
>>

o.a threw an error but surprisingly o.b is working.

I was a bit confused by looking this code because of the variables used and also usage of attr_accessors for more confusion.

To understand how this code works, we need to go back to basics.

What we learned in the “How Ruby initializes objects” blog post is that the Class#new method does three things.

  • Allocate object
  • Call initialize on object
  • Return the object

In Ruby, return value of a method is return value of the last statement in the method.

Let’s see our definition of new again.

def self.new(a, b)
  @a = a
  @b = b
end

This method will return value of b as the return value of new method. We can confirm this in IRB.

>> Abc.new("Hello", "World")
=> "World"

So no magic is going on and Ruby is not preferring b over a.

Now to know why o.b is working, we can check if someone has defined a method b on the o object.

>> o.method(:b)
=> #<Method: String#b>

Indeed! Ruby’s String class defines a method named b which returns copied string whose encoding is ASCII-8BIT.

>> checkmark = "\u2713"
=> "✓"
>> checkmark.b
=> "\xE2\x9C\x93"
>>

So there is no dark magic going on. It is just plain Ruby and we just found a mysterious method String#b.

Note: The documentation for this method already exists as pointed by few people. But it was a surprise for me to see a method named b. I had not come across this method before. Also some people asked what is the purpose of this blog post. I just want to share what I found interesting and learned.

Subscribe to my newsletter to know more about such interesting insights from Ruby language.