2016-07-27 2 views
1
  1. Salutméthode Ruby avec des options facultatives et paramètre & bloc

    Est-il possible d'avoir des attributs en option et un bloc comme paramètres pour un appel de méthode?

    Exemple: Je dois appeler

    method(foo, foo: bar, -> { do_something } 
    

    et ai essayé avec

    def method(foo, *bar, &block) 
    end 
    

    Quant à ma compréhension du bloc doit toujours être en dernière position? Après un peu de recherche, j'ai découvert que l'unaire (?) * semble être pour les tableaux . Depuis que j'essaie de passer un Hash j'ai changé le code pour

    def method(foo, bar={}, &block) 
    end 
    

    Mais cela ne fait pas non plus l'affaire. Je suppose que c'est parce qu'il ne peut pas savoir où la barre se termine et le bloc commence.

    Des idées ou des suggestions? Merci d'avance

    Ajouter: Juste pour les curieux pourquoi j'ai besoin de cela. Nous avons un grand schéma json fonctionnant et avons un petit DSL qui construit le json de la définition de modèle . Sans trop entrer dans les détails, nous voulions mettre en œuvre exportable_scopes .

    class FooBar 
        exportable_scope :some_scope, title: 'Some Scope', -> { rewhere archived: true } 
    end 
    

    Sur certains initialiseur cela est censé se produit:

    def exportable_scope scope, attributes, &block 
        scope scope block 
        if attributes.any? 
        attributes.each do |attribute| 
         exportable_schema.scopes[scope] = attribute 
        end 
        else 
        exportable_schema.scopes[scope] = {title: scope} 
        end 
    end 
    

    Alors que cela fonctionne bien, je juste besoin d'un indice pour la méthode paramètres.

+0

Vous pouvez utiliser 'exportable_scope (: some_scope, title: 'Some Scope') {rewhere archivé: true}'. Vous n'avez pas besoin d'envoyer un bloc comme parametter. –

+1

Je pense que vous confondez en passant un bloc avec le passage d'un objet appelable (lambda) en tant qu'argument, ce que l'ActiveRecord '.scope' s'attend à recevoir. Le corps de la portée est obligatoire, vous pouvez donc changer la signature de votre méthode en 'exportable_scope (nom, corps, attributs = {})' et appeler 'nom de portée, corps '. Jetez un oeil à la définition '.scope' ici: https://github.com/rails/rails/blob/dc925119a3912ecfe0df400007163f33b99d6385/activerecord/lib/active_record/scoping/named.rb#L143. 'exportable_scope: some_scope, -> {rewhere archivé: true}, titre: 'Some Scope''. –

Répondre

1

Oui, c'est possible.

Lors du mélange différents types de paramètres, ils doivent être inclus dans la définition de la méthode dans un ordre spécifique:

  1. paramètres positionnels (obligatoires et facultatifs) et un seul paramètre floc, dans un ordre quelconque;
  2. Paramètres des mots-clés (obligatoires et facultatifs), dans n'importe quel ordre;
  3. Double paramètre splat;
  4. Paramètre de bloc (préfixé par &);

La commande ci-dessus est un peu flexible. Nous pourrions définir une méthode et commencer la liste des paramètres avec un seul argument splat, puis quelques arguments positionnels optionnels, et ainsi de suite. Même si Ruby le permet, c'est généralement une très mauvaise pratique car le code serait difficile à lire et encore plus difficile à déboguer.Il est généralement préférable d'utiliser l'ordre suivant:

  1. Paramètres de position requis;
  2. Paramètres de position facultatifs (avec valeurs par défaut);
  3. Paramètre splat unique;
  4. Paramètres des mots-clés (obligatoires et facultatifs, leur ordre est sans importance);
  5. Double paramètre splat;
  6. Paramètre de bloc explicite (préfixé par &).

Exemple:

def meditate cushion, meditation="kinhin", *room_items, time: , posture: "kekkafuza", **periods, &b 
    puts "We are practicing #{meditation}, for #{time} minutes, in the #{posture} posture (ouch, my knees!)." 
    puts "Room items: #{room_items}" 
    puts "Periods: #{periods}" 
    b.call # Run the proc received through the &b parameter 
end 

meditate("zafu", "zazen", "zabuton", "incense", time: 40, period1: "morning", period2: "afternoon") { puts "Hello from inside the block" } 

# Output: 
We are practicing zazen, for 40 minutes, in the kekkafuza posture (ouch, my knees!). 
Room items: ["zabuton", "incense"] 
Periods: {:period1=>"morning", :period2=>"afternoon"} 
Hello from inside the block 

Notez que lorsque vous appelez la méthode, nous avons:

  • fourni le coussin obligatoire l'argument de position;
  • Ecrasé la valeur par défaut de l'argument positionnel facultatif de la méditation;
  • Passé un couple d'arguments positionnels supplémentaires (zabuton et encens) via le paramètre * room_items;
  • Fourni l'argument mot-clé obligatoire de temps;
  • Omis l'argument mot-clé facultatif posture;
  • Passé deux mots-clés supplémentaires (période1: "matin", période2: "après-midi") via le paramètre ** périodes;
  • Passé le bloc {met "Bonjour de l'intérieur du bloc"} via le paramètre & b;

Veuillez noter l'exemple ci-dessus des serveurs uniquement pour illustrer la possibilité de mélanger différents types de paramètres. Construire une méthode comme celle-ci en code réel serait une mauvaise pratique. Si une méthode nécessite plusieurs arguments, il est probablement préférable de la diviser en méthodes plus petites. S'il est absolument nécessaire de transmettre autant de données à une seule méthode, nous devrions probablement créer une classe pour stocker les données d'une manière plus organisée, puis passer une instance de cette classe à la méthode en tant qu'argument unique.