rails-erd 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGES.rdoc +17 -1
- data/Gemfile +3 -2
- data/Gemfile.lock +8 -4
- data/README.md +60 -0
- data/Rakefile +10 -50
- data/VERSION +1 -1
- data/lib/rails_erd.rb +28 -1
- data/lib/rails_erd/diagram.rb +66 -33
- data/lib/rails_erd/diagram/graphviz.rb +123 -92
- data/lib/rails_erd/diagram/templates/node.erb +2 -2
- data/lib/rails_erd/domain.rb +51 -23
- data/lib/rails_erd/domain/attribute.rb +102 -0
- data/lib/rails_erd/domain/entity.rb +102 -0
- data/lib/rails_erd/domain/relationship.rb +189 -0
- data/lib/rails_erd/domain/relationship/cardinality.rb +118 -0
- data/lib/rails_erd/domain/specialization.rb +58 -0
- data/lib/rails_erd/railtie.rb +1 -1
- data/rails-erd.gemspec +19 -16
- data/test/test_helper.rb +21 -5
- data/test/unit/attribute_test.rb +35 -8
- data/test/unit/cardinality_test.rb +41 -35
- data/test/unit/diagram_test.rb +130 -43
- data/test/unit/domain_test.rb +131 -8
- data/test/unit/entity_test.rb +150 -46
- data/test/unit/graphviz_test.rb +52 -14
- data/test/unit/rake_task_test.rb +2 -2
- data/test/unit/relationship_test.rb +73 -24
- data/test/unit/specialization_test.rb +57 -0
- metadata +15 -13
- data/README.rdoc +0 -51
- data/lib/rails_erd/attribute.rb +0 -95
- data/lib/rails_erd/entity.rb +0 -73
- data/lib/rails_erd/relationship.rb +0 -177
- data/lib/rails_erd/relationship/cardinality.rb +0 -118
data/.gitignore
CHANGED
data/CHANGES.rdoc
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
=== 0.4.0:
|
2
|
+
|
3
|
+
* Support to optionally display single table inheritance relationships
|
4
|
+
(inheritance=true).
|
5
|
+
* Support to optionally display polymorphic associations (polymorphism=true).
|
6
|
+
* Adjustments to 'advanced' style so that it matches original Bachman style,
|
7
|
+
and therefore now called 'bachman'.
|
8
|
+
* Ignore models without tables (reported by Mark Chapman).
|
9
|
+
* Mutual indirect relationships are now combined.
|
10
|
+
* Changed API for diagram generation.
|
11
|
+
* Restructured classes and renamed several API properties and methods.
|
12
|
+
* Added new edge type to describe single table inheritance and polymorphic
|
13
|
+
associations: Specialization.
|
14
|
+
* Added compatibility for Active Record 3.1 (beta), removed dependency on Arel.
|
15
|
+
* Rubinius compatibility.
|
16
|
+
|
1
17
|
=== 0.3.0:
|
2
18
|
|
3
19
|
* Added the ability to support multiple styles of cardinality notations.
|
@@ -10,7 +26,7 @@
|
|
10
26
|
* More versatile API that allows you to inspect relationships and their
|
11
27
|
cardinalities.
|
12
28
|
* Changed line widths to 1.0 to avoid invisible node boundaries with older
|
13
|
-
versions of Graphviz.
|
29
|
+
versions of Graphviz (reported by Mike McQuinn).
|
14
30
|
* Bundled examples based on actual applications.
|
15
31
|
|
16
32
|
=== 0.2.0
|
data/Gemfile
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
3
|
gem "rails-erd", :path => "."
|
4
|
-
gem "
|
5
|
-
gem "
|
4
|
+
gem "activerecord"
|
5
|
+
gem "activesupport"
|
6
6
|
gem "rake"
|
7
7
|
gem "jeweler"
|
8
8
|
|
@@ -13,4 +13,5 @@ end
|
|
13
13
|
platforms :jruby do
|
14
14
|
gem "jdbc-sqlite3", :require => "jdbc/sqlite3"
|
15
15
|
gem "activerecord-jdbc-adapter", "1.0.0.beta2"
|
16
|
+
gem "jruby-openssl", :require => false # Silence openssl warnings.
|
16
17
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rails-erd (0.
|
5
|
-
activerecord (~> 3.0
|
4
|
+
rails-erd (0.3.0)
|
5
|
+
activerecord (~> 3.0)
|
6
6
|
activesupport (~> 3.0)
|
7
|
-
ruby-graphviz (~> 0.9.
|
7
|
+
ruby-graphviz (~> 0.9.18)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
@@ -22,6 +22,7 @@ GEM
|
|
22
22
|
activesupport (3.0.0)
|
23
23
|
arel (1.0.1)
|
24
24
|
activesupport (~> 3.0.0)
|
25
|
+
bouncy-castle-java (1.5.0145.2)
|
25
26
|
builder (2.1.2)
|
26
27
|
gemcutter (0.6.1)
|
27
28
|
git (1.2.5)
|
@@ -31,9 +32,11 @@ GEM
|
|
31
32
|
gemcutter (>= 0.1.0)
|
32
33
|
git (>= 1.2.5)
|
33
34
|
rubyforge (>= 2.0.0)
|
35
|
+
jruby-openssl (0.7.1)
|
36
|
+
bouncy-castle-java
|
34
37
|
json_pure (1.4.6)
|
35
38
|
rake (0.8.7)
|
36
|
-
ruby-graphviz (0.9.
|
39
|
+
ruby-graphviz (0.9.18)
|
37
40
|
rubyforge (2.0.4)
|
38
41
|
json_pure (>= 1.1.7)
|
39
42
|
sqlite3-ruby (1.3.1)
|
@@ -49,6 +52,7 @@ DEPENDENCIES
|
|
49
52
|
activesupport
|
50
53
|
jdbc-sqlite3
|
51
54
|
jeweler
|
55
|
+
jruby-openssl
|
52
56
|
rails-erd!
|
53
57
|
rake
|
54
58
|
sqlite3-ruby
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
|
2
|
+
========================================================================
|
3
|
+
|
4
|
+
[Rails ERD](http://rails-erd.rubyforge.org/) is a Rails plugin that allows
|
5
|
+
you to easily generate a diagram based on your Active Record models. The
|
6
|
+
diagram gives an overview of how your models are related. Having a diagram
|
7
|
+
that describes your models is perfect documentation for your application.
|
8
|
+
|
9
|
+
The second goal of Rails ERD is to provide you with a tool to inspect your
|
10
|
+
application's domain model. If you don't like the default output, it is very
|
11
|
+
easy to use the API to build your own diagrams.
|
12
|
+
|
13
|
+
Rails ERD was created specifically for Rails 3. It uses Active Record's
|
14
|
+
built-in reflection capabilities to figure out how your models are associated.
|
15
|
+
|
16
|
+
|
17
|
+
Preview
|
18
|
+
-------
|
19
|
+
|
20
|
+
Here's an example entity-relationship diagram that was generated by Rails ERD:
|
21
|
+
|
22
|
+
![Entity-Relationship Diagram](http://rails-erd.rubyforge.org/images/entity-relationship-diagram.png)
|
23
|
+
|
24
|
+
Browse the [gallery](http://rails-erd.rubyforge.org/gallery.html) for more
|
25
|
+
example diagrams.
|
26
|
+
|
27
|
+
|
28
|
+
Getting started
|
29
|
+
---------------
|
30
|
+
|
31
|
+
See the [installation instructions](http://rails-erd.rubyforge.org/install.html)
|
32
|
+
for a complete description of how to install Rails ERD. Here's a summary:
|
33
|
+
|
34
|
+
* Install Graphviz 2.22+ with Pango and Cairo support ([how?](http://rails-erd.rubyforge.org/install.html))
|
35
|
+
|
36
|
+
* Add <tt>gem "rails-erd"</tt> to your application's Gemfile
|
37
|
+
|
38
|
+
* Run <tt>rake erd</tt>
|
39
|
+
|
40
|
+
|
41
|
+
Learn more
|
42
|
+
----------
|
43
|
+
|
44
|
+
More information can be found on [Rails ERD's project homepage](http://rails-erd.rubyforge.org/).
|
45
|
+
|
46
|
+
If you wish to extend or customise Rails ERD, take a look at the [API documentation](http://rails-erd.rubyforge.org/doc/).
|
47
|
+
|
48
|
+
|
49
|
+
About Rails ERD
|
50
|
+
---------------
|
51
|
+
|
52
|
+
Rails ERD was created by Rolf Timmermans (r.timmermans *at* voormedia.com)
|
53
|
+
|
54
|
+
Copyright 2010 Voormedia - [www.voormedia.com](http://www.voormedia.com/)
|
55
|
+
|
56
|
+
|
57
|
+
License
|
58
|
+
-------
|
59
|
+
|
60
|
+
Rails ERD is released under the MIT license.
|
data/Rakefile
CHANGED
@@ -12,9 +12,9 @@ Jeweler::Tasks.new do |spec|
|
|
12
12
|
spec.email = "r.timmermans@voormedia.com"
|
13
13
|
spec.homepage = "http://rails-erd.rubyforge.org/"
|
14
14
|
|
15
|
-
spec.add_runtime_dependency "activerecord", "~> 3.0
|
15
|
+
spec.add_runtime_dependency "activerecord", "~> 3.0"
|
16
16
|
spec.add_runtime_dependency "activesupport", "~> 3.0"
|
17
|
-
spec.add_runtime_dependency "ruby-graphviz", "~> 0.9.
|
17
|
+
spec.add_runtime_dependency "ruby-graphviz", "~> 0.9.18"
|
18
18
|
spec.add_development_dependency "sqlite3-ruby"
|
19
19
|
|
20
20
|
# Don't bundle examples or website in gem.
|
@@ -39,61 +39,21 @@ task :default => :test
|
|
39
39
|
begin
|
40
40
|
require "hanna/rdoctask"
|
41
41
|
Rake::RDocTask.new do |rdoc|
|
42
|
-
rdoc.rdoc_files =
|
43
|
-
rdoc.title = "Rails ERD –
|
42
|
+
rdoc.rdoc_files = %w{CHANGES.rdoc LICENSE} + Dir["lib/**/*.rb"]
|
43
|
+
rdoc.title = "Rails ERD – API Documentation"
|
44
44
|
rdoc.rdoc_dir = "rdoc"
|
45
|
+
rdoc.main = "RailsERD"
|
45
46
|
end
|
46
47
|
rescue LoadError
|
47
48
|
end
|
48
49
|
|
49
50
|
desc "Generate diagrams for bundled examples"
|
50
51
|
task :examples do
|
51
|
-
require "
|
52
|
-
|
53
|
-
Bundler.require
|
54
|
-
require "rails_erd/diagram/graphviz"
|
55
|
-
|
56
|
-
Dir["examples/*/*"].each do |path|
|
57
|
-
name = File.basename(path)
|
58
|
-
print "==> Generating ERD for #{name.capitalize}... "
|
59
|
-
begin
|
60
|
-
# Load database schema.
|
61
|
-
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
|
62
|
-
ActiveRecord::Migration.suppress_messages do
|
63
|
-
begin
|
64
|
-
require File.expand_path("#{path}/schema.rb", File.dirname(__FILE__))
|
65
|
-
rescue LoadError
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Load domain models for this example.
|
70
|
-
Dir["#{path}/**/*.rb"].each do |model|
|
71
|
-
require File.expand_path(model, File.dirname(__FILE__))
|
72
|
-
end
|
73
|
-
|
74
|
-
# Skip empty domain models.
|
75
|
-
next if ActiveRecord::Base.descendants.empty?
|
76
|
-
|
77
|
-
puts "#{ActiveRecord::Base.descendants.length} models"
|
78
|
-
[:simple, :advanced].each do |notation|
|
79
|
-
filename = File.expand_path("examples/#{name}#{notation != :simple ? "-#{notation}" : ""}", File.dirname(__FILE__))
|
80
|
-
|
81
|
-
default_options = { :notation => notation, :filename => filename, :attributes => [:regular],
|
82
|
-
:title => name.classify + " domain model" }
|
83
|
-
|
84
|
-
specific_options = eval((File.read("#{path}/options.rb") rescue "")) || {}
|
52
|
+
require File.expand_path("examples/generate", File.dirname(__FILE__))
|
53
|
+
end
|
85
54
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
ensure
|
90
|
-
# Completely remove all loaded Active Record models.
|
91
|
-
ActiveRecord::Base.descendants.each do |model|
|
92
|
-
Object.send :remove_const, model.name.to_sym rescue nil
|
93
|
-
end
|
94
|
-
ActiveRecord::Base.direct_descendants.clear
|
95
|
-
Arel::Relation.send :class_variable_set, :@@connection_tables_primary_keys, {}
|
96
|
-
ActiveSupport::Dependencies::Reference.clear!
|
97
|
-
end
|
55
|
+
namespace :examples do
|
56
|
+
task :sfdp do
|
57
|
+
require File.expand_path("examples/sfdp", File.dirname(__FILE__))
|
98
58
|
end
|
99
59
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0
|
data/lib/rails_erd.rb
CHANGED
@@ -1,6 +1,18 @@
|
|
1
1
|
require "active_support/ordered_options"
|
2
2
|
require "rails_erd/railtie" if defined? Rails
|
3
3
|
|
4
|
+
# Welcome to the API documentation of Rails ERD. If you wish to extend or
|
5
|
+
# customise the output that is generated by Rails ERD, you have come to the
|
6
|
+
# right place.
|
7
|
+
#
|
8
|
+
# == Creating custom output
|
9
|
+
#
|
10
|
+
# If you want to create your own kind of diagrams, or some other output, a
|
11
|
+
# good starting point is the RailsERD::Diagram class. It can serve as the base
|
12
|
+
# of your output generation code.
|
13
|
+
#
|
14
|
+
# == Options
|
15
|
+
#
|
4
16
|
# Rails ERD provides several options that allow you to customise the
|
5
17
|
# generation of the diagram and the domain model itself. For an overview of
|
6
18
|
# all options available in Rails ERD, see README.rdoc.
|
@@ -21,15 +33,30 @@ module RailsERD
|
|
21
33
|
# RailsERD::Diagram will use these options unless overridden.
|
22
34
|
attr_accessor :options
|
23
35
|
end
|
36
|
+
|
37
|
+
module Inspectable # @private :nodoc:
|
38
|
+
def inspection_attributes(*attributes)
|
39
|
+
attribute_inspection = attributes.collect { |attribute|
|
40
|
+
" @#{attribute}=\#{[Symbol, String].include?(#{attribute}.class) ? #{attribute}.inspect : #{attribute}}"
|
41
|
+
}.join
|
42
|
+
class_eval <<-RUBY
|
43
|
+
def inspect
|
44
|
+
"#<\#{self.class}:0x%.14x#{attribute_inspection}>" % (object_id << 1)
|
45
|
+
end
|
46
|
+
RUBY
|
47
|
+
end
|
48
|
+
end
|
24
49
|
|
25
50
|
self.options = ActiveSupport::OrderedOptions[
|
26
|
-
:attributes, :
|
51
|
+
:attributes, :content,
|
27
52
|
:disconnected, true,
|
28
53
|
:filename, "ERD",
|
29
54
|
:filetype, :pdf,
|
30
55
|
:indirect, true,
|
56
|
+
:inheritance, false,
|
31
57
|
:notation, :simple,
|
32
58
|
:orientation, :horizontal,
|
59
|
+
:polymorphism, false,
|
33
60
|
:warn, true,
|
34
61
|
:title, true
|
35
62
|
]
|
data/lib/rails_erd/diagram.rb
CHANGED
@@ -12,7 +12,9 @@ module RailsERD
|
|
12
12
|
# require "rails_erd/diagram"
|
13
13
|
#
|
14
14
|
# class YumlDiagram < RailsERD::Diagram
|
15
|
-
#
|
15
|
+
# setup { @edges = [] }
|
16
|
+
#
|
17
|
+
# each_relationship do |relationship|
|
16
18
|
# return if relationship.indirect?
|
17
19
|
#
|
18
20
|
# arrow = case
|
@@ -21,12 +23,10 @@ module RailsERD
|
|
21
23
|
# when relationship.many_to_many? then "*-*>"
|
22
24
|
# end
|
23
25
|
#
|
24
|
-
#
|
26
|
+
# @edges << "[#{relationship.source}] #{arrow} [#{relationship.destination}]"
|
25
27
|
# end
|
26
28
|
#
|
27
|
-
#
|
28
|
-
# instructions * "\n"
|
29
|
-
# end
|
29
|
+
# save { @edges * "\n" }
|
30
30
|
# end
|
31
31
|
#
|
32
32
|
# Then, to generate the diagram (example based on the domain model of Gemcutter):
|
@@ -51,12 +51,17 @@ module RailsERD
|
|
51
51
|
# diagram generator inheriting from this class.
|
52
52
|
#
|
53
53
|
# attributes:: Selects which attributes to display. Can be any combination of
|
54
|
-
# +:
|
54
|
+
# +:content+, +:primary_keys+, +:foreign_keys+, +:timestamps+, or
|
55
|
+
# +:inheritance+.
|
55
56
|
# disconnected:: Set to +false+ to exclude entities that are not connected to other
|
56
57
|
# entities. Defaults to +false+.
|
57
58
|
# indirect:: Set to +false+ to exclude relationships that are indirect.
|
58
59
|
# Indirect relationships are defined in Active Record with
|
59
60
|
# <tt>has_many :through</tt> associations.
|
61
|
+
# inheritance:: Set to +true+ to include specializations, which correspond to
|
62
|
+
# Rails single table inheritance.
|
63
|
+
# polymorphism:: Set to +true+ to include generalizations, which correspond to
|
64
|
+
# Rails polymorphic associations.
|
60
65
|
# warn:: When set to +false+, no warnings are printed to the
|
61
66
|
# command line while processing the domain model. Defaults
|
62
67
|
# to +true+.
|
@@ -68,6 +73,34 @@ module RailsERD
|
|
68
73
|
def create(options = {})
|
69
74
|
new(Domain.generate(options), options).create
|
70
75
|
end
|
76
|
+
|
77
|
+
protected
|
78
|
+
|
79
|
+
def setup(&block)
|
80
|
+
callbacks[:setup] = block
|
81
|
+
end
|
82
|
+
|
83
|
+
def each_entity(&block)
|
84
|
+
callbacks[:each_entity] = block
|
85
|
+
end
|
86
|
+
|
87
|
+
def each_relationship(&block)
|
88
|
+
callbacks[:each_relationship] = block
|
89
|
+
end
|
90
|
+
|
91
|
+
def each_specialization(&block)
|
92
|
+
callbacks[:each_specialization] = block
|
93
|
+
end
|
94
|
+
|
95
|
+
def save(&block)
|
96
|
+
callbacks[:save] = block
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def callbacks
|
102
|
+
@callbacks ||= Hash.new { proc {} }
|
103
|
+
end
|
71
104
|
end
|
72
105
|
|
73
106
|
# The options that are used to create this diagram.
|
@@ -90,41 +123,35 @@ module RailsERD
|
|
90
123
|
# Generates the diagram, but does not save the output. It is called
|
91
124
|
# internally by Diagram#create.
|
92
125
|
def generate
|
126
|
+
instance_eval &callbacks[:setup]
|
127
|
+
|
93
128
|
filtered_entities.each do |entity|
|
94
|
-
|
129
|
+
instance_exec entity, filtered_attributes(entity), &callbacks[:each_entity]
|
95
130
|
end
|
96
131
|
|
97
|
-
|
98
|
-
|
132
|
+
filtered_specializations.each do |specialization|
|
133
|
+
instance_exec specialization, &callbacks[:each_specialization]
|
99
134
|
end
|
100
|
-
end
|
101
|
-
|
102
|
-
# Saves the diagram. Can be overridden in subclasses to write to an output
|
103
|
-
# file. It is called internally by Diagram#create.
|
104
|
-
def save
|
105
|
-
end
|
106
|
-
|
107
|
-
protected
|
108
135
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
# be displayed, typically in alphabetic order.
|
113
|
-
def process_entity(entity, attributes)
|
136
|
+
filtered_relationships.each do |relationship|
|
137
|
+
instance_exec relationship, &callbacks[:each_relationship]
|
138
|
+
end
|
114
139
|
end
|
115
140
|
|
116
|
-
|
117
|
-
|
118
|
-
# the diagram. This method will be called once for eacn relationship
|
119
|
-
# that should be displayed.
|
120
|
-
def process_relationship(relationship)
|
141
|
+
def save
|
142
|
+
instance_eval &callbacks[:save]
|
121
143
|
end
|
122
144
|
|
123
145
|
private
|
124
146
|
|
147
|
+
def callbacks
|
148
|
+
@callbacks ||= self.class.send(:callbacks)
|
149
|
+
end
|
150
|
+
|
125
151
|
def filtered_entities
|
126
152
|
@domain.entities.reject { |entity|
|
127
|
-
entity.
|
153
|
+
!options.inheritance && entity.specialized? or
|
154
|
+
!options.polymorphism && entity.generalized? or
|
128
155
|
!options.disconnected && entity.disconnected?
|
129
156
|
}.compact.tap do |entities|
|
130
157
|
raise "No entities found; create your models first!" if entities.empty?
|
@@ -133,19 +160,25 @@ module RailsERD
|
|
133
160
|
|
134
161
|
def filtered_relationships
|
135
162
|
@domain.relationships.reject { |relationship|
|
136
|
-
relationship.source.descendant? or
|
137
|
-
relationship.destination.descendant? or
|
138
163
|
!options.indirect && relationship.indirect?
|
139
164
|
}
|
140
165
|
end
|
141
166
|
|
167
|
+
def filtered_specializations
|
168
|
+
@domain.specializations.reject { |specialization|
|
169
|
+
!options.inheritance && specialization.inheritance? or
|
170
|
+
!options.polymorphism && specialization.polymorphic?
|
171
|
+
}
|
172
|
+
end
|
173
|
+
|
142
174
|
def filtered_attributes(entity)
|
143
|
-
entity.attributes.
|
175
|
+
entity.attributes.reject { |attribute|
|
144
176
|
# Select attributes that satisfy the conditions in the :attributes option.
|
145
|
-
options.attributes
|
177
|
+
!options.attributes or entity.specialized? or
|
178
|
+
[*options.attributes].none? { |type| attribute.send(:"#{type.to_s.chomp('s')}?") }
|
146
179
|
}
|
147
180
|
end
|
148
|
-
|
181
|
+
|
149
182
|
def warn(message)
|
150
183
|
puts "Warning: #{message}" if options.warn
|
151
184
|
end
|