3

当我使用像 Sequel 这样的 ORM 时,模型的列由连接的数据库定义。如何获取表格列的文档?

示例(续集,但我认为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

没有办法向数据库添加列描述(或者有没有办法?请不要使用特定于数据库的解决方案)。

对应的模型定义为

class Person < Sequel::Model
end

当我使用 rdoc 生成文档时,Person 的文档是“空的”,我没有得到列的描述。

我可以为这里的列添加一个 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 方法。

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

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

所以我的问题是:存储列描述的最佳实践是什么?

4

1 回答 1

0

到目前为止没有答案 - 也许没有最佳实践。

与此同时,我有一个想法,修改了annotate-gem的想法。

附加的脚本会创建一个包含模型文档的新 ruby​​ 文件。这个 ruby​​ 文件可能不会添加到您的应用程序中(它会破坏模型),但您可以将它添加到您的 rdoc 调用中。

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

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

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

于 2013-03-08T23:22:27.257 回答