2010-07-01 11 views

回答

27

這是幾個星期前從a piece of code I wrote in an answer to another question改編的,雖然它當然不是原創的。這一個着名的Ruby成語,畢竟這已經在使用多年,至少從rakesdesc的方法。

module Annotations 
    def annotations(meth=nil) 
    return @__annotations__[meth] if meth 
    @__annotations__ 
    end 

    private 

    def method_added(m) 
    (@__annotations__ ||= {})[m] = @__last_annotation__ if @__last_annotation__ 
    @__last_annotation__ = nil 
    super 
    end 

    def method_missing(meth, *args) 
    return super unless /\A_/ =~ meth 
    @__last_annotation__ ||= {} 
    @__last_annotation__[meth[1..-1].to_sym] = args.size == 1 ? args.first : args 
    end 
end 

class Module 
    private 

    def annotate! 
    extend Annotations 
    end 
end 

這裏有一個小例子:

class A 
    annotate! 

    _hello color: 'red', ancho: 23 
    _goodbye color: 'green', alto: -123 
    _foobar color: 'blew' 
    def m1; end 

    def m2; end 

    _foobar color: 'cyan' 
    def m3; end 
end 

當然沒有Ruby代碼將是不完整的測試套件:

require 'test/unit' 
class TestAnnotations < Test::Unit::TestCase 
    def test_that_m1_is_annotated_with_hello_and_has_value_red 
    assert_equal 'red', A.annotations(:m1)[:hello][:color] 
    end 
    def test_that_m3_is_annotated_with_foobar_and_has_value_cyan 
    assert_equal 'cyan', A.annotations[:m3][:foobar][:color] 
    end 
    def test_that_m1_is_annotated_with_goodbye 
    assert A.annotations[:m1][:goodbye] 
    end 
    def test_that_all_annotations_are_there 
    annotations = { 
     m1: { 
     hello: { color: 'red', ancho: 23 }, 
     goodbye: { color: 'green', alto: -123 }, 
     foobar: { color: 'blew'    } 
     }, 
     m3: { 
     foobar: { color: 'cyan'    } 
     } 
    } 
    assert_equal annotations, A.annotations 
    end 
end 
+1

您的代碼使用更簡單:它不需要提前聲明註釋!一個問題: 當存儲的註釋的參數 爲什麼@__last_annotation__[meth[1..-1].to_sym] = args.first 代替@__last_annotation__[meth.to_sym] = args 我不能趕上機器人甲基[1 ..- 1],或任一args.first(是不是隻的第一個元素數組,包裝參數)。 – cibercitizen1 2010-07-01 22:05:00

+1

@ cibercitizen1:'meth [1 ..- 1]'基本上是說「除了方法名的第一個字符之外的所有東西」,IOW它刪除了下劃線。 'args.first'只是因爲我只想讓方法接受一個參數,散列與註釋鍵值對。但是我必須定義'method_missing'來取任意數量的參數,以便我可以發送它們,如果我不想自己處理這個方法(即它不是以下劃線開頭的話)。畢竟,在其他DSL或Rails或其他系統中可能存在系統中method_missing的其他定義。 – 2010-07-01 22:43:33

+0

@ cibercitizen1:你當然可以做更聰明的事情,比如檢查大小是否爲1,然後解開它,否則就把它作爲一個數組。 – 2010-07-01 22:44:41

2

這是預期用途:

首先,你標註的類。

class A 

    extend Annotations 

    extend MyAnnotations 

    create_annotation("_foobar") 

    _hello({:color=>'red', :ancho=>23}) 
    _goodbye({:color=>'green', :alto=>-123}) 
    _foobar({:color=>'blew'}) 
    def m1 
    end 

    def m2 
    end 

    _foobar({:color=>'cyan'}) 
    def m3 
    end 
end 

然後,你想不檢查A的annoations這樣的:

anots = A.annotations 
puts anots.keys 

puts anots[:m1][:_hello][:color] 
puts anots[:m3][:_foobar][:color] 

puts anots[:m1].key?(:_goodbye) 

puts "---------------" 

anots.each do |met| # each annotated method 
    puts "-- annotated method --" 
    puts met[0] # method name 
    met[1].each do |a| # each annotation for the method 
    puts "-> " + a[0].to_s # annotation name 
    a[1].each do |par| # each pair: key-value 
     puts " key=" + par[0].to_s + " value=" + par[1].to_s 
    end 
    end 
end 

嘛。要做到這一點,你需要這個模塊

module Annotations 

    @@annotation_list = {} 
    @@pending = {} 

    def method_added(met_sym) 
    #puts "-> adding " + met_sym.to_s + " to class + self.to_s 
    if @@pending.size > 0 
     #puts met_sym.to_s + " is annotated " 
     @@annotation_list[met_sym] = @@pending 
     #puts @@annotation_list 
    else 
     #puts met_sym.to_s + " is not annotated " 
    end 
    @@pending = {} 
    end 

    def annotate_method(a,b) 
    @@pending[a] = b 
    end 

    def create_annotation(anot_sym) 
    code = "def #{anot_sym.to_s}(val) 
     annotate_method(:#{anot_sym} ,val) 
     end" 
    instance_eval code 
    end 

    def annotations 
    return @@annotation_list 
    end 

end 

,你可以你的模塊中定義的一組註解:

module MyAnnotations 

    def _goodbye(val) 
    annotate_method(:_goodbye, val) 
    end 

    def _hello(val) 
    annotate_method(:_hello, val) 
    end 
end 

或將其定義直接進入你註釋類:

create_annotation("_foobar") 
2

我的要求是

在一個第I頁顯示了ABC類的所有instance_methods的列表並且應該有一個1行描述過在每次方法

現在,我不知道這是否只是我或存儲的描述對所有與他們的名字在DB這些方法在一個新的表音「超級LAME」

答案是 - 「集註」

以下是我做到了 -

  1. 通過cibercitizen1
  2. 代碼中給出的模塊註釋包括該模塊並在所需類

ABC類激活的功能。RB

class Abc 
    extend Annotations 
    create_annotation("_annotation") 

_annotation({:description=>"Info e-mail address"}) 
def info_email 
    APP_CONFIG['info_email'] 
end 

_annotation({:description=>"Location of order"}) 
def location 
    unless self.order.blank? 
     @location ||= self.order.location.description 
    end 
end 
  • 代碼以顯示通過註釋給定的描述(只,而不是方法名稱)屬性哈希instance_methods的集合,其中可以訪問該視圖Abc類。
  • VIEW methods_list.html.erb

    <html> 
    <head> 
    </head> 
    <body> 
    <% default_description = "Description not specified" %> 
        <% Abc.instance_methods.each do |method| %> 
        <span style="float:right"> 
        <%= (Abc.annotations[method.to_sym].present? 
        ? 
        (Abc.annotations[method.to_sym][:_annotation][:description].blank? 
        ? default_description : 
        Abc.annotations[method.to_sym][:_annotation][:description]) 
        : default_description) %> 
        </span> 
    
        <% end %> 
    </body> 
    </html> 
    

    希望它能幫助!