2011-11-05 17 views
9

Estoy aprendiendo rails y volviendo a ruby ​​para entender cómo funcionan los métodos en rieles (y ruby ​​realmente funciona). Cuando veo llamadas a métodos como:Usar símbolos como argumentos para los métodos de ruby ​​

validates validates :first_name, :presence => true 

Me confundo. ¿Cómo se escriben los métodos en ruby ​​que aceptan símbolos o hashes? El código fuente para el método validates también es confuso. ¿Podría alguien simplificar este tema de usar símbolos como argumentos en clase ruby ​​y métodos de instancia para mí?

ACTUALIZACIÓN:

Buena esa @Dave! Pero lo que estaba probando era algo así como:

def full_name (:first_name, :last_name) 
    @first_name = :first_name 
    @last_name = :last_name 
    p "#{@first_name} #{last_name}" 
end 

full_name("Breta", "Von Sustern") 

Lo que obviamente provoca errores. Estoy tratando de entender: ¿por qué pasar símbolos como este como argumentos incorrectos si los símbolos son como cualquier otro valor?

+0

Los símbolos y valores hash son valores como cualquier otro; no hay nada diferente en pasar un símbolo o un hash que cualquier otra cosa. ¿Qué específicamente te está confundiendo? –

+0

Lo que me confunde es que nunca he visto un ejemplo de hashes que se usen como valores en los métodos ruby. Entonces no puedo visualizar lo que estás diciendo. –

+1

Sí * pass *, los nombres de los parámetros siguen siendo solo eso - nombres de parámetros, y no deberían tener el carácter ':' inicial. –

Respuesta

15

Los símbolos y valores hash son valores como cualquier otro y se pueden pasar como cualquier otro tipo de valor.

Recordar que los modelos ActiveRecord aceptan un hash como argumento; que termina siendo similar a esto (no es este sencillo, pero es la misma idea en el final):

class User 
    attr_accessor :fname, :lname 

    def initialize(args) 
    @fname = args[:fname] if args[:fname] 
    @lname = args[:lname] if args[:lname] 
    end 
end 

u = User.new(:fname => 'Joe', :lname => 'Hacker') 

Esto toma ventaja de no tener que poner el hash de rizado soportes en {} a menos que necesite para eliminar la ambigüedad parámetros (y hay un problema de análisis de bloques también cuando se salta los parens).

mismo modo:

class TestItOut 
    attr_accessor :field_name, :validations 

    def initialize(field_name, validations) 
    @field_name = field_name 
    @validations = validations 
    end 

    def show_validations 
    puts "Validating field '#{field_name}' with:" 
    validations.each do |type, args| 
     puts " validator '#{type}' with args '#{args}'" 
    end 
    end 
end 

t = TestItOut.new(:name, presence: true, length: { min: 2, max: 10 }) 
t.show_validations 

Este salidas:

Validating field 'name' with: 
    validator 'presence' with args 'true' 
    validator 'length' with args '{min: 2, max: 10}' 

Desde allí se puede empezar a ver cómo cosas como esta obra.

+0

Además, considere usar el método 'fetch' para proporcionar los valores predeterminados al obtener los argumentos dentro de un hash. –

4

En Ruby, si se llama a un método con un montón de name => value pares al final de la lista de argumentos, éstos envolverse de forma automática en un Hash y pasó a su método como último argumento:

def foo(kwargs) 
    p kwargs 
end 

>> foo(:abc=>"def", 123=>456) 
{:abc=>"def", 123=>456} 

>> foo("cabbage") 
"cabbage" 

>> foo(:fluff) 
:fluff 

No hay nada "especial" sobre cómo escribir el método, es cómo lo llamas. Sería perfectamente legal pasar un objeto Hash normal como el parámetro kwargs. Este acceso directo sintáctico se usa para implementar los parámetros con nombre en una API.

Un símbolo de Ruby es solo un valor como cualquier otro, por lo que en su ejemplo, :first_name es solo un argumento posicional regular. :presence es un símbolo utilizado como tecla Hash: cualquier tipo se puede utilizar como tecla Hash, pero los símbolos son una opción común porque son valores inmutables.

+1

Y, más importante aún que ser inmutable, son más comunicativos en el sentido de que específicamente actúan como un nombre o etiqueta para algo. –

2

Los símbolos no están limitados a hash. Son identificadores, sin el espacio de almacenamiento adicional de una cadena. Es solo una manera de decir "esto es ..."

Una posible definición de la función de la llamada podría ser valida (sólo para simplificar, no sé de la parte superior de mi cabeza lo que realmente es):

def validates(column, options) 
    puts column.to_s 
    if options[:presence] 
    puts "Found a presence option" 
    end 
end 

Note como el primer símbolo es un parámetro por sí mismo, y el resto es el hash.

+0

Todavía están almacenados, es solo que cada etiqueta única se almacena solo una vez, como una cadena interna. OTOH, no son elegibles para GC (quizás están en 1.9), tampoco, así que se quedan para la vida útil de la aplicación. –

+0

Los símbolos no están clasificados por GC en 1.9 tampoco. – sheldonh

+0

Ruby 2.2 ahora tiene el símbolo GC – DGM

2

Creo que todas las respuestas han perdido el punto de la pregunta, y el hecho es que alguien que es, supongo, no tiene claro qué es un símbolo ?

Como recién llegado a Ruby tuve confusiones similares y para mí una n respuesta como la siguiente tendría más sentido

Método Los argumentos son variables locales pobladas por valores pasados.

You usar símbolos cativos como Argumentos de sí mismos, como no puede cambiar el valor de un símbolo.

+2

No estoy seguro de lo que quiere decir con "usted no puede usar símbolos como argumentos por sí mismos", porque puede ... 'foo (: bar)' es una llamada de función perfectamente legítima. Quizás he entendido mal? –

9

Pensé en agregar una actualización para Ruby 2+ ya que este es el primer resultado que encontré para 'symbols as arguments'.

Desde Ruby 2.0.0 también puede usar símbolos al definir un método. Al llamar al método, estos símbolos actuarán casi igual que los parámetros opcionales nombrados en otros idiomas. Consulte el siguiente ejemplo:

def variable_symbol_method(arg, arg_two: "two", arg_three: "three") 
    [arg, arg_two, arg_three] 
end 

result = variable_symbol_method :custom_symbol, arg_three: "Modified symbol arg" 

# result is now equal to: 
[:custom_symbol, "two", "Modified symbol arg"] 

Como se muestra en el ejemplo, omitimos arg_two: al llamar al método y en el cuerpo del método todavía podemos acceder a él como variable de arg_two. También tenga en cuenta que la variable llamada arg_three sí se ve alterada.

Cuestiones relacionadas