Jay-Ar Polidario
Jay-Ar Polidario

Reputation: 6603

How to define unnamed method in Ruby?

I was reading on cells gem when I suddenly got curious on its implementation of unnamed method in its documentation.

Particularly the code below:

CommentCell.(@comment).()

and

cell(:comment, @song).(:index)

where it uses .(arguments) without a method name.

I am certain the answer is just somewhere in the source code itself. But briefly looking at Cell::ViewModel doesn't immediately help me, so I was just wondering first if anyone knows how to do this before I thoroughly inspect the source code, and hopefully satisfies my curiosity.

I can see some uses of this in the app that I will be making soon.

Upvotes: 2

Views: 210

Answers (2)

Jörg W Mittag
Jörg W Mittag

Reputation: 369458

If you want to figure out what method call a particular piece of syntax translates to, you can try that out yourself:

class << foo = BasicObject.new
  def method_missing(meth, *args)
    $>.puts "`foo.#{meth}(#{args.inspect[1...-1]})`"
  end

  BasicObject.instance_methods.each(&method(:undef_method))
end

print '`foo.(1, 2, 3)` gets translated to '
foo.(1, 2, 3)
# `foo.(1, 2, 3)` gets translated to `foo.call(1, 2, 3)`

print '`not foo` gets translated to '
not foo
# `not foo` gets translated to `foo.!()`

print '`+foo` gets translated to '
+foo
# `+foo` gets translated to `foo.+@()`

print '`~foo` gets translated to '
~foo
# `~foo` gets translated to `foo.~()`

print '`foo[1, 2, 3] = 4` gets translated to '
foo[1, 2, 3] = 4
`foo[1, 2, 3] = 4` gets translated to `foo.[]=(1, 2, 3, 4)`

And so on …

As you can see, foo.(bar, baz) gets translated to foo.call(bar, baz).

Upvotes: 1

trust_nickol
trust_nickol

Reputation: 2114

.() looks like a method invocation missing the method name. This is syntactic-sugar that invokes the call method. It can be used with any object that defines a call method and works with Proc or lambda.

class Test
  def call
    puts "test"
  end
end

t = Test.new
t.()
# => "test"
lambda {puts "test"}.()
Proc.new {puts "test"}.()

But there are other possible solutions to react on .(). You could override method_missing or set an alias.

class Test
  def test
    puts "test"
  end

  alias call test;
end

t = Test.new
t.()
# => "test"

Upvotes: 4

Related Questions