Ruby: определите класс, который возвращает что-то кроме себя, когда экземпляр вызывается без каких-либо методов - PullRequest
1 голос
/ 07 июля 2011

Мне интересно, есть ли способ вернуть объект вместо строки при вызове объекта без каких-либо методов.

Например:

class Foo
  def initialize
    @bar = Bar.new
  end
end

Есть ли способ определить класс Foo, чтобы произошло следующее:

foo = Foo.new
foo #returns @bar  

В конкретном случае, который меня интересует, я использую презентатор в представлении Rails. Докладчик устанавливает один основной объект, а затем загружает кучу связанного содержимого. Важная часть выглядит так:

class ExamplePresenter

  def initialize( id )
    @example = Example.find( id )
  end

  def example
    @example
  end

  ...

end

Если я хочу вернуть пример, используемый ExamplePresenter, я могу позвонить:

@presenter = ExamplePresenter.new(1)
@presenter.example

Было бы неплохо, если бы я мог также вернуть пример объекта, просто вызвав:

@presenter

Итак, есть ли способ установить метод по умолчанию, который будет возвращаться при вызове объекта, например, to_s, но возвращать объект вместо строки?

Ответы [ 2 ]

1 голос
/ 07 июля 2011

Если я правильно понимаю, вы хотите вернуть экземпляр Example при вызове экземпляра ExamplePresenter. Такого прямого механизма не существует ни в одном языке, и даже если бы он существовал, он заблокировал бы весь доступ к экземпляру ExamplePresenter и его методам. Так что это не логично.

Однако вы можете кое-что сделать. Вы можете создать методы делегата класса ExamplePresenter для экземпляра Example внутри него. По сути, вы не получаете реальное Example от @presenter, но вы получаете ExamplePresenter, который передает все подходящие методы в свой внутренний Example, эффективно действующий от его имени.

Некоторые способы сделать это:

method_missing

class ExamplePresenter
  … # as defined in the question

  def method_missing symbol, *args
    if @example.respond_to?(symbol)
      @example.send(symbol, *args)
    else
      super
    end
  end
end

Это передаст любой вызов метода внутреннему Example, если ExamplePresenter не сможет ответить на него. Будьте осторожны, вы можете выставить больше, чем вы хотите, для внутреннего Example таким образом, и любой метод, уже определенный в ExamplePresenter, не может быть передан.

Вы можете использовать дополнительную логику внутри method_missing для ограничения экспозиции или предварительной / последующей обработки аргументов / возвращаемых значений.

Методы обертки

Вы можете определить методы-оболочки в ExamplePresenter, которые ничего не делают, но передают все во внутренний Example. Это дает вам явный контроль над тем, сколько из этого вы хотите выставить.

class ExamplePresenter
  … # as before

  def a_method
    @example.a_method
  end
  def another_method(argument, another_argument)
    @example.another_method(argument, another_argument)
  end
end

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

Вы также можете смешивать и сочетать два вышеуказанных метода

Делегатор Библиотека

В Ruby stdlib есть библиотека с именем Делегатор , созданная специально для этой цели. Вы можете посмотреть на это.

0 голосов
/ 07 июля 2011

Хотя это не рекомендуется, вы можете сделать:

class Foo
  def self.new
    @bar = Bar.new
  end
end

Если вам действительно нужно создать экземпляр Foo, тогда

class << Foo
  alias original_new :new
end

class Foo
  def self.new
    self.original_new # It will not be useful unless you assign this to some variable.
    @bar = Bar.new
  end
end
...