13. Метапрограмиране II

13. Метапрограмиране II

13. Метапрограмиране II

3 декември 2012

Днес

Въпрос 1

Как Ruby пази полета и методи?

  • Полетата се пазят в обекти
  • Методите се пазят в модули
  • Обеките нямат методи (освен ако не са модули)

Въпрос 2

Кажете ми всичко, което знаете за instance променливите.

  • Достъпни са в наследници
  • Не са директно достъпни извън обекта
  • Трябва да се ползват методи за достъп (напр. attr_accessor)
  • Могат да се достъпят "заобиколно" с instance_variable_get и компания

Въпрос 3

Кой е класът на "foo"? На Integer? На Class?

Кой е родителят на String? На Object? На Class?

"foo".class == String  # true
Integer.class == Class # true
Class.class == Class   # true

String < Object        # true
Object < BasicObject   # true
Class < Module         # true

Въпрос 4

Какво прави instance_eval?

Изпълнява блока с променен self.

Въпрос 5

Как Ruby знае къде да постави метод, дефиниран с def?

Винаги има текущ клас, в който този метод отива. Той може да се промени с module, class и class_eval. Всъщност, дори с instance_eval, но за това — по-късно.

def object.method

Може да (пре)дефинирате метод в конркетен обект.

things = [22, :f, 'Sofia']

def things.size
  -5
end

def things.asl
  "#{self[0]}/#{self[1]}/#{self[2]}"
end

things        # [22, :f, "Sofia"]
things.size   # -5
things.length # 3
things.asl    # "22/f/Sofia"

[].asl        # error: NoMethodError
[].size       # 0

Singleton класове

Singleton класове

визуализация

Object#singleton_class

Собственият клас е достъпен чрез #singleton_class

things = []

def things.answer
  42
end

things.singleton_class # #<Class:#<Array:0x9a4ec24>>
things.singleton_class.instance_methods(false) # [:answer]

[].singleton_class.instance_methods(false)     # []

Symbol и Integer

...и техните метакласове

Целите числа и символите нямат собствени класове. Това е заради оптимизация. В Ruby интерпретатора, те се представят по много различен начин от всички други обекти.

1_000.singleton_class # error: TypeError
:blah.singleton_class # error: TypeError

class << thing

алтернативен синтаксис

Можете да отворите собствения клас на обект с class <<

things = [22, :f, 'Sofia']

class << things
  def size
    -5
  end

  def asl
    "#{self[0]}/#{self[1]}/#{self[2]}"
  end
end

things.asl  # "22/f/Sofia"
things.size # -5

super и eigenclass

Оригиналният метод е достъпен чрез super.

super и eigenclass (2)

things = [22, :f, 'Sofia']

class << things
  def each
    super
    yield :P
  end
end

aggregated = []
for thing in things
  aggregated << thing
end

aggregated # [22, :f, "Sofia", :P]

super и eigenclass

OMG момент

Някой има ли идея защо super работи?

things = []

def things.answer
  42
end

things.singleton_class # #<Class:#<Array:0xa374f9c>>
things.singleton_class.superclass # Array

Да, eigenclass-ът е наследник на класа на обекта

superclass и eigenclass

визуализация

Класови методи

Вероятно помните, че класови методи могат да се дефинират така:

class Something
  def Something.foo() 42 end
  def self.bar() 42 end

  class << self
    def qux() 42 end
  end
end

Класови методи

...всъщност

Класовите методи се пазят в собствения клас на класа

class Something
  def self.answer() 42 end
end

Something.singleton_class # #<Class:Something>
Something.singleton_class.instance_methods(false) # [:answer]

Класови методи

визуализация

extend

...върху клас

Помните ли extend?

module Knowledge
  def answer() 42 end
end

class Something
  extend Knowledge
end

Something.answer # 42

extend

...върху не-клас

module Knowledge
  def answer() 42 end
end

text = "fourty-two"
text.extend Knowledge

text.answer # 42

Сещате ли се как може да се имплементира?

extend

...с class <<

module Knowledge
  def answer() 42 end
end

class Something; end

class << Something
  include Knowledge
end

Something.answer # 42

extend

...чрез instance_eval и eigenclass

module Knowledge
  def answer() 42 end
end

class Something; end

Something.singleton_class.instance_eval { include Knowledge }

Something.answer # 42

Класови методи и наследяване

Класовите методи на родителя са достъпни в класовите методи на наследника

class Something
  def self.answer() 42 end
end

class Other < Something
  def self.better_answer() answer * 2 end
end

Other.better_answer # 84

Класови методи и наследяване

друг OMG момент

Собственият клас на наследника наследява собствения клас на родителя

class Something; end
class Other < Something; end

Something.singleton_class        # #<Class:Something>
Other.superclass.singleton_class # #<Class:Something>

Something.singleton_class == Other.singleton_class.superclass # true

Класови методи и наследяване

визуализация

Класови методи и наследяване

takeaway

Метакласът на суперкласа е суперкласът на метакласа.

Grand Unified Theory

  1. Има само един вид обекти - били те обикновени или модули
  2. Има само един вид модули - били те обикновени или клас
  3. Има само един вид методи - живеят в модули, които често са класове
  4. Всеки обект има "реален клас" - бил той обикновен клас или собствен клас
  5. Всеки клас има точно един суперклас - с изключение на BasicObject
  6. Суперкласът на метакласа на обект е класът на обекта. Суперкласът на метакласа на клас е метакласът на родителя на класа.
  7. При извикване на метод, Ruby взема "реалния клас" и търси в неговия ancestor chain

Въпроси