Методы Ruby Singleton для класса и объектов
Я изучаю Ruby Singletons, и я нашел несколько способов определить и получить список методов Singleton класса и объекта.
Методы Singleton класса
Способы определения методов класса singleton:
class MyClass
def MyClass.first_sing_method
'first'
end
def self.second_sing_method
'second'
end
class << self
def third_sing_method
'third'
end
end
class << MyClass
def fourth_sing_method
'fourth'
end
end
end
def MyClass.fifth_sing_method
'fifth'
end
MyClass.define_singleton_method(:sixth_sing_method) do
'sixth'
end
Способы получения списка методов сингл-класса :
#get singleton methods list for class and it ancestors
MyClass.singleton_methods
#get singleton methods list for current class only
MyClass.methods(false)
Методы Singleton для объектов
Способы определения методов Singleton
class MyClass
end
obj = MyClass.new
class << obj
def first_sing_method
'first'
end
end
def obj.second_sing_method
'second'
end
obj.define_singleton_method(:third_sing_method) do
'third'
end
Способ получения списка методов Singleton
#get singleton methods list for object and it ancestors
obj.singleton_methods
#get singleton methods list for current object only
obj.methods(false)
Есть ли другие способы сделать это?
Ответы
Ответ 1
Прежде всего, способ перечислить методы singleton с помощью singleton_methods
. Метод methods
возвращает список имен общедоступных и защищенных методов объекта. Кроме того, он определен в классе Object
. Попробуйте extend
выполнить экземпляр. Это один из самых элегантных способов, поскольку он поддерживает повторное использование кода и кажется мне очень объектно-ориентированным:
class Foo
def bar
puts "Hi"
end
end
module Bar
def foo
puts "Bye"
end
end
f = Foo.new
f.bar
#=> hi
f.extend Bar
f.foo
#=> bye
f.methods(false)
#=> []
# the module we extended from is not a superclass
# therefore, this must be empty, as expected
f.singleton_methods
#=> ["foo"]
# this lists the singleton method correctly
g = Foo.new
g.foo
#=> NoMethodError
Изменить. В комментарии вы спросили, почему methods(false)
ничего не возвращает в этом случае. После прочтения кода C кажется, что:
-
methods
возвращает все доступные для объекта методы (также входящие в состав модулей)
-
singleton_methods
возвращает все однотипные методы для объекта (также входящие в состав модулей) (документация)
-
singleton_methods(false)
возвращает все одиночные методы для объекта, но не те, которые объявлены в включенных модулях
-
methods(false)
якобы возвращает одиночные методы, вызывая singleton_methods
, , но он также передает ему параметр false
; будь то ошибка или функция - я не знаю
Надеюсь, это немного разъяснит проблему. Итог: вызов singleton_methods
, кажется более надежным.
Ответ 2
Еще несколько способов:
Одноуровневые методы класса
class << MyClass
define_method :sixth_sing_method do
puts "sixth"
end
end
class MyClass
class << self
define_method :fourth_sing_method do
puts "seventh"
end
end
end
Одиночные методы объекта
class << obj
define_method :fourth_sing_method do
puts "fourth"
end
end
Далее вы можете использовать define_method
и define_singleton_method
в комбинации с send
, например
obj.send :define_singleton_method, :nth_sing_method, lambda{ puts "nth" }
и всех возможных комбинаций. Чтобы использовать define_method
, вам нужно сначала захватить класс singleton, как в этом (то же самое работает и для объектов класса)
singleton_class = class << obj; self end
singleton_class.send :define_method, :nth_sing_method, lambda{ puts "nth" }
Другие способы использования class_eval
для объектов одноэлементного класса:
singleton_class.class_eval do
def nth_sing_method
puts "nth"
end
end
И затем вы снова можете объединить send
с class_eval
...
Есть множество способов, я думаю:)
Ответ 3
Одиночные методы объекта
instance_eval
class A
end
a = A.new
a.instance_eval do
def v
"asd"
end
end
a.singleton_methods
=> [:z, :v]