rails-erd 1.7.2 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +112 -16
- data/lib/generators/erd/install_generator.rb +2 -0
- data/lib/generators/erd/templates/auto_generate_diagram.rake +1 -1
- data/lib/rails-erd.rb +2 -0
- data/lib/rails_erd/cli.rb +47 -5
- data/lib/rails_erd/config.rb +7 -2
- data/lib/rails_erd/diagram/graphviz.rb +28 -15
- data/lib/rails_erd/diagram/mermaid.rb +152 -0
- data/lib/rails_erd/diagram/templates/node.html.erb +1 -1
- data/lib/rails_erd/diagram/templates/node.record.erb +2 -2
- data/lib/rails_erd/diagram.rb +5 -1
- data/lib/rails_erd/domain/attribute.rb +15 -5
- data/lib/rails_erd/domain/entity.rb +6 -0
- data/lib/rails_erd/domain/relationship/cardinality.rb +2 -0
- data/lib/rails_erd/domain/relationship.rb +2 -0
- data/lib/rails_erd/domain/specialization.rb +2 -0
- data/lib/rails_erd/domain.rb +43 -6
- data/lib/rails_erd/railtie.rb +3 -1
- data/lib/rails_erd/tasks.rake +24 -9
- data/lib/rails_erd/version.rb +3 -1
- data/lib/rails_erd.rb +7 -1
- data/test/support_files/erdconfig.empty +0 -0
- data/test/unit/cli_test.rb +75 -0
- data/test/unit/config_test.rb +7 -0
- data/test/unit/domain_test.rb +8 -13
- data/test/unit/graphviz_test.rb +11 -14
- data/test/unit/mermaid_test.rb +388 -0
- data/test/unit/rake_task_test.rb +23 -2
- metadata +36 -18
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module RailsERD
|
|
2
4
|
class Domain
|
|
3
5
|
# Entities represent your Active Record models. Entities may be connected
|
|
@@ -38,6 +40,10 @@ module RailsERD
|
|
|
38
40
|
@domain, @name, @model = domain, name, model
|
|
39
41
|
end
|
|
40
42
|
|
|
43
|
+
def label
|
|
44
|
+
RailsERD.options[:table_names] ? model.table_name : name
|
|
45
|
+
end
|
|
46
|
+
|
|
41
47
|
# Returns an array of attributes for this entity.
|
|
42
48
|
def attributes
|
|
43
49
|
@attributes ||= generalized? ? [] : Attribute.from_model(domain, model)
|
data/lib/rails_erd/domain.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "rails_erd"
|
|
2
4
|
require "rails_erd/domain/attribute"
|
|
3
5
|
require "rails_erd/domain/entity"
|
|
@@ -65,7 +67,9 @@ module RailsERD
|
|
|
65
67
|
|
|
66
68
|
# Returns all relationships in your domain model.
|
|
67
69
|
def relationships
|
|
68
|
-
@relationships ||= Relationship.from_associations(self, associations)
|
|
70
|
+
@relationships ||= Relationship.from_associations(self, associations).select do |relationship|
|
|
71
|
+
relationship.source && relationship.destination
|
|
72
|
+
end
|
|
69
73
|
end
|
|
70
74
|
|
|
71
75
|
# Returns all specializations in your domain model.
|
|
@@ -130,12 +134,26 @@ module RailsERD
|
|
|
130
134
|
def rails_models
|
|
131
135
|
%w(
|
|
132
136
|
ActionMailbox::InboundEmail
|
|
137
|
+
ActionText::EncryptedRichText
|
|
138
|
+
ActionText::RichText
|
|
133
139
|
ActiveStorage::Attachment
|
|
134
140
|
ActiveStorage::Blob
|
|
135
141
|
ActiveStorage::VariantRecord
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
142
|
+
SolidCable::Message
|
|
143
|
+
SolidCache::Entry
|
|
144
|
+
SolidQueue::BlockedExecution
|
|
145
|
+
SolidQueue::ClaimedExecution
|
|
146
|
+
SolidQueue::Execution
|
|
147
|
+
SolidQueue::FailedExecution
|
|
148
|
+
SolidQueue::Job
|
|
149
|
+
SolidQueue::Pause
|
|
150
|
+
SolidQueue::Process
|
|
151
|
+
SolidQueue::ReadyExecution
|
|
152
|
+
SolidQueue::RecurringExecution
|
|
153
|
+
SolidQueue::RecurringTask
|
|
154
|
+
SolidQueue::ScheduledExecution
|
|
155
|
+
SolidQueue::Semaphore
|
|
156
|
+
).map { |model| Object.const_get(model) rescue nil }.compact
|
|
139
157
|
end
|
|
140
158
|
|
|
141
159
|
def tableless_rails_models
|
|
@@ -163,7 +181,13 @@ module RailsERD
|
|
|
163
181
|
raise "table #{model.table_name} does not exist"
|
|
164
182
|
end
|
|
165
183
|
rescue => e
|
|
166
|
-
warn "Ignoring invalid model #{model.name} (#{e.message})"
|
|
184
|
+
warn "Ignoring invalid model #{model.name} (#{e.message})" unless excluded_model?(model)
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def excluded_model?(model)
|
|
188
|
+
return false unless options.exclude.present?
|
|
189
|
+
|
|
190
|
+
[options.exclude].flatten.map(&:to_sym).include?(model.name.to_sym)
|
|
167
191
|
end
|
|
168
192
|
|
|
169
193
|
def check_association_validity(association)
|
|
@@ -177,7 +201,20 @@ module RailsERD
|
|
|
177
201
|
entity_by_name(entity_name) or raise "model #{entity_name} exists, but is not included in domain"
|
|
178
202
|
end
|
|
179
203
|
rescue => e
|
|
180
|
-
warn "Ignoring invalid association #{association_description(association)} (#{e.message})"
|
|
204
|
+
warn "Ignoring invalid association #{association_description(association)} (#{e.message})" unless excluded_association?(association)
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def excluded_association?(association)
|
|
208
|
+
return false unless options.exclude.present?
|
|
209
|
+
|
|
210
|
+
excluded_names = [options.exclude].flatten.map(&:to_sym)
|
|
211
|
+
|
|
212
|
+
# Suppress warning if either the source model or target model is excluded
|
|
213
|
+
excluded_names.include?(association.active_record.name.to_sym) ||
|
|
214
|
+
(association.klass.name && excluded_names.include?(association.klass.name.to_sym))
|
|
215
|
+
rescue NameError
|
|
216
|
+
# If we can't determine the target class, check only the source model
|
|
217
|
+
excluded_names.include?(association.active_record.name.to_sym)
|
|
181
218
|
end
|
|
182
219
|
|
|
183
220
|
def check_polymorphic_association_validity(association)
|
data/lib/rails_erd/railtie.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module RailsERD
|
|
2
|
-
# Rails ERD integrates with Rails
|
|
4
|
+
# Rails ERD integrates with Rails. If you add it to your +Gemfile+, you
|
|
3
5
|
# will gain a Rake task called +erd+, which you can use to generate diagrams
|
|
4
6
|
# of your domain model.
|
|
5
7
|
class Railtie < Rails::Railtie
|
data/lib/rails_erd/tasks.rake
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
require 'graphviz/utils'
|
|
2
|
-
|
|
3
1
|
module ErdRakeHelper
|
|
4
2
|
def say(message)
|
|
5
3
|
puts message unless Rake.application.options.silent
|
|
@@ -8,10 +6,18 @@ end
|
|
|
8
6
|
|
|
9
7
|
namespace :erd do
|
|
10
8
|
task :check_dependencies do
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
9
|
+
if RailsERD.options.generator == :graphviz
|
|
10
|
+
begin
|
|
11
|
+
require 'graphviz/utils'
|
|
12
|
+
include GraphViz::Utils
|
|
13
|
+
unless find_executable("dot", nil)
|
|
14
|
+
raise "Unable to find GraphViz's \"dot\" executable. Please " \
|
|
15
|
+
"visit https://voormedia.github.io/rails-erd/install.html for installation instructions."
|
|
16
|
+
end
|
|
17
|
+
rescue LoadError
|
|
18
|
+
raise "The ruby-graphviz gem is required for Graphviz output. " \
|
|
19
|
+
"Add `gem 'ruby-graphviz'` to your Gemfile, or use `generator=mermaid` instead."
|
|
20
|
+
end
|
|
15
21
|
end
|
|
16
22
|
end
|
|
17
23
|
|
|
@@ -58,13 +64,22 @@ namespace :erd do
|
|
|
58
64
|
raise "Active Record was not loaded." unless defined? ActiveRecord
|
|
59
65
|
end
|
|
60
66
|
|
|
61
|
-
task :generate => [:
|
|
67
|
+
task :generate => [:options, :check_dependencies, :load_models] do
|
|
62
68
|
include ErdRakeHelper
|
|
63
69
|
|
|
64
70
|
say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
|
|
65
71
|
|
|
66
|
-
|
|
67
|
-
|
|
72
|
+
file = case RailsERD.options.generator
|
|
73
|
+
when :mermaid
|
|
74
|
+
require "rails_erd/diagram/mermaid"
|
|
75
|
+
RailsERD::Diagram::Mermaid.create
|
|
76
|
+
when :graphviz
|
|
77
|
+
require "rails_erd/diagram/graphviz"
|
|
78
|
+
RailsERD::Diagram::Graphviz.create
|
|
79
|
+
else
|
|
80
|
+
raise "Unknown generator: #{RailsERD.options.generator}"
|
|
81
|
+
end
|
|
82
|
+
|
|
68
83
|
|
|
69
84
|
say "Done! Saved diagram to ./#{file}"
|
|
70
85
|
end
|
data/lib/rails_erd/version.rb
CHANGED
data/lib/rails_erd.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require "active_support/ordered_options"
|
|
2
4
|
require "rails_erd/railtie" if defined? Rails
|
|
3
5
|
require "rails_erd/config"
|
|
@@ -36,14 +38,16 @@ module RailsERD
|
|
|
36
38
|
|
|
37
39
|
def default_options
|
|
38
40
|
ActiveSupport::OrderedOptions[
|
|
41
|
+
:generator, :mermaid,
|
|
39
42
|
:attributes, :content,
|
|
40
43
|
:disconnected, true,
|
|
41
44
|
:filename, "erd",
|
|
42
|
-
:filetype, :
|
|
45
|
+
:filetype, :mmd,
|
|
43
46
|
:fonts, {},
|
|
44
47
|
:indirect, true,
|
|
45
48
|
:inheritance, false,
|
|
46
49
|
:markup, true,
|
|
50
|
+
:mermaid_style, :erdiagram,
|
|
47
51
|
:notation, :simple,
|
|
48
52
|
:orientation, :horizontal,
|
|
49
53
|
:polymorphism, false,
|
|
@@ -55,6 +59,8 @@ module RailsERD
|
|
|
55
59
|
:only_recursion_depth, nil,
|
|
56
60
|
:prepend_primary, false,
|
|
57
61
|
:cluster, false,
|
|
62
|
+
:table_names, false,
|
|
63
|
+
:native_types, false
|
|
58
64
|
]
|
|
59
65
|
end
|
|
60
66
|
|
|
File without changes
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
|
2
|
+
require "rails_erd/cli"
|
|
3
|
+
|
|
4
|
+
class CLITest < ActiveSupport::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
RailsERD.options.filetype = :dot
|
|
7
|
+
RailsERD.options.warn = false
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Generator selection ========================================================
|
|
11
|
+
test "CLI should use mermaid generator by default" do
|
|
12
|
+
require "rails_erd/diagram/mermaid"
|
|
13
|
+
cli = RailsERD::CLI.new(Dir.pwd, {})
|
|
14
|
+
assert_equal RailsERD::Diagram::Mermaid, cli.send(:generator)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
test "CLI should use graphviz generator when generator option is graphviz symbol" do
|
|
18
|
+
cli = RailsERD::CLI.new(Dir.pwd, { generator: :graphviz })
|
|
19
|
+
assert_equal RailsERD::Diagram::Graphviz, cli.send(:generator)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
test "CLI should use mermaid generator when generator option is mermaid symbol" do
|
|
23
|
+
require "rails_erd/diagram/mermaid"
|
|
24
|
+
cli = RailsERD::CLI.new(Dir.pwd, { generator: :mermaid })
|
|
25
|
+
assert_equal RailsERD::Diagram::Mermaid, cli.send(:generator)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Option parsing (SYMBOL_OPTIONS conversion) =================================
|
|
29
|
+
test "CLI start should convert generator string to symbol" do
|
|
30
|
+
# Simulate what Choice.choices returns (strings)
|
|
31
|
+
Choice.stubs(:choices).returns({ "generator" => "mermaid" })
|
|
32
|
+
Choice.stubs(:rest).returns([])
|
|
33
|
+
|
|
34
|
+
# Capture the options passed to new
|
|
35
|
+
captured_options = nil
|
|
36
|
+
RailsERD::CLI.stubs(:new).with do |path, options|
|
|
37
|
+
captured_options = options
|
|
38
|
+
true
|
|
39
|
+
end.returns(stub(start: nil))
|
|
40
|
+
|
|
41
|
+
RailsERD::CLI.start
|
|
42
|
+
|
|
43
|
+
assert_equal :mermaid, captured_options[:generator]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
test "CLI start should convert mermaid_style string to symbol" do
|
|
47
|
+
Choice.stubs(:choices).returns({ "mermaid_style" => "erdiagram" })
|
|
48
|
+
Choice.stubs(:rest).returns([])
|
|
49
|
+
|
|
50
|
+
captured_options = nil
|
|
51
|
+
RailsERD::CLI.stubs(:new).with do |path, options|
|
|
52
|
+
captured_options = options
|
|
53
|
+
true
|
|
54
|
+
end.returns(stub(start: nil))
|
|
55
|
+
|
|
56
|
+
RailsERD::CLI.start
|
|
57
|
+
|
|
58
|
+
assert_equal :erdiagram, captured_options[:mermaid_style]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
test "CLI start should convert filetype string to symbol" do
|
|
62
|
+
Choice.stubs(:choices).returns({ "filetype" => "pdf" })
|
|
63
|
+
Choice.stubs(:rest).returns([])
|
|
64
|
+
|
|
65
|
+
captured_options = nil
|
|
66
|
+
RailsERD::CLI.stubs(:new).with do |path, options|
|
|
67
|
+
captured_options = options
|
|
68
|
+
true
|
|
69
|
+
end.returns(stub(start: nil))
|
|
70
|
+
|
|
71
|
+
RailsERD::CLI.start
|
|
72
|
+
|
|
73
|
+
assert_equal :pdf, captured_options[:filetype]
|
|
74
|
+
end
|
|
75
|
+
end
|
data/test/unit/config_test.rb
CHANGED
|
@@ -8,6 +8,13 @@ class ConfigTest < ActiveSupport::TestCase
|
|
|
8
8
|
assert_equal expected_hash, RailsERD::Config.load
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
+
test "load_config_file should return blank hash when config file is empty" do
|
|
12
|
+
set_local_config_file_to("erdconfig.empty")
|
|
13
|
+
|
|
14
|
+
expected_hash = {}
|
|
15
|
+
assert_equal expected_hash, RailsERD::Config.load
|
|
16
|
+
end
|
|
17
|
+
|
|
11
18
|
test "load_config_gile should return a hash from USER_WIDE_CONFIG_FILE when only USER_WIDE_CONFIG_FILE exists." do
|
|
12
19
|
set_user_config_file_to("erdconfig.example")
|
|
13
20
|
|
data/test/unit/domain_test.rb
CHANGED
|
@@ -127,21 +127,16 @@ class DomainTest < ActiveSupport::TestCase
|
|
|
127
127
|
end
|
|
128
128
|
|
|
129
129
|
test "relationships should count relationship between same models with distinct foreign key seperately" do
|
|
130
|
-
|
|
131
|
-
# :respond_to? check
|
|
132
|
-
#
|
|
133
|
-
if respond_to? :skip
|
|
134
|
-
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
|
130
|
+
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
|
135
131
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
end
|
|
139
|
-
create_model "Bar" do
|
|
140
|
-
has_many :foos, :foreign_key => :special_bar_id
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
|
|
132
|
+
create_model "Foo", :bar => :references, :special_bar => :references do
|
|
133
|
+
belongs_to :bar
|
|
144
134
|
end
|
|
135
|
+
create_model "Bar" do
|
|
136
|
+
has_many :foos, :foreign_key => :special_bar_id
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
|
|
145
140
|
end
|
|
146
141
|
|
|
147
142
|
test "relationships should use model name first in alphabet as source for many to many relationships" do
|
data/test/unit/graphviz_test.rb
CHANGED
|
@@ -193,7 +193,9 @@ class GraphvizTest < ActiveSupport::TestCase
|
|
|
193
193
|
|
|
194
194
|
test "generate should add set value for fontname attribute" do
|
|
195
195
|
create_simple_domain
|
|
196
|
-
|
|
196
|
+
# Use OS-appropriate font name (macOS uses PostScript names like "Arial BoldMT")
|
|
197
|
+
expected_font = RailsERD::Config.font_names_based_on_os[:bold]
|
|
198
|
+
assert_equal "\"#{expected_font}\"", diagram(fonts: {bold: expected_font}).graph.graph[:fontname].to_s
|
|
197
199
|
end
|
|
198
200
|
|
|
199
201
|
test "generate should add default value for splines attribute" do
|
|
@@ -314,21 +316,16 @@ class GraphvizTest < ActiveSupport::TestCase
|
|
|
314
316
|
end
|
|
315
317
|
|
|
316
318
|
test "generate should create edge for each relationship" do
|
|
317
|
-
|
|
318
|
-
# :respond_to? check
|
|
319
|
-
#
|
|
320
|
-
if respond_to? :skip
|
|
321
|
-
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
|
322
|
-
|
|
323
|
-
create_model "Foo", :bar => :references do
|
|
324
|
-
belongs_to :bar
|
|
325
|
-
end
|
|
326
|
-
create_model "Bar", :foo => :references do
|
|
327
|
-
belongs_to :foo
|
|
328
|
-
end
|
|
319
|
+
skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
|
|
329
320
|
|
|
330
|
-
|
|
321
|
+
create_model "Foo", :bar => :references do
|
|
322
|
+
belongs_to :bar
|
|
323
|
+
end
|
|
324
|
+
create_model "Bar", :foo => :references do
|
|
325
|
+
belongs_to :foo
|
|
331
326
|
end
|
|
327
|
+
|
|
328
|
+
assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
|
|
332
329
|
end
|
|
333
330
|
|
|
334
331
|
test "generate should create edge to polymorphic entity if polymorphism is true" do
|