Rails生成Model文档
辛卯[兔]年 二月十七
rails model文档生成(beta version)
包含: table schema, table index, model associations etc...
== TODO LIST
1. 关联处理完善
2. 查找model定义多平台处理
3. 转为GEM发布
存放路径:https://github.com/elvuel/rails-model-doc-generator
code:
require 'fileutils'
namespace :elvuel do
# Fetch all has*** :as =〉 item polymorphic associations
def store_polymorphic_as_associations(models)
reflects = []
models.each do |model|
model.reflections.each do |key, association|
reflects 〈〈 association if association.send(:options).has_key?(:as) #only polymorphic
end
end
@polymorphic_as_reflections = reflects
end
# Model belongs_to :item, :polymorphic =〉 true, get all item's class
def get_polymorphic_as_associations_classes(model, reflection)
classes = []
@polymorphic_as_reflections.each do |poly_as_reflection|
if poly_as_reflection.send(:options)[:as] == reflection.send(:name)
if poly_as_reflection.active_record.send(:compute_type, poly_as_reflection.send(:class_name)).to_s == model.to_s
classes 〈〈 poly_as_reflection.active_record.to_s.constantize
end
end
end
classes
end
# Simple quoting for the default column value
def quote(value)
case value
when NilClass then
"NULL"
when TrueClass then
"TRUE"
when FalseClass then
"FALSE"
when Float, Fixnum, Bignum then
value.to_s
# BigDecimals need to be output in a non-normalized form and quoted.
when BigDecimal then
value.to_s('F')
else
value.inspect
end
end
# Use the column information in an ActiveRecord class
# to create a comment block containing a line for
# each column. The line contains the column name,
# the type (and length), and any optional attributes
def get_schema_info(klass, options)
info = []
klass.columns.each do |col|
attrs = []
attrs 〈〈 "default(#{quote(col.default)})" unless col.default.nil?
attrs 〈〈 "not null" unless col.null
attrs 〈〈 "primary key" if col.name == klass.primary_key
col_type = col.type.to_s
if col_type == "decimal"
col_type 〈〈 "(#{col.precision}, #{col.scale})"
else
col_type 〈〈 "(#{col.limit})" if col.limit
end
# Check out if we got a geometric column
# and print the type and SRID
if col.respond_to?(:geometry_type)
attrs 〈〈 "#{col.geometry_type}, #{col.srid}"
end
# Check if the column has indices and print "indexed" if true
# If the indice include another colum, print it too.
if options[:simple_indexes] # Check out if this column is indexed
indices = klass.connection.indexes(klass.table_name)
if indices = indices.select { |ind| ind.columns.include? col.name }
indices.each do |ind|
ind = ind.columns.reject! { |i| i == col.name }
attrs 〈〈 (ind.length == 0 ? "indexed" : "indexed =〉 [#{ind.join(", ")}]")
end
end
end
info 〈〈 { :name =〉 col.name, :type =〉 col_type, :attrs =〉 attrs.join(", "), :human_name =〉 klass.respond_to?(:human_attribute_name) ? klass.human_attribute_name(col.name) : col.name }
end
info
end
# Get table indexes info
def get_index_info(klass)
index_info = []
indexes = klass.connection.indexes(klass.table_name)
indexes.each do |index|
index_info 〈〈 { :name =〉 index.name, :columns =〉 index.columns.join(", "), :unique =〉 (index.unique ? "UNIQUE" : "NO") }
end
index_info
end
# Get association info
def get_association_info(klass)
reflections = klass.reflections
associations = []
unless reflections.empty?
reflections.each do |key, association|
begin
info = {}
info[:name]= key.to_s
info[:type]= association.class.to_s.gsub(/ActiveRecord|Reflection|::/, "")
info[:macro]= association.send(:macro).to_s
# ActiveRecord::Reflection::ThroughReflection[::AssociationReflection|::AggregateReflection]
association_classes = []
case info[:type