2009-11-24 4 views
17

Considérez le code suivant:méthodes d'instance dans les modules

module ModName 
    def aux 
    puts 'aux' 
    end 
end 

Si nous remplaçons module avec class, nous pouvons faire ce qui suit:

ModName.new.aux 

Les modules ne peuvent pas être instanciés, cependant. Est-il possible d'appeler la méthode aux sur le module?

+3

pour une utilisation jetable, vous pouvez le faire 'Object.new.extend (ModeName) .aux' – AJcodez

Répondre

22

Pensez à ce que aux est. Quel objet répondra à aux? C'est une méthode d'instance, ce qui signifie que les instances de classes qui incluent ModName y répondront. Le module ModName lui-même n'est pas une instance d'une telle classe. Cela ne fonctionnerait pas non plus si vous aviez défini ModName comme une classe - vous ne pouvez pas appeler une méthode d'instance sans une instance.

Les modules ressemblent beaucoup aux classes qui peuvent être mélangées dans d'autres classes pour ajouter un comportement. Quand une classe se mélange dans un module, toutes les méthodes d'instance du module deviennent des méthodes d'instance de la classe. C'est une façon d'implémenter l'héritage multiple.

Ils servent également de substituts aux espaces de noms, puisque chaque module définit un espace de noms. Mais c'est un peu sans rapport. (Soit dit en passant, les classes ont aussi leurs propres espaces de noms, mais ce qui en fait une classe implique que vous allez créer des instances de celui-ci, ils sont donc conceptuellement mal à cette fin.)

+2

Un cas d'utilisation réel pour cela est avec la méthode 'helper' de Sinatra qui prend un module et le mélange en requêtes. Si vos méthodes de module ne dépendent pas de l'état (par exemple, une fonction qui formate une chaîne), elles peuvent également être appelées de manière externe sous la forme «MyHelperModule.foo (bar)». L'utilisation de 'module_function' (selon la réponse de @ JPabloFernández ci-dessous) permet d'accéder à une seule méthode 'instance' de module en tant que demandes OP. – Phrogz

5

la définition du module évalue à «c'est ...', Pourquoi?

Dans Ruby, tout est une expression, il n'y a pas d'instructions ou de déclarations. Ce qui signifie que everyhing évalue à une valeur. (Cependant, cela ne signifie pas nécessairement qu'il évalue à un utile valeur. Par exemple, la méthode puts évalue toujours nil, comme une expression de définition de la méthode def (sauf dans Rubinius, où l'expression def évalue à un CompiledMethod objet pour la méthode en cours de définition.)

Donc, si tout évalue à une valeur, à quoi devrait évaluer une expression de définition de module? Eh bien, il y a un couple de candidats: il pourrait évaluer à nil, tout comme une expression de définition de méthode. Ou il pourrait évaluer à l'objet module lui-même, après tout, ce est ce que nous définissons, non? Mais en réalité, Matz a choisi une troisième option: les expressions de définition de module (et de classe) évaluent en fait à quel que soit l'évaluation de la dernière expression dans le corps de définition de module. (Cela vous permet de simuler facilement les deux autres possibilités en mettant simplement nil ou self comme dernière expression dans un corps de définition de module.)

Dans votre cas, la dernière expression dans le corps de définition de module est une affectation. Mais, une mission? Que diable ne que retourner? N'est-ce pas une déclaration? Non, pas en Ruby. Tout est une expression, et les affectations ne font pas exception: les expressions d'affectation évaluent tout ce que le côté droit évalue. Ici, le côté droit de l'expression d'affectation est un littéral de chaîne, qui évalue un objet chaîne. Par conséquent, l'expression de définition de module entière est évaluée par rapport à la chaîne 'this is a const in module'.

+0

merci Jörg W Mittag, compris. – freenight

+6

La question a été fortement modifiée depuis la réponse de Joerg, si quelqu'un est un peu confus quant à ce dont il parle. –

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

Vous pouvez le faire de cette façon:

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

puis simplement l'appeler:

ModName.aux 
+4

Aussi: si vous utilisez le module * exclusivement * comme espace de nom, 'extend self 'est une option plus propre pour définir chaque méthode comme une fonction_module. – yaauie

+1

@yaauie Si vous ne transmettez pas un argument à 'module_funciton', toute fonction située en-dessous deviendra une fonction de module. Cela fonctionne de la même manière que 'private'. – LandonSchropp

14

Vous pouvez aussi dire

module ModName 
    extend self 

    def aux 
    puts 'aux' 
    end 
end 

Ensuite, vous pouvez inclure les module normalement, mais aussi appeler des méthodes via ModName.

2

Et un peu plus ...

module Y 
    def Y.a 
    puts "a" 
    end 

    def Y.b 
    c 
    end 

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

appel (sans '.new'):

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

'Y.c' fonctionne aussi bien. Vous pouvez aussi faire le module Y; classe << self; def c; met "b - c"; fin; end; 'et définit' :: c' sur sa classe propre. –

Questions connexes