Parámetros opcionales de Ruby


Si defino una función Ruby como esta:

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

¿Cómo puedo llamarlo suministrar solo los primeros 2 y los últimos args? ¿Por qué no es algo como

ldap_get( base_dn, filter, , X)

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

Author: Nakilon, 2009-05-01

8 answers

Esto no es posible con ruby actualmente. No puede pasar atributos 'vacíos' a los métodos. Lo más cercano que puedes conseguir es pasar nil:

ldap_get(base_dn, filter, nil, X)

Sin embargo, esto establecerá el ámbito a nil, no LDAP::LDAP_SCOPE_SUBTREE.

Lo que puede hacer es establecer el valor predeterminado 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 llamas al método como antes, el comportamiento será como esperas.

 126
Author: tomafro,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-19 17:42:54

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)
 135
Author: jshen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-01 16:33:20

El tiempo ha pasado y desde la versión 2 Ruby soporta parámetros con nombre:

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"
 46
Author: steenslag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-14 19:00:27

No es posible hacerlo de la manera que has definido ldap_get. Sin embargo, si defines ldap_get así:

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

Ahora puedes:

ldap_get( base_dn, filter, X )

Pero ahora tienes el problema de que no puedes llamarlo con los dos primeros args y el último arg (el mismo problema que antes, pero ahora el último arg es diferente).

La justificación para esto es simple: No se requiere 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, la primera dos argumentos no tienen valores predeterminados.

 3
Author: Chris Bunch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-01 16:21:18

1) No se puede sobrecargar el método ( ¿Por qué ruby no soporta la sobrecarga del método?) entonces, ¿por qué no escribir un nuevo método por completo?

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 Lenguaje de programación Ruby páginas 186/187

 1
Author: rupweb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:41

Es posible :) Simplemente cambie 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

El ámbito estará ahora en array en su primer lugar. Cuando proporcione 3 argumentos, entonces tendrá asignado base_dn, filter y attrs y param_array será [] Cuando 4 y más argumentos entonces param_array será [argument1, or_more, and_more]

La desventaja es... es una solución poco clara, realmente fea. Esto es para responder que es posible ommit argumento en el medio de la llamada a la función en ruby :)

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

 0
Author: m4risU,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-09 13:50:30

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

La forma en que simulé esto fue pasando un array como parámetro, y luego comprobando si el valor en ese índice era nil 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

Probando nuestro 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)

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

Bueno, genial que funciona como estaba previsto. Ahora vamos a comprobar y ver qué pasa si no lo hacemos pase el tercer parámetro option (1) en el array.

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)

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

Como puede ver, la tercera opción en el array ha sido eliminada, iniciando así una sección diferente en el método y eliminando todos los valores ASCII que no están en nuestro rango (32-126)

Alternativamente, podríamos haber emitido el valor como nil en los parámetros. Que se vería 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
 0
Author: Singularity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-01-31 13:10:51

Podría hacer esto con una aplicación parcial, aunque el uso de variables con nombre definitivamente conduce a un código más legible. John Resig escribió un artículo de 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 Ruby (excepto para la herencia prototípica).

 0
Author: EriF89,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-09 09:49:00