Domanda

voglio definire un metodo di classe che ha accesso a una variabile locale. Quindi questo sarebbe diverso per ogni istanza della classe. So che si può fare un metodo di classe dinamico con lambda come quando lo si utilizza con named_scope. Ma questo può essere fatto per i valori che sono specifici a un'istanza?

Nel dettaglio è il metodo has_attached_file per il plugin graffetta in Rails. Voglio passare un lambda per gli stili di hash in modo che gli stili di immagine possono essere in base al largo di attributi dell'oggetto memorizzato nel DB. È possibile?

È stato utile?

Soluzione

Avviso: In primo luogo, la questione ( Can You Pass auto per lambda ?) E il problema si sta cercando di risolvere (stili dinamici con graffetta) non lo fanno completamente abbinare. Non voglio rispondere alla domanda iniziale, perché non è del tutto legato al tuo problema, e raperonzolo ha preso una pugnalata valente a questo.

Io invece rispondere alla tua domanda graffetta.

  

In dettaglio è il metodo has_attached_file per il plugin graffetta in Rails. Voglio passare un lambda per gli stili di hash in modo che gli stili di immagine possono essere in base al largo di attributi dell'oggetto memorizzato nel DB. È possibile?

Sì, è possibile. In graffetta, l'opzione :styles può prendere un Proc. Quando l'allegato viene inizializzato, se è stato utilizzato un Proc, l'allegato stesso viene trasmesso al Proc. L'attacco ha un riferimento all'oggetto ActiveRecord associato, in modo da poter utilizzare che per determinare gli stili dinamici.

Per esempio, la vostra dichiarazione has_attached_file potrebbe essere simile a questa (supponendo un utente e avatar scenario in cui l'utente può personalizzare la dimensione del loro 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

Altri suggerimenti

Ok, sei stato poco chiaro.

Le variabili locali in rubino iniziano con una lettera minuscola (come foo, bar o steve), e sono con scope lessicale (come le variabili C). Non hanno nulla a che fare con "un'istanza di una classe"

variabili istanza rubino iniziano con un sigillo @ (come @foo, @bar o @carl), e sono in ambito ogni volta che il valore corrente della self è l'oggetto sono memorizzati in.

Se si desidera un metodo che può accedere alle variabili di un oggetto direttamente esempio, che si chiama un metodo di istanza. Ad esempio, battle_cry e initialize sono entrambi metodi di istanza:

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

Un metodo di classe, al contrario, è un metodo per un oggetto Class, e non ha accesso a qualsiasi delle variabili di quell'oggetto istanza. Nell'esempio di cui sopra, default è un metodo della classe.

Se si desidera un metodo (classe o istanza) che innesca un cambiamento o ottiene un valore dall'ambito corrente, rubino utilizza un tipo di callback chiama un blocco.

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"

Nell'esempio precedente, attack utilizza la parola chiave yield per chiamare il blocco passato ad esso. Quando chiamiamo attack, quindi, il num_attacks variabile locale è ancora portata nel blocco passiamo esso (delimitato da qui do ... end), in modo che possiamo incrementarlo. attack è in grado di passare i valori nel blocco, qui sono catturati nella variabile saying. Il blocco passa anche valori torna al metodo, che mostrano come il valore restituito yield.

La parola lambda in Ruby di solito significa la parola lambda, che viene utilizzato fare blocchi in autoportante, funzionano come oggetti (che si sono solitamente denominati lambdas, procs o Procs).

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

Quindi penso che quello che stai chiedendo è se è possibile passare un Proc al posto di un Hash un argomento a un metodo. E la risposta è "dipende". Se il metodo solo sempre utilizza il metodo #[], allora sì:

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)

Tuttavia, potrebbe utilizzare alcuni metodi specifici altra Hash, oppure chiamare lo stesso tasto più volte, che può produrre risultati strani:

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

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

In questo caso, si può essere meglio cache le richieste in un hash intermedio. Questo è abbastanza facile, poiché un Hash può avere un blocco di inizializzazione. Quindi, se si cambia la precedenza a:

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

I risultati vengono tenuti nella hash

Per saperne di più sui initializers blocco Hash, vedi 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"]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top