2015-01-20 21 views
5

Sto scrivendo un metodo che definirà un metodo di istanza all'interno di una classe; qualcosa di simile a attr_accessor:Determinazione della visibilità del metodo al volo

class Foo 
    custom_method(:foo) 
end 

Ho implementato che aggiungendo la funzione custom_method al modulo modulo, e definente con il metodo define_method, che funziona bene. Ma non riesco a capire come tenere conto degli attributi di visibilità della classe. Ad esempio, nel seguente classe

class Foo 
    custom_method(:foo) 
private 
    custom_method(:bar) 
end 

il primo metodo generato (foo) deve essere pubblica, e la seconda (bar) deve essere privato. Come lo faccio? Oppure, come faccio a trovare il contesto in cui viene chiamato my_method: privato, pubblico o protetto?

Grazie!

+0

@Aguardientico Non penso che sia un duplicato. Il titolo della domanda duplicato riguarda la forzatura di un metodo come privato. Questa domanda riguarda la determinazione dell'attuale "ambito".L'unica sovrapposizione è che la domanda correlata ha una risposta dicendo che a partire da Ruby 2.1 'define_method' onora l'attuale ambito 'predefinito'. – Phrogz

+0

L'OP chiede come rendere privato 'custom_method (: bar) ', anche OP ha detto che sta usando' define_method' quindi penso che sia duplicato perché nell'altra domanda l'OP chiede come usare 'define_method' per definire il metodo come privato – Aguardientico

+0

Non è un duplicato. Non sto chiedendo come impostare la visibilità su un metodo che generi; Devo sapere come determinare la visibilità per un metodo chiamato all'interno di una definizione di classe. @Aguardientico –

risposta

2

Penso che questo sia impossibile, perché il livello di visibilità dell'ambito impostato da Module.private è gestito a livello di macchina virtuale C e non esposto a Ruby.

EDIT: ed è disponibile solo nella stessa portata sintattica che è chiamata, in modo che quando si chiama custom_method perde il livello di visibilità impostato all'interno della dichiarazione della classe.

È impostato su set_visibility() e utilizzato in vm_define_method(), ma non riesco a trovare alcun riferimento alla variabile corrispondente disponibile da Ruby.

Suggerisco di utilizzare un tipo di parametro personalizzato per specificare il livello di visibilità dei metodi.

+0

Grazie! Credo che resterò con specificatori di visibilità espliciti per il mio metodo. –

-1

È possibile utilizzare Module#private_method_defined? per verificare se un metodo viene definito come privato

+0

Questo risponde alla seconda domanda ("O, come posso ..."), assumendo che l'OP non sia soddisfatto con una risposta a entrambe le domande. Penso che "Or" significhi "Anche" qui. –

+0

@CarySwoveland In realtà non è così. Se osservi attentamente, l'OP non stava chiedendo come stabilire se un metodo specifico è pubblico o privato. Invece l'OP chiedeva come determinare la visibilità predefinita corrente dei nuovi metodi definiti. – Ajedi32

7

Dopo aver sperimentato questo per un po ', io sono completamente sconcertato. Inizialmente, pensavo che Ruby avesse preso in considerazione la visibilità predefinita (pubblica, privata o protetta) quando chiami Module#define_method. Si scopre però che sulle versioni di Ruby < = 2.0, che non è il caso:

class Foo 
    private 
    define_method :foo do 
    puts "Foo called!" 
    end 
end 

Foo.new.foo # Prints "Foo called!" 

su Ruby 2.1 +, è ancora più confusa. Module#define_method sembra prendere la visibilità metodo di default in considerazione:

class Foo 
    private 
    define_method :foo do 
    puts "Foo called!" 
    end 
end 

Foo.new.foo # NoMethodError: private method `foo' called for #<Foo:0x8cb75ac> 

ma funziona solo quando si sta chiamando dal define_method direttamente all'interno della classe. Chiamare un metodo che quindi chiama define_method non funziona:

class Foo 
    def self.hello_on name 
    define_method name do 
     puts "Hello, #{name}!" 
    end 
    end 

    private 
    hello_on :foo 
end 

Foo.new.foo # Prints "Hello, foo!" 

relative a IT Rubino! Perché?

Okay, questo chiede misure disperate ...

module DefaultMethodVisibilityAccessor 
    attr_reader :current_default_method_visibility 

    def public(*args) 
    @current_default_method_visibility = :public if args.empty? 
    super 
    end 
    def protected(*args) 
    @current_default_method_visibility = :protected if args.empty? 
    super 
    end 
    def private(*args) 
    @current_default_method_visibility = :private if args.empty? 
    super 
    end 
end 

class Module 
    prepend DefaultMethodVisibilityAccessor 
end 

module MethodDefiner 
    def hello_on name 
    define_method name do 
     puts "Hello, #{name}!" 
    end 

    case current_default_method_visibility 
    when :public 
     public name 
    when :protected 
     protected name 
    when :private 
     private name 
    end 
    end 
end 

Usage:

class Foo 
    extend MethodDefiner 
    hello_on :foo 
    private 
    hello_on :bar 
end 

Foo.new.foo # Prints "Hello, foo!" 
Foo.new.bar # NoMethodError: private method `bar' called for #<Foo:0x8ec18fc> 

Lì, fisso!

Problemi correlati