Метод Ruby Bracket с блоком

Я хотел бы определить метод [] в классе моего собственного создания, чтобы взять блок. Я сделал это следующим образом.

class A
  def self.[](*args, &block)
    puts "I am calling #{block} on #{args}."
    block.(*args)
  end
end

Я могу вызвать это следующим образом.

# Explicit method invocation
A.[](1) { |x| puts x }
# With a procedure argument
arg = proc { |x| puts x }
A[2, &arg]

Однако, что я хотел бы быть в состоянии сделать это.

A[3] { |x| puts x }

Что, к сожалению, похоже, вызывает синтаксическую ошибку. Есть ли синтаксис блока для метода скобок, или я застрял с первыми двумя способами его вызова? На самом деле, в более общем смысле, какие имена методов Ruby будут разрешать блоки в их вызове, поскольку кажется, что может быть ограничение на то, когда это разрешено?


person Silvio Mayolo    schedule 22.01.2017    source источник
comment
Я не думаю, что есть способ. A.send('[]', 3) { |x| puts x } - это альтернатива, но не такая красивая.   -  person mrlew    schedule 22.01.2017


Ответы (2)


Вы мало что можете сделать против синтаксической ошибки, поэтому вам придется изменить синтаксис.

Если вы принимаете :

  • для определения (т.е. загрязнения) метода в верхнем регистре внутри Kernel (аналогично Kernel#Array)
  • использовать круглые скобки вместо скобок

Вы могли бы написать:

class A
  def self.call_block_with_args(*args, &block)
    puts "I am calling #{block} on #{args}."
    block.call(*args)
  end
end

module Kernel
  def A(*args, &block)
    A.call_block_with_args(*args, &block)
  end
end

Это работает следующим образом:

A(3) { |x| puts x }
#=>
# I am calling #<Proc:0x000000012b9c50@block_brackets.rb:14> on [3].
# 3

Это не чисто, но, вероятно, это самое близкое к A[3] { |x| puts x } место.

person Eric Duminil    schedule 22.01.2017
comment
Мне понравилось решение, не знал о модуле ядра +1 - person mrlew; 22.01.2017

Блоки работают только с обычными вызовами методов.

Ruby имеет множество операторов, перечислять их здесь было бы исчерпывающе, их более двух десятков. Даже `a`, !a и -a являются вызовами методов в Ruby. И очевидно, что у всех этих операторов есть ограничения, например, + должен принимать один параметр, но не больше, и так далее.

Забавный факт, loop тоже является вызовом метода.

person akuhn    schedule 22.01.2017