2009-05-01 36 views
115

Si defino a las funciones de Ruby como este:Rubí parámetros opcionales

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

¿Cómo puedo llamarlo suministrar sólo los primeros 2 y los últimos argumentos? ¿Por qué no es algo así como

ldap_get(base_dn, filter, , X) 

posible o si es posible, ¿cómo se puede hacer?

Respuesta

122

Esto no es posible con ruby ​​actualmente. No puede pasar atributos 'vacíos' a los métodos. Lo más cerca que se puede obtener es pasar nada:

ldap_get(base_dn, filter, nil, X) 

Sin embargo, esto va a fijar el alcance a cero, no LDAP :: LDAP_SCOPE_SUBTREE.

Lo que puede hacer es fijar el valor por defecto dentro de su método:

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

Ahora bien, si se llama al método que el anterior, el comportamiento será como se espera.

+21

Un poco con este método: p. Si intenta hacer que el valor predeterminado para 'scope' sea verdadero y pase' false', 'scope || = true' no funcionará. Evalúa lo mismo que 'nil' y lo configurará en' true' –

+4

¿es posible con la versión actual de ruby, 3 años después de esta respuesta? – dalloliogm

+1

@JoshPinter, buena explicación. Básicamente || = no es a = b o c, me encogí al ver 'xyz || = true'. Está diciendo que si es nula, siempre es verdad. Si es verdad, es verdad. –

3

No es posible hacerlo de la manera que ha definido ldap_get. Sin embargo, si se define ldap_get así:

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

Ahora usted puede:

ldap_get(base_dn, filter, X) 

Pero ahora usted tiene un problema que no se puede llamar con los dos primeros argumentos y la última arg (la mismo problema que antes pero ahora el último arg es diferente).

La razón de esto es simple: no es necesario que cada argumento en Ruby tenga un valor predeterminado, por lo que no puede llamarlo de la manera que ha especificado. En su caso, por ejemplo, los primeros dos argumentos no tienen valores predeterminados.

134

Casi siempre es mejor usar un hash de opciones.

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

ldap_get(base_dn, filter, :attrs => X) 
+23

Una estrategia común es tener un hash de opciones predeterminadas y fusionarlo en lo que pasó: 'options = default_options.merge (opciones)' –

+4

Desaconsejo esto porque las opciones no indican qué espera el método o cuáles son los valores predeterminados son –

0

Es posible :) Sólo cambia la definición

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

a

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

alcance será ahora en la serie en su primer lugar. Cuando proporciona 3 argumentos, a continuación, se le han asignado dn_base, filtro y attrs y param_array serán [] Cuando 4 y más argumentos a continuación param_array habrá [argumento1 or_more, and_more]

desventaja es que ... es una solución poco clara, realmente fea. Esto es para responder que es posible omitir un argumento en el medio de una llamada de función en ruby ​​:)

Otra cosa que tienes que hacer es reescribir el valor predeterminado del alcance.

+3

Esta solución es completamente incorrecta. Es un error de sintaxis utilizar un parámetro de valor predeterminado ('attrs = nil') después de un splat (' * param_array'). –

+3

-1: Erik tiene razón. Causa un error de sintaxis en irb 2.0.0p247. De acuerdo con _The Ruby Programming Language_, en Ruby 1.8 el parámetro splat tenía que ser el último excepto por un '& parameter', pero en Ruby 1.9 podría ser seguido por" parámetros ordinarios "también. En ningún caso fue un parámetro con un valor predeterminado legal después de un parámetro con un splat. – andyg0808

+0

Ruby Programming Language page 186/187 splat está bien para usar con métodos. Tiene que ser el último parámetro en el método a menos que & se use. – rupweb

0

Recientemente he encontrado una forma de evitar esto. Quería crear un método en la clase de matriz con un parámetro opcional, para mantener o descartar elementos en la matriz.

La forma en que simulé esto fue pasando una matriz como parámetro y luego verificando si el valor en ese índice era nulo o no.

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 

Tratando nuestra método de clase con diferentes parámetros:

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) 

de salida: ["1", "2", "a", "b", "c"]

bien, fresco que funciona según lo previsto. Ahora revisemos y veamos qué sucede si no pasamos la tercera opción de parámetro (1) en la matriz.

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) 

de salida: ["a", "b", "c"]

Como se puede ver, la tercera opción de la matriz se ha eliminado, dando así inicio a una sección diferente en el método y la eliminación de todos los valores ASCII que no están en nuestra gama (32 -126)

Alternativamente, podríamos haber emitido el valor como nulo en los parámetros. Que un aspecto similar al siguiente bloque de código:

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 
1

1) No se puede sobrecargar el método (Why doesn't ruby support method overloading?) ¿por qué no escribir un nuevo método en total?

2) Resolví un problema similar usando el operador splat * para una matriz de cero o más longitud. Entonces, si quiero pasar un parámetro (s) que puedo, se interpreta como una matriz, pero si quiero llamar al método sin ningún parámetro, entonces no tengo que pasar nada. Ver de Ruby Programming Language páginas 186/187

44

El tiempo ha cambiado y desde la versión 2 de Ruby soporta nombrado parámetros:

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" 
+0

También puede usar un doble símbolo para recopilar argumentos indefinidos de palabra clave. Esto está relacionado con este problema: http://stackoverflow.com/a/35259850/160363 –

0

usted puede hacer esto con la aplicación parcial, aunque el uso de variables con nombre, sin duda conduce a una mayor código legible John Resig escribió un artículo en el blog en 2008 sobre cómo hacerlo 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); 
    }; 
}; 

probablemente sería posible aplicar el mismo principio en Rubí (a excepción de la herencia de prototipos).

Cuestiones relacionadas