Понимание класса Ruby и методов экземпляра - PullRequest
2 голосов
/ 20 апреля 2010

У меня есть следующий код:

#!/usr/bin/ruby

class Person
  def self.speak
    p = self.new
    puts "Hello"
    p.chatter
  end

private

  def chatter
    puts "Chattering"
  end
end

p = Person.new
Person.speak

Я хотел бы сделать чат частным, доступным только в пределах p ... но я хочу, чтобы p мог получить к нему доступ в методе класса. Есть ли лучший способ сделать это так, чтобы болтовня была недоступна для публики, но такой «фабричный» метод, как self.speak, может вызвать болтовню?

Ответы [ 2 ]

8 голосов
/ 20 апреля 2010

В Ruby 1.8.7 «send» обходит обычную защиту от вызова приватных методов:

#!/usr/bin/ruby1.8

class Person

  def self.speak
    puts "Hello"
    new.send(:chatter)
  end

  def speak
    puts "Hello"
    puts chatter
  end

  private

  def chatter
    puts "Chattering"
  end

end

Person.speak        # => Hello
                    # => Chattering
Person.new.speak    # => Hello
                    # => Chattering

Однако то, что вы хотите, может быть достигнуто без какого-либо вуду, просто заставив метод класса выполнить всю работу, а метод экземпляра отложить до метода класса:

class Person

  def self.speak
    puts "Hello"
    puts "Chatter"
  end

  def speak
    self.class.speak
  end

end

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

module DelegateToClass

  def delegate_to_class(name)
    define_method(name) do |*args|
      self.class.send(name, *args)
    end
  end

end

class Person

  extend DelegateToClass

  def self.speak
    puts "Hello"
    puts "Chatter"
  end
  delegate_to_class :speak

end

Встроенный модуль Forwardable может сделать это так же:

require 'forwardable'

class Person

  extend Forwardable

  def self.speak
    puts "Hello"
    puts "Chatter"
  end

  def_delegator self, :speak

end

def_delegator также обходит защиту от частных методов.

1 голос
/ 20 апреля 2010

Есть несколько способов сделать это. Одним из подходов будет метод класса, который создает новый экземпляр и вызывает метод #speak для этого экземпляра.

class Person
  def self.speak
    new.speak
  end

  def speak
    puts "Hello"
    chatter
  end

  private

  def chatter
    puts "Chattering"
  end
end

Тогда вы можете вызвать его в контексте класса или экземпляра:

p = Person.new
p.speak
# ...or...
Person.speak
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...