rails-erd 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+

|
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
|