annotator 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright 2012 YOURNAME
1
+ Copyright 2012 Tech-Angels
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -62,15 +62,14 @@ Of course similar thing happens when you remove column or change it's type.
62
62
  * for some fields like title above you can just skip description including dash sometimes name is just obvious enough
63
63
  * multiline comments are ok
64
64
  * generating initial descriptions it understands things like
65
- ** belongs_to association columns
66
- ** devise columns
67
- ** paperclip colums
65
+ * belongs_to association columns
66
+ * devise columns
67
+ * paperclip colums
68
68
 
69
69
  Contributions are very much welcome.
70
70
 
71
71
  == Todos
72
72
 
73
- * it could be written a bit cleaner
74
73
  * since name does not have "model" in it, we could possibly use "rake routes" to annotate controller actions, not sure if it's worth it
75
74
 
76
75
  == Authors
data/lib/annotator.rb CHANGED
@@ -1,189 +1,15 @@
1
1
  require 'annotator/railtie'
2
+ require 'annotator/model'
3
+ require 'annotator/attributes'
4
+ require 'annotator/initial_description'
2
5
 
3
6
  module Annotator
4
- def self.run
5
- models = Dir.glob("#{Rails.root}/app/models/*.rb").map do |filename|
6
- klass = filename.split('/').last.split(/\.rb$/).first.camelize.constantize
7
- [filename, klass]
8
- end.sort_by {|x| x.last.to_s}
9
-
10
-
11
- models.each do |filename, model|
12
- next unless model.ancestors.include? ActiveRecord::Base
13
- begin
14
- file = File.read(filename)
15
- lines = file.split("\n")
16
- out = ''
17
- ia = false # inside attributes block
18
- after_block = false # we are already after comments block
19
- changed = false
20
- skip_file = false
21
- attrs_arr = []
22
- lines.each do |line|
23
- break if skip_file
24
- out << "#{line}\n" && next if after_block
25
-
26
- if ia && !line.match(/^# \*/) && !line.match(/^# \S/)
27
- out << stringify_attrs_arr(update_attrs_arr(attrs_arr, model))
28
- ia = false
29
- changed = true
30
- end
31
-
32
- # check if we are still in the comments part of the file
33
- unless line.strip.empty? || line.match(/^\s*#/)
34
- after_block = true
35
- unless changed
36
- out << "# Attributes:\n"
37
- out << stringify_attrs_arr(update_attrs_arr(attrs_arr, model))
38
- end
39
- end
40
-
41
- if ia
42
- if line.match(/^# \*/)
43
- m = line.match(/^# \* (\w+) \[(.*?)\]( \- )?(.*)/)
44
- if m
45
- attrs_arr << [m[1], m[2], m[4]].map(&:strip)
46
- else
47
- puts "!! Unrecognized line format on attributes list in #{model}:"
48
- puts line
49
- end
50
- else
51
- attrs_arr[-1][2] << " #{line[4..-1]}"
52
- end
53
- else
54
- out << "#{line}\n"
55
- end
56
-
57
- ia = true if line.match(/^# Attributes:/i)
58
- skip_file = true if line.match(/^# Attributes\(nodoc\):/i)
59
- end
60
-
61
- File.open(filename,'w') { |f| f.write(out) } if out.strip != file.strip && !skip_file
62
-
63
- rescue Exception => e
64
- puts "FAILURE while trying to update model #{model}:\n #{e}"
65
- end
66
- end
67
-
68
-
69
- end
70
-
71
- protected
72
-
73
- def self.update_attrs_arr(arr, model)
74
- arr = arr.dup
75
- model.columns.each do |column|
76
- attrs_str = column_attrs(column)
77
- if row = arr.find {|x| x[0] == column.name}
78
- if row[1] != attrs_str
79
- puts " M #{model}##{column.name} [#{row[1]} -> #{attrs_str}]"
80
- row[1] = attrs_str
81
- end
82
- else
83
- puts " A #{model}##{column.name} [#{attrs_str}]"
84
- desc = initial_description model, column
85
- arr << [column.name, attrs_str, desc]
86
- end
87
- end
88
-
89
- # find columns that no more exist in db
90
- orphans = arr.map(&:first) - model.columns.map(&:name)
91
- unless orphans.empty?
92
- orphans.each do |orphan|
93
- puts " D #{model}#{orphan}"
94
- arr = arr.select {|x| x[0] != orphan}
95
- end
96
- end
97
- arr
98
- end
99
7
 
100
- def self.initial_description(model, column)
101
- case column.name
102
- when 'id' then return 'primary key'
103
- when 'created_at' then return 'creation time'
104
- when 'updated_at' then return 'last update time'
105
- end
106
-
107
- # TODO stop writing like it's functional lang and make class for Description ;)
108
-
109
- # Belongs to association
110
- model.reflect_on_all_associations.each do |reflect|
111
- if reflect.foreign_key == column.name && reflect.macro == :belongs_to
112
- return "belongs to #{reflect.klass}"
113
- end
114
- end
115
-
116
- # Devise column names
117
- if model.respond_to? :devise_modules
118
- devise_columns = {
119
- :reset_password_token => "Devise Recoverable module",
120
- :reset_password_sent_at => "Devise Recoverable module",
121
- :remember_created_at => "Devise Rememberable module",
122
- :sign_in_count => "Devise Trackable module",
123
- :current_sign_in_at => "Devise Trackable module",
124
- :last_sign_in_at => "Devise Trackable module",
125
- :current_sign_in_ip => "Devise Trackable module",
126
- :last_sign_in_ip => "Devise Trackable module",
127
- :password_salt => "Devise Encriptable module",
128
- :confirmation_token => "Devise Confirmable module",
129
- :confirmed_at => "Devise Confirmable module",
130
- :confiramtion_sent_at => "Devise Confirmable module",
131
- :unconfirmed_email => "Devise Confirmable module",
132
- :failed_attempts => "Devise Lockable module",
133
- :unlock_token => "Devise Locakble module",
134
- :locked_at => "Devise Lockable module",
135
- :authentication_token => "Devise Token authenticable module"
136
- }
137
- guess = devise_columns[column.name.to_sym]
138
- return guess if guess
139
- end
140
-
141
- # Paperclip column names
142
- if model.respond_to? :attachments_definitions
143
- model.attachments_definitions.keys.each do |att|
144
- cols = ["#{att}_file_name", "#{att}_content_type", "#{att}_file_size", "#{att}_updated_at"]
145
- return "Paperclip for #{att}" if cols.include? column.name
146
- end
147
- end
148
-
149
- # let's not add "document me" note for these obvious ones:
150
- return '' if %w{email name title body}.include? column.name
151
-
152
- return 'TODO: document me'
153
- end
154
-
155
- def self.column_attrs(c)
156
- ret = c.type.to_s
157
- ret << ", primary" if c.primary
158
- ret << ", default=#{c.default}" if c.default
159
- ret << ", not null" unless c.null
160
- ret << ", limit=#{c.limit}" if c.limit && (c.limit != 255 && c.type != :string)
161
- ret
162
- end
163
-
164
- def self.stringify_attrs_arr(arr)
165
- ret = ''
166
- arr.sort_by{|x| x[0] == 'id' ? '_' : x[0]}.each do |name, attrs, desc|
167
- # split into lines that don't exceed 80 chars
168
- desc = " - #{desc}" unless desc.empty?
169
- line = "# * #{name} [#{attrs}]#{desc}"
170
- lt = wrap_text(line, opts[:max_chars_per_line]-3).split("\n")
171
- line = ([lt[0]] + lt[1..-1].map{|x| "# #{x}"}).join("\n")
172
- ret << "#{line}\n"
8
+ def self.run
9
+ Dir.glob("#{Rails.root}/app/models/**/*.rb").sort.map do |filename|
10
+ Model.new(filename).update!
173
11
  end
174
- ret
175
12
  end
176
13
 
177
- def self.wrap_text(txt, col)
178
- txt.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/,"\\1\\3\n")
179
- end
180
-
181
- def self.opts
182
- {
183
- :max_chars_per_line => 120
184
- }
185
- end
186
-
187
-
188
14
  end
189
15
 
@@ -0,0 +1,92 @@
1
+ module Annotator
2
+
3
+ # Attributes within given model file
4
+ class Attributes
5
+ R_ATTRIBUTE = /^# \* (\w+) \[(.*?)\]( \- )?(.*)$/
6
+ R_ATTRIBUTE_NEXT_LINE = /^# (.*?)$/
7
+ R_ATTRIBUTE_LINE = /(#{R_ATTRIBUTE})|(#{R_ATTRIBUTE_NEXT_LINE})/
8
+ HEADER = "# Attributes:"
9
+ MAX_CHARS_PER_LINE = 120
10
+
11
+ def initialize(model, lines)
12
+ @model = model
13
+ @lines = lines
14
+ @attrs = []
15
+ @changes = []
16
+ parse
17
+ end
18
+
19
+ # Convert attributes array back to attributes lines representation to be put into file
20
+ def lines
21
+ ret = [Attributes::HEADER]
22
+ # Sort by name, but id goes first
23
+ @attrs.sort_by{|x| x[:name] == 'id' ? '_' : x[:name]}.each do |row|
24
+ line = "# * #{row[:name]} [#{row[:type]}]#{row[:desc].to_s.empty? ? "" : " - #{row[:desc]}"}"
25
+ # split into lines that don't exceed 80 chars
26
+ lt = wrap_text(line, MAX_CHARS_PER_LINE-3).split("\n")
27
+ line = ([lt[0]] + lt[1..-1].map{|x| "# #{x}"}).join("\n")
28
+ ret << line
29
+ end
30
+ ret
31
+ end
32
+
33
+ # Update attribudes array to the current database state
34
+ def update!
35
+ @model.columns.each do |column|
36
+ if row = @attrs.find {|x| x[:name] == column.name}
37
+ if row[:type] != type_str(column)
38
+ puts " M #{@model}##{column.name} [#{row[:type]} -> #{type_str(column)}]"
39
+ row[:type] = type_str(column)
40
+ end
41
+ else
42
+ puts " A #{@model}##{column.name} [#{type_str(column)}]"
43
+ @attrs << {
44
+ :name => column.name,
45
+ :type => type_str(column),
46
+ :desc => InitialDescription.for(@model, column.name)
47
+ }
48
+ end
49
+ end
50
+
51
+ # find columns that no more exist in db
52
+ orphans = @attrs.map{|x| x[:name]} - @model.columns.map(&:name)
53
+ unless orphans.empty?
54
+ orphans.each do |orphan|
55
+ puts " D #{@model}#{orphan}"
56
+ @attrs = @attrs.select {|x| x[0] != orphan}
57
+ end
58
+ end
59
+
60
+ @attrs
61
+ end
62
+
63
+ protected
64
+
65
+ # Convert attributes lines into meaniningful array
66
+ def parse
67
+ @lines.each do |line|
68
+ if m = line.match(R_ATTRIBUTE)
69
+ @attrs << {:name => m[1].strip, :type => m[2].strip, :desc => m[4].strip}
70
+ elsif m = line.match(R_ATTRIBUTE_NEXT_LINE)
71
+ @attrs[-1][:desc] += " #{m[1].strip}"
72
+ end
73
+ end
74
+ end
75
+
76
+ # Human readable description of given column type
77
+ def type_str(c)
78
+ ret = c.type.to_s
79
+ ret << ", primary" if c.primary
80
+ ret << ", default=#{c.default}" if c.default
81
+ ret << ", not null" unless c.null
82
+ ret << ", limit=#{c.limit}" if c.limit && (c.limit != 255 && c.type != :string)
83
+ ret
84
+ end
85
+
86
+ # Wraps text nicely, not breaking in the middle of the word
87
+ def wrap_text(txt, col)
88
+ txt.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/,"\\1\\3\n")
89
+ end
90
+
91
+ end
92
+ end
@@ -0,0 +1,23 @@
1
+ require 'annotator/initial_description/base'
2
+ Dir[File.dirname(__FILE__) + '/initial_description/*.rb'].each {|file| require file }
3
+
4
+ module Annotator
5
+ module InitialDescription
6
+
7
+ NO_DESCRIPTION_COLUMNS = %w{email name title body}
8
+
9
+ # Get initial description for given model & column
10
+ def self.for(model, column)
11
+ # Check if any module provides such description
12
+ Base.providers.each do |klass|
13
+ provider = klass.new model, column
14
+ return provider.text if provider.check
15
+ end
16
+ # Some columns are just too obvious
17
+ return "" if NO_DESCRIPTION_COLUMNS.include? column
18
+ # Let user do the work
19
+ return "TODO: document me"
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ module Annotator
2
+ module InitialDescription
3
+
4
+ # Base class from which all other description providers inherit
5
+ class Base
6
+ def initialize(model, column)
7
+ @model = model
8
+ @column = column
9
+ end
10
+
11
+ def self.inherited(klass)
12
+ @providers ||= []
13
+ @providers << klass
14
+ end
15
+
16
+ def self.providers
17
+ @providers
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ module Annotator
2
+ module InitialDescription
3
+
4
+ # Initial descriptions for columns associated with belongs_to
5
+ class BelongsTo < Base
6
+
7
+ def check
8
+ # check if there is belongs to association where this column is a foreign key
9
+ @model.reflect_on_all_associations.each do |reflection|
10
+ if reflection.foreign_key == @column && reflection.macro == :belongs_to
11
+ @reflection = reflection
12
+ return true
13
+ end
14
+ end
15
+
16
+ # Polymorphic association type column
17
+ if @column.ends_with? '_type'
18
+ return true if @reflection = @model.reflect_on_association(@column.match(/(.*?)_type$/)[1].to_sym)
19
+ end
20
+
21
+ return false
22
+ end
23
+
24
+ def text
25
+ "belongs to :#{@reflection.name}#{@reflection.options[:polymorphic] ? ' (polymorphic)' : ''}"
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,39 @@
1
+ module Annotator
2
+ module InitialDescription
3
+
4
+ # Initila descriptions for devise specific columns
5
+ class Devise < Base
6
+
7
+ def check
8
+ @model.respond_to?(:devise_modules) && columns.keys.include?(@column.to_sym)
9
+ end
10
+
11
+ def columns
12
+ {
13
+ :reset_password_token => "Devise Recoverable module",
14
+ :reset_password_sent_at => "Devise Recoverable module",
15
+ :remember_created_at => "Devise Rememberable module",
16
+ :sign_in_count => "Devise Trackable module",
17
+ :current_sign_in_at => "Devise Trackable module",
18
+ :last_sign_in_at => "Devise Trackable module",
19
+ :current_sign_in_ip => "Devise Trackable module",
20
+ :last_sign_in_ip => "Devise Trackable module",
21
+ :password_salt => "Devise Encriptable module",
22
+ :confirmation_token => "Devise Confirmable module",
23
+ :confirmed_at => "Devise Confirmable module",
24
+ :confiramtion_sent_at => "Devise Confirmable module",
25
+ :unconfirmed_email => "Devise Confirmable module",
26
+ :failed_attempts => "Devise Lockable module",
27
+ :unlock_token => "Devise Locakble module",
28
+ :locked_at => "Devise Lockable module",
29
+ :authentication_token => "Devise Token authenticable module"
30
+ }
31
+ end
32
+
33
+ def text
34
+ columns[@column.to_sym]
35
+ end
36
+
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,26 @@
1
+ module Annotator
2
+ module InitialDescription
3
+
4
+ # Initial descriptinos for paperclip attachments columns
5
+ class Paperclip < Base
6
+
7
+ def check
8
+ if @model.respond_to? :attachments_definitions
9
+ @model.attachments_definitions.keys.each do |att|
10
+ cols = ["#{att}_file_name", "#{att}_content_type", "#{att}_file_size", "#{att}_updated_at"]
11
+ if cols.include? @column
12
+ @attachment = att
13
+ return true
14
+ end
15
+ end
16
+ end
17
+ return false
18
+ end
19
+
20
+ def text
21
+ "Paperclip for #{@attachment}"
22
+ end
23
+
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Annotator
2
+ module InitialDescription
3
+
4
+ # Initial descriptions for rails specific columns
5
+ class Rails < Base
6
+ def check
7
+ columns.keys.include? @column.to_sym
8
+ end
9
+
10
+ def columns
11
+ {
12
+ :id => "primary key", # TODO check if it actually is a primary key, find primary keys with other names
13
+ :created_at => "creation time",
14
+ :updated_at => "last update time"
15
+ }
16
+ end
17
+
18
+ def text
19
+ columns[@column.to_sym]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,57 @@
1
+ module Annotator
2
+
3
+ # Represents a single model file and associated class
4
+ class Model
5
+
6
+ def initialize(filename)
7
+ @filename = filename
8
+ @blocks = Hash.new {[]}
9
+ end
10
+
11
+ # Model class
12
+ def klass
13
+ @filename.split('app/models/').last.split(/\.rb$/).first.camelize.constantize rescue nil
14
+ end
15
+
16
+ # Split file into 3 blocks: before attributes, attributes block, and after
17
+ # If there's no attributes block, content will be in :after part (for easier insertion)
18
+ def parse
19
+ @file = File.read(@filename).strip
20
+ current_block = :before
21
+ return @nodoc = true if @file.match(/^# Attributes\(nodoc\):$/i)
22
+ @file.split("\n").each do |line|
23
+ if line.match(/^#{Regexp.escape Attributes::HEADER} *$/)
24
+ current_block = :attributes
25
+ next
26
+ end
27
+ current_block = :after if current_block == :attributes && !line.match(Attributes::R_ATTRIBUTE_LINE)
28
+ @blocks[current_block] += [line]
29
+ end
30
+
31
+ @blocks[:after], @blocks[:before] = @blocks[:before], [] if @blocks[:after].empty?
32
+ end
33
+
34
+ # If this file does not have associated AR class it should be skipped
35
+ def skipped?
36
+ !klass || !klass.ancestors.include?(ActiveRecord::Base) || @nodoc
37
+ end
38
+
39
+ # Save changes to file if there were any
40
+ def update_file
41
+ output = (@blocks[:before] + @blocks[:attributes] + @blocks[:after]).join("\n").strip + "\n"
42
+ File.open(@filename,'w') { |f| f.write(output) } if output != @file
43
+ end
44
+
45
+ # Update file with new database information
46
+ def update!
47
+ parse
48
+ return true if skipped?
49
+ attributes = Attributes.new klass, @blocks[:attributes]
50
+ attributes.update!
51
+ @blocks[:attributes] = attributes.lines
52
+ update_file
53
+ end
54
+ end
55
+ end
56
+
57
+
@@ -1,3 +1,3 @@
1
1
  module Annotator
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -3,7 +3,7 @@ require 'tempfile'
3
3
 
4
4
  class AnnotatorTest < ActiveSupport::TestCase
5
5
  def setup
6
- @output = execute("cd #{$test_app} && rake annotate")
6
+ @output = execute("rake annotate")
7
7
  end
8
8
 
9
9
  test "annotating foo" do
@@ -12,13 +12,13 @@ class AnnotatorTest < ActiveSupport::TestCase
12
12
 
13
13
  test "leaving existing comments" do
14
14
  FileUtils.cp asset_file('foo_annotated_with_comments.rb'), app_file('foo.rb')
15
- assert system("cd #{$test_app} && rake annotate")
15
+ execute "rake annotate"
16
16
  assert_equal File.read(asset_file 'foo_annotated_with_comments.rb' ), File.read(app_file 'foo.rb' )
17
17
  end
18
18
 
19
19
  test "updating column type" do
20
20
  FileUtils.cp asset_file('foo_annotated_bad_column.rb'), app_file('foo.rb')
21
- output = execute("cd #{$test_app} && rake annotate")
21
+ output = execute "rake annotate"
22
22
  assert_equal File.read(asset_file 'foo_annotated_column_fixed.rb' ), File.read(app_file 'foo.rb' )
23
23
  assert output.include?('M Foo#title [octopus -> string]')
24
24
  assert output.include?('M Foo#created_at [foobar -> datetime, not null]')
@@ -26,34 +26,44 @@ class AnnotatorTest < ActiveSupport::TestCase
26
26
 
27
27
  test "skipping when nodoc is preesnt" do
28
28
  FileUtils.cp asset_file('foo_annotated_bad_column_nodoc.rb'), app_file('foo.rb')
29
- execute("cd #{$test_app} && rake annotate")
29
+ execute "rake annotate"
30
30
  assert_equal File.read(asset_file 'foo_annotated_bad_column_nodoc.rb' ), File.read(app_file 'foo.rb' )
31
31
  end
32
32
 
33
33
  test "annotating devise columns" do
34
34
  assert_equal File.read(asset_file 'user_annotated.rb' ), File.read(app_file 'user.rb' )
35
- end
35
+ end
36
36
 
37
37
  test "annotating paperclip columns" do
38
38
  assert_equal File.read(asset_file 'paper_annotated.rb' ), File.read(app_file 'paper.rb' )
39
39
  end
40
40
 
41
- test "annotating belongs_to associations" do
41
+ test "annotating belongs_to and polymorphic associations" do
42
42
  assert_equal File.read(asset_file 'boo_annotated.rb' ), File.read(app_file 'boo.rb' )
43
43
  end
44
44
 
45
+ test "handling some code before annotitions block" do
46
+ FileUtils.cp asset_file('foo_require_first.rb'), app_file('foo.rb')
47
+ execute "rake annotate"
48
+ assert_equal File.read(asset_file 'foo_require_first.rb' ), File.read(app_file 'foo.rb' )
49
+ end
50
+
51
+ test "annotating namespaced models" do
52
+ assert_equal File.read(asset_file 'moo_hoo_annotated.rb' ), File.read(app_file 'moo/hoo.rb' )
53
+ end
54
+
45
55
  def asset_file(name)
46
56
  File.join(File.expand_path("../assets/", __FILE__), name)
47
57
  end
48
58
 
49
59
  def app_file(name)
50
- File.join($test_app,'app','models',name)
60
+ File.join(TestApp.path,'app','models',name)
51
61
  end
52
62
 
53
63
  # Check exit code while grabbing output
54
64
  def execute(command)
55
65
  tmp = Tempfile.new "output"
56
- assert system("#{command} > #{tmp.path}")
66
+ assert system("cd #{TestApp.path} && #{command} > #{tmp.path}")
57
67
  output = tmp.read
58
68
  tmp.unlink
59
69
  output
@@ -1,8 +1,11 @@
1
1
  # Attributes:
2
2
  # * id [integer, primary, not null] - primary key
3
3
  # * created_at [datetime, not null] - creation time
4
- # * foo_id [integer] - belongs to Foo
4
+ # * foo_id [integer] - belongs to :foo
5
+ # * poly_id [integer] - belongs to :poly (polymorphic)
6
+ # * poly_type [string] - belongs to :poly (polymorphic)
5
7
  # * updated_at [datetime, not null] - last update time
6
8
  class Boo < ActiveRecord::Base
7
9
  belongs_to :foo
10
+ belongs_to :poly, :polymorphic => true
8
11
  end
@@ -0,0 +1,11 @@
1
+ require 'pp'
2
+
3
+ # Attributes:
4
+ # * id [integer, primary, not null] - primary key
5
+ # * body [text]
6
+ # * created_at [datetime, not null] - creation time
7
+ # * random_number [integer] - TODO: document me
8
+ # * title [string]
9
+ # * updated_at [datetime, not null] - last update time
10
+ class Foo < ActiveRecord::Base
11
+ end
@@ -0,0 +1,13 @@
1
+ # Attributes:
2
+ # * id [integer, primary, not null] - primary key
3
+ # * body [text]
4
+ # * created_at [datetime, not null] - creation time
5
+ # * random_number [integer] - TODO: document me
6
+ # * title [string]
7
+ # * updated_at [datetime, not null] - last update time
8
+ # Some existing stupid comment
9
+ module Moo
10
+ class Hoo < ActiveRecord::Base
11
+ self.table_name = 'foos'
12
+ end
13
+ end
@@ -1,3 +1,4 @@
1
1
  class Boo < ActiveRecord::Base
2
2
  belongs_to :foo
3
+ belongs_to :poly, :polymorphic => true
3
4
  end
@@ -0,0 +1,6 @@
1
+ # Some existing stupid comment
2
+ module Moo
3
+ class Hoo < ActiveRecord::Base
4
+ self.table_name = 'foos'
5
+ end
6
+ end
Binary file
@@ -2,6 +2,8 @@ class CreateBoos < ActiveRecord::Migration
2
2
  def change
3
3
  create_table :boos do |t|
4
4
  t.references :foo
5
+ t.integer :poly_id
6
+ t.string :poly_type
5
7
  t.timestamps
6
8
  end
7
9
  end
@@ -11,7 +11,15 @@
11
11
  #
12
12
  # It's strongly recommended to check this file into your version control system.
13
13
 
14
- ActiveRecord::Schema.define(:version => 20120527020350) do
14
+ ActiveRecord::Schema.define(:version => 20120527025142) do
15
+
16
+ create_table "boos", :force => true do |t|
17
+ t.integer "foo_id"
18
+ t.integer "poly_id"
19
+ t.string "poly_type"
20
+ t.datetime "created_at", :null => false
21
+ t.datetime "updated_at", :null => false
22
+ end
15
23
 
16
24
  create_table "foos", :force => true do |t|
17
25
  t.text "body"
@@ -21,6 +29,15 @@ ActiveRecord::Schema.define(:version => 20120527020350) do
21
29
  t.datetime "updated_at", :null => false
22
30
  end
23
31
 
32
+ create_table "papers", :force => true do |t|
33
+ t.datetime "created_at", :null => false
34
+ t.datetime "updated_at", :null => false
35
+ t.string "avatar_file_name"
36
+ t.string "avatar_content_type"
37
+ t.integer "avatar_file_size"
38
+ t.datetime "avatar_updated_at"
39
+ end
40
+
24
41
  create_table "users", :force => true do |t|
25
42
  t.string "email", :default => "", :null => false
26
43
  t.string "encrypted_password", :default => "", :null => false
@@ -71,3 +71,100 @@ Migrating to DeviseCreateUsers (20120527020350)
71
71
   (0.0ms) PRAGMA index_info('index_users_on_confirmation_token')
72
72
   (0.0ms) PRAGMA index_info('index_users_on_reset_password_token')
73
73
   (0.0ms) PRAGMA index_info('index_users_on_email')
74
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" 
75
+ Migrating to CreateFoos (20120219112425)
76
+ Migrating to DeviseCreateUsers (20120527020350)
77
+ Migrating to CreatePapers (20120527023350)
78
+  (0.0ms) select sqlite_version(*)
79
+  (0.0ms) begin transaction
80
+  (0.2ms) CREATE TABLE "papers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)
81
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527023350')
82
+  (5.4ms) commit transaction
83
+ Migrating to AddAttachmentAvatarToPapers (20120527023417)
84
+  (0.0ms) begin transaction
85
+  (0.3ms) ALTER TABLE "papers" ADD "avatar_file_name" varchar(255)
86
+  (0.2ms) ALTER TABLE "papers" ADD "avatar_content_type" varchar(255)
87
+  (0.2ms) ALTER TABLE "papers" ADD "avatar_file_size" integer
88
+  (0.2ms) ALTER TABLE "papers" ADD "avatar_updated_at" datetime
89
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527023417')
90
+  (3.8ms) commit transaction
91
+ Migrating to CreateBoos (20120527025142)
92
+  (0.0ms) begin transaction
93
+  (0.4ms) CREATE TABLE "boos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "foo_id" integer, "poly_id" integer, "poly_type" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL) 
94
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527025142')
95
+  (4.0ms) commit transaction
96
+  (0.4ms) select sqlite_version(*)
97
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" 
98
+  (0.0ms) PRAGMA index_list("boos")
99
+  (0.0ms) PRAGMA index_list("foos")
100
+  (0.0ms) PRAGMA index_list("papers")
101
+  (0.1ms) PRAGMA index_list("users")
102
+  (0.1ms) PRAGMA index_info('index_users_on_authentication_token')
103
+  (0.1ms) PRAGMA index_info('index_users_on_unlock_token')
104
+  (0.0ms) PRAGMA index_info('index_users_on_confirmation_token')
105
+  (0.1ms) PRAGMA index_info('index_users_on_reset_password_token')
106
+  (0.0ms) PRAGMA index_info('index_users_on_email')
107
+  (0.1ms) select sqlite_version(*)
108
+  (14.9ms) CREATE TABLE "schema_migrations" ("version" varchar(255) NOT NULL)
109
+  (0.0ms) PRAGMA index_list("schema_migrations")
110
+  (4.1ms) CREATE UNIQUE INDEX "unique_schema_migrations" ON "schema_migrations" ("version")
111
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" 
112
+ Migrating to CreateFoos (20120219112425)
113
+  (0.0ms) begin transaction
114
+  (0.4ms) CREATE TABLE "foos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "body" text, "title" varchar(255), "random_number" integer, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL) 
115
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120219112425')
116
+  (7.1ms) commit transaction
117
+ Migrating to DeviseCreateUsers (20120527020350)
118
+  (0.0ms) begin transaction
119
+  (0.4ms) CREATE TABLE "users" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar(255) DEFAULT '' NOT NULL, "encrypted_password" varchar(255) DEFAULT '' NOT NULL, "reset_password_token" varchar(255), "reset_password_sent_at" datetime, "remember_created_at" datetime, "sign_in_count" integer DEFAULT 0, "current_sign_in_at" datetime, "last_sign_in_at" datetime, "current_sign_in_ip" varchar(255), "last_sign_in_ip" varchar(255), "password_salt" varchar(255), "confirmation_token" varchar(255), "confirmed_at" datetime, "confirmation_sent_at" datetime, "unconfirmed_email" varchar(255), "failed_attempts" integer DEFAULT 0, "unlock_token" varchar(255), "locked_at" datetime, "authentication_token" varchar(255), "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL) 
120
+  (0.0ms) PRAGMA index_list("users")
121
+  (0.3ms) CREATE UNIQUE INDEX "index_users_on_email" ON "users" ("email")
122
+  (0.1ms) PRAGMA index_list("users")
123
+  (0.0ms) PRAGMA index_info('index_users_on_email')
124
+  (0.2ms) CREATE UNIQUE INDEX "index_users_on_reset_password_token" ON "users" ("reset_password_token")
125
+  (0.1ms) PRAGMA index_list("users")
126
+  (0.1ms) PRAGMA index_info('index_users_on_reset_password_token')
127
+  (0.0ms) PRAGMA index_info('index_users_on_email')
128
+  (0.2ms) CREATE UNIQUE INDEX "index_users_on_confirmation_token" ON "users" ("confirmation_token")
129
+  (0.1ms) PRAGMA index_list("users")
130
+  (0.1ms) PRAGMA index_info('index_users_on_confirmation_token')
131
+  (0.0ms) PRAGMA index_info('index_users_on_reset_password_token')
132
+  (0.0ms) PRAGMA index_info('index_users_on_email')
133
+  (0.2ms) CREATE UNIQUE INDEX "index_users_on_unlock_token" ON "users" ("unlock_token")
134
+  (0.1ms) PRAGMA index_list("users")
135
+  (0.1ms) PRAGMA index_info('index_users_on_unlock_token')
136
+  (0.0ms) PRAGMA index_info('index_users_on_confirmation_token')
137
+  (0.0ms) PRAGMA index_info('index_users_on_reset_password_token')
138
+  (0.0ms) PRAGMA index_info('index_users_on_email')
139
+  (0.2ms) CREATE UNIQUE INDEX "index_users_on_authentication_token" ON "users" ("authentication_token")
140
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527020350')
141
+  (3.8ms) commit transaction
142
+ Migrating to CreatePapers (20120527023350)
143
+  (0.0ms) begin transaction
144
+  (0.2ms) CREATE TABLE "papers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL) 
145
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527023350')
146
+  (3.8ms) commit transaction
147
+ Migrating to AddAttachmentAvatarToPapers (20120527023417)
148
+  (0.0ms) begin transaction
149
+  (0.3ms) ALTER TABLE "papers" ADD "avatar_file_name" varchar(255)
150
+  (0.1ms) ALTER TABLE "papers" ADD "avatar_content_type" varchar(255)
151
+  (0.2ms) ALTER TABLE "papers" ADD "avatar_file_size" integer
152
+  (0.2ms) ALTER TABLE "papers" ADD "avatar_updated_at" datetime
153
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527023417')
154
+  (3.2ms) commit transaction
155
+ Migrating to CreateBoos (20120527025142)
156
+  (0.0ms) begin transaction
157
+  (0.3ms) CREATE TABLE "boos" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "foo_id" integer, "poly_id" integer, "poly_type" varchar(255), "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)
158
+  (0.1ms) INSERT INTO "schema_migrations" ("version") VALUES ('20120527025142')
159
+  (3.7ms) commit transaction
160
+  (0.4ms) select sqlite_version(*)
161
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations"
162
+  (0.0ms) PRAGMA index_list("boos")
163
+  (0.0ms) PRAGMA index_list("foos")
164
+  (0.0ms) PRAGMA index_list("papers")
165
+  (0.0ms) PRAGMA index_list("users")
166
+  (0.0ms) PRAGMA index_info('index_users_on_authentication_token')
167
+  (0.0ms) PRAGMA index_info('index_users_on_unlock_token')
168
+  (0.0ms) PRAGMA index_info('index_users_on_confirmation_token')
169
+  (0.0ms) PRAGMA index_info('index_users_on_reset_password_token')
170
+  (0.0ms) PRAGMA index_info('index_users_on_email')
@@ -0,0 +1,19 @@
1
+ module TestApp
2
+
3
+ # No mattr_accessor before initialization ;(
4
+ def self.path=(new_path)
5
+ @path = new_path
6
+ end
7
+
8
+ def self.path
9
+ @path
10
+ end
11
+
12
+ def self.prepare!
13
+ self.path = File.expand_path("../../../tmp/dummy", __FILE__)
14
+ FileUtils.rm_rf path
15
+ FileUtils.mkdir_p path
16
+ FileUtils.cp_r File.expand_path("../../dummy//", __FILE__), File.expand_path(path+"/../")
17
+ system("cd #{path} && bundle exec rake db:migrate > /dev/null")
18
+ end
19
+ end
data/test/test_helper.rb CHANGED
@@ -3,17 +3,13 @@ require 'fileutils'
3
3
  # Configure Rails Environment
4
4
  ENV["RAILS_ENV"] = "test"
5
5
 
6
- $test_app = test_app_dir = File.expand_path("../../tmp/dummy", __FILE__)
7
- FileUtils.rm_rf test_app_dir
8
- FileUtils.mkdir_p test_app_dir
9
- FileUtils.cp_r File.expand_path("../dummy//", __FILE__), File.expand_path(test_app_dir+"/../")
10
- system("cd #{$test_app} && bundle exec rake db:migrate > /dev/null")
11
-
6
+ # Load support files
7
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
8
+
9
+ TestApp.prepare!
12
10
 
13
- require File.expand_path("#{test_app_dir}/config/environment.rb", __FILE__)
11
+ require File.expand_path("#{TestApp.path}/config/environment.rb", __FILE__)
14
12
  require "rails/test_help"
15
13
 
16
14
  Rails.backtrace_cleaner.remove_silencers!
17
15
 
18
- # Load support files
19
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: annotator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-05-27 00:00:00.000000000 Z
13
+ date: 2012-06-05 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -53,11 +53,20 @@ extra_rdoc_files: []
53
53
  files:
54
54
  - lib/tasks/annotator_tasks.rake
55
55
  - lib/annotator.rb
56
+ - lib/annotator/initial_description/belongs_to.rb
57
+ - lib/annotator/initial_description/devise.rb
58
+ - lib/annotator/initial_description/paperclip.rb
59
+ - lib/annotator/initial_description/base.rb
60
+ - lib/annotator/initial_description/rails.rb
61
+ - lib/annotator/model.rb
56
62
  - lib/annotator/version.rb
63
+ - lib/annotator/attributes.rb
64
+ - lib/annotator/initial_description.rb
57
65
  - lib/annotator/railtie.rb
58
66
  - MIT-LICENSE
59
67
  - Rakefile
60
68
  - README.rdoc
69
+ - test/support/test_app.rb
61
70
  - test/test_helper.rb
62
71
  - test/assets/paper_annotated.rb
63
72
  - test/assets/foo_annotated_bad_column.rb
@@ -67,6 +76,8 @@ files:
67
76
  - test/assets/boo_annotated.rb
68
77
  - test/assets/foo_annotated.rb
69
78
  - test/assets/foo_annotated_column_fixed.rb
79
+ - test/assets/foo_require_first.rb
80
+ - test/assets/moo_hoo_annotated.rb
70
81
  - test/annotator_test.rb
71
82
  - test/dummy/public/500.html
72
83
  - test/dummy/public/favicon.ico
@@ -93,6 +104,7 @@ files:
93
104
  - test/dummy/app/helpers/application_helper.rb
94
105
  - test/dummy/app/models/boo.rb
95
106
  - test/dummy/app/models/paper.rb
107
+ - test/dummy/app/models/moo/hoo.rb
96
108
  - test/dummy/app/models/user.rb
97
109
  - test/dummy/app/models/foo.rb
98
110
  - test/dummy/app/models/nomodel.rb
@@ -138,11 +150,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
150
  version: '0'
139
151
  requirements: []
140
152
  rubyforge_project:
141
- rubygems_version: 1.8.24
153
+ rubygems_version: 1.8.23
142
154
  signing_key:
143
155
  specification_version: 3
144
156
  summary: Annotate your models and keep your comments about fields.
145
157
  test_files:
158
+ - test/support/test_app.rb
146
159
  - test/test_helper.rb
147
160
  - test/assets/paper_annotated.rb
148
161
  - test/assets/foo_annotated_bad_column.rb
@@ -152,6 +165,8 @@ test_files:
152
165
  - test/assets/boo_annotated.rb
153
166
  - test/assets/foo_annotated.rb
154
167
  - test/assets/foo_annotated_column_fixed.rb
168
+ - test/assets/foo_require_first.rb
169
+ - test/assets/moo_hoo_annotated.rb
155
170
  - test/annotator_test.rb
156
171
  - test/dummy/public/500.html
157
172
  - test/dummy/public/favicon.ico
@@ -178,6 +193,7 @@ test_files:
178
193
  - test/dummy/app/helpers/application_helper.rb
179
194
  - test/dummy/app/models/boo.rb
180
195
  - test/dummy/app/models/paper.rb
196
+ - test/dummy/app/models/moo/hoo.rb
181
197
  - test/dummy/app/models/user.rb
182
198
  - test/dummy/app/models/foo.rb
183
199
  - test/dummy/app/models/nomodel.rb