Pergunta

Eu quero definir um método de classe que tem acesso a uma variável local. Portanto, este seria diferente para cada instância da classe. Eu sei que você pode fazer uma dinâmica método de classe com lambda como quando você usá-lo com named_scope. Mas isso pode ser feito para valores que são específicos para uma instância?

Em detalhe, é o método has_attached_file para o plugin de clipe de papel em trilhos. Eu quero passar um lambda para o hash estilos para que os estilos de imagem pode ser baseado fora de atributos do objeto armazenado no DB. Isso é possível?

Foi útil?

Solução

Disclaimer: Primeiro, a questão (? Você pode passar self para lambda ) e o problema que você está tentando resolver (estilos dinâmicos com clipe de papel) não coincidem totalmente para cima. Eu não vou responder a pergunta original, porque ele não está totalmente relacionado com o seu problema, e rampion levou uma facada valente para ele.

eu vou vez responder à sua pergunta clipe de papel.

Em detalhe, é o método has_attached_file para o plugin de clipe de papel em trilhos. Eu quero passar um lambda para o hash estilos para que os estilos de imagem pode ser baseado fora de atributos do objeto armazenado no DB. Isso é possível?

Sim, é possível. No clipe, a opção :styles pode tomar um Proc. Quando a fixação é inicializado, se foi utilizado um Proc, a própria ligação é passado para o Proc. O anexo tem uma referência para o objeto ActiveRecord associado, então você pode usar isso para determinar seus estilos dinâmicos.

Por exemplo, sua declaração has_attached_file poderia ser algo como isto (assumindo um cenário de usuário e avatar, onde o usuário pode personalizar o tamanho do seu 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

Outras dicas

Ok, você está sendo claro.

As variáveis ??locais em ruby ??começar com uma letra minúscula (como foo, bar, ou steve), e possuem escopo léxico (como variáveis ??C). Eles não têm nada a ver com "uma instância de uma classe"

As variáveis ??de instância em Ruby começar com uma sigilo @ (como @foo, @bar, ou @carl), e estão no escopo sempre que o valor atual de self é o objeto que eles são armazenados em.

Se você quer um método que pode acessar as variáveis ??de instância de um objeto diretamente, que é chamado um método de instância. Por exemplo, battle_cry e initialize são os dois métodos de instância:

class Character
  def initialize(name)
    @name=name
  end
  def battle_cry
    @name.upcase + "!!!"
  end
  def Character.default
    new("Leeroy Jenkins")
  end
end

Um método de classe, ao contrário, é um método para um objeto Class, e não tem acesso a qualquer uma das variáveis ??de instância desse objeto. No exemplo acima, default é um método de classe.

Se você quiser um método (classe ou instância) que desencadeia uma mudança no ou obtém um valor do escopo atual, rubi usa um tipo de retorno de chamada chamado de bloco.

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"

No exemplo acima, attack usa a palavra-chave yield para chamar o bloco passado a ele. Quando chamamos attack, então, o num_attacks variável local ainda é no escopo no bloco que passá-lo (delimitado aqui por do ... end), para que possamos incrementará. attack é capaz de passar valores para o bloco, aqui eles são capturados na variável saying. O bloco também passa valores de volta para o método, que aparece como o valor de retorno de yield.

A palavra lambda em ruby ??geralmente significa a palavra-chave lambda, que é usado para fazer blocos em monobloco, função como objetos (que em si são normalmente referido como lambdas, procs, ou Procs).

bounce = lambda { |thing| puts "I'm bouncing a #{thing}" }
bounce["ball"]
bounce["frog"]

Então eu acho que você está perguntando é se você pode passar um Proc no lugar de um Hash para um argumento para um método. E a resposta é "depende". Se o método só já usa o método #[], então sim:

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)

No entanto, pode usar alguns outros métodos Hash específicos, ou ligue para a mesma tecla várias vezes, que pode produzir resultados estranhos:

monster = Character.new("Frankenstein's Monster")
monster.set_stats(lambda do |stat_name|
  rand(20)
end)

monster.stats[:dex] #=> 19
monster.stats[:dex] #=> 1

Nesse caso, você pode ser melhor fora cache os pedidos em um hash intermediária. Isto é bastante fácil, uma vez que um Hash pode ter um bloco inicializador. Então, se nós mudar o acima para:

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

Os resultados são armazenados em cache no hash

Para ver mais sobre initializers bloco Hash, consulte 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"]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top