Paramètres facultatifs Ruby

Si je définis une fonction Ruby comme ceci:

def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil ) 

Comment puis-je l’appeler en fournissant uniquement les 2 premiers et les derniers arguments? Pourquoi n’est pas quelque chose comme

 ldap_get( base_dn, filter, , X) 

possible ou si c’est possible, comment peut-on le faire?

Ce n’est pas possible avec Ruby actuellement. Vous ne pouvez pas transmettre d’atsortingbuts “vides” aux méthodes. Le plus proche que vous pouvez obtenir est de passer à zéro:

 ldap_get(base_dn, filter, nil, X) 

Cependant, cela définira la scope à nil, pas LDAP :: LDAP_SCOPE_SUBTREE.

Ce que vous pouvez faire est de définir la valeur par défaut dans votre méthode:

 def ldap_get(base_dn, filter, scope = nil, attrs = nil) scope ||= LDAP::LDAP_SCOPE_SUBTREE ... do something ... end 

Maintenant, si vous appelez la méthode comme ci-dessus, le comportement sera comme prévu.

Vous êtes presque toujours mieux d’utiliser un hachage d’options.

 def ldap_get(base_dn, filter, options = {}) options[:scope] ||= LDAP::LDAP_SCOPE_SUBTREE ... end ldap_get(base_dn, filter, :attrs => X) 

Le temps a passé et depuis la version 2, Ruby prend en charge les parameters nommés:

 def ldap_get ( base_dn, filter, scope: "some_scope", attrs: nil ) p attrs end ldap_get("first_arg", "second_arg", attrs: "attr1, attr2") # => "attr1, attr2" 

Il n’est pas possible de le faire comme vous l’avez défini ldap_get . Cependant, si vous définissez ldap_get comme ceci:

 def ldap_get ( base_dn, filter, attrs=nil, scope=LDAP::LDAP_SCOPE_SUBTREE ) 

Maintenant vous pouvez:

 ldap_get( base_dn, filter, X ) 

Mais maintenant, vous avez un problème, à savoir que vous ne pouvez pas l’appeler avec les deux premiers arguments et le dernier argument (le même problème qu’auparavant, mais le dernier argument est différent).

La raison en est simple: chaque argument de Ruby ne doit pas nécessairement avoir une valeur par défaut, vous ne pouvez donc pas l’appeler comme vous l’avez spécifié. Dans votre cas, par exemple, les deux premiers arguments n’ont pas de valeurs par défaut.

1) Vous ne pouvez pas surcharger la méthode ( Pourquoi ruby ​​ne prend-il pas en charge la surcharge de méthode? ), Alors pourquoi ne pas écrire une nouvelle méthode?

2) J’ai résolu un problème similaire en utilisant l’opérateur splat * pour un tableau de zéro ou plus. Ensuite, si je veux passer un paramètre, je peux, il est interprété comme un tableau, mais si je veux appeler la méthode sans aucun paramètre, je n’ai rien à passer. Voir le langage de programmation Ruby pages 186/187

C’est possible 🙂 Changez simplement la définition

 def ldap_get ( base_dn, filter, scope=LDAP::LDAP_SCOPE_SUBTREE, attrs=nil ) 

à

 def ldap_get ( base_dn, filter, *param_array, attrs=nil ) scope = param_array.first || LDAP::LDAP_SCOPE_SUBTREE 

scope sera maintenant dans le tableau à sa première place. Lorsque vous fournissez 3 arguments, vous aurez alors assigné base_dn, filter et attrs et param_array sera [] Lorsque 4 arguments et plus, alors param_array sera [argument1 ou_more, et_more]

L’inconvénient est que … la solution n’est pas claire, vraiment moche. C’est pour répondre qu’il est possible d’omettre un argument au milieu d’un appel de fonction dans ruby ​​:)

Une autre chose à faire est de réécrire la valeur par défaut de la scope.

Récemment, j’ai trouvé un moyen de contourner cela. Je voulais créer une méthode dans la classe tableau avec un paramètre facultatif, pour conserver ou ignorer les éléments du tableau.

La façon dont j’ai simulé cela était en passant un tableau comme paramètre, puis en vérifiant si la valeur à cet index était nulle ou non.

 class Array def ascii_to_text(params) param_len = params.length if param_len > 3 or param_len < 2 then raise "Invalid number of arguments #{param_len} for 2 || 3." end bottom = params[0] top = params[1] keep = params[2] if keep.nil? == false if keep == 1 self.map{|x| if x >= bottom and x < = top then x = x.chr else x = x.to_s end} else raise "Invalid option #{keep} at argument position 3 in #{p params}, must be 1 or nil" end else self.map{|x| if x >= bottom and x < = top then x = x.chr end}.compact end end end 

Essayer notre méthode de classe avec différents parameters:

 array = [1, 2, 97, 98, 99] p array.ascii_to_text([32, 126, 1]) # Convert all ASCII values of 32-126 to their chr value otherwise keep it the same (That's what the optional 1 is for) 

sortie: ["1", "2", "a", "b", "c"]

Ok, cool qui fonctionne comme prévu. Maintenant, vérifions et voyons ce qui se passe si nous ne transmettons pas l'option du troisième paramètre (1) dans le tableau.

 array = [1, 2, 97, 98, 99] p array.ascii_to_text([32, 126]) # Convert all ASCII values of 32-126 to their chr value else remove it (1 isn't a parameter option) 

sortie: ["a", "b", "c"]

Comme vous pouvez le voir, la troisième option du tableau a été supprimée, initiant ainsi une section différente de la méthode et supprimant toutes les valeurs ASCII ne figurant pas dans notre plage (32-126).

Sinon, nous aurions pu donner la valeur nulle dans les parameters. Qui ressemblerait au bloc de code suivant:

 def ascii_to_text(top, bottom, keep = nil) if keep.nil? self.map{|x| if x >= bottom and x < = top then x = x.chr end}.compact else self.map{|x| if x >= bottom and x < = top then x = x.chr else x = x.to_s end} end 

Vous pouvez le faire avec une application partielle, bien que l’utilisation de variables nommées mène définitivement à un code plus lisible. John Resig a écrit un article de blog en 2008 sur la façon de le faire en JavaScript: http://ejohn.org/blog/partial-functions-in-javascript/

 Function.prototype.partial = function(){ var fn = this, args = Array.prototype.slice.call(arguments); return function(){ var arg = 0; for ( var i = 0; i < args.length && arg < arguments.length; i++ ) if ( args[i] === undefined ) args[i] = arguments[arg++]; return fn.apply(this, args); }; }; 

Il serait probablement possible d'appliquer le même principe dans Ruby (sauf pour l'inheritance prototype).