2012-03-27 15 views
8

Mam następujący kod:Nie rozumiejąc, moduły, klasy i metody klasy << samodzielne

class MyClass 
    module MyModule 
    class << self 

     attr_accessor :first_name 

     def myfunction 
     MyModule.first_name = "Nathan" 
     end 

    end 
    end 
end 

Kiedy wywołać metodę myfunction jak tak, to działa dobrze:

> me = MyClass::MyModule.myfunction 
=> "Nathan" 
> me 
=> "Nathan" 

Ale jeśli usunę kod class << self i dodaję prefiks self. do myfunction, to nie działa.

Na przykład:

class MyClass 
    module MyModule 

    attr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 


> me = MyClass::MyModule.myfunction 
NoMethodError: undefined method `first_name=' for MyClass::MyModule:Module 

Próbuję zrozumieć metodę class << self. Pomyślałem, że jest to sposób dodania prefiksu self. do wszystkich metod w nim zawartych, ale jeśli to prawda, dlaczego to nie działa, jeśli ją usunę i ręcznie każdą prefiksię ręcznie self.?

Z góry dziękuję za pomoc.

+2

Jeśli naprawdę chcesz dowiedzieć się szczegółów Ruby metaprogramowanie, polecam [metaprogramowanie Ruby książki Paolo Perrotta] (http://pragprog.com/book/ppmetr/metaprogramming-ruby) . – sarnold

Odpowiedz

7

Dzieje się tak, ponieważ twój attr_accessor :first_name jest również opakowany przez class << self.

to zrobić tak, jak sugerują, można użyć mattr_accessor tak:

require 'active_support' 

class MyClass 
    module MyModule 

    mattr_accessor :first_name 

    def self.myfunction 
     MyModule.first_name = "Nathan" 
    end 

    end 
end 
+0

A więc jest to specyficzna sprawa dla szyn, która polega na active_support? Zakładam, że mattr_accessor jest specyficzną dla modułu metodą ustawiającą/pobierającą? – Nathan

+0

Zgadza się. Na dobre i na złe, 'mattr_accessor' jest dostępny tylko przez Railsy. – jnevelson

+0

Istnieje kilka rzeczy, które czasami chciałbym były dostępne również w zwykłych Ruby, nie tylko Railsach czy ActiveRecord. –

4

Aby lepiej zrozumieć, w jaki sposób można osiągnąć to, co chcesz, spójrz na poniższym przykładzie:

module PrintingModule 

    def self.included(object) 
    object.extend(ClassMethods) 
    end 

    module ClassMethods 

    def class_method_of_class 
     puts "I am class #{self.name}" 
    end 

    end 

    def instance_method_of_class 
    puts "My name is: #{@name}" 
    end 

    class << self 
    def static_module_method 
     puts "Printer version 1.0" 
    end 
    end 
end 

class SomeObject 
    include PrintingModule 
    def initialize(name) 
    @name = name 
    end 
end 

object = SomeObject.new("Something") 
object.instance_method_of_class 
SomeObject.class_method_of_class 
PrintingModule.static_module_method 

mam nadzieję, że jest to bardziej oczywiste, teraz, trzeba pamiętać, że jest to tylko jeden z możliwych sposobów (są inne)

UPDATE: Postaram się być bardziej szczegółowy. Kiedy definiujesz metody instancji/singleton w module, to tak naprawdę to, że definiujesz metody instancji klasy, które będą zawierały ten moduł, a z drugiej strony, metody klasy zdefiniowane w module staną się metodami klasy tego modułu. Druga myśl polega na tym, że attr_accessor tworzy metodę instancji dla gettera i ustawiającego dla danego parametru.

Teraz, aby odpowiedzieć na jedną część pytania, w pierwszym przykładzie tworzysz 3 klasy metod w klasie modułu. W drugim tworzysz metodę 1-klasową, w której próbujesz uzyskać dostęp do innej metody klasy (setter), ale twoje pobierające i ustawiające są zdefiniowane jako metody instancji = staną się instancją metody klasy, która będzie zawierać twój moduł, nie można się do nich dostać w ten sposób = nie masz dostępu do swoich pobierających i ustawiających. Co do wyjaśnienia siebie, cóż, nie jestem tak utalentowany, ale o ile wiem, kiedy używasz "class < < self", otwierasz eigenclass (każdy obiekt ma swój własny anonimowy) obiektu (zauważ że Klasa, moduły lub instancje klas są oczywiście obiektami), w których definiujesz metody instancji. Metoda klas obiektu w Ruby = metoda instancji obiektu obiektu. Więc można to zrobić na przykład:

text = "something" 
class << text 
    def say_hi 
    puts "Hi!" 
    end 
end 

text.say_hi 

Podczas tworzenia instancji klasy (string w tym przykładzie), że instancja dostaje swój własny niepowtarzalny anonimowy klasy, która jest podklasą tej klasy. W tym przykładzie zdefiniowano metodę instancji w elemencie podklasy anonimowej klasy String. Możesz więc użyć metody "say_hi" na obiekcie tekstowym, ale nie w klasie String. Tak więc "klasa < < self" otwiera te eigenclasses.

Z drugiej strony samo "samo" reprezentuje obiekt w bieżącym kontekście, co oznacza to samo w niektórych scenariuszach (na przykład w twoim). Jeśli chodzi o metodę self.included, jest to po prostu metoda wywołania zwrotnego, która jest wywoływana, gdy moduł jest zawarty w klasie z parametrem reprezentującym obiekt (tutaj klasa SomeObject).

Mam nadzieję, że odpowiedziałem na przynajmniej część Twojego pytania. Więcej informacji tutaj: Difference between 'self.method_name' and 'class << self' in Ruby

+0

Widzę, jak używasz mixinów i większość z nich ma sens, z wyjątkiem 'def self.included (object) ...' stuff up top. Chodzi o to, że nie tyle staram się osiągnąć coś tak dużo, jak próbuję zrozumieć zachowanie. Nie jestem pewien, czy twój przykład wyjaśnił, dlaczego 'klasa << self' działała z modułem mieszanym, ale przedrostek' .self 'nie próbował uzyskać dostępu do metody klasy. Właściwie jestem zdezorientowany w moich przykładach, w jaki sposób metoda instance: first_name jest dostępna z wywołaniem klasy. – Nathan

+0

Mam zaktualizowaną odpowiedź, mam nadzieję, że odpowie na przynajmniej część twoich pytań. Miłego dnia. – Giron

Powiązane problemy