我想定义一个可以访问局部变量的类方法。因此,对于每个类的实例,这将是不同的。我知道你可以使用lambda创建一个类方法动态,就像你在named_scope中使用它一样。但是,这可以针对特定于实例的值进行吗?
详细说明,它是rails中paperclip插件的has_attached_file方法。我想为样式哈希传递lambda,以便图像样式可以基于存储在DB中的对象的属性。这可能吗?
答案 0 :(得分:13)
免责声明:首先,问题(你能将自己传递给lambda吗?)和你想要解决的问题(使用回形针的动态样式)不完全匹配。我不会回答原来的问题,因为它与你的问题并不完全相关,而且猖獗地对它进行了勇敢的抨击。
我会回答你的回形针问题。
详细说明,它是rails中回形针插件的
has_attached_file
方法。我想为样式哈希传递lambda,以便图像样式可以基于存储在DB中的对象的属性。这可能吗?
是的,这是可能的。在回形针中,: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
答案 1 :(得分:9)
好的,你还不清楚。
ruby中的局部变量以小写字母开头(如foo
,bar
或steve
),并且是词法范围的(如C
个变量)。它们与“一个类的实例”
ruby中的实例变量以@
sigil开头(例如@foo
,@bar
或@carl
),并且只要{{1}的当前值在范围内是存储它们的对象。
如果您想要一个可以直接访问对象的实例变量的方法,那就称为实例方法。例如,self
和battle_cry
都是实例方法:
initialize
相比之下,类方法是class Character
def initialize(name)
@name=name
end
def battle_cry
@name.upcase + "!!!"
end
def Character.default
new("Leeroy Jenkins")
end
end
对象的方法,并且无法访问该对象的任何实例变量。在上面的例子中,
Class
是一种类方法。
如果你想要一个(类或实例)方法触发更改或从当前范围获取值,ruby使用一种称为块的回调。
default
在上面的示例中,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
的返回值。
ruby中的单词yield
通常表示使用的lambda
关键字
使块成为独立的,像物体一样的功能(通常它们本身
被称为lambda
s,lambda
s或proc
s。。
Proc
所以我认为您所问的是,您是否可以通过bounce = lambda { |thing| puts "I'm bouncing a #{thing}" }
bounce["ball"]
bounce["frog"]
代替Proc
用于方法的参数。答案是“它取决于”。如果方法只
曾经使用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
可以有初始化块。因此,如果我们将上述内容更改为:
Hash
结果缓存在哈希
中要了解有关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