Commit f2a1a2acdbd497fb577d942e9726c5f4ae52309e

added annotate_models plugin to give a better overview for models

Commit diff

vendor/plugins/annotate_models/ChangeLog

 
12007-03-05: Dave Thomas <dave@pragprog.com>
2 * Forgot to call the quote method
3
42007-03-02: Dave Thomas <dave@pragprog.com>
5 * Allow non-printing characters in column defaults (suggested by Ben Booth)
6
72007-02-28: Dave Thomas <dave@pragprog.com>
8 * Report errors loading model classes better. Change suggested by Niels Knacke
9
102007-02-22: Dave Thomas <dave@pragprog.com>
11* Ignore models with no underlying database table (based on patch from Jamie van Dyke)
12* Handle case where database has no session_info table (patch by David Vrensk)
13
14
152006-07-13: Dave Thomas <dave@pragprog.com>
16 * Support :scale for decimal columns
17
182006-07-13: Wes Gamble
19 * Don't annotate abstract models
20
212006-06-13: Dave Thomas <dave@pragprog.com>
22 * Fix bug where we corrupted the PREFIX string and therefore duplicated
23 the header
24 * No longer include the datetime, so we don't trigger a commit
25 back into repos
26
27 -- NOTE -- just this once, you'll get a duplicate header after you run
28 a_m on an already-annotated model. Sorry.... Dave
29
30
31
322006-06-11 Dave Thomas <dave@pragprog.com>
33 * lib/annotate_models.rb: At Kian Wright's suggestion, document the table
34 name and primary key. Also make the timestamp prettier
35
362006-04-17 Dave Thomas <dave@pragprog.com>
37
38 * lib/annnotate_models.rb: Include Bruce William's patch to allow
39 models in subdirectories
40
412006-03-11 Dave Thomas <dave@pragprog.com>
42
43 * lib/annotate_models.rb: Use camelize, not classify, to construct
44 class names (Grant Hollingworth)
45
463/3/06 Now annotates fixture files too (thanks to Josha Susser)
toggle raw diff

vendor/plugins/annotate_models/README

 
1AnnotateSchema
2==============
3
4Add a comment summarizing the current schema to the top
5of each ActiveRecord model source file:
6
7 # Schema as of Sun Feb 26 21:58:32 CST 2006 (schema version 7)
8 #
9 # id :integer(11) not null
10 # quantity :integer(11)
11 # product_id :integer(11)
12 # unit_price :float
13 # order_id :integer(11)
14 #
15
16 class LineItem < ActiveRecord::Base belongs_to :product
17
18 . . .
19
20Note that this code will blow away the initial comment block in your models if it looks ike it was
21previously added by annotate models, so you don't want to add additional text to an automatically
22created comment block.
23
24Author:
25 Dave Thomas
26 Pragmatic Programmers, LLC
27
28Released under the same license as Ruby. No Support. No Warranty.
29
30Back up your model files before using...
31
toggle raw diff

vendor/plugins/annotate_models/lib/annotate_models.rb

 
1require "config/environment"
2
3MODEL_DIR = File.join(RAILS_ROOT, "app/models")
4FIXTURE_DIR = File.join(RAILS_ROOT, "spec/fixtures")
5
6module AnnotateModels
7
8 PREFIX = "== Schema Information"
9
10 # Simple quoting for the default column value
11 def self.quote(value)
12 case value
13 when NilClass then "NULL"
14 when TrueClass then "TRUE"
15 when FalseClass then "FALSE"
16 when Float, Fixnum, Bignum then value.to_s
17 # BigDecimals need to be output in a non-normalized form and quoted.
18 when BigDecimal then value.to_s('F')
19 else
20 value.inspect
21 end
22 end
23
24 # Use the column information in an ActiveRecord class
25 # to create a comment block containing a line for
26 # each column. The line contains the column name,
27 # the type (and length), and any optional attributes
28 def self.get_schema_info(klass, header)
29 info = "# #{header}\n#\n"
30 info << "# Table name: #{klass.table_name}\n#\n"
31
32 max_size = klass.column_names.collect{|name| name.size}.max + 1
33 klass.columns.each do |col|
34 attrs = []
35 attrs << "default(#{quote(col.default)})" if col.default
36 attrs << "not null" unless col.null
37 attrs << "primary key" if col.name == klass.primary_key
38
39 col_type = col.type.to_s
40 if col_type == "decimal"
41 col_type << "(#{col.precision}, #{col.scale})"
42 else
43 col_type << "(#{col.limit})" if col.limit
44 end
45 info << sprintf("# %-#{max_size}.#{max_size}s:%-13.13s %s\n", col.name, col_type, attrs.join(", "))
46 end
47
48 info << "#\n\n"
49 end
50
51 # Add a schema block to a file. If the file already contains
52 # a schema info block (a comment starting
53 # with "Schema as of ..."), remove it first.
54
55 def self.annotate_one_file(file_name, info_block)
56 if File.exist?(file_name)
57 content = File.read(file_name)
58
59 # Remove old schema info
60 content.sub!(/^# #{PREFIX}.*?\n(#.*\n)*\n/, '')
61
62 # Write it back
63 File.open(file_name, "w") { |f| f.puts info_block + content }
64 end
65 end
66
67 # Given the name of an ActiveRecord class, create a schema
68 # info block (basically a comment containing information
69 # on the columns and their types) and put it at the front
70 # of the model and fixture source files.
71
72 def self.annotate(klass, header)
73 info = get_schema_info(klass, header)
74
75 model_file_name = File.join(MODEL_DIR, klass.name.underscore + ".rb")
76 annotate_one_file(model_file_name, info)
77
78 fixture_file_name = File.join(FIXTURE_DIR, klass.table_name + ".yml")
79 annotate_one_file(fixture_file_name, info)
80 end
81
82 # Return a list of the model files to annotate. If we have
83 # command line arguments, they're assumed to be either
84 # the underscore or CamelCase versions of model names.
85 # Otherwise we take all the model files in the
86 # app/models directory.
87 def self.get_model_names
88 models = ARGV.dup
89 models.shift
90
91 if models.empty?
92 Dir.chdir(MODEL_DIR) do
93 models = Dir["**/*.rb"]
94 end
95 end
96 models
97 end
98
99 # We're passed a name of things that might be
100 # ActiveRecord models. If we can find the class, and
101 # if its a subclass of ActiveRecord::Base,
102 # then pas it to the associated block
103
104 def self.do_annotations
105 header = PREFIX.dup
106 version = ActiveRecord::Migrator.current_version rescue 0
107 # if version > 0
108 # header << "\n# Schema version: #{version}"
109 # end
110
111 self.get_model_names.each do |m|
112 class_name = m.sub(/\.rb$/,'').camelize
113 begin
114 klass = class_name.split('::').inject(Object){ |klass,part| klass.const_get(part) }
115 if klass < ActiveRecord::Base && !klass.abstract_class?
116 puts "Annotating #{class_name}"
117 self.annotate(klass, header)
118 else
119 puts "Skipping #{class_name}"
120 end
121 rescue Exception => e
122 puts "Unable to annotate #{class_name}: #{e.message}"
123 end
124
125 end
126 end
127end
toggle raw diff

vendor/plugins/annotate_models/tasks/annotate_models_tasks.rake

 
1desc "Add schema information (as comments) to model files"
2
3task :annotate_models do
4 require File.join(File.dirname(__FILE__), "../lib/annotate_models.rb")
5 AnnotateModels.do_annotations
6end
toggle raw diff