Question

Je veux définir une méthode de classe qui a accès à une variable locale. Donc, ce serait différent pour chaque instance de la classe. Je sais que vous pouvez faire une méthode de classe dynamique avec lambda comme quand vous l'utilisez avec named_scope. Mais cela peut être fait pour les valeurs qui sont spécifiques à une instance?

Dans le détail, il est procédé de la has_attached_file pour le plugin trombone dans des rails. Je veux passer un lambda pour les styles de hachage de sorte que les styles d'image peuvent être basé sur des attributs de l'objet stocké dans la base de données. Est-ce possible?

Était-ce utile?

La solution

Disclaimer: Tout d'abord, la question ( Pouvez-vous passer à l'auto lambda ?) Et le problème que vous essayez de résoudre (styles dynamiques avec paperclip) ne le font pas entièrement correspondre. Je ne vais pas répondre à la question initiale, car il est pas tout à fait lié à votre problème, et raiponce a pris un coup de poignard vaillant dans ce domaine.

Je vais répondre à votre question au lieu de paperclip.

  

Dans le détail, il est la méthode has_attached_file pour le plug-in dans des rails paperclip. Je veux passer un lambda pour les styles de hachage de sorte que les styles d'image peuvent être basé sur des attributs de l'objet stocké dans la base de données. Est-ce possible?

Oui, il est possible. Dans paperclip, l'option :styles peut prendre Proc. Lorsque la fixation est initialisé, si un Proc a été utilisé, la fixation elle-même est transmis à la Proc. La pièce jointe est une référence à l'objet ActiveRecord associé, vous pouvez donc l'utiliser pour déterminer vos styles dynamiques.

Par exemple, votre déclaration de has_attached_file pourrait ressembler à ceci (en supposant un scénario utilisateur et avatar où l'utilisateur peut personnaliser la taille de leur 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

Autres conseils

Ok, tu es pas clair.

Les variables locales commencent à Ruby par une lettre minuscule (comme foo, bar ou steve), et sont une portée lexicale limitée (comme les variables de C). Ils ont rien à voir avec « une instance d'une classe »

Les variables d'instance en rubis commencent avec un sceau de @ (comme @foo, @bar ou @carl), et sont dans la portée chaque fois que la valeur courante de l'objet est self ils sont stockés dans.

Si vous voulez une méthode qui peut accéder aux variables d'instance d'un objet directement, ce qu'on appelle une méthode d'instance. Par exemple, battle_cry et initialize sont les deux méthodes d'instance:

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

Une méthode de classe, en revanche, est une méthode pour un objet Class, et n'a pas accès à l'une des variables d'instance de cet objet. Dans l'exemple ci-dessus, default est une méthode de classe.

Si vous voulez une méthode (classe ou instance) qui déclenche un changement ou obtient une valeur de la portée actuelle, Ruby utilise un type de rappel appelé bloc.

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"

Dans l'exemple ci-dessus, attack utilise le mot-clé yield pour appeler le bloc passé à elle. Lorsque nous appelons attack, puis, la num_attacks variable locale est toujours portée dans le bloc que nous transmettons (délimité ici par do ... end), afin que nous puissions incrémenter. attack est capable de transmettre des valeurs dans le bloc, ici ils sont capturés dans la variable saying. Le bloc passe également des valeurs retour à la méthode, qui apparaissent comme la valeur de retour de yield.

Le mot lambda en rubis signifie généralement le mot-clé lambda, qui est utilisé pour faire des blocs en pose libre, fonctionnent comme des objets (qui sont eux-mêmes habituellement dénommé lambdas, procs ou Procs).

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

Je pense donc que vous demandez est de savoir si vous pouvez passer un Proc en place d'un Hash pour un argument d'une méthode. Et la réponse est « ça dépend ». Si la seule méthode utilise toujours la méthode #[], alors oui:

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)

Cependant, il peut utiliser d'autres méthodes spécifiques de Hash, ou appeler les mêmes moments clés multiples, qui peut produire des résultats étranges:

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

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

Dans ce cas, vous pouvez être mieux mise en cache des requêtes dans un hachage intermédiaire. Ceci est assez facile, étant donné qu'un Hash peut avoir un bloc d'initialisation. Donc, si nous changeons ci-dessus à:

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

Les résultats sont mises en cache dans le hachage

Pour en savoir plus sur initializers de bloc Hash, voir 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"]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top