web-dev-qa-db-fra.com

Ruby: module, nécessite et inclut

J'essaie d'utiliser Ruby modules (mixins).

J'ai test.rb:

#!/usr/bin/env Ruby
require_relative 'lib/mymodule'

class MyApp
  include MyModule
  self.hallo
end

et lib/mymodule.rb:

module MyModule
  def hallo
    puts "hallo"
  end
end

Configuration assez simple. Mais cela ne fonctionne pas :(:

Ruby test.rb
test.rb:8:in `<class:MyApp>': undefined method `hallo' for MyApp:Class (NoMethodError)
        from test.rb:6:in `<main>'

Où est mon erreur?

41
Dakkar

En bref: vous devez extend au lieu de include le module.

class MyApp
  extend MyModule
  self.hallo
end

include fournit des méthodes d'instance pour la classe qui la mélange.

extend fournit des méthodes de classe pour la classe qui la mélange.

Donnez ceci une lecture.

67
Kyle

Le problème est que vous appelez hallo dans la définition de classe, tandis que vous l'ajoutez en tant que méthode d'instance (include).

Vous pouvez donc soit utiliser extend (hallo deviendrait une méthode de classe):

module MyModule
  def hallo
    puts "hallo"
  end
end

class MyApp
  extend MyModule
  self.hallo
end

Ou appelez hallo dans une instance de MyApp:

module MyModule
  def hallo
    puts "hallo"
  end
end

class MyApp
  include MyModule
end

an_instance = MyApp.new
an_instance.hallo
11
CCD

Votre code fonctionne - mais l'inclusion d'un module ne fait pas ce que vous pensez qu'il fait. La classe incluant le module n'obtiendra pas les méthodes - les objets de cette classe le seront.

Cela fonctionnera donc:

class MyApp
  include MyModule
end

my_app_object = MyApp.new
my_app_object.hallo # => hallo

my_app_object est un objet de classe MyApp, qui a un mixins de module MyModule. Jetez un oeil pour une explication complète des modules et mixins.

7
Martin
class MyApp
  class << self
    include MyModule
  end
  self.hallo
end

est le même que

class MyApp
  extend MyModule
  self.hallo
end

étend ouvre simplement l'objet classe et inclut les méthodes du module. "hallo" devient un objet de classe aka. méthode statique de la classe MyApp.

Donc, "include" injecte les méthodes dans les instances du récepteur, dans votre cas étant "self" PAS à l'objet lui-même. "étendre" injectez les méthodes au récepteur dans votre cas étant "auto".

self.include MyModule // inject the methods into the instances of self
self.extend MyModule // inject the methods into object self

Au niveau de la classe "self" pointera vers votre objet de classe qui est MyApp.

Souvenez-vous également que "include" et "extend" ne sont que des méthodes définies dans module.rb. "include" est une méthode d'objet de classe (méthode statique) et "extend" est une méthode d'instance.

4
Viorel