diff options
author | francis <francis> | 2007-12-11 12:16:29 +0000 |
---|---|---|
committer | francis <francis> | 2007-12-11 12:16:29 +0000 |
commit | 38732c1cd909d7566956aecb54187cbaec26309d (patch) | |
tree | 132fa2487b7c7ba73ba03b037fd41ec9d74b37cb /vendor/plugins/annotate_models/lib | |
parent | 77f2ceeb179b8143d0a34991fb64d0561007330d (diff) |
Annotate model files with their members.
Type "rake annotate_models" to do this.
Diffstat (limited to 'vendor/plugins/annotate_models/lib')
-rw-r--r-- | vendor/plugins/annotate_models/lib/annotate_models.rb | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/vendor/plugins/annotate_models/lib/annotate_models.rb b/vendor/plugins/annotate_models/lib/annotate_models.rb new file mode 100644 index 000000000..1d84113af --- /dev/null +++ b/vendor/plugins/annotate_models/lib/annotate_models.rb @@ -0,0 +1,127 @@ +require "config/environment" + +MODEL_DIR = File.join(RAILS_ROOT, "app/models") +FIXTURE_DIR = File.join(RAILS_ROOT, "test/fixtures") + +module AnnotateModels + + PREFIX = "== Schema Information" + + # Simple quoting for the default column value + def self.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 self.get_schema_info(klass, header) + info = "# #{header}\n#\n" + info << "# Table name: #{klass.table_name}\n#\n" + + max_size = klass.column_names.collect{|name| name.size}.max + 1 + klass.columns.each do |col| + attrs = [] + attrs << "default(#{quote(col.default)})" if col.default + 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 + info << sprintf("# %-#{max_size}.#{max_size}s:%-15.15s %s\n", col.name, col_type, attrs.join(", ")) + end + + info << "#\n\n" + end + + # Add a schema block to a file. If the file already contains + # a schema info block (a comment starting + # with "Schema as of ..."), remove it first. + + def self.annotate_one_file(file_name, info_block) + if File.exist?(file_name) + content = File.read(file_name) + + # Remove old schema info + content.sub!(/^# #{PREFIX}.*?\n(#.*\n)*\n/, '') + + # Write it back + File.open(file_name, "w") { |f| f.puts info_block + content } + end + end + + # Given the name of an ActiveRecord class, create a schema + # info block (basically a comment containing information + # on the columns and their types) and put it at the front + # of the model and fixture source files. + + def self.annotate(klass, header) + info = get_schema_info(klass, header) + + model_file_name = File.join(MODEL_DIR, klass.name.underscore + ".rb") + annotate_one_file(model_file_name, info) + + fixture_file_name = File.join(FIXTURE_DIR, klass.table_name + ".yml") + annotate_one_file(fixture_file_name, info) + end + + # Return a list of the model files to annotate. If we have + # command line arguments, they're assumed to be either + # the underscore or CamelCase versions of model names. + # Otherwise we take all the model files in the + # app/models directory. + def self.get_model_names + models = ARGV.dup + models.shift + + if models.empty? + Dir.chdir(MODEL_DIR) do + models = Dir["**/*.rb"] + end + end + models + end + + # We're passed a name of things that might be + # ActiveRecord models. If we can find the class, and + # if its a subclass of ActiveRecord::Base, + # then pas it to the associated block + + def self.do_annotations + header = PREFIX.dup + version = ActiveRecord::Migrator.current_version rescue 0 + if version > 0 + header << "\n# Schema version: #{version}" + end + + self.get_model_names.each do |m| + class_name = m.sub(/\.rb$/,'').camelize + begin + klass = class_name.split('::').inject(Object){ |klass,part| klass.const_get(part) } + if klass < ActiveRecord::Base && !klass.abstract_class? + puts "Annotating #{class_name}" + self.annotate(klass, header) + else + puts "Skipping #{class_name}" + end + rescue Exception => e + puts "Unable to annotate #{class_name}: #{e.message}" + end + + end + end +end |