Как смоделировать Java-подобные аннотации в Ruby? - PullRequest
20 голосов
/ 01 июля 2010

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

(У нас будет ответ, обобщающий http://bens.me.uk/2009/java-style-annotations-in-ruby)

Ответы [ 3 ]

30 голосов
/ 02 июля 2010

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

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
4 голосов
/ 01 июля 2010

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

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

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

Затем вы хотели бы проверить аннотации А следующим образом:

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 голосов
/ 13 января 2011

Мое требование:

На странице я отображаю список всех instance_methods для класса ABC, и для каждого метода также должно быть описание в 1 строку

Теперь я не знаю, если это только я или сохраняю описания всех этих методов с их именами в новой таблице в БД, звучит "Super 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 method_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>

Надеюсь, это поможет!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...