Метод класса, чтобы «знать» имя класса в Ruby? - PullRequest
14 голосов
/ 13 ноября 2010

Я хочу, чтобы унаследованный класс ruby ​​«знал» имя своего класса через метод класса. Это лучше всего иллюстрируется надуманным примером:

class Parent
  def self.whoami
    ??
  end
end

class Child < Parent
  #No code should be needed.
end

Так что я должен быть в состоянии позвонить:

Parent.whomai

и ожидайте возвращения «Родителя», тогда я смогу позвонить:

Child.whoami

и ожидаю возвращения «ребенка». У меня такое чувство, что на обычных языках это может быть невозможно. Но модель метапрограммирования Руби поражала меня раньше. Какие-нибудь мысли? Заранее спасибо.

Ответы [ 4 ]

20 голосов
/ 13 ноября 2010

Метод класса - это метод, в котором CLASS является получателем, поэтому, чтобы найти объект, для которого вызывается метод (то, что вы пытаетесь сделать здесь), просто проверьте значение self.

class Parent
  def self.whoami
    self
  end
end

class Child < Parent
end

puts Parent.whoami #=> Parent
puts Child.whoami #=> Child
15 голосов
/ 13 ноября 2010

Метод для получения имени класса (на самом деле модуля) - это просто Module#name. Там нет необходимости писать свои собственные:

Parent.name # => 'Parent'
Child.name  # => 'Child'

Однако в Ruby действительно не существует такой вещи, как «имя класса», как в некоторых других языках. В Ruby класс - это просто объект, похожий на любой другой объект, который назначается переменной, как и любая другая переменная.

Все, что делает метод Module#name, это перебирает все константы в системе и проверяет, назначен ли модуль какой-либо из них, и возвращает имя этой константы или nil, если он не может их найти.

Таким образом, как и любой другой объект, «имя» класса - это на самом деле ничего, кроме любой переменной, которую вы используете для ссылки на него.

Пример:

foo = Class.new
foo.name # => nil

Теперь «имя» класса - foo. Однако Module#name возвращает nil, поскольку foo не является константой.

bar = foo
bar.name # => nil

Теперь «имя» класса равно и foo и bar, но Module#name, очевидно, все еще возвращает nil.

BAZ = foo
foo.name # => 'BAZ'

Теперь, поскольку класс был присвоен константе, имя этой константы будет считаться именем этого класса & hellip;

BAZ = nil
foo.name # => 'BAZ'
* * & Одна тысяча тридцать восемь hellip; даже после того, как константа была присвоена чему-то другому и & hellip;
QUX = foo
QUX.name # => 'BAZ'

& hellip; даже после присвоения классу другой константы.

Module#to_s использует Module#name, если это не nil, поэтому, чтобы напечатать имя класса, вы просто делаете

puts Parent

На самом деле абсолютно нет необходимости во всех сложных пухах в других ответах.

2 голосов
/ 13 ноября 2010

Разве это не то, что Parent.class скажет вам?

class Parent
  def self.whoami
    self.to_s
  end
end

class Child < Parent
end

> Parent.whoami
=> "Parent"
> Child.whoami
=> "Child"
1 голос
/ 11 июня 2013

Предположим, вы класс:

class ABC
 def self.some_method
   self.name #it will return 'ABC'
   self.name.constantize #it will return ABC
 end
end 
...