Как связать методы в ruby, передавая вывод одного метода последовательным методам

Как я могу передать результаты метода другому методу в ruby? например:

class D
  def initialize(text)
    @text = text
  end

  def a s
    "hello #{s}"    
  end

  def b s
    "hi #{s}"
  end
end

Итак, что я хочу сделать, это передать вывод метода a методу b. Итак, по существу (если методы не находятся внутри класса) я могу сделать следующее:

puts b(a "Tom") #=>hi hello Tom

Однако, даже если это не внутри класса, было бы не очень хорошо, если бы было много методов, поэтому должен быть более элегантный способ сделать это. Так как же правильно получить вывод hi hello Tom, применив методы a и b к экземпляру класса D?

ОБНОВЛЕНИЕ Я просто хотел сделать это немного более ясным. Например, в F# вы можете сделать что-то вроде этого:

let a s = "hello " + s
let b s = "hi " + s
"Tom" |> a |> b #=> hello hi Tom

Здесь мы определили функции a и b, а затем передали результаты следующей функции. Я знаю, что это функциональный язык, поэтому способы ведения дел там будут другими. Но мне просто интересно, есть ли такие трюки в Ruby?


person B A    schedule 23.11.2016    source источник
comment
«Значит, должен быть более элегантный способ сделать это» — почему? Можно было бы использовать puts b a 'Tom', но я сомневаюсь, что это «более элегантно».   -  person Aleksei Matiushkin    schedule 23.11.2016
comment
@mudasobwa я понимаю. Я только что обновил вопрос, чтобы сделать его немного более понятным. Может быть, это помогло бы? :)   -  person B A    schedule 23.11.2016
comment
Остается вопрос: с какой стати вы считаете, что путь F# более элегантен?   -  person Aleksei Matiushkin    schedule 23.11.2016


Ответы (1)


Вы можете оставить ()

def a s
  "hello #{s}"
end

def b s
  "hi #{s}"
end

puts b a "Tom"

Если у вас много методов:

puts [:a,:b].inject("Tom"){|result,method| self.send(method,result)}

Если вы хотите использовать эти методы с любым объектом (включая классы):

module Kernel
  def chain_methods(start_value, *methods)
    methods.inject(start_value){|result,method| self.send(method,result)}
  end
end

class D
  def a s
    "hello #{s}"
  end

  def b s
    "hi #{s}"
  end
end

class E
  class << self
    def a s
      "hello #{s}"
    end

    def b s
      "hi #{s}"
    end
  end
end


# Example with instance methods
puts D.new.chain_methods("Tom", :a, :b)

# Example with class methods
puts E.chain_methods("Tom", :a, :b)

# Thanks mudasobwa :
E.chain_methods("Tom", :a, :b, :puts)
person Eric Duminil    schedule 23.11.2016
comment
Ура, проголосовал за puts [:a,:b].inject("Tom"){|result,method| Object.send(method,result)} :) Кстати, puts тоже можно связать. - person Aleksei Matiushkin; 23.11.2016
comment
Вау, это здорово! спасибо Эрик. Теперь, как я могу получить тот же результат, если методы находятся внутри класса, в моем примере допустим класс D, так как я могу получить результат, применяя методы к экземпляру класса D? Или я должен вместо этого использовать методы класса для этого? - person B A; 23.11.2016
comment
@BA вы можете определить экземпляр с помощью d = D.new("test") и вызвать d.send вместо Object.send - person Lukas Baliak; 23.11.2016
comment
@EricDuminil спасибо, кажется немного сложнее, чем ваш другой метод. :) - person B A; 23.11.2016
comment
Почему вы отправляете методы Object? В исходном коде они отправляются на self, поэтому вы вызываете совершенно другой метод. Хотя, пожалуйста, используйте вместо этого public_send, здесь нет причин нарушать инкапсуляцию. - person Jörg W Mittag; 26.11.2016
comment
Я хотел, чтобы код также работал, когда a и b определены в main, поскольку OP упомянул об этом. В этом случае это приватные методы, доступные каждому объекту. - person Eric Duminil; 27.11.2016