2013-03-08 64 views
3

当我使用像Sequel这样的ORM时,模型的列由连接的数据库定义。我如何获得表格列的文档?ORM(特别是Sequel)存储列描述的位置?

(续集,但我认为原则是AR相同):

我创建一个表,这个迁移:

Sequel.migration do 
    up do 
    create_table(:person) do 
     primary_key :id 
     String :name, :null=>false 
    end 
    end 
    down do 
    drop_table(:person) 
    end 
end 

没有办法添加一列描述到数据库(或者是否有?请不要DB特定的解决方案)。

当我产生我的RDoc文档对应的模型被定义为

class Person < Sequel::Model 
end 

,对人的文档是“空”的,我没有得到任何列的说明。

我可以一个栏添加一个getter法喜欢这里:

class Person < Sequel::Model 
    #Name of the person 
    attr_reader :name 
end 

我得到RDoc的描述,但这里有两个问题:

  • Person#name永远是零,连接到数据库丢失
  • 如果它能工作,这是违反DRY原则。

我可以添加所有列的列表:

#Columns: 
# * name: Name of the person 
# ... 
class Person < Sequel::Model 
end 

但同样:

  • 这破坏了DRY原则。
  • 我想查看所有可用的列,如getter-methods。

我创建了annotate-gem。但这个宝石删除了以前的评论,它只增加了技术信息。我无法添加评论。

一些其他模型框架,如datamapper,mongomaper和mongoid直接定义模型中的属性。 (source)但我不想改变我的ORM。

所以我的问题:什么是最好的做法来存储列的描述?

回答

0

到目前为止没有答案 - 也许没有最佳做法。

在此期间,我有一个想法,修改了annotate-gem的想法。

附加的脚本创建一个新的红宝石文件与模型的文档。 这个ruby文件可能不会被添加到你的应用程序(它会打破模型),但你可以将它添加到你的rdoc调用。

添加以下代码ATT以下脚本的末尾:

require 'your_application' #Get your model definitions 

#Define ModelDocumentation with comments for the different fields 
doc = ModelDoc.new(
    #reference with table.field 
    'tables.field1' => 'field one of table tables', 
    #reference with model.field 
    'Table#field2' => "field two of table, referenced by model Table", 
) 
doc.save('my_doc.rb') 

而且现在的脚本:

#encoding: utf-8 
=begin rdoc 
Generate documentation file for Model, 
enriched with data from docdata 
=end 

=begin rdoc 
Get all subclasses from a class. 

Code from http://stackoverflow.com/a/436724/676874 
=end 
class Class 
    def subclasses 
    ObjectSpace.each_object(Class).select { |klass| klass < self } 
    end 
end 


=begin rdoc 
Class to generate a Model-documentation 

==Usage: 

Write a script like this: 

    require 'my_application' 
    require 'model_doc' #this script 

    doc = ModelDoc.new(
    #reference with table.field 
    'tables.field1' => 'field one of table tables', 
    #reference with model.field 
    'Table#field2' => "field two of table, referenced by model Table", 
) 
    doc.save('my_doc.rb') 

my_doc.rb can be included to your library. 
Don't load it to your application! 
Only add it to your documentation with rdoc. 
=end 
class ModelDoc 
=begin rdoc 
Class to generate a Model-documentation. 

Comments are a hash with. 

Keys may be: 
* Modelname#field 
* tablename.field 
=end 
    def initialize(comments = {}) 
    @comments = comments 
    end 

    def save(filename) 
    docfile = File.new(filename, 'w') 

    puts "(Re-)Generate #{docfile.path}" 
    docfile << <<doc 
=begin 
This file is generated by #{__FILE__}, 
based on data from #{Sequel::Model.db.inspect} 

Don't use this code in your implementation! 
This code will overwrite your real model. 


This is only for usage with rdoc. 

=end 
doc 
    Sequel::Model.subclasses.each{|model| 
     docfile << "\n\n#\n" 
     docfile << "#Model for table '#{model.table_name}'\n" 
     docfile << "#\n" 
     docfile << "class #{model} < Sequel::Model\n" 
     model.columns.each{|column| 
     comment = @comments[[model, column].join('#')] 
     comment = @comments[[model.table_name, column].join('.')] unless comment 

     docfile << " #\n #table field #{field_description(model.table_name, column, model.db_schema[column]).join("\n #* ")}\n" 
     if comment 
      docfile << comment.gsub(/^/, " #") 
      docfile << "\n" 
     end 
     #~ docfile << " #\n#accessor generated by Model\n" 
     docfile << " attr_reader #{column.inspect}\n" 
     } 
     docfile << "end\n\n" 
    } 

    docfile.close 
    end 

    def field_description(table_name, column, db_schema) 
    [ 
     "#{table_name}.#{column} (#{db_schema[:type]}/#{db_schema[:db_type]})", 
     db_schema[:primary_key] ? "This is a key field" : nil, 
     "Default is #{db_schema[:default] || 'undefined'}", 
     #fixme: ruby_default 
     "Null-values are #{'not ' unless db_schema[:allow_null]}allowed", 
    ].compact 
    end 
end #ModelDoc 

该脚本仅适用于续集,但我认为它可以适应AR。