2011-10-12 18 views
5

yakut, sen bunu yapabilirsiniz:"Kamu/korunan/özel" yöntem nasıl uygulanır ve nasıl taklit edebilirim?

class Thing 
    public 
    def f1 
    puts "f1" 
    end 

    private 
    def f2 
    puts "f2" 
    end 

    public 
    def f3 
    puts "f3" 
    end 

    private 
    def f4 
    puts "f4" 
    end 
end 

nerede şimdi f1 ve f3 ve kamu, f2 ve f4 özeldir. Dahili olarak, yöntem tanımını değiştiren bir sınıf yöntemini çağırmanıza izin veren nedir? Aynı işlevleri uygulayabilirsiniz nasıl

class Thing 
    fun 
    def f1 
    puts "hey" 
    end 

    notfun 
    def f2 
    puts "hey" 
    end 
end 

... örneğin

(görünüşte ek açıklamalar gibi kendi java oluşturmak için) ve eğlenceli ve notfun aşağıdaki fonksiyon tanımlarını değiştirmek olacaktır. Eğer mümkün Yakut dili kendisi uzantıları yazmak istiyorum gibi

Teşekkür

cevap

8

Bazen Ruby'yi espressso kabına sokabilirsiniz. Nasıl görelim.

Thing.new.f1 
# => hey 
# => That was fun 

Thing.new.f2 
# => hey 
# => That was not fun 
: Burada

bu sonuçla ... Eğer bir sınıf genişletmek için kullanabileceği

module FunNotFun 

    def fun 
    @method_type = 'fun' 
    end 

    def notfun 
    @method_type = 'not fun' 
    end 

    def method_added(id) 
    return unless @method_type 
    return if @bypass_method_added_hook 
    orig_method = instance_method(id) 
    @bypass_method_added_hook = true 
    method_type = @method_type 
    define_method(id) do |*args| 
     orig_method.bind(self).call(*args).tap do 
     puts "That was #{method_type}" 
     end 
    end 
    @bypass_method_added_hook = false 
    end 

end 

... ...

class Thing 

    extend FunNotFun 

    fun 
    def f1 
    puts "hey" 
    end 

    notfun 
    def f2 
    puts "hey" 
    end 
end 

... Bir modül FunNotFun var

Ama daha iyi bir yol için çizginin altına bakın.


Açıklamalar (normalocity cevabını bakın) daha az sorun ve ortak bir Ruby deyim olan daha kolay kodun niyetini bildirecektir. İşte ek açıklamalarla bunu nasıl açıklanmıştır:

Kullanımda
module FunNotFun 

    def fun(method_id) 
    wrap_method(method_id, "fun") 
    end 

    def notfun(method_id) 
    wrap_method(method_id, "not fun") 
    end 

    def wrap_method(method_id, type_of_method) 
    orig_method = instance_method(method_id) 
    define_method(method_id) do |*args| 
     orig_method.bind(self).call(*args).tap do 
     puts "That was #{type_of_method}" 
     end 
    end 
    end 

end 

yöntemi belirlendikten sonra, açıklama yerine daha önce hiç, gelir:

class Thing 

    extend FunNotFun 

    def f1 
    puts "hey" 
    end 
    fun :f1 

    def f2 
    puts "hey" 
    end 
    notfun :f2 

end 

sonuç aynıdır:

Thing.new.f1 
# => hey 
# => That was fun 

Thing.new.f2 
# => hey 
# => That was not fun 
+0

ah, aklımda olan bu daha fazla –

+0

İlk yaklaşım iplik güvenli midir? –

+1

@Semyon, Aynı sınıfa aynı anda birden fazla iş parçacığı ekleme yönteminiz yoksa. Neredeyse her zaman, yöntemler ekleyerek sadece bir iş parçacığı tarafından yapılır. –

1

geliyor. Bu kısaca izah edilebilir bir şey değil, ama sizi almalısınız bu bağlantıyı başlatan:

http://ruby-doc.org/docs/ProgrammingRuby/html/ext_ruby.html

Bu referans, Ruby ek açıklamalarla yapmak zorunda, ayrıca/yararlı alakalı olabilir:

http://martinfowler.com/bliki/RubyAnnotations.html

+1

Mümkün olduğu kadar yakutun uzatılması gerçekten gerekli midir? Akıllı bir meta programlamayla veya bir şeyle yapılabilmesi gerektiği gibi geliyor, ama sanırım bu durum böyle olmayabilir. –

1

İşte size doğru yönde ulaşmak için saf yakut bir çözüm. method_added üzerinde menteşelenir. Koruma maddesi kullanarak tekrardan kaçınmaya dikkat edin.

module Annotations 
    def fun 
    @state = :fun 
    end 

    def not_fun 
    @state = :not_fun 
    end 

    def inject_label(method_name) 
    state = @state 
    define_method(:"#{method_name}_with_label") do |*args, &block| 
     puts "Invoking #{method_name} in state #{state}" 
     send(:"#{method_name}_without_label", *args, &block) 
    end 

    alias_method :"#{method_name}_without_label", :"#{method_name}" 
    alias_method :"#{method_name}", :"#{method_name}_with_label" 
    end 

    def self.extended(base) 
    base.instance_eval do 
     def self.method_added(method_name) 
     return if method_name.to_s =~ /_with(out)?_label\Z/ 
     @seen ||= {} 
     unless @seen[method_name] 
      @seen[method_name] = true 
      inject_label(method_name) 
     end 
     end 
    end 
    end 
end 

class Foo 
    extend Annotations 

    fun 

    def something 
    puts "I'm something" 
    end 

    not_fun 

    def other 
    puts "I'm the other" 
    end 
end 
İlgili konular