aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/plugins/annotate_models/lib
diff options
context:
space:
mode:
authorfrancis <francis>2007-12-11 12:16:29 +0000
committerfrancis <francis>2007-12-11 12:16:29 +0000
commit38732c1cd909d7566956aecb54187cbaec26309d (patch)
tree132fa2487b7c7ba73ba03b037fd41ec9d74b37cb /vendor/plugins/annotate_models/lib
parent77f2ceeb179b8143d0a34991fb64d0561007330d (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.rb127
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