171 votes

Puis-je invoquer une méthode d'instance sur un module Ruby sans l'inclure?

Arrière-plan:

J'ai un module qui déclare un certain nombre de méthodes d'instance

module UsefulThings
  def get_file; ...
  def delete_file; ...

  def format_text(x); ...
end

Et je tiens à appeler certains de ces méthodes au sein d'une classe. Comment vous le feriez normalement ce en ruby, c'est comme ceci:

class UsefulWorker
  include UsefulThings

  def do_work
    format_text("abc")
    ...
  end
end

Problème

include UsefulThings apporte à tous des méthodes d' UsefulThings. Dans ce cas, je veux seulement format_text et expressément ne pas vouloir get_file et delete_file.

Je vois plusieurs solutions possibles à cela:

  1. En quelque sorte appeler la méthode directement sur le module sans l'inclure n'importe où
    • Je ne sais pas comment/si cela peut être fait. (D'où cette question)
  2. En quelque sorte comprennent Usefulthings et seulement d'amener quelques-uns de ses méthodes
    • Aussi, je ne sais pas comment/si cela peut être fait
  3. Créer une classe proxy, comprennent UsefulThings en, puis délégué format_text de proxy instance
    • Ce serait le travail, mais proxy anonyme des classes est un hack. Beurk.
  4. Diviser le module en 2 ou plusieurs modules plus petits
    • Ce serait également le travail, et est probablement la meilleure solution je pense, mais je préfère éviter, autant que je l'aimerais jusqu'à la fin avec la prolifération des dizaines et des dizaines de modules - gestion ce serait lourd

Pourquoi il y a beaucoup de fonctions sans rapport dans un module unique? Il est ApplicationHelper à partir d'une application rails, notre équipe a de facto décidé que le dépotoir de ce qui n'est pas assez spécifique appartiennent partout ailleurs. Surtout utilitaire autonome des méthodes qui sont utilisés partout. Je pourrais le briser en deux assistants, mais il faudrait être de 30 d'entre eux, le tout avec la méthode 1 de chaque... cela semble improductif

Merci à l'avance!

139voto

dolzenko Points 2098

Je pense que le moyen le plus court de faire simplement un appel unique (sans modifier les modules existants ou d'en créer de nouveaux) serait le suivant:

 Class.new.extend(UsefulThings).get_file
 

130voto

dgtized Points 764

Si une méthode sur un module est transformé en un module de fonction, vous pouvez simplement appeler hors de Mods comme si elle avait été déclarée comme

module Mods
  def self.foo
     puts "Mods.foo(self)"
  end
end

Le module_function approche ci-dessous permettra d'éviter la rupture de toutes les classes qui comprennent tous les Mods.

module Mods
  def foo
    puts "Mods.foo"
  end
end

class Includer
  include Mods
end

Includer.new.foo

Mods.module_eval do
  module_function(:foo)
  public :foo
end

Includer.new.foo # this would break without public :foo above

class Thing
  def bar
    Mods.foo
  end
end

Thing.new.bar

Cependant, je suis curieux de savoir pourquoi un ensemble de fonctions sans rapport, sont toutes contenues dans le même module en premier lieu?

Édité pour montrer que comprend encore du travail si public :foo est appelée après l' module_function :foo

80voto

Dustin Points 35205

Une autre façon de le faire si vous "possédez" le module est d'utiliser module_function .

 module UsefulThings
  def a()
    puts "aaay"
  end
  module_function :a

  def b()
    puts "beee"
  end
end

def test()
  UsefulThings.a
  UsefulThings.b # Fails!  Not a module method
end

test
 

18voto

Si vous voulez appeler ces méthodes, sans y compris le module dans une autre classe, alors vous avez besoin de les définir comme des méthodes de module:

module UsefulThings
  def self.get_file; ...
  def self.delete_file; ...

  def self.format_text(x); ...
end

et puis vous pouvez les appeler avec

UsefulThings.format_text("xxx")

ou

UsefulThings::format_text("xxx")

Mais de toute façon je vous recommande de mettre juste les méthodes connexes dans un module ou dans une classe. Si vous avez un problème que vous souhaitez inclure uniquement une méthode de module puis il sonne comme une mauvaise odeur de code et c'est pas bon Ruby style pour mettre indépendants des méthodes.

6voto

Dustin Points 35205

Tout d'abord, je vous recommande de diviser le module en éléments utiles dont vous avez besoin. Mais vous pouvez toujours créer une classe qui étend cela pour votre appel:

 module UsefulThings
  def a
    puts "aaay"
  end
  def b
    puts "beee"
  end
end

def test
  ob = Class.new.send(:include, UsefulThings).new
  ob.a
end

test
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X