Метод, который возвращает выход для объекта в Ruby

Есть ли в Ruby метод, который возвращает содержимое блока, переданного объекту?

Например, что, если у меня есть объект, который я хочу поместить в массив?

В идеальном мире мы бы сделали (что я ищу):

"string".reverse.upcase.something{ |s| send(s) }

который вернет массив с моим объектом, что эквивалентно:

send("string".reverse.upcase)

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

Таким образом, метод something вернет оценку блока, например Array#map, но только для одного элемента.


person Jonathan Allard    schedule 28.09.2011    source источник
comment
Что вы имеете в виду под returns the content of the block passed on to an object?   -  person Dogbert    schedule 28.09.2011
comment
Метод будет оценивать содержимое блока и возвращать его.   -  person Jonathan Allard    schedule 28.09.2011
comment
Что вы подразумеваете под сохранением цепной связи? Каков результат JSON.parse(j)?   -  person mliebelt    schedule 28.09.2011
comment
@mlie Если вы посмотрите на первый фрагмент кода, мы можем повторно использовать результат метода, чтобы передать его другому методу и так далее, «связность». Если вы посмотрите на второй кусок кода, код несколько более беспорядочный, так как метод находится в начале. (Мне трудно выразить это словами, не стесняйтесь редактировать/комментировать)   -  person Jonathan Allard    schedule 28.09.2011
comment
Хорошо, теперь я понимаю. Я лично думаю, что наоборот: вызов во второй строке мне намного понятнее, фигурные скобки плохо читаются, а другие должны знать, что означает something...   -  person mliebelt    schedule 28.09.2011
comment
Я вижу, вы отредактировали свой вопрос, потому что, как я понимаю, вы хотите именно то, что ответил undur_gongor, так это или нет?   -  person derp    schedule 29.09.2011


Ответы (4)


Я не знаю такой встроенной вещи, но вы можете легко сделать это самостоятельно:

class Object
  def something(&block)
    block.call(self)
  end
end

p "foo".something { | o | [o] }
p 23.something { | x | p x; 42 }

дает

["foo"]      # object "foo" put into an array
23           # object handed to block
42           # something return block's result
person undur_gongor    schedule 28.09.2011
comment
Будущие читатели, это реализовано в ядре Ruby 2.5.0 как Object#yield_self. Смотрите мой обновленный ответ. - person Jonathan Allard; 11.10.2017

Вы ищете Object.tap?

person steenslag    schedule 28.09.2011
comment
Нет, Object#tap возвращает объект, для которого вызывается метод, тогда как мой метод вернет оценку блока. - person Jonathan Allard; 28.09.2011
comment
Интересная техника, не знала. - person mliebelt; 28.09.2011

Иногда мне хочется иметь подобную функцию в стандартной библиотеке. Например, имя может быть with или with_it.

(Повторение предыдущего кода с новым именем)

class Object
  def with_it(&block)
    block.call(self)
  end
end

Пример использования:

x = [1, 2, 3, 4, 5].map {|x| x * x }.with_it do |list|
   head = list.unshift
   list << head * 10
   list.join " / "
end

В отличие от:

list = [1, 2, 3, 4, 5].map {|x| x * x }
head = list.unshift
list << head * 10
x = list.join " / "

В то время как последнее легче понять, первое имеет то преимущество, что переменные list и head остаются ограниченными, а назначение x, на мой взгляд, более понятно (назначение x должно быть вставлено в последнюю строку кода). Область действия была бы полезной, если бы код был частью более крупного метода.

Таким образом, другим вариантом использования with_it будет размещение кода в отдельном методе. Например:

def mult_head_and_join(list)
    head = list.unshift
    list << head * 10
    list.join " / "
end

x = mult_head_and_join [1, 2, 3, 4, 5].map {|x| x * x }

Не знаю, чем здесь закончить, но я бы проголосовал за то, чтобы with_it был включен в стандартную библиотеку.

person Tallak Tveide    schedule 15.04.2014

Через шесть лет после первоначального вопроса в Ruby 2.5.0 появился Object#yield_self, который в Ruby 2.6 был сокращен до #then:

 class Object
   def yield_self(*args)
     yield(self, *args)
   end
 end

[...]

Он выполняет блок и возвращает результат.

(Функция Ruby #6721)

Например:

2.then{ |x| x*x }  # => 4
person Jonathan Allard    schedule 11.10.2017