Pregunta ¿Sin parámetros nombrados en Ruby?


Esto es tan simple que no puedo creer que me haya atrapado.

def meth(id, options = "options", scope = "scope")
  puts options
end

meth(1, scope = "meh")

-> "meh"

Tiendo a usar hashes para las opciones de argumento solo porque así fue como lo hizo la manada, y está bastante limpio. Pensé que era el estándar. Hoy, después de aproximadamente 3 horas de búsqueda de errores, he rastreado un error en esta gema, que estoy usando asume los parámetros nombrados serán honrados. Ellos no son.

Entonces, mi pregunta es esta: ¿El parámetro nombrado oficialmente no se respeta en Ruby (1.9.3), o es este un efecto secundario de algo que me falta? Si no lo son, ¿por qué no?


32
2018-03-08 03:30


origen


Respuestas:


Lo que está sucediendo en realidad:

# Assign a value of "meh" to scope, which is OUTSIDE meth and equivalent to
#   scope = "meth"
#   meth(1, scope)
meth(1, scope = "meh")

# Ruby takes the return value of assignment to scope, which is "meh"
# If you were to run `puts scope` at this point you would get "meh"
meth(1, "meh")

# id = 1, options = "meh", scope = "scope"
puts options

# => "meh"

No hay soporte * para los parámetros con nombre (ver a continuación la actualización 2.0). Lo que estás viendo es solo el resultado de asignar "meh" a scope siendo pasado como el options valor en meth. El valor de esa tarea, por supuesto, es "meh".

Hay varias formas de hacerlo:

def meth(id, opts = {})
  # Method 1
  options = opts[:options] || "options"
  scope   = opts[:scope]   || "scope"

  # Method 2
  opts = { :options => "options", :scope => "scope" }.merge(opts)

  # Method 3, for setting instance variables
  opts.each do |key, value|
    instance_variable_set "@#{key}", value
    # or, if you have setter methods
    send "#{key}=", value
  end
  @options ||= "options"
  @scope   ||= "scope"
end

# Then you can call it with either of these:
meth 1, :scope => "meh"
meth 1, scope: "meh"

Y así. Sin embargo, son soluciones alternativas por la falta de parámetros nombrados.


Editar (15 de febrero de 2013):

* Bien, al menos hasta la próxima Ruby 2.0, que admite argumentos de palabra clave! Al momento de escribir esto, está en el lanzamiento del candidato 2, el último antes del lanzamiento oficial. Aunque deberá conocer los métodos anteriores para trabajar con 1.8.7, 1.9.3, etc., los que pueden trabajar con versiones más nuevas ahora tienen la siguiente opción:

def meth(id, options: "options", scope: "scope")
  puts options
end

meth 1, scope: "meh"
# => "options"

38
2018-03-08 04:32



Creo que dos cosas están sucediendo aquí:

  1. Está definiendo un parámetro en el método llamado 'alcance' con un valor predeterminado de "alcance"
  2. Cuando llama al método, está asignando el valor "meh" a un nuevo local variable llamada 'alcance', que no está relacionada con el nombre del parámetro en el método que está llamando.

5
2018-03-08 03:35



Aunque los parámetros nombrados no son compatibles con el lenguaje Ruby, puede simularlos pasando los argumentos de su función a través de un hash. Por ejemplo:

def meth(id, parameters = {})
  options = parameters["options"] || "options"
  scope = parameters["scope"] || "scope"

  puts options
end

Que se puede usar de la siguiente manera:

meth(1, scope: "meh")

Su código existente simplemente asigna un valor variable, luego pasa esa variable a su función. Para más información, ver: http://deepfall.blogspot.com/2008/08/named-parameters-in-ruby.html.


3
2018-03-08 04:01



Ruby no tiene parámetros nombrados.

La definición de método de ejemplo tiene parámetros con valores predeterminados.

El ejemplo de sitio de llamada asigna un valor a una variable local de ámbito de llamada llamada alcance y luego pasa su valor (meh) al opciones parámetro.


0
2018-03-08 03:35