2016-02-11 15 views
11

ho esteso Kernel per sé, e nella definizione del metodo di istanza Kernel#abort, ho chiamato il metodo singleton Kernel.abort:chiamata di un metodo singleton all'interno di un metodo di istanza in un modulo che si estende

module Kernel 
    extend self 

    def abort 
    puts "Press ENTER to exit..." 
    gets 
    Kernel.abort 
    end 
end 

abort 

Quando chiamo Kernel#abort, sembra che la chiamata Kernel.abort all'interno della definizione del metodo faccia riferimento all'originale Kernel#abort (esteso come Kernel.abort).

Come fa Ruby a sapere che quando scrivo Kernel.abort, intendo il metodo originale abort, non quello che ho appena creato? Come chiamerei ricorsivamente il nuovo metodo abort che ho appena creato?

+0

Se si desidera la ricorsione, utilizzare 'abort' invece di' Kernel.abort'. –

+0

'abort' è una chiamata con 'self' implicito. 'Kernel' in' Kernel.abort' è il 'self' esplicito, si specifica l'oggetto su cui il metodo deve essere richiamato. Oh, e ho riaperto la tua domanda. –

+0

Non sono del tutto sicuro di come funzioni la risoluzione dei nomi qui, quindi non sto inviando una risposta. Questa domanda deve essere già stata fatta su questo sito, però :) –

risposta

4

Kernel.abort viene definito definendo prima un metodo di istanza Kernel#abort e quindi rendendolo anche un metodo singleton con module_function. (This is definitely the case in Rubinius; Impossibile trovarlo nella sorgente MRI ma vedere di seguito.) module_functionmakes a copy of the method. Quando si ridefinisce il numero abort, si ridefinisce il metodo di istanza ma non la copia del singleton.

Object include Kernel, in modo che quando si dice abort si ottiene il metodo di istanza, che hai ridefinito, ma quando dici Kernel.abort si ottiene il metodo Singleton, che non avete ridefinito.

Se si desidera utilizzare la ricorsione in abort o semplicemente per dimostrare che questa spiegazione è corretta, chiamare module_function :abort dopo aver ridefinito il metodo. Il metodo Singleton verrà aggiornato per essere uguale al metodo di istanza e verranno richiamati entrambi i metodi.

Nota che non è necessario extend self per ridefinire la versione dell'istanza di abort. Poiché Kernel è già incluso in Object, è necessario ridefinire il metodo di istanza per tutti gli oggetti per visualizzare la versione ridefinita. D'altra parte, se avesse utilizzato extend self per esporre #abort in primo luogo, potremmo ridefinirlo senza complicazioni.

Quanto segue dimostra che la mancanza di ricorsione avviene con metodi di Ruby puro definiti dall'utente, vale a dire che module_function è responsabile e metodi nativi non sono:

$ cat foo.rb 
module Foo 
    def bar 
    puts "old version" 
    end 
    module_function :bar 
end 

module Foo 
    def bar 
    puts "new version" 
    Foo.bar 
    end 
end 

Object.include Foo 
bar 
$ ruby foo.rb 
new version 
old version 
+0

Grazie. Leggerò tutti e 3 gli articoli di utilizzo dei moduli, quindi tornerò su questa domanda. –

+0

Mi sono distratto dal lavoro, ho dimenticato questa domanda, mi dispiace. –

1

Si dovrebbe fare qualcosa di simile:

Il motivo per cui IRB sta invocando l'abort originale e non il tuo definito abort è perché l'IRB repl ha un metodo di interruzione che è una variante in linguaggio C. di esso.

Lo si può vedere facendo show-source sulla leva

[1] pry(main)> show-source abort 

From: process.c (C Method): 
Owner: Kernel 
Visibility: private 
Number of lines: 22 

VALUE 
rb_f_abort(int argc, const VALUE *argv) 
{ 
    rb_check_arity(argc, 0, 1); 
    if (argc == 0) { 
    if (!NIL_P(GET_THREAD()->errinfo)) { 
     ruby_error_print(); 
    } 
    rb_exit(EXIT_FAILURE); 
    } 
    else { 
    VALUE args[2]; 

    args[1] = args[0] = argv[0]; 
    StringValue(args[0]); 
    rb_io_puts(1, args, rb_stderr); 
    args[0] = INT2NUM(EXIT_FAILURE); 
    rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit)); 
    } 

    UNREACHABLE; 
} 

Nel codice lei ha citato il thats di interruzione viene eseguita non Kernel.abortire ma il linguaggio C abort questo è mappate all'IRB quando si richiama da riga di comando

Se si vuole che essere mascherato si potrebbe fare qualcosa di simile in modo che il abort in repl IRB potrebbe eseguire il ridefinito abort

def abort; Kernel.abort; end 

Quindi se si esegue abort invocherà il metodo del singleton annullato dal kernel ridefinito.

+0

Ho aggiunto un esempio alla mia risposta che mostra che il fenomeno non è dovuto al metodo nativo. –

+0

Giù votante puoi contraddire la mia risposta e dire che è sbagliato ?? – uday

Problemi correlati