se puede pasar el auto a lambda en rails?
-
12-09-2019 - |
Pregunta
Quiero definir un método de clase que tiene acceso a una variable local.Así que esto sería diferente para cada instancia de la clase.Sé que se puede hacer una clase de método dinámico con lambda como cuando se utiliza con named_scope.Pero se puede hacer esto para los valores que son específicos de una instancia?
En detalle es el has_attached_file método para el clip plugin de rails.Quiero pasar un lambda para los estilos de hash, de modo que los estilos de imagen que pueden ser basados en los atributos de los objetos almacenados en la base de datos.Es esto posible?
Solución
Descargo de responsabilidad: En primer lugar, la pregunta (Se puede pasar el auto a lambda?) y el problema que estamos tratando de resolver (dinámica de estilos con clip) no coinciden plenamente.No voy a responder a la pregunta original porque no está totalmente relacionado con su problema, y rampion tomó una valiente puñalada en ella.
Lugar de ello voy a responder a su clip pregunta.
En detalle es el
has_attached_file
método para el clip plugin de rails.Quiero pasar un lambda para los estilos de hash, de modo que los estilos de imagen que pueden ser basados en los atributos de los objetos almacenados en la base de datos.Es esto posible?
Sí, es posible. En el clip, la :styles
opción puede tomar un Proc.Cuando el adjunto es inicializado, si un Proc fue utilizado, el apego a sí mismo se pasa a la Proc.El apego tiene una referencia a los asociados de ActiveRecord objeto, de modo que usted puede utilizar para determinar su dinámica de estilos.
Por ejemplo, su has_attached_file
declaración podría ser algo como esto (suponiendo que el Usuario y avatar escenario donde el usuario puede personalizar el tamaño de su avatar):
class User < ActiveRecord::Base
has_attached_file :avatar, :styles => lambda { |attachment|
user = attachment.instance
dimensions = "#{user.avatar_width}x#{user.avatar_height}#"
{ :custom => dimensions }
}
end
Otros consejos
Ok, estás siendo poco clara.
Las variables locales en rubí comienzan con una letra minúscula (como foo
, bar
o steve
), y están en el ámbito léxico (como las variables C
). No tienen nada que ver con "una instancia de una clase"
Las variables de instancia en Ruby comienzan con un sigilo @
(como @foo
, @bar
, o @carl
), y están en el alcance cada vez que el valor actual de self
es el objeto que se almacenan en.
Si quieres un método que se puede acceder a las variables de instancia de un objeto directamente, eso se llama un método de instancia. Por ejemplo, battle_cry
y initialize
son ambos métodos de instancia:
class Character
def initialize(name)
@name=name
end
def battle_cry
@name.upcase + "!!!"
end
def Character.default
new("Leeroy Jenkins")
end
end
un método de clase, por el contrario, es un método para un objeto Class
, y no tiene acceso a ninguna de las variables de instancia de ese objeto. En el ejemplo anterior,
default
es un método de clase.
Si desea un método (clase o instancia) que desencadena un cambio en o se pone un valor en el ámbito actual, rubí utiliza un tipo de devolución de llamada denomina bloque.
class Character
ATTACKS = [ "Ho!", "Haha!", "Guard!", "Turn!", "Parry!", "Dodge!", "Spin!", "Ha", "THRUST!" ]
def attack
ATTACKS.inject(0) { |dmg, word| dmg + yield(word) }
end
end
person = Character.default
puts person.battle_cry
num_attacks = 0;
damage = person.attack do |saying|
puts saying
num_attacks += 1
rand(3)
end
puts "#{damage} points of damage done in #{num_attacks} attacks"
En el ejemplo anterior, attack
utiliza la palabra clave yield
para llamar al bloque pasado
lo. Cuando llamamos attack
, entonces, el num_attacks
variable local sigue siendo
en su alcance en el bloque lo pasamos (delimitado por aquí do ... end
), de modo que podamos
se incrementará. attack
es capaz de pasar los valores en el bloque, aquí
que son capturados en la variable saying
. El bloque también pasa los valores de
de vuelta al método, que se muestran como el valor de retorno de yield
.
La palabra lambda
en rubí generalmente significa la palabra clave lambda
, que se utiliza
para hacer bloques en independiente, funcionan como objetos (que de por sí son normalmente
se hace referencia como lambda
s, proc
s, o Proc
s).
bounce = lambda { |thing| puts "I'm bouncing a #{thing}" }
bounce["ball"]
bounce["frog"]
Así que creo que lo que estás preguntando es si se puede pasar una Proc
en lugar de un Hash
para un argumento a un método. Y la respuesta es "depende". Si el único método
siempre utiliza el método #[]
, entonces sí:
class Character
attr_accessor :stats
def set_stats(stats)
@stats = stats
end
end
frank = Character.new("Victor Frankenstein")
frank.set_stats({ :str => 7, :dex => 14, :con => 9, :int => 19, :wis => 7, :cha => 11 })
monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
rand(20)
end)
Sin embargo, podría usar algunos métodos específicos Hash
otra, o llamar a la misma clave varias veces,
que puede producir resultados extraños:
monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
rand(20)
end)
monster.stats[:dex] #=> 19
monster.stats[:dex] #=> 1
En cuyo caso, usted puede ser mejor de almacenamiento en caché de las solicitudes en un hash intermedia. Esto es bastante fácil,
ya que una Hash
puede tener un bloque de inicialización. Así que si cambiamos el anterior a:
monster.set_stats(Hash.new do |stats_hash, stat_name|
stats_hash[stat_name] = rand(20)
end)
monster.stats[:dex] #=> 3
monster.stats[:dex] #=> 3
Los resultados se almacenan en caché en el hash
Para ver más sobre inicializadores bloque Hash
, ver ri Hash::new
:
-------------------------------------------------------------- Hash::new
Hash.new => hash
Hash.new(obj) => aHash
Hash.new {|hash, key| block } => aHash
------------------------------------------------------------------------
Returns a new, empty hash. If this hash is subsequently accessed
by a key that doesn't correspond to a hash entry, the value
returned depends on the style of new used to create the hash. In
the first form, the access returns nil. If obj is specified, this
single object will be used for all default values. If a block is
specified, it will be called with the hash object and the key, and
should return the default value. It is the block's responsibility
to store the value in the hash if required.
h = Hash.new("Go Fish")
h["a"] = 100
h["b"] = 200
h["a"] #=> 100
h["c"] #=> "Go Fish"
# The following alters the single default object
h["c"].upcase! #=> "GO FISH"
h["d"] #=> "GO FISH"
h.keys #=> ["a", "b"]
# While this creates a new default object each time
h = Hash.new { |hash, key| hash[key] = "Go Fish: #{key}" }
h["c"] #=> "Go Fish: c"
h["c"].upcase! #=> "GO FISH: C"
h["d"] #=> "Go Fish: d"
h.keys #=> ["c", "d"]