rails-erd 0.4.5 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.rdoc +18 -0
- data/LICENSE +1 -1
- data/README.md +3 -3
- data/Rakefile +57 -46
- data/bin/erd +4 -0
- data/lib/rails_erd.rb +4 -2
- data/lib/rails_erd/cli.rb +149 -0
- data/lib/rails_erd/diagram.rb +18 -16
- data/lib/rails_erd/diagram/graphviz.rb +23 -2
- data/lib/rails_erd/domain/attribute.rb +9 -3
- data/lib/rails_erd/domain/entity.rb +15 -15
- data/lib/rails_erd/domain/relationship.rb +11 -1
- data/lib/rails_erd/domain/relationship/cardinality.rb +15 -15
- data/lib/rails_erd/domain/specialization.rb +8 -8
- data/lib/rails_erd/version.rb +4 -0
- data/test/test_helper.rb +14 -11
- data/test/unit/attribute_test.rb +66 -3
- data/test/unit/cardinality_test.rb +10 -10
- data/test/unit/diagram_test.rb +44 -18
- data/test/unit/domain_test.rb +20 -20
- data/test/unit/entity_test.rb +19 -19
- data/test/unit/graphviz_test.rb +53 -10
- data/test/unit/rake_task_test.rb +8 -8
- data/test/unit/relationship_test.rb +31 -31
- data/test/unit/specialization_test.rb +3 -3
- metadata +72 -108
- data/.gemtest +0 -0
- data/Gemfile +0 -19
- data/Gemfile.lock +0 -44
- data/VERSION +0 -1
- data/rails-erd.gemspec +0 -105
data/CHANGES.rdoc
CHANGED
@@ -1,3 +1,21 @@
|
|
1
|
+
=== 1.0.0:
|
2
|
+
|
3
|
+
* The internal API is now stable and will be backwards compatible until
|
4
|
+
the next major version.
|
5
|
+
* Added experimental command line interface (erd). The CLI still requires a
|
6
|
+
Rails application to be present, but it may one day support other kinds of
|
7
|
+
applications.
|
8
|
+
* Crow's foot notation (also known as the Information Engineering notation)
|
9
|
+
can be used by adding 'notation=crowsfoot' to the 'rake erd' command
|
10
|
+
(contributed by Jeremy Holland).
|
11
|
+
* Filter models by using the only or exclude options (only=ModelOne,ModelTwo
|
12
|
+
or exclude=ModelThree,ModelFour) from the command line (contributed by
|
13
|
+
Milovan Zogovic).
|
14
|
+
* Process column types that are unsupported by Rails (contributed by Erik
|
15
|
+
Gustavson).
|
16
|
+
* Ignore custom limit/scale attributes that cannot be converted to an integer
|
17
|
+
(reported by Adam St. John).
|
18
|
+
|
1
19
|
=== 0.4.5:
|
2
20
|
|
3
21
|
* Display more helpful error message when the application models could not be
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -31,11 +31,11 @@ Getting started
|
|
31
31
|
See the [installation instructions](http://rails-erd.rubyforge.org/install.html)
|
32
32
|
for a complete description of how to install Rails ERD. Here's a summary:
|
33
33
|
|
34
|
-
* Install Graphviz 2.22+
|
34
|
+
* Install Graphviz 2.22+ ([how?](http://rails-erd.rubyforge.org/install.html))
|
35
35
|
|
36
36
|
* Add <tt>gem "rails-erd"</tt> to your application's Gemfile
|
37
37
|
|
38
|
-
* Run <tt>
|
38
|
+
* Run <tt>bundle exec erd</tt>
|
39
39
|
|
40
40
|
|
41
41
|
Learn more
|
@@ -51,7 +51,7 @@ About Rails ERD
|
|
51
51
|
|
52
52
|
Rails ERD was created by Rolf Timmermans (r.timmermans *at* voormedia.com)
|
53
53
|
|
54
|
-
Copyright 2010-
|
54
|
+
Copyright 2010-2012 Voormedia - [www.voormedia.com](http://www.voormedia.com/)
|
55
55
|
|
56
56
|
|
57
57
|
License
|
data/Rakefile
CHANGED
@@ -1,54 +1,65 @@
|
|
1
|
-
|
2
|
-
require "jeweler"
|
1
|
+
require "bundler"
|
3
2
|
require "rake/testtask"
|
4
3
|
|
5
|
-
|
6
|
-
spec.name = "rails-erd"
|
7
|
-
spec.rubyforge_project = "rails-erd"
|
8
|
-
spec.summary = "Entity-relationship diagram for your Rails models."
|
9
|
-
spec.description = "Automatically generate an entity-relationship diagram (ERD) for your Rails models."
|
10
|
-
|
11
|
-
spec.authors = ["Rolf Timmermans"]
|
12
|
-
spec.email = "r.timmermans@voormedia.com"
|
13
|
-
spec.homepage = "http://rails-erd.rubyforge.org/"
|
14
|
-
|
15
|
-
# Don't bundle examples or website in gem.
|
16
|
-
excluded = Dir["{examples,site}/**/*"]
|
17
|
-
spec.files -= excluded
|
18
|
-
spec.test_files -= excluded
|
19
|
-
end
|
20
|
-
|
21
|
-
Jeweler::GemcutterTasks.new
|
22
|
-
|
23
|
-
Jeweler::RubyforgeTasks.new do |rubyforge|
|
24
|
-
rubyforge.doc_task = "rdoc"
|
25
|
-
rubyforge.remote_doc_path = "doc"
|
26
|
-
end
|
4
|
+
Bundler::GemHelper.install_tasks
|
27
5
|
|
28
6
|
Rake::TestTask.new do |test|
|
29
|
-
test.
|
7
|
+
test.test_files = FileList["test/**/*_test.rb"]
|
30
8
|
end
|
31
9
|
|
32
10
|
task :default => :test
|
33
11
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
12
|
+
# # encoding: utf-8
|
13
|
+
# require "jeweler"
|
14
|
+
# require "rake/testtask"
|
15
|
+
#
|
16
|
+
# Jeweler::Tasks.new do |spec|
|
17
|
+
# spec.name = "rails-erd"
|
18
|
+
# spec.rubyforge_project = "rails-erd"
|
19
|
+
# spec.summary = "Entity-relationship diagram for your Rails models."
|
20
|
+
# spec.description = "Automatically generate an entity-relationship diagram (ERD) for your Rails models."
|
21
|
+
#
|
22
|
+
# spec.authors = ["Rolf Timmermans"]
|
23
|
+
# spec.email = "r.timmermans@voormedia.com"
|
24
|
+
# spec.homepage = "http://rails-erd.rubyforge.org/"
|
25
|
+
#
|
26
|
+
# # Don't bundle examples or website in gem.
|
27
|
+
# excluded = Dir["{examples,site}/**/*"]
|
28
|
+
# spec.files -= excluded
|
29
|
+
# spec.test_files -= excluded
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# Jeweler::GemcutterTasks.new
|
33
|
+
#
|
34
|
+
# Jeweler::RubyforgeTasks.new do |rubyforge|
|
35
|
+
# rubyforge.doc_task = "rdoc"
|
36
|
+
# rubyforge.remote_doc_path = "doc"
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# Rake::TestTask.new do |test|
|
40
|
+
# test.pattern = "test/unit/**/*_test.rb"
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# task :default => :test
|
44
|
+
#
|
45
|
+
# begin
|
46
|
+
# require "hanna/rdoctask"
|
47
|
+
# Rake::RDocTask.new do |rdoc|
|
48
|
+
# rdoc.rdoc_files = %w{CHANGES.rdoc LICENSE} + Dir["lib/**/*.rb"]
|
49
|
+
# rdoc.title = "Rails ERD – API Documentation"
|
50
|
+
# rdoc.rdoc_dir = "rdoc"
|
51
|
+
# rdoc.main = "RailsERD"
|
52
|
+
# end
|
53
|
+
# rescue LoadError
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# desc "Generate diagrams for bundled examples"
|
57
|
+
# task :examples do
|
58
|
+
# require File.expand_path("examples/generate", File.dirname(__FILE__))
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# namespace :examples do
|
62
|
+
# task :sfdp do
|
63
|
+
# require File.expand_path("examples/sfdp", File.dirname(__FILE__))
|
64
|
+
# end
|
65
|
+
# end
|
data/bin/erd
ADDED
data/lib/rails_erd.rb
CHANGED
@@ -50,7 +50,7 @@ module RailsERD
|
|
50
50
|
self.options = ActiveSupport::OrderedOptions[
|
51
51
|
:attributes, :content,
|
52
52
|
:disconnected, true,
|
53
|
-
:filename, "
|
53
|
+
:filename, "erd",
|
54
54
|
:filetype, :pdf,
|
55
55
|
:indirect, true,
|
56
56
|
:inheritance, false,
|
@@ -59,6 +59,8 @@ module RailsERD
|
|
59
59
|
:orientation, :horizontal,
|
60
60
|
:polymorphism, false,
|
61
61
|
:warn, true,
|
62
|
-
:title, true
|
62
|
+
:title, true,
|
63
|
+
:exclude, nil,
|
64
|
+
:only, nil
|
63
65
|
]
|
64
66
|
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
require "choice"
|
2
|
+
|
3
|
+
Choice.options do
|
4
|
+
separator ""
|
5
|
+
separator "Diagram options:"
|
6
|
+
|
7
|
+
option :title do
|
8
|
+
long "--title=TITLE"
|
9
|
+
desc "Replace default diagram title with a custom one."
|
10
|
+
end
|
11
|
+
|
12
|
+
option :notation do
|
13
|
+
long "--notation=STYLE"
|
14
|
+
desc "Diagram notation style, one of simple, bachman, uml or crowsfoot."
|
15
|
+
default "simple"
|
16
|
+
end
|
17
|
+
|
18
|
+
option :attributes do
|
19
|
+
long "--attributes=TYPE,..."
|
20
|
+
desc "Attribute groups to display: content, primary_keys, foreign_keys, timestamps and/or inheritance."
|
21
|
+
default "content"
|
22
|
+
end
|
23
|
+
|
24
|
+
option :orientation do
|
25
|
+
long "--orientation=ORIENTATION"
|
26
|
+
desc "Orientation of diagram, either horizontal (default) or vertical."
|
27
|
+
default "orientation"
|
28
|
+
end
|
29
|
+
|
30
|
+
option :inheritance do
|
31
|
+
long "--inheritance"
|
32
|
+
desc "Display (single table) inheritance relationships."
|
33
|
+
end
|
34
|
+
|
35
|
+
option :polymorphism do
|
36
|
+
long "--polymorphism"
|
37
|
+
desc "Display polymorphic relationships."
|
38
|
+
end
|
39
|
+
|
40
|
+
option :no_indirect do
|
41
|
+
long "--direct"
|
42
|
+
desc "Omit indirect relationships (through other entities)."
|
43
|
+
end
|
44
|
+
|
45
|
+
option :no_disconnected do
|
46
|
+
long "--connected"
|
47
|
+
desc "Omit entities without relationships."
|
48
|
+
end
|
49
|
+
|
50
|
+
separator ""
|
51
|
+
separator "Output options:"
|
52
|
+
|
53
|
+
option :filename do
|
54
|
+
long "--filename=FILENAME"
|
55
|
+
desc "Basename of the output diagram."
|
56
|
+
default "erd"
|
57
|
+
end
|
58
|
+
|
59
|
+
option :filetype do
|
60
|
+
long "--filetype=TYPE"
|
61
|
+
desc "Output file type. Available types depend on the diagram renderer."
|
62
|
+
default "pdf"
|
63
|
+
end
|
64
|
+
|
65
|
+
option :no_markup do
|
66
|
+
long "--no-markup"
|
67
|
+
desc "Disable markup for enhanced compatibility of .dot output with other applications."
|
68
|
+
end
|
69
|
+
|
70
|
+
option :open do
|
71
|
+
long "--open"
|
72
|
+
desc "Open the output file after it has been saved."
|
73
|
+
end
|
74
|
+
|
75
|
+
separator ""
|
76
|
+
separator "Common options:"
|
77
|
+
|
78
|
+
option :help do
|
79
|
+
long "--help"
|
80
|
+
desc "Display this help message."
|
81
|
+
end
|
82
|
+
|
83
|
+
option :debug do
|
84
|
+
long "--debug"
|
85
|
+
desc "Show stack traces when an error occurs."
|
86
|
+
end
|
87
|
+
|
88
|
+
option :version do
|
89
|
+
short "-v"
|
90
|
+
long "--version"
|
91
|
+
desc "Show version and quit."
|
92
|
+
action do
|
93
|
+
require "rails_erd/version"
|
94
|
+
$stderr.puts RailsERD::BANNER
|
95
|
+
exit
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module RailsERD
|
101
|
+
class CLI
|
102
|
+
attr_reader :path, :options
|
103
|
+
|
104
|
+
class << self
|
105
|
+
def start
|
106
|
+
path = Choice.rest.first || Dir.pwd
|
107
|
+
options = Choice.choices.each_with_object({}) do |(key, value), opts|
|
108
|
+
if key.start_with? "no_"
|
109
|
+
opts[key.gsub("no_", "").to_sym] = !value
|
110
|
+
elsif value.to_s.include? ","
|
111
|
+
opts[key.to_sym] = value.split(",").map(&:to_sym)
|
112
|
+
else
|
113
|
+
opts[key.to_sym] = value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
new(path, options).start
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def initialize(path, options)
|
121
|
+
@path, @options = path, options
|
122
|
+
require "rails_erd/diagram/graphviz"
|
123
|
+
end
|
124
|
+
|
125
|
+
def start
|
126
|
+
load_application
|
127
|
+
create_diagram
|
128
|
+
rescue Exception => e
|
129
|
+
$stderr.puts "Failed: #{e.class}: #{e.message}"
|
130
|
+
$stderr.puts e.backtrace.map { |t| " from #{t}" } if options[:debug]
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def load_application
|
136
|
+
$stderr.puts "Loading application in '#{File.basename(path)}'..."
|
137
|
+
# TODO: Add support for different kinds of environment.
|
138
|
+
require "#{path}/config/environment"
|
139
|
+
Rails.application.eager_load!
|
140
|
+
end
|
141
|
+
|
142
|
+
def create_diagram
|
143
|
+
$stderr.puts "Generating entity-relationship diagram for #{ActiveRecord::Base.descendants.length} models..."
|
144
|
+
file = RailsERD::Diagram::Graphviz.create(options)
|
145
|
+
$stderr.puts "Diagram saved to '#{file}'."
|
146
|
+
`open #{file}` if options[:open]
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
data/lib/rails_erd/diagram.rb
CHANGED
@@ -3,7 +3,7 @@ require "rails_erd/domain"
|
|
3
3
|
module RailsERD
|
4
4
|
# This class is an abstract class that will process a domain model and
|
5
5
|
# allows easy creation of diagrams. To implement a new diagram type, derive
|
6
|
-
# from this class and override +process_entity+, +process_relationship+,
|
6
|
+
# from this class and override +process_entity+, +process_relationship+,
|
7
7
|
# and (optionally) +save+.
|
8
8
|
#
|
9
9
|
# As an example, a diagram class that generates code that can be used with
|
@@ -73,13 +73,13 @@ module RailsERD
|
|
73
73
|
def create(options = {})
|
74
74
|
new(Domain.generate(options), options).create
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
protected
|
78
|
-
|
78
|
+
|
79
79
|
def setup(&block)
|
80
80
|
callbacks[:setup] = block
|
81
81
|
end
|
82
|
-
|
82
|
+
|
83
83
|
def each_entity(&block)
|
84
84
|
callbacks[:each_entity] = block
|
85
85
|
end
|
@@ -91,7 +91,7 @@ module RailsERD
|
|
91
91
|
def each_specialization(&block)
|
92
92
|
callbacks[:each_specialization] = block
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
def save(&block)
|
96
96
|
callbacks[:save] = block
|
97
97
|
end
|
@@ -105,7 +105,7 @@ module RailsERD
|
|
105
105
|
|
106
106
|
# The options that are used to create this diagram.
|
107
107
|
attr_reader :options
|
108
|
-
|
108
|
+
|
109
109
|
# The domain that this diagram represents.
|
110
110
|
attr_reader :domain
|
111
111
|
|
@@ -113,13 +113,13 @@ module RailsERD
|
|
113
113
|
def initialize(domain, options = {})
|
114
114
|
@domain, @options = domain, RailsERD.options.merge(options)
|
115
115
|
end
|
116
|
-
|
116
|
+
|
117
117
|
# Generates and saves the diagram, returning the result of +save+.
|
118
118
|
def create
|
119
119
|
generate
|
120
120
|
save
|
121
121
|
end
|
122
|
-
|
122
|
+
|
123
123
|
# Generates the diagram, but does not save the output. It is called
|
124
124
|
# internally by Diagram#create.
|
125
125
|
def generate
|
@@ -137,19 +137,21 @@ module RailsERD
|
|
137
137
|
instance_exec relationship, &callbacks[:each_relationship]
|
138
138
|
end
|
139
139
|
end
|
140
|
-
|
140
|
+
|
141
141
|
def save
|
142
142
|
instance_eval &callbacks[:save]
|
143
143
|
end
|
144
|
-
|
144
|
+
|
145
145
|
private
|
146
|
-
|
146
|
+
|
147
147
|
def callbacks
|
148
148
|
@callbacks ||= self.class.send(:callbacks)
|
149
149
|
end
|
150
|
-
|
150
|
+
|
151
151
|
def filtered_entities
|
152
152
|
@domain.entities.reject { |entity|
|
153
|
+
options.exclude && entity.model && [options.exclude].flatten.include?(entity.name.to_sym) or
|
154
|
+
options.only && entity.model && ![options.only].flatten.include?(entity.name.to_sym) or
|
153
155
|
!options.inheritance && entity.specialized? or
|
154
156
|
!options.polymorphism && entity.generalized? or
|
155
157
|
!options.disconnected && entity.disconnected?
|
@@ -157,20 +159,20 @@ module RailsERD
|
|
157
159
|
raise "No entities found; create your models first!" if entities.empty?
|
158
160
|
end
|
159
161
|
end
|
160
|
-
|
162
|
+
|
161
163
|
def filtered_relationships
|
162
164
|
@domain.relationships.reject { |relationship|
|
163
165
|
!options.indirect && relationship.indirect?
|
164
166
|
}
|
165
167
|
end
|
166
|
-
|
168
|
+
|
167
169
|
def filtered_specializations
|
168
170
|
@domain.specializations.reject { |specialization|
|
169
171
|
!options.inheritance && specialization.inheritance? or
|
170
172
|
!options.polymorphism && specialization.polymorphic?
|
171
173
|
}
|
172
174
|
end
|
173
|
-
|
175
|
+
|
174
176
|
def filtered_attributes(entity)
|
175
177
|
entity.attributes.reject { |attribute|
|
176
178
|
# Select attributes that satisfy the conditions in the :attributes option.
|
@@ -178,7 +180,7 @@ module RailsERD
|
|
178
180
|
[*options.attributes].none? { |type| attribute.send(:"#{type.to_s.chomp('s')}?") }
|
179
181
|
}
|
180
182
|
end
|
181
|
-
|
183
|
+
|
182
184
|
def warn(message)
|
183
185
|
puts "Warning: #{message}" if options.warn
|
184
186
|
end
|