2009-11-24 4 views
17

Рассмотрим следующий код:методы экземпляра в модулях

module ModName 
    def aux 
    puts 'aux' 
    end 
end 

Если заменить module с class, мы можем сделать следующее:

ModName.new.aux 

модули не могут быть инстанс, хотя. Есть ли способ вызвать метод aux на модуле?

+3

для одноразового использования одноразового, вы можете сделать 'Object.new.extend (ModeName) .aux' – AJcodez

ответ

22

Подумайте о том, что aux есть. Какой объект ответит aux? Это метод экземпляра, который означает, что экземпляры классов, которые включают ModName, будут отвечать на него. Сам модуль ModName не является экземпляром такого класса. Это также не сработает, если вы определили ModName как класс - вы не можете вызвать метод экземпляра без экземпляра.

Модули очень похожи на классы, которые могут быть смешаны с другими классами, чтобы добавить поведение. Когда класс смешивается в модуле, все методы экземпляра модуля становятся экземплярами класса класса. Это способ реализации множественного наследования.

Они также служат заменой пространств имен, поскольку каждый модуль определяет пространство имен. Но это несколько не связано. (Кстати, классы также имеют свои собственные пространства имен, но делая это класс подразумевает, что вы будете создавать экземпляры этого, поэтому они концептуально неправильно для этой цели.)

+2

Один реальный прецедент для этого - это метод «помощника» Sinatra, который принимает модуль и смешивает его с запросами. Если ваши методы модуля не зависят от состояния (например, функции, которая форматирует строку, переданную в нее), они также могут быть соответствующим образом вызваны как «MyHelperModule.foo (bar)». Использование 'module_function' (в ответ на @ JPabloFernández ниже) позволяет получить доступ к модулю« экземпляр »в качестве запросов OP. – Phrogz

5

определения модуля имеет значение «это ...', Зачем?

В Ruby все выражается, нет заявлений или деклараций. Это означает, что каждый элемент оценивает значение. (Тем не менее, это не обязательно означает, что она имеет значения полезной значения . Например, метод puts всегда вычисляется в nil, так же, как выражение определению def метода (за исключением Rubinius, где выражение def оценивает к CompiledMethod объект для определяемого метода).

Итак, если все оценивает значение, что должно оценивать выражение определения модуля? Ну, есть пара кандидатов: он может оценивать до nil, как и выражение определения метода. Или он мог бы оценить сам объект модуля, в конце концов, это является, что мы определяем, не так ли? Но на самом деле, Matz выбрал третий вариант: выражения определения (и класса) фактически оценивают то, что оценивает последнее выражение внутри тела определения модуля. (Это позволяет легко имитировать две другие возможности, просто поместив nil или self в качестве последнего выражения внутри тела определения модуля.)

В вашем случае последним выражением внутри тела определения модуля является назначение. Но, задание? Что, черт возьми, , что возвращение? Разве это не утверждение? Нет, не в Руби. Все - это выражение, а присваивания не являются исключением: выражения присваивания оцениваются независимо от того, что оценивает правая сторона. Здесь правая часть выражения присваивания представляет собой строковый литерал, который вычисляет строковый объект.

Итак, выражение определения всего модуля оценивается по строке 'this is a const in module'.

+0

спасибо, Йорг W Миттаг, понял. – freenight

+6

Вопрос был сильно отредактирован с ответа Йорга, если кто-то немного смутился относительно того, о чем он говорит. –

0
class Foo 
    include ModName 
end 
Foo.new.aux 
# output: aux 
19

Вы можете сделать это следующим образом:

module ModName 
    def aux 
    puts 'aux' 
    end 
    module_function :aux 
end 

, а затем просто назвать его:

ModName.aux 
+4

Также: если вы используете модуль * исключительно * в качестве пространства имен, 'extend self' является более чистым вариантом для определения каждого метода в качестве модуля_функции. – yaauie

+1

@yaauie Если вы не передадите аргумент 'module_funciton', то любая функция под ним будет сделана функцией модуля. Он работает так же, как «частный». – LandonSchropp

14

Вы можете также сказать,

module ModName 
    extend self 

    def aux 
    puts 'aux' 
    end 
end 

Затем вы можете включать модуль, но также и методы вызова через ModName.

2

И немного больше ...

module Y 
    def Y.a 
    puts "a" 
    end 

    def Y.b 
    c 
    end 

    def self.c 
    puts "b -- c" 
    end 
end 

вызова (без '.new'):

Y.a #=> "a" 
Y.b #=> "b -- c" 
Y.C#=> "b -- c" 
+1

'Y.c' работает также. Вы также можете выполнить 'модуль Y; класс << self; def c; ставит «b-c»; конец; end; 'и определите' :: c' на своем eigenclass. –

Смежные вопросы