你能把自己传给lambda的铁轨吗?

时间:2009-07-10 13:24:35

标签: ruby-on-rails ruby ruby-on-rails-plugins paperclip

我想定义一个可以访问局部变量的类方法。因此,对于每个类的实例,这将是不同的。我知道你可以使用lambda创建一个类方法动态,就像你在named_scope中使用它一样。但是,这可以针对特定于实例的值进行吗?

详细说明,它是rails中paperclip插件的has_attached_file方法。我想为样式哈希传递lambda,以便图像样式可以基于存储在DB中的对象的属性。这可能吗?

2 个答案:

答案 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​​中的局部变量以小写字母开头(如foobarsteve),并且是词法范围的(如C个变量)。它们与“一个类的实例”

无关

ruby​​中的实例变量以@ sigil开头(例如@foo@bar@carl),并且只要{{1}的当前值在范围内是存储它们的对象。

如果您想要一个可以直接访问对象的实例变量的方法,那就称为实例方法。例如,selfbattle_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