【问题标题】:How to simulate Java-like annotations in Ruby?如何在 Ruby 中模拟类似 Java 的注解?
【发布时间】:2011-03-10 14:28:00
【问题描述】:

如何在 ruby​​ 中模拟类似 Java 的注解?

(嗯,我有答案,概括 http://bens.me.uk/2009/java-style-annotations-in-ruby)

【问题讨论】:

  • 在投票之前,您可以转到引用的网址并检查我的回复不是它的副本,而是一种简化,这可能对其他人有用。 (谢谢)

标签: ruby annotations


【解决方案1】:

这是几周前改编自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

【讨论】:

  • 您的代码使用起来更简单:它不需要预先声明注释!一个问题:当您存储注释的参数时,为什么 @__last_annotation__[meth[1..-1].to_sym] = args.first 而不是 @__last_annotation__[meth.to_sym] = args 我无法捕获 bot meth[1..-1] 或 args.first(它不只是数组的第一个元素,它包含参数)。
  • @cibercitizen1:meth[1..-1] 基本上说“除了方法名称的第一个字符之外的所有内容”,IOW 它删除了下划线。 args.first 只是因为我只希望该方法采用一个参数,即带有注释键值对的哈希。但是我必须定义method_missing 来接受任意数量的参数,以便如果我不想自己处理该方法(即,如果它不以下划线开头),我可以发送它们。毕竟,对于其他 DSL 或 Rails 之类的系统,method_missing 可能还有其他定义。
  • @cibercitizen1:你当然可以做一些更聪明的事情,比如检查大小是否为1,然后解包,否则就将其保留为数组。
  • 我必须做以下更改,才能与 ruby​​ 1.8 一起使用(我该如何格式化?)
     def method_missing(meth, *args) return super unless /\ A_/ =~ meth.to_s @__last_annotation__ ||= {} @__last_annotation__[meth] = (args.size == 1 ? args.first : args) end 
    and
     _hello :color => 'red ', :ancho => 23 _goodbye :color => 'green', :alto => -123 _foobar :color => 'blew' def m1;结束
  • @jwill:Sun 花了 8 年时间为 Java 添加注解,而且它们只能由 Sun 添加,其他任何人都不能。我花了大约 10 分钟和 23 行代码为 Ruby 添加注释,任何人都可以做到,您不必依赖语言设计器。我觉得这很酷。如果你想说服我,请尝试用 Java 实现不到 30 行的注解。
【解决方案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 的注释:

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")

【讨论】:

    【解决方案3】:

    我的要求是

    在一个页面上,我显示了一个 ABC 类的所有 instance_methods 的列表, 并且每个方法也应该有一个 1 行描述

    现在我不知道是我自己还是将所有这些方法的描述及其名称存储在数据库的新表中听起来“超级 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
    
    1. 在有权访问类 Abc 的视图中,通过 instance_methods 集合的注释属性哈希显示给定描述(仅,而不是方法名称)的代码。

    查看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>
    

    希望对你有帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多