我想定义一个可以访问局部变量的类方法。所以这对于类的每个实例都是不同的。我知道您可以使用 lambda 使类方法动态化,就像将其与 named_scope 一起使用时一样。但是对于特定于实例的值可以这样做吗?
详细来说它是 rails 中回形针插件的 has_attached_file 方法。我想为样式散列传递一个 lambda,以便图像样式可以基于存储在数据库中的对象的属性。这可能吗?
我想定义一个可以访问局部变量的类方法。所以这对于类的每个实例都是不同的。我知道您可以使用 lambda 使类方法动态化,就像将其与 named_scope 一起使用时一样。但是对于特定于实例的值可以这样做吗?
详细来说它是 rails 中回形针插件的 has_attached_file 方法。我想为样式散列传递一个 lambda,以便图像样式可以基于存储在数据库中的对象的属性。这可能吗?
免责声明:首先,问题(Can you pass self to lambda?)和您试图解决的问题(使用回形针的动态样式)并不完全匹配。我不会回答最初的问题,因为它与您的问题并不完全相关,并且rampion对此进行了勇敢的尝试。
我会回答你的回形针问题。
详细来说就是
has_attached_file
rails中的回形针插件的方法。我想为样式散列传递一个 lambda,以便图像样式可以基于存储在数据库中的对象的属性。这可能吗?
是的,有可能。 在回形针中,该:styles
选项可以采用 Proc。初始化附件时,如果使用了 Proc,则将附件本身传递给 Proc。附件引用了关联的 ActiveRecord 对象,因此您可以使用它来确定您的动态样式。
例如,您的has_attached_file
声明可能看起来像这样(假设用户和头像场景,用户可以自定义头像的大小):
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
好吧,你说的不清楚。
ruby 中的局部变量以小写字母开头(如foo
、bar
或steve
),并且是词法范围的(如C
变量)。它们与“类的实例”无关
ruby 中的实例变量以@
sigil(如@foo
、@bar
或@carl
)开头,并且只要 的当前值self
是它们存储的对象,就在范围内。
如果您想要一个可以直接访问对象的实例变量的方法,则称为实例方法。例如,battle_cry
andinitialize
都是实例方法:
class Character
def initialize(name)
@name=name
end
def battle_cry
@name.upcase + "!!!"
end
def Character.default
new("Leeroy Jenkins")
end
end
相比之下,类方法是Class
对象的方法,并且不能访问该对象的任何实例变量。在上面的例子中,
default
是一个类方法。
如果您想要一个(类或实例)方法来触发当前范围的更改或从当前范围获取值,那么 ruby 使用一种称为块的回调类型。
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"
在上面的例子中,attack
使用yield
关键字来调用传递给它的块。当我们调用attack
时,局部变量num_attacks
仍然在我们传递它的块的范围内(这里用 分隔do ... end
),所以我们可以递增它。 attack
能够将值传递到块中,在这里它们被捕获到saying
变量中。该块还将值传递回该方法,该方法显示为 的返回值yield
。
lambda
ruby 中的词通常表示lambda
关键字,用于使块成为独立的、功能类似的对象(它们本身通常称为lambda
s、proc
s 或Proc
s)。
bounce = lambda { |thing| puts "I'm bouncing a #{thing}" }
bounce["ball"]
bounce["frog"]
所以我认为您要问的是您是否可以将 aProc
代替 a传递Hash
给方法的参数。答案是“视情况而定”。如果该方法只使用该#[]
方法,那么是的:
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)
但是,它可能会使用其他一些Hash
特定的方法,或者多次调用同一个键,这可能会产生奇怪的结果:
monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
rand(20)
end)
monster.stats[:dex] #=> 19
monster.stats[:dex] #=> 1
在这种情况下,您最好将请求缓存在中间哈希中。这相当容易,因为 aHash
可以有一个初始化块。因此,如果我们将上面的内容更改为:
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
结果缓存在哈希中
要了解有关Hash
块初始化程序的更多信息,请参阅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"]