Eredita una variabile di istanza dall'ambito globale

1

Sto usando Maledizioni per creare una GUI da riga di comando con Ruby. Tutto sta andando bene, ma ho colpito un leggero intoppo. Non credo che la conoscenza delle maledizioni (esoterica sia giusta ) è necessario per rispondere a questa domanda, solo concetti di Ruby come oggetti ed ereditarietà.

Ora spiegherò il mio problema, ma se mi capita, guarda l'esempio qui sotto.

Fondamentalmente, ogni istanza di Window deve avere .close chiamata su di essa per chiuderla. Alcune istanze di Window hanno altre finestre associate. Quando chiudi un'istanza di Windows, voglio poter chiudere tutte le altre istanze di Windows associate allo stesso tempo.

Poiché Windows associato viene generato in modo logico, (aggiungo il nome con un numero: instance_variable_set(self + integer, Window.new(10,10,10,10)) ), è facile scegliere come target finestre generate, perché i metodi possono anticipare ciò che verrà chiamato windows assosiated, (I can recreate the instance variable name from scratch, and almost query it: instance_variable_get(self + integer) .

Ho un metodo di cancellazione che gestisce questo. Se il metodo delete è solo un normale metodo globale (chiamato in questo modo: delete_window(@win543) allora tutto funziona perfettamente, tuttavia, se il metodo delete è un metodo di istanza, che deve essere in-order per utilizzare la parola chiave self , non funziona per una ragione molto chiara, può 'interrogare' perfettamente la variabile d'istanza corretta ( instance_variable_get(self + integer) ), tuttavia, perché è un metodo di istanza, le istanze globali non hanno un ambito!

Ora, un modo per ovviare a questo sarebbe ovviamente semplicemente creare un metodo globale come questo: delete_window(@win543) . Ma ho attributi associati alle mie istanze di finestre e tutto funziona in modo molto elegante.

Questo è molto semplificato, ma traduce letteralmente il problema esattamente:

class Dog
        def speak
                woof
        end
end

def woof
        if @dog_generic == nil
                puts "@dog_generic isn't scoped when .woof is called from a class method!\n"
        else
                puts "@dog_generic is scoped when .woof is called from the global scope. See:\n" + @dog_generic
        end
end

@dog_generic = "Woof!"
lassie = Dog.new
lassie.speak #=> @dog_generic isn't scoped when .woof is called from an instance method!\n

woof #=> @dog_generic is scoped when .woof is called from the global scope. See:\nWoof!

TL / DR: ho bisogno di lassie.speak per restituire questa stringa: "@dog_generic is scoped when .woof is called from the global scope. See:\nWoof!" @dog_generic deve rimanere come variabile insance. L'uso di Globali o Costanti non è accettabile.

Potrebbe woof ereditare dall'ambito globale? Forse una sorta di parola chiave:

def woof < global # This 'code' is just to conceptualise what I want to do, don't take offence!
end

C'è un modo in cui il metodo .woof potrebbe 'inserire' @dog_generic dall'ambito globale? @Dog_generic deve essere passato come parametro?

    
posta Crazy JIm 22.10.2013 - 14:14
fonte

1 risposta

1

Dovresti essere in grado di ottenerlo da instance_variable_get(:@dog_generic) ma c'è una percentuale implicita di% co_de in quella chiamata. Quindi, questo significa che dovremmo specificare esattamente da quale oggetto vuoi ottenere quella variabile d'istanza. E il fatto che sia una variabile di istanza implica che devi specificare quale istanza di quale oggetto. Qui sta il puzzle, vero?

E così, da qualche parte, potresti passare self da quel punto, dove self è 'main' (che è di classe Object).

class Dog
  def initialize(generic_dog)
    @from_outside = generic_dog # => main
  end
  def speak
    @from_outside.instance_variable_get(:@dog_generic) # => "Woof!"
  end
end

def woof
  if @dog_generic == nil
    "@dog_generic isn't scoped when .woof is called from a class method!\n"
  else
    "@dog_generic is scoped when .woof is called from the global scope. See:\n" + @dog_generic
  end
end

@dog_generic = "Woof!"
lassie = Dog.new(self)
puts lassie.speak
puts woof

# Output shown as >> and returns shown as =>
# >> Woof!
# >> @dog_generic is scoped when .woof is called from the global scope. See:
# >> Woof!

Quindi, no, @dog_generic non ha necessariamente bisogno di essere passato come argomento, ma devi passare qualcosa da qualche parte.

Ho modificato if statement per non usare self come incondizionatamente puts ing non è DRY, e probabilmente vorremmo restituire il risultato di the_if statement_ piuttosto che restituire nil dal metodo. Quindi mettiamo il metodo chiamato.

    
risposta data 22.10.2013 - 15:33
fonte

Leggi altre domande sui tag