Zoeken…


Syntaxis

  • singleton_class = class << object; zelf einde

Opmerkingen

Singleton-klassen hebben slechts één instantie: het bijbehorende object. Dit kan worden geverifieerd door te vragen naar Ruby's ObjectSpace :

instances = ObjectSpace.each_object object.singleton_class

instances.count            # => 1
instances.include? object  # => true

Met < kunnen ze ook worden geverifieerd als subklassen van de werkelijke klasse van het object:

object.singleton_class < object.class  # => true

Referenties:

Invoering

Ruby heeft drie soorten objecten:

  • Klassen en modules die instanties zijn van klasse Klasse of klasse Module.
  • Gevallen van klassen.
  • Singleton klassen.

Elk object heeft een klasse die zijn methoden bevat:

class Example
end

object = Example.new

object.class  # => Example
Example.class # => Class
Class.class   # => Class

Objecten zelf kunnen geen methoden bevatten, alleen hun klasse kan dat. Maar met singleton-klassen is het mogelijk om methoden aan elk object toe te voegen, inclusief andere singleton-klassen.

def object.foo
  :foo
end
object.foo #=> :foo

foo is gedefinieerd op de singleton-klasse van het object . Andere Example kunnen niet op foo reageren.

Ruby maakt op verzoek singleton-lessen. Door ze te openen of methoden toe te voegen, moet Ruby ze maken.

Toegang tot Singleton Class

Er zijn twee manieren om de singleton-klasse van een object te verkrijgen

  • methode singleton_class .
  • Heropening singleton klasse van een object en terug te keren self .
object.singleton_class

singleton_class = class << object
  self
end

Toegang tot instantie- / klassenvariabelen in Singleton-klassen

Singleton-klassen delen hun instantie / klassenvariabelen met hun object.

class Example
  @@foo = :example
end

def Example.foo
  class_variable_get :@@foo
end

Example.foo #=> :example

class Example
  def initialize
    @foo = 1
  end

  def foo
    @foo
  end
end

e = Example.new

e.instance_eval <<-BLOCK
  def self.increase_foo
    @foo += 1
  end
BLOCK

e.increase_foo
e.foo #=> 2

Blokken sluiten rond hun doel / klasse variabelen doel. Toegang tot instantie- of klassenvariabelen met een blok in class_eval of instance_eval is niet mogelijk. Een string class_eval aan class_eval of class_variable_get gebruiken, class_variable_get het probleem.

class Foo
  @@foo = :foo
end

class Example
  @@foo = :example 

  Foo.define_singleton_method :foo do
    @@foo
  end
end

Foo.foo #=> :example

Overerving van Singleton Class

Subklasse ook Subklasse Singleton Class

class Example
end

Example.singleton_class #=> #<Class:Example>

def Example.foo
  :example
end

class SubExample < Example
end

SubExample.foo #=> :example

SubExample.singleton_class.superclass #=> #<Class:Example>

Het uitbreiden of opnemen van een module verlengt de Singleton Class niet

module ExampleModule
end

def ExampleModule.foo
  :foo
end

class Example
  extend ExampleModule
  include ExampleModule
end

Example.foo #=> NoMethodError: undefined method

Berichtpropagatie met Singleton Class

Instanties bevatten nooit een methode, ze dragen alleen gegevens. We kunnen echter een singleton-klasse definiëren voor elk object, inclusief een instantie van een klasse.

Wanneer een bericht wordt doorgegeven aan een object (methode wordt de methode genoemd), controleert Ruby eerst of een singleton-klasse voor dat object is gedefinieerd en of het op dat bericht kan reageren, anders controleert Ruby de klasse van de voorouders van de instantie en loopt daarop verder.

class Example
  def foo
    :example
  end
end

Example.new.foo #=> :example

module PrependedModule
  def foo
    :prepend
  end
end

class Example
  prepend PrependedModule
end

Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended

def e.foo
  :singleton
end

e.foo #=> :singleton

Singleton Classes heropenen (monkey-patching)

Er zijn drie manieren om een Singleton Class te heropenen

  • class_eval op een singleton-klasse.
  • class << blok gebruiken.
  • def gebruikt om rechtstreeks een methode voor de singleton-klasse van het object te definiëren
class Example
end

Example.singleton_class.class_eval do
  def foo
    :foo
  end
end

Example.foo #=> :foo

class Example
end

class << Example
  def bar
    :bar
  end
end

Example.bar #=> :bar

class Example
end

def Example.baz
  :baz
end

Example.baz #=> :baz

Elk object heeft een singleton-klasse waartoe u toegang hebt

class Example
end
ex1 = Example.new
def ex1.foobar
  :foobar
end
ex1.foobar #=> :foobar

ex2 = Example.new
ex2.foobar #=> NoMethodError

Singleton lessen

Alle objecten zijn instanties van een klasse. Dat is echter niet de hele waarheid. In Ruby heeft elk object ook een ietwat verborgen singleton-klasse .

Hierdoor kunnen methoden worden gedefinieerd voor afzonderlijke objecten. De klasse singleton bevindt zich tussen het object zelf en de werkelijke klasse, dus alle methoden die erop zijn gedefinieerd, zijn beschikbaar voor dat object en alleen voor dat object.

object = Object.new

def object.exclusive_method
  'Only this object will respond to this method'
end

object.exclusive_method
# => "Only this object will respond to this method"

Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>

Het bovenstaande voorbeeld had kunnen worden geschreven met define_singleton_method :

object.define_singleton_method :exclusive_method do
  "The method is actually defined in the object's singleton class"
end

Dat is hetzelfde als het definiëren van de methode in de singleton_class van het object :

# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
  "Now we're defining an instance method directly on the singleton class"
end

Vóór het bestaan van singleton_class als onderdeel van Ruby's kern-API, stonden singleton-klassen bekend als metaclasses en waren ze toegankelijk via het volgende idioom:

class << object
  self  # refers to object's singleton_class
end


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow