Вызов метода методом в Ruby


У меня есть модуль, который генерирует номер телефона в нужном мне формате.

module PhoneNumber
  def self.prefix
    '+'
  end
  def self.country
    rand(1..9).to_s
  end
  def self.code
    rand(100..999).to_s
  end
  def self.number
    rand(1000000..9999999).to_s
  end
end

Я использую его следующим образом. Или в виде форматированной строки "#{}#{}".

phone_number = PhoneNumber.prefix +
               PhoneNumber.country +
               PhoneNumber.code +
               PhoneNumber.number

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

PhoneNumber.prefix.code.number
3   3   2018-08-24 21:22:47

3 ответа:

К цепным методам следует в основном постоянно возвращаться self из всех методов, которые вы собираетесь цеплять:

module PhoneNumber
  @number = ''
  def self.prefix
    @number << '+'
    self
  end
  def self.country
    @number << rand(1..9).to_s
    self
  end
  def self.code
    @number << rand(100..999).to_s
    self
  end
  def self.number
    @number << rand(1000000..9999999).to_s
    self
  end
  def self.to_s
    @number
  end
end

puts PhoneNumber.prefix.code.number
#⇒ +9065560843
Обратите внимание на явную реализацию #to_s для последнего шага, так как вам, вероятно, нужна строка в качестве результата, а не сам класс.

Эта реализация имеет Глюк: она вряд ли может быть повторно использована, так как существует один общий @number, поэтому вам лучше сделать все методы как методы экземпляра и сделать:

class PhoneNumber
  def initialize
    @number = ''
  end
  def prefix
    @number << '+'
    self
  end
  def country
    @number << rand(1..9).to_s
    self
  end
  def code
    @number << rand(100..999).to_s
    self
  end
  def number
    @number << rand(1000000..9999999).to_s
    self
  end
  def to_s
    @number
  end
end

puts PhoneNumber.new.prefix.code.number
#⇒ +6117160297

Теперь он работает для последующих вызовов.

Я согласен с Тоддом, что вы не должны этого делать; это будет неудобно реализовать и запутать людей, которые читают код (включая вас в будущем), поскольку это не типичный способ написания операций, о которых вы говорите.

Тем не менее, если вы действительно хотите сделать это, вам нужно будет предоставить метод под названием prefix, который возвращает другой объект, имеющий Метод code и так далее, сохраняя состояние вдоль цепочки и объединяя строки в конце. Он получит еще больше сложно, если вы хотите поменять местами порядок.

Настоятельно рекомендую метод, который выглядит следующим образом:

PhoneNumber.build(:prefix, :code, :number)

Оберните строковую конструкцию в метод класса

"точечный формат" на самом деле представляет собой набор цепных методов. Хотя вы могли бы предположительно сделать что-топодобное тому, что вы пытаетесь сделать, добавляя выходные данные каждого метода класса к строке в вашей цепочке методов, я бы счел это хрупким и сомнительным дизайном ООП.

На семантическом уровне, каждый метод в цепочке означает "делать X, чтобы возвращаемое значение предыдущий метод."Когда вы хотите описать членов АН объект, или другой вид инициализации, есть более идиоматические способы сделать это.

Не внося существенных изменений в существующий код, вы можете просто добавить метод PhoneNumber#create class, чтобы сделать тяжелую работу за вас. Например:

module PhoneNumber
  def self.create
    [self.prefix, self.country, self.code, self.number].join
  end

  def self.prefix
    '+'
  end

  def self.country
    rand(1..9).to_s
  end

  def self.code
    rand(100..999).to_s
  end

  def self.number
    rand(1000000..9999999).to_s
  end
end

if __FILE__ == $0
  puts PhoneNumber.create
end

Присоединение к массиву строковых объектов, возвращаемых другими методами класса, является достаточно идиоматичным, семантически ясным и устраняет необходимость изменения существующих методов класса, которые могут использоваться другими объектами в ваших программах. в настоящее время полагаются на. Это локализует изменения, что часто является хорошей вещью в дизайне ООП.

Параметризация метода илипреобразование модуля в класс , как описано в других ответах на ваш вопрос, также являются разумными альтернативами. Естественно, ваш пробег и стилистические вкусы могут отличаться.