Rubyでアノテーション
RubyでJava的なアノテーションが使いたくなったので実装してみました。
参考にしたのは以下の質問に対する回答。
How to simulate Java-like annotations in Ruby?
http://stackoverflow.com/questions/3157426/how-to-simulate-java-like-annotations-in-ruby
そのまんまだとインスタンスメソッドにしか対応できなかったので、クラスメソッド含めアノテーションを付与できるようにしてみました。
使い方
メソッドに対して_
で始まるアノテーションを記述する。
sample.rb
require './annotations'
class Sample
annotate!
_label_only
def instance_method1; end
_with_args arg1: 'val1', arg2: 1
def instance_method2; end
_label_only
def self.class_method1; end
_with_args arg1: 'val2', arg2: 2
def self.class_method2; end
end
クラス名.annotations()
でメソッド名をシンボルで指定することで、メソッドに追加されたアノテーションを取得できる。引数も指定可能。
クラスメソッドとインスタンスメソッドで同名が使われるとアノテーションが混在してしまうので、インスタンスメソッドのシンボルはメソッド名の頭に_
を付与することにした。
test.rb
require './sample'
p Sample.annotations(:_instance_method1) # {:label_only=>[]}
p Sample.annotations(:_instance_method2) # {:with_args=>{:arg1=>"val1", :arg2=>1}}
p Sample.annotations(:class_method1) # {:label_only=>[]}
p Sample.annotations(:class_method2) # {:with_args=>{:arg1=>"val2", :arg2=>2}}
annotations.rbの実装
annotations.rb
module Annotations
@@__last_annotation__ = nil
def annotations(meth=nil)
return @@__annotations__[meth] if meth
@@__annotations__
end
private
def singleton_method_added(m)
(@@__annotations__ ||= {})[m] = @@__last_annotation__ if @@__last_annotation__
@@__last_annotation__ = nil
super
end
def method_added(m)
(@@__annotations__ ||= {})["_#{m.to_s}".to_sym] = @@__last_annotation__ if @@__last_annotation__
@@__last_annotation__ = nil
super
end
def method_missing(meth, *args)
return super unless /^\_/ =~ 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
Gistにも投稿しました。
https://gist.github.com/matsukaz/06bd42aca25cba9dc569bc5aaaf3374f