Как моделировать подобные Java аннотации в Ruby?

Как моделировать подобные Java аннотации в рубине?

(Мы будем я иметь ответ, обобщая http://bens.me.uk/2009/java-style-annotations-in-ruby),

20
задан skaffman 2 November 2011 в 23:05
поделиться

2 ответа

Это адаптировано из фрагмента кода, который я написал в ответе на другой вопрос пару недель назад, хотя это, конечно, вряд ли оригинально. В конце концов, это хорошо известная идиома Ruby, которая использовалась много лет, по крайней мере, с тех пор, как rakes desc метод.

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
30
ответ дан 30 November 2019 в 00:09
поделиться

Это предполагаемое использование:

Сначала вы аннотируете класс.

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 следующим образом:

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")
4
ответ дан 30 November 2019 в 00:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: