Подтвердить что ты не робот

Как работает оператор Ruby.()?

Недавно я встретил некоторый код, используя вызов метода, состоящий из формата object.(arg1, arg2), не видя хорошего объяснения того, как он работает. См. Этот пример кода:

class TestServiceObject
  def call
    'method'
  end
end

TestServiceObject.new.()
# => 'method'

Какой термин для такого рода сокращений?

4b9b3361

Ответ 1

Обозначение в виде точечных скобок является сокращенным способом передачи аргументов в неявный метод call объекта Ruby:

foo = lambda {|bar| puts bar}

foo.call('baz')
#=> baz
foo.('baz')

foo.call('baz') === foo.('baz')
#=> true

Также обратите внимание, что следующие обозначения также являются действительными (и эквивалентными) вызовами метода call:

foo['baz']
#=> baz
foo::('baz')
#=> baz

В вашем примере вы явно переопределяете метод call в классе TestServiceObject, чтобы он возвращал строку 'method' при вызове. Соответственно, вы можете явно переопределить метод call для принятия аргументов:

class TestServiceObject
  def call(foo=nil)
    foo || 'method'
  end
end

TestServiceObject.new.()
#=> method
TestServicesObject.new.('bar')
#=> bar

UPDATE

Как отмечает комментатор @LoganSerman, сокращенный оператор работает на все, что отвечает на call, что частично подтверждается следующим примером:

m = 12.method("+")

m.call(3)
#=> 15
m.(3)
#=> 15

ОБНОВЛЕНИЕ 2:

Как комментатор @Stefan также указывает на документацию на Proc#call

prc.() вызывает prc.call() с указанными параметрами. Его синтаксический сахар, чтобы скрыть "вызов".

Ответ 2

obj.(args) - это просто функция, предоставляемая через синтаксический анализатор. Технически не псевдоним, но он имеет тот же эффект, что и вызов obj.call(args) объекта, который определяет метод call.

Ответ 3

foo.(bar, baz)

интерпретируется как

foo.call(bar, baz)

как

foo + bar

интерпретируется как

foo.+(bar)

или

foo[bar, baz] = quux

интерпретируется как

foo.[]=(bar, baz, quux)

Цель состоит в том, чтобы объекты, похожие на функции, похожи на вызывающие методы:

foo.(bar, baz) # function
foo(bar, baz)  # method

Несмотря на утверждения в других ответах на этот вопрос, это не имеет никакого отношения к "неявному методу call" (Ruby даже не имеет неявных методов, только Scala) или оператора индексирования.

Оператор индексирования преобразуется в другой вызов метода ([]), а не в вызов call:

o = Object.new

def o.call(*args); "`call` called with #{args.join(', ')}" end

o.(42)
# => "`call` called with 42"

o[42]
# NoMethodError: undefined method `[]' for #<Object:0xdeadbeefc0ffee>

def o.[](*args);   "`[]` called with #{args.join(', ')}"   end

o[42]
# => "`[]` called with 42"