2011-01-15 3 views
46

Скажите, что существует три класса: A, B & C. Я хочу, чтобы каждый класс имел метод класса, скажем self.foo, который имеет точно такой же код для A, B & C.Ruby: Можно ли определить метод класса в модуле?

Можно ли определить self.foo в модуле и включить этот модуль в A, B & C? Я попытался сделать это и получил сообщение об ошибке, заявив, что foo не распознается.

+1

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

ответ

34
module Common 
    def foo 
    puts 'foo' 
    end 
end 

class A 
    extend Common 
end 

class B 
    extend Common 
end 

class C 
    extend Common 
end 

A.foo 

Или, вы можете расширить классы впоследствии:

class A 
end 

class B 
end 

class C 
end 

[A, B, C].each do |klass| 
    klass.extend Common 
end 
+5

Не является ли 'foo' методом экземпляра A, B и C в этом случае? –

+3

Как уже указывал Андрей, методы Ruby всегда являются методами экземпляра. Но в этом случае экземплярами являются классы. Итак, 'foo' - это метод экземпляра класса. Вы называете это классом в качестве получателя: 'A.foo'. Из методов экземпляров A вы также можете использовать 'self.class.foo'. –

+1

@ MladenJablanović well, _instance_ обычно используется для обозначения объектов, которые генерирует класс, а не для самого объекта класса. Я предлагаю называть их _class methods_ вместо методов класса _class_, чтобы избежать путаницы. – Magne

88

Yep

module Foo 
    def self.included(base) 
    base.extend(ClassMethods) 
    end 
    module ClassMethods 
    def some_method 
     # stuff 
    end 
    end 
end 

Возможным примечание Я хотел бы добавить - если модуль будет ВСЕ методы класса - лучше всего с помощью extend ModuleName в модели и определения методов непосредственно в модуле, а не - а не имеющий модуль внутри методы класса модуля, а-ля

module ModuleName 
    def foo 
    # stuff 
    end 
end 
+0

Ах, это довольно изящно - спасибо Cratchitimo –

12

В Rails 3 представлен модуль с именем ActiveSupport::Concern, целью которого является упрощение синтаксиса модулей.

module Foo 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def some_method 
     # stuff 
    end 
    end 
end 

Это позволило нам сэкономить несколько строк кода «шаблона» в модуле.

7

Это базовая функциональность ruby ​​mixin, которая делает рубин таким особенным. В то время как extend превращает методы модуля в методы класса, include превращает методы модуля в методы экземпляра в классе/модуле включения/расширения.

module SomeClassMethods 
    def a_class_method 
    'I´m a class method' 
    end 
end 

module SomeInstanceMethods 
    def an_instance_method 
    'I´m an instance method!' 
    end 
end 

class SomeClass 
    include SomeInstanceMethods 
    extend SomeClassMethods 
end 

instance = SomeClass.new 
instance.an_instance_method => 'I´m an instance method!' 

SomeClass.a_class_method => 'I´m a class method'