J'écris une petite application en ligne de commande Ruby qui utilise Depuis Définir une variable globale dans l'espace de noms de l'application basée sur le choix de l'utilisateur, puis faire inclure conditionnelle dans la classe: p>
Créer des sous-classes, où la seule différence est la version de fileutils code> de la bibliothèque standard pour les opérations de fichiers. Selon la façon dont l'utilisateur appelle l'application, je veux inclure soit
FileUtils code>,
FileUtils :: DryRun code> ou
FileUtils :: verbose code>.
include code> est privé, cependant, je ne peux pas mettre la logique de choisir dans l'objet
méthode initialize code>. (Ce fut ma première pensée, car je pouvais transmettre les informations sur le choix de l'utilisateur en tant que paramètre
nouveau code>.) Je suis venu avec deux options qui semblent fonctionner, mais je suis pas heureux avec soit: p>
class Worker
include FileUtils
# shared Worker methods go here
end
class Worker::DryRun < Worker
include FileUtils::DryRun
end
class Worker::Verbose < Worker
include FileUtils::Verbose
end
FileUtils code> ils comprennent. Choisissez celui qui convient, selon le choix de l'utilisateur. P>
class Worker
case App::OPTION
when "dry-run"
include FileUtils::DryRun
etc.
3 Réponses :
Et si c'est privé?
class Worker def initialize(verbose=false) if verbose (class <<self; include FileUtils::Verbose; end) else (class <<self; include FileUtils; end) end touch "test" end end
"Alors qu'est-ce qui" sonne bien pour moi. (C'était le exactement i> la chose la plus simple que je ne voyais pas.) Merci.
Oups, mon erreur. Le code que j'ai donné auparavant modifierait ouvrier code> de sorte que tout
travailleur code> s utiliserait les mêmes paramètres. Maintenant, il utilise réellement la métaclass et permet des paramètres pré-travailleurs.
Au lieu de (classe << auto; inclure FileUtils; extrémité) code> Vous pouvez également utiliser
étendre les fichiersUtils code>.
Merci d'édition. En fait, je suis heureux de l'avoir vu à la fois, car dans un cas, je pourrais souhaiter que le inclure code> pour être global à la classe et dans d'autres personnes par instance. @Konstantin - Merci pour la syntaxe alternative.
Si vous souhaitez éviter le "commutateur" et injecter le module, la syntaxe
def initialize(injected_module = MyDefaultModule) extend injected_module end
conditionnellement compris le module via les méthodes d'envoi fonctionne pour moi comme dans l'exemple testé ci-dessous:
class Artefact include HPALMGenericApi # the initializer just sets the server name we will be using ans also the 'transport' method : Rest or OTA (set in the opt parameter) def initialize server, opt = {} # conditionally include the Rest or OTA module self.class.send(:include, HPALMApiRest) if (opt.empty? || (opt && opt[:using] opt[:using] == :Rest)) self.class.send(:include, HPALMApiOTA) if (opt && opt[:using] opt[:using] == :OTA) # ... rest of initialization code end end