rails-erd 1.5.2 → 1.7.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 33b2df60c7db63f567ecf08e5e221d7e47dc0234
4
- data.tar.gz: 85fd38a21b0bb31cdbe1e19c20d0fbdd56e5d617
2
+ SHA256:
3
+ metadata.gz: 8b58372ac1652af1b21bd00ea88b434bb2d303247eca241f57efd84210bc9367
4
+ data.tar.gz: aecdcd4cfdb25ed3ef1713da019b456512d2b7bc965ebe0d7acea86e56b4f586
5
5
  SHA512:
6
- metadata.gz: 0f10ee2e13c4d6e25c5bd3e4bc1e0df346a44f874e61f7f38ff0503639d046623a28bab1883cc49ff9fee1da3f5ecd1455a301b066eaa516c61ed04efe2fbe3b
7
- data.tar.gz: 6b4ddb644d1966ff5f5a3d34a016ea5668f5ddfcc3914eeb539f10760e7eda79ecc5fca593e84a141f23b420919aab783811e99c9d7ba76cc28110aeb86b365a
6
+ metadata.gz: 1d8c7c596bf41d7753c0c34a468c142021ed66e7b7168dab70f68e57cf587640b5d5c35693b14c4a4c7778cf55b30f5740393454773901720f29c71f16e91c73
7
+ data.tar.gz: 733fe6e3c637a1f31f750621af09b9803102663b8d5cb611f978c600bc0940856e491a853325f57b4c126cf6e1ec50d55a4d0425ed573f1b722f144333ff4cf9
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
2
2
  ========================================================================
3
- [![Build Status](https://travis-ci.org/voormedia/rails-erd.svg?branch=master)](https://travis-ci.org/voormedia/rails-erd) [![Code Climate](https://codeclimate.com/github/voormedia/rails-erd/badges/gpa.svg)](https://codeclimate.com/github/voormedia/rails-erd)
3
+ [![Tests](https://github.com/voormedia/rails-erd/actions/workflows/test.yml/badge.svg)](https://github.com/voormedia/rails-erd/actions/workflows/test.yml) [![Code Climate](https://codeclimate.com/github/voormedia/rails-erd/badges/gpa.svg)](https://codeclimate.com/github/voormedia/rails-erd)
4
4
 
5
5
  [Rails ERD](https://voormedia.github.io/rails-erd/) is a gem that allows you to easily generate a diagram based on your application's Active Record models. The diagram gives an overview of how your models are related. Having a diagram that describes your models is perfect documentation for your application.
6
6
 
@@ -30,9 +30,11 @@ Getting started
30
30
 
31
31
  See the [installation instructions](https://voormedia.github.io/rails-erd/install.html) for a complete description of how to install Rails ERD. Here's a summary:
32
32
 
33
- * Install Graphviz 2.22+ ([how?](https://voormedia.github.io/rails-erd/install.html))
33
+ * Install Graphviz 2.22+ ([how?](https://voormedia.github.io/rails-erd/install.html)). On macOS with Homebrew run `brew install graphviz`.
34
34
 
35
- * Add <tt>gem "rails-erd"</tt> to your application's Gemfile
35
+ * on linux - `sudo apt-get install graphviz`
36
+
37
+ * Add <tt>gem 'rails-erd', group: :development</tt> to your application's Gemfile
36
38
 
37
39
  * Run <tt>bundle exec erd</tt>
38
40
 
@@ -44,7 +46,7 @@ Rails ERD has the ability to be configured via the command line or through the u
44
46
  ```yaml
45
47
  attributes:
46
48
  - content
47
- - foreign_key
49
+ - foreign_keys
48
50
  - inheritance
49
51
  disconnected: true
50
52
  filename: erd
@@ -64,13 +66,17 @@ only_recursion_depth: null
64
66
  prepend_primary: false
65
67
  cluster: false
66
68
  splines: spline
69
+ fonts:
70
+ normal: "Arial"
71
+ bold: "Arial Bold"
72
+ italic: "Arial Italic"
67
73
  ```
68
74
 
69
75
  Auto generation
70
76
  ---------------
71
77
 
72
- * Run <tt>rails generate erd:install</tt>
73
- * Run <tt>rails db:migrate</tt>, then the diagram is generated
78
+ * Run <tt>bundle exec rails g erd:install</tt>
79
+ * Run <tt>bundle exec rails db:migrate</tt>, then the diagram is generated
74
80
 
75
81
  Learn more
76
82
  ----------
data/lib/rails_erd/cli.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "rails_erd"
1
2
  require "choice"
2
3
 
3
4
  Choice.options do
@@ -125,6 +126,12 @@ Choice.options do
125
126
  exit
126
127
  end
127
128
  end
129
+
130
+ option :config_file do
131
+ short "-c"
132
+ long "--config=FILENAME"
133
+ desc "Configuration file to use"
134
+ end
128
135
  end
129
136
 
130
137
  module RailsERD
@@ -143,6 +150,9 @@ module RailsERD
143
150
  opts[key.to_sym] = value
144
151
  end
145
152
  end
153
+ if options[:config_file] && options[:config_file] != ''
154
+ RailsERD.options = RailsERD.default_options.merge(Config.load(options[:config_file]))
155
+ end
146
156
  new(path, options).start
147
157
  end
148
158
  end
@@ -164,17 +174,25 @@ module RailsERD
164
174
 
165
175
  def load_application
166
176
  $stderr.puts "Loading application in '#{File.basename(path)}'..."
167
- begin
168
- environment_path = "#{path}/config/environment.rb"
169
- require environment_path
170
- rescue ::LoadError
171
- puts "Please create a file in '#{environment_path}' that loads your application environment."
172
- raise
173
- end
177
+ environment_path = "#{path}/config/environment.rb"
178
+ require environment_path
179
+
174
180
  if defined? Rails
175
181
  Rails.application.eager_load!
176
182
  Rails.application.config.eager_load_namespaces.each(&:eager_load!) if Rails.application.config.respond_to?(:eager_load_namespaces)
177
183
  end
184
+ rescue ::LoadError
185
+ error_message = <<~EOS
186
+ Tried to load your application environment from '#{environment_path}' but the file was not present.
187
+ This means that your models might not get loaded fully when the diagram gets built. This can
188
+ make your entity diagram incomplete.
189
+
190
+ However, if you are using ActiveRecord without Rails just make sure your models get
191
+ loaded eagerly before we generate the ERD (for example, explicitly require your application
192
+ bootstrap file before calling rails-erd from your Rakefile). We will continue without loading the environment file,
193
+ and recommend you check your diagram for missing models after it gets generated.
194
+ EOS
195
+ puts error_message
178
196
  rescue TypeError
179
197
  end
180
198
 
@@ -7,17 +7,21 @@ module RailsERD
7
7
 
8
8
  attr_reader :options
9
9
 
10
- def self.load
11
- new.load
10
+ def self.load(extra_config_file=nil)
11
+ new.load extra_config_file
12
12
  end
13
13
 
14
14
  def initialize
15
15
  @options = {}
16
16
  end
17
17
 
18
- def load
18
+ def load(extra_config_file=nil)
19
19
  load_file(USER_WIDE_CONFIG_FILE)
20
20
  load_file(CURRENT_CONFIG_FILE)
21
+ if extra_config_file
22
+ extra_config_path = File.expand_path(extra_config_file, Dir.pwd)
23
+ load_file(extra_config_path) if File.exist?(extra_config_path)
24
+ end
21
25
 
22
26
  @options
23
27
  end
@@ -77,6 +81,12 @@ module RailsERD
77
81
  when :title
78
82
  value.is_a?(String) ? value : !!value
79
83
 
84
+ # nil | <Hash>
85
+ when :fonts
86
+ if value
87
+ Hash(value).transform_keys(&:to_sym)
88
+ end
89
+
80
90
  else
81
91
  value
82
92
  end
@@ -50,7 +50,7 @@ module RailsERD
50
50
 
51
51
  NODE_WIDTH = 130 # @private :nodoc:
52
52
 
53
- FONTS = Config.font_names_based_on_os
53
+ FONTS = Config.font_names_based_on_os.merge(RailsERD.options[:fonts])
54
54
 
55
55
  # Default graph attributes.
56
56
  GRAPH_ATTRIBUTES = {
@@ -86,6 +86,11 @@ module RailsERD
86
86
  labeldistance: 1.8,
87
87
  }
88
88
 
89
+ # Default cluster attributes.
90
+ CLUSTER_ATTRIBUTES = {
91
+ margin: "10,10"
92
+ }
93
+
89
94
  module Simple
90
95
  def entity_style(entity, attributes)
91
96
  {}.tap do |options|
@@ -216,8 +221,10 @@ module RailsERD
216
221
  each_entity do |entity, attributes|
217
222
  if options[:cluster] && entity.namespace
218
223
  cluster_name = "cluster_#{entity.namespace}"
224
+ cluster_options = CLUSTER_ATTRIBUTES.merge(label: entity.namespace)
219
225
  cluster = graph.get_graph(cluster_name) ||
220
- graph.add_graph(cluster_name, label: entity.namespace)
226
+ graph.add_graph(cluster_name, cluster_options)
227
+
221
228
  draw_cluster_node cluster, entity.name, entity_options(entity, attributes)
222
229
  else
223
230
  draw_node entity.name, entity_options(entity, attributes)
@@ -303,7 +310,12 @@ module RailsERD
303
310
  end
304
311
 
305
312
  def read_template(type)
306
- ERB.new(File.read(File.expand_path("templates/#{NODE_LABEL_TEMPLATES[type]}", File.dirname(__FILE__))), nil, "<>")
313
+ template_text = File.read(File.expand_path("templates/#{NODE_LABEL_TEMPLATES[type]}", File.dirname(__FILE__)))
314
+ if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+
315
+ ERB.new(template_text, trim_mode: "<>")
316
+ else
317
+ ERB.new(template_text, nil, "<>")
318
+ end
307
319
  end
308
320
  end
309
321
  end
@@ -125,7 +125,7 @@ module RailsERD
125
125
  def generate
126
126
  instance_eval(&callbacks[:setup])
127
127
  if options.only_recursion_depth.present?
128
- depth = options.only_recursion_depth.to_i
128
+ depth = options.only_recursion_depth.to_s.to_i
129
129
  options[:only].dup.each do |class_name|
130
130
  options[:only]+= recurse_into_relationships(@domain.entity_by_name(class_name), depth)
131
131
  end
@@ -177,7 +177,7 @@ module RailsERD
177
177
 
178
178
  def filtered_entities
179
179
  @domain.entities.reject { |entity|
180
- options.exclude.present? && entity.model && [options.exclude].flatten.map(&:to_sym).include?(entity.name.to_sym) or
180
+ options.exclude.present? && [options.exclude].flatten.map(&:to_sym).include?(entity.name.to_sym) or
181
181
  options[:only].present? && entity.model && ![options[:only]].flatten.map(&:to_sym).include?(entity.name.to_sym) or
182
182
  !options.inheritance && entity.specialized? or
183
183
  !options.polymorphism && entity.generalized? or
@@ -78,8 +78,8 @@ module RailsERD
78
78
  # relationship.
79
79
  def foreign_key?
80
80
  @domain.relationships_by_entity_name(@model.name).map(&:associations).flatten.map { |associaton|
81
- associaton.send(Domain.foreign_key_method_name)
82
- }.include?(name)
81
+ associaton.send(Domain.foreign_key_method_name).to_sym
82
+ }.include?(name.to_sym)
83
83
  end
84
84
 
85
85
  # Returns +true+ if this attribute is used for single table inheritance.
@@ -119,7 +119,7 @@ module RailsERD
119
119
  # <tt>:decimal, :precision => 5, :scale => 2/tt>:: decimal (5,2)
120
120
  # <tt>:boolean, :null => false</tt>:: boolean *
121
121
  def type_description
122
- type.to_s.tap do |desc|
122
+ type.to_s.dup.tap do |desc|
123
123
  desc << " #{limit_description}" if limit_description
124
124
  desc << " ∗" if mandatory? && !primary_key? # Add a hair space + low asterisk (Unicode characters)
125
125
  desc << " U" if unique? && !primary_key? && !foreign_key? # Add U if unique but non-key
@@ -93,7 +93,7 @@ module RailsERD
93
93
  end
94
94
 
95
95
  def namespace
96
- $1 if name.match /(.*)::.*/
96
+ $1 if name.match(/(.*)::.*/)
97
97
  end
98
98
 
99
99
  def to_s # @private :nodoc:
@@ -21,8 +21,7 @@ module RailsERD
21
21
  private
22
22
 
23
23
  def association_identity(association)
24
- identifier = association_identifier(association).to_s
25
- Set[identifier, association_owner(association), association_target(association)]
24
+ Set[association_owner(association), association_target(association)]
26
25
  end
27
26
 
28
27
  def association_identifier(association)
@@ -30,7 +30,14 @@ module RailsERD
30
30
  end
31
31
 
32
32
  def abstract_from_models(domain, models)
33
- models.select(&:abstract_class?).collect(&:direct_descendants).flatten.collect { |model|
33
+ abstract_classes = models.select(&:abstract_class?)
34
+ direct_descendants = if ActiveRecord.version >= Gem::Version.new("7.0.0")
35
+ abstract_classes.collect(&:subclasses)
36
+ else
37
+ abstract_classes.collect(&:direct_descendants)
38
+ end
39
+
40
+ direct_descendants.flatten.collect { |model|
34
41
  new(domain, domain.entity_by_name(model.superclass.name), domain.entity_by_name(model.name))
35
42
  }
36
43
  end
@@ -49,7 +49,13 @@ module RailsERD
49
49
  # Returns the domain model name, which is the name of your Rails
50
50
  # application or +nil+ outside of Rails.
51
51
  def name
52
- defined? Rails and Rails.application and Rails.application.class.parent.name
52
+ return unless defined?(Rails) && Rails.application
53
+
54
+ if Rails.application.class.respond_to?(:module_parent)
55
+ Rails.application.class.module_parent.name
56
+ else
57
+ Rails.application.class.parent.name
58
+ end
53
59
  end
54
60
 
55
61
  # Returns all entities of your domain model.
@@ -114,7 +120,32 @@ module RailsERD
114
120
  end
115
121
 
116
122
  def models
117
- @models ||= @source_models.select { |model| check_model_validity(model) }.reject { |model| check_habtm_model(model) }
123
+ @models ||= @source_models
124
+ .reject { |model| tableless_rails_models.include?(model) }
125
+ .select { |model| check_model_validity(model) }
126
+ .reject { |model| check_habtm_model(model) }
127
+ end
128
+
129
+ # Returns Rails model classes defined in the app
130
+ def rails_models
131
+ %w(
132
+ ActionMailbox::InboundEmail
133
+ ActiveStorage::Attachment
134
+ ActiveStorage::Blob
135
+ ActiveStorage::VariantRecord
136
+ ActionText::RichText
137
+ ActionText::EncryptedRichText
138
+ ).map{ |model| Object.const_get(model) rescue nil }.compact
139
+ end
140
+
141
+ def tableless_rails_models
142
+ @tableless_rails_models ||= begin
143
+ if defined? Rails
144
+ rails_models.reject{ |model| model.table_exists? }
145
+ else
146
+ []
147
+ end
148
+ end
118
149
  end
119
150
 
120
151
  def associations
@@ -140,8 +171,7 @@ module RailsERD
140
171
  association.check_validity!
141
172
 
142
173
  if association.options[:polymorphic]
143
- entity_name = association.class_name
144
- entity_by_name(entity_name) or raise "polymorphic interface #{entity_name} does not exist"
174
+ check_polymorphic_association_validity(association)
145
175
  else
146
176
  entity_name = association.klass.name # Raises NameError if the associated class cannot be found.
147
177
  entity_by_name(entity_name) or raise "model #{entity_name} exists, but is not included in domain"
@@ -150,6 +180,17 @@ module RailsERD
150
180
  warn "Ignoring invalid association #{association_description(association)} (#{e.message})"
151
181
  end
152
182
 
183
+ def check_polymorphic_association_validity(association)
184
+ entity_name = association.class_name
185
+ entity = entity_by_name(entity_name)
186
+
187
+ if entity || (entity && entity.generalized?)
188
+ return entity
189
+ else
190
+ raise("polymorphic interface #{entity_name} does not exist")
191
+ end
192
+ end
193
+
153
194
  def association_description(association)
154
195
  "#{association.name.inspect} on #{association.active_record}"
155
196
  end
@@ -1,7 +1,9 @@
1
1
  require 'graphviz/utils'
2
2
 
3
- def say(message)
4
- puts message unless Rake.application.options.silent
3
+ module ErdRakeHelper
4
+ def say(message)
5
+ puts message unless Rake.application.options.silent
6
+ end
5
7
  end
6
8
 
7
9
  namespace :erd do
@@ -19,12 +21,20 @@ namespace :erd do
19
21
  when "true", "yes" then true
20
22
  when "false", "no" then false
21
23
  when /,/ then ENV[option].split(/\s*,\s*/)
22
- else ENV[option].to_sym
24
+ when /^\d+$/ then ENV[option].to_i
25
+ else
26
+ if option == 'only'
27
+ [ENV[option]]
28
+ else
29
+ ENV[option].to_sym
30
+ end
23
31
  end
24
32
  end
25
33
  end
26
34
 
27
35
  task :load_models do
36
+ include ErdRakeHelper
37
+
28
38
  say "Loading application environment..."
29
39
  Rake::Task[:environment].invoke
30
40
 
@@ -49,12 +59,14 @@ namespace :erd do
49
59
  end
50
60
 
51
61
  task :generate => [:check_dependencies, :options, :load_models] do
62
+ include ErdRakeHelper
63
+
52
64
  say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
53
65
 
54
66
  require "rails_erd/diagram/graphviz"
55
67
  file = RailsERD::Diagram::Graphviz.create
56
68
 
57
- say "Done! Saved diagram to #{file}."
69
+ say "Done! Saved diagram to ./#{file}"
58
70
  end
59
71
  end
60
72
 
@@ -1,4 +1,4 @@
1
1
  module RailsERD
2
- VERSION = "1.5.2"
2
+ VERSION = "1.7.2"
3
3
  BANNER = "RailsERD #{VERSION}"
4
4
  end
data/lib/rails_erd.rb CHANGED
@@ -40,6 +40,7 @@ module RailsERD
40
40
  :disconnected, true,
41
41
  :filename, "erd",
42
42
  :filetype, :pdf,
43
+ :fonts, {},
43
44
  :indirect, true,
44
45
  :inheritance, false,
45
46
  :markup, true,
data/test/test_helper.rb CHANGED
@@ -1,15 +1,12 @@
1
1
  require "rubygems"
2
2
  require "bundler/setup"
3
+ require 'pry'
4
+ require 'pry-nav'
3
5
 
4
6
  require "active_record"
5
7
 
6
- if ActiveSupport::VERSION::MAJOR >= 4
7
- require "minitest/autorun"
8
- require 'mocha/mini_test'
9
- else
10
- require "test/unit"
11
- require 'mocha/test_unit'
12
- end
8
+ require "minitest/autorun"
9
+ require 'mocha/minitest'
13
10
 
14
11
  require "rails_erd/domain"
15
12
 
@@ -19,6 +16,14 @@ if ActiveSupport::TestCase.respond_to?(:test_order=)
19
16
  ActiveSupport::TestCase.test_order = :random
20
17
  end
21
18
 
19
+ # Patch to make Rails 6.1 work.
20
+ module Kernel
21
+ # class_eval on an object acts like singleton_class.class_eval.
22
+ def class_eval(*args, &block)
23
+ singleton_class.class_eval(*args, &block)
24
+ end
25
+ end
26
+
22
27
  class ActiveSupport::TestCase
23
28
  include RailsERD
24
29
 
@@ -29,9 +34,11 @@ class ActiveSupport::TestCase
29
34
  opts = if pk then { :primary_key => pk } else { :id => false } end
30
35
  ActiveRecord::Schema.instance_eval do
31
36
  suppress_messages do
32
- create_table table, opts do |t|
33
- columns.each do |column, type|
34
- t.send type, column
37
+ unless ActiveRecord::Base.connection.table_exists?(table)
38
+ create_table table, **opts do |t|
39
+ columns.each do |column, type|
40
+ t.send type, column
41
+ end
35
42
  end
36
43
  end
37
44
  end
@@ -42,7 +49,8 @@ class ActiveSupport::TestCase
42
49
  def add_column(*args)
43
50
  ActiveRecord::Schema.instance_eval do
44
51
  suppress_messages do
45
- add_column(*args)
52
+ opts = args.slice!(3) || {}
53
+ add_column(*args, **opts)
46
54
  end
47
55
  end
48
56
  ActiveRecord::Base.clear_cache!
@@ -75,8 +83,9 @@ class ActiveSupport::TestCase
75
83
  superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
76
84
  columns = args.first || {}
77
85
  klass = Object.const_set name.to_sym, Class.new(superklass)
86
+
78
87
  if superklass == ActiveRecord::Base || superklass.abstract_class?
79
- create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key rescue nil
88
+ create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key
80
89
  end
81
90
  klass.class_eval(&block) if block_given?
82
91
  Object.const_get(name.to_sym)
@@ -173,6 +182,11 @@ class ActiveSupport::TestCase
173
182
 
174
183
  parts[1..-1].inject([[Object, parts.first.to_sym]]) do |pairs,string|
175
184
  last_parent, last_child = pairs.last
185
+ # Fixes for Rails 6. No idea if this is actually correct as I can't decipher what the heck is going on in this
186
+ # code.
187
+ if last_child == :ActiveRecord || last_child == :primary
188
+ break []
189
+ end
176
190
 
177
191
  break pairs unless last_parent.const_defined?(last_child)
178
192
 
@@ -196,11 +210,23 @@ class ActiveSupport::TestCase
196
210
  model.reset_column_information
197
211
  remove_fully_qualified_constant(model.name)
198
212
  end
213
+
199
214
  tables_and_views.each do |table|
200
215
  ActiveRecord::Base.connection.drop_table table
201
216
  end
202
- ActiveRecord::Base.direct_descendants.clear
203
- ActiveSupport::Dependencies::Reference.clear!
217
+
218
+ if ActiveRecord.version >= Gem::Version.new("7.0.0")
219
+ ActiveSupport::DescendantsTracker.clear(ActiveRecord::Base.subclasses)
220
+ elsif ActiveRecord.version >= Gem::Version.new("6.0.0.rc1")
221
+ cv = ActiveSupport::DescendantsTracker.class_variable_get(:@@direct_descendants)
222
+ cv.delete(ActiveRecord::Base)
223
+ ActiveSupport::DescendantsTracker.class_variable_set(:@@direct_descendants, cv)
224
+ ActiveSupport::Dependencies::Reference.clear!
225
+ else
226
+ ActiveRecord::Base.direct_descendants.clear
227
+ ActiveSupport::Dependencies::Reference.clear!
228
+ end
229
+
204
230
  ActiveRecord::Base.clear_cache!
205
231
  end
206
232
  end
@@ -3,9 +3,9 @@ require File.expand_path("../test_helper", File.dirname(__FILE__))
3
3
 
4
4
  class AttributeTest < ActiveSupport::TestCase
5
5
  def with_native_limit(type, new_limit)
6
- ActiveRecord::Base.connection.class_eval do
6
+ ActiveRecord::Base.connection.singleton_class.class_eval do
7
7
  undef :native_database_types
8
- define_method :native_database_types do
8
+ define_method(:native_database_types) do
9
9
  super().tap do |types|
10
10
  types[type][:limit] = new_limit
11
11
  end
@@ -13,9 +13,9 @@ class AttributeTest < ActiveSupport::TestCase
13
13
  end
14
14
  yield
15
15
  ensure
16
- ActiveRecord::Base.connection.class_eval do
16
+ ActiveRecord::Base.connection.singleton_class.class_eval do
17
17
  undef :native_database_types
18
- define_method :native_database_types do
18
+ define_method(:native_database_types) do
19
19
  super()
20
20
  end
21
21
  end
@@ -266,14 +266,14 @@ class AttributeTest < ActiveSupport::TestCase
266
266
  end
267
267
 
268
268
  test "limit should return nil for oddball column types that misuse the limit attribute" do
269
- create_model "Business", :location => :integer
270
- attribute = create_attribute(Business, "location")
271
- attribute.column.class_eval do
272
- define_method :limit do
269
+ create_model "Business", :location => :integer do
270
+ define_singleton_method :limit do
273
271
  # https://github.com/voormedia/rails-erd/issues/21
274
272
  { :srid => 4326, :type => "point", :geographic => true }
275
273
  end
276
274
  end
275
+
276
+ attribute = create_attribute(Business, "location")
277
277
  assert_nil attribute.limit
278
278
  end
279
279
 
@@ -306,13 +306,12 @@ class AttributeTest < ActiveSupport::TestCase
306
306
  end
307
307
 
308
308
  test "scale should return nil for oddball column types that misuse the scale attribute" do
309
- create_model "Kobold", :size => :integer
310
- attribute = create_attribute(Kobold, "size")
311
- attribute.column.class_eval do
309
+ create_model "Kobold", :size => :integer do
312
310
  define_method :scale do
313
311
  1..5
314
312
  end
315
313
  end
314
+ attribute = create_attribute(Kobold, "size")
316
315
  assert_nil attribute.scale
317
316
  end
318
317
  end
@@ -61,6 +61,29 @@ class ConfigTest < ActiveSupport::TestCase
61
61
  assert_equal expected_hash, RailsERD::Config.load
62
62
  end
63
63
 
64
+ test "load_config_file should return a hash from the configured config file when a new config file is given as an argument" do
65
+ set_local_config_file_to("erdconfig.another_example")
66
+
67
+ expected_hash = {
68
+ attributes: [:content, :foreign_key, :inheritance, :false],
69
+ disconnected: true,
70
+ filename: "erd",
71
+ filetype: :pdf,
72
+ indirect: true,
73
+ inheritance: false,
74
+ markup: true,
75
+ notation: :simple,
76
+ orientation: "horizontal",
77
+ polymorphism: false,
78
+ warn: true,
79
+ title: "sample title",
80
+ exclude: [],
81
+ only: []
82
+ }
83
+
84
+ assert_equal expected_hash, RailsERD::Config.load("test/support_files/erdconfig.example")
85
+ end
86
+
64
87
  test "load_config_gile should return a hash from CURRENT_CONFIG_FILE overriding USER_WIDE_CONFIG_FILE when both of them exist." do
65
88
  set_user_config_file_to("erdconfig.example")
66
89
  set_local_config_file_to("erdconfig.another_example")
@@ -92,6 +115,12 @@ class ConfigTest < ActiveSupport::TestCase
92
115
  assert_equal [:content, :primary_keys], normalize_value(:attributes, ["content", "primary_keys"])
93
116
  end
94
117
 
118
+ test "normalize_value should return hash with symbol keys when key is :fonts and value is a hash." do
119
+ fonts_value = { "normal" => "Arial", "bold" => "Arial Bold", "italic" => "Arial Italic" }
120
+ expected = {:normal => "Arial", :bold => "Arial Bold", :italic => "Arial Italic"}
121
+ assert_equal expected, normalize_value(:fonts, fonts_value)
122
+ end
123
+
95
124
  def normalize_value(key, value)
96
125
  RailsERD::Config.new.send(:normalize_value, key, value)
97
126
  end
@@ -136,6 +136,15 @@ class DiagramTest < ActiveSupport::TestCase
136
136
  assert_equal [Book], retrieve_entities(:exclude => [:Author, :Editor]).map(&:model)
137
137
  end
138
138
 
139
+ test "generate should filter excluded polymorphic entities" do
140
+ create_model "Cannon"
141
+ create_model "Galleon" do
142
+ has_many :cannons, as: :defensible
143
+ end
144
+ assert_equal ["Cannon", "Galleon"], retrieve_entities(polymorphism: true, exclude: :Defensible).map(&:name)
145
+ end
146
+
147
+
139
148
  test "generate should include only specified entity" do
140
149
  create_model "Book"
141
150
  create_model "Author"
@@ -127,13 +127,21 @@ 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
- create_model "Foo", :bar => :references, :special_bar => :references do
131
- belongs_to :bar
132
- end
133
- create_model "Bar" do
134
- has_many :foos, :foreign_key => :special_bar_id
130
+ # TODO: Once we drop Rails 3.2 support, we _should_ be able to drop the
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")
135
+
136
+ create_model "Foo", :bar => :references, :special_bar => :references do
137
+ belongs_to :bar
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)
135
144
  end
136
- assert_equal [Domain::Relationship] * 2, Domain.generate.relationships.collect(&:class)
137
145
  end
138
146
 
139
147
  test "relationships should use model name first in alphabet as source for many to many relationships" do
@@ -275,4 +283,14 @@ class DomainTest < ActiveSupport::TestCase
275
283
  end
276
284
  assert_match(/Ignoring invalid model Foo \(table foos does not exist\)/, output)
277
285
  end
286
+
287
+ test "entities should not output a warning when a Rails model table does not exist" do
288
+ module ActionMailbox; end
289
+
290
+ Object.const_set :InboundEmail, ActionMailbox
291
+ output = collect_stdout do
292
+ Domain.generate.entities
293
+ end
294
+ assert_equal "", output
295
+ end
278
296
  end
@@ -186,6 +186,16 @@ class GraphvizTest < ActiveSupport::TestCase
186
186
  assert_equal '"Domain model\n\n"', diagram.graph.graph[:label].to_s
187
187
  end
188
188
 
189
+ test "generate should use default value for fontname attribute" do
190
+ create_simple_domain
191
+ assert_equal "\"#{RailsERD::Config.font_names_based_on_os[:bold]}\"", diagram.graph.graph[:fontname].to_s
192
+ end
193
+
194
+ test "generate should add set value for fontname attribute" do
195
+ create_simple_domain
196
+ assert_equal '"Arial Bold"', diagram(fonts: {bold: "Arial Bold"}).graph.graph[:fontname].to_s
197
+ end
198
+
189
199
  test "generate should add default value for splines attribute" do
190
200
  create_simple_domain
191
201
  assert_equal '"spline"', diagram.graph.graph[:splines].to_s
@@ -304,13 +314,21 @@ class GraphvizTest < ActiveSupport::TestCase
304
314
  end
305
315
 
306
316
  test "generate should create edge for each relationship" do
307
- create_model "Foo", :bar => :references do
308
- belongs_to :bar
309
- end
310
- create_model "Bar", :foo => :references do
311
- belongs_to :foo
317
+ # TODO: Once we drop Rails 3.2 support, we _should_ be able to drop the
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
329
+
330
+ assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
312
331
  end
313
- assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
314
332
  end
315
333
 
316
334
  test "generate should create edge to polymorphic entity if polymorphism is true" do
@@ -173,4 +173,22 @@ Error occurred while loading application: FooBar (RuntimeError)
173
173
  Rake::Task["erd:options"].execute
174
174
  assert_equal %w[content timestamps], RailsERD.options.attributes
175
175
  end
176
+
177
+ test "options task should set known integer command line options when value is only digits" do
178
+ ENV["only_recursion_depth"] = "2"
179
+ Rake::Task["erd:options"].execute
180
+ assert_equal 2, RailsERD.options.only_recursion_depth
181
+ end
182
+
183
+ test "options task sets known command line options as symbols when not boolean or numeric" do
184
+ ENV["only_recursion_depth"] = "test"
185
+ Rake::Task["erd:options"].execute
186
+ assert_equal :test, RailsERD.options.only_recursion_depth
187
+ end
188
+
189
+ test "options task should set single parameter to only as array xxx" do
190
+ ENV["only"] = "model"
191
+ Rake::Task["erd:options"].execute
192
+ assert_equal ["model"], RailsERD.options.only
193
+ end
176
194
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-erd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rolf Timmermans
8
8
  - Kerri Miller
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-05-24 00:00:00.000000000 Z
12
+ date: 2022-08-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -17,28 +17,28 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '3.2'
20
+ version: '4.2'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '3.2'
27
+ version: '4.2'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: activesupport
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '3.2'
34
+ version: '4.2'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '3.2'
41
+ version: '4.2'
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: ruby-graphviz
44
44
  requirement: !ruby/object:Gem::Requirement
@@ -67,6 +67,34 @@ dependencies:
67
67
  - - "~>"
68
68
  - !ruby/object:Gem::Version
69
69
  version: 0.2.0
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry-nav
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
70
98
  description: Automatically generate an entity-relationship diagram (ERD) for your
71
99
  Rails models.
72
100
  email:
@@ -119,7 +147,7 @@ homepage: https://github.com/voormedia/rails-erd
119
147
  licenses:
120
148
  - MIT
121
149
  metadata: {}
122
- post_install_message:
150
+ post_install_message:
123
151
  rdoc_options: []
124
152
  require_paths:
125
153
  - lib
@@ -127,16 +155,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
155
  requirements:
128
156
  - - ">="
129
157
  - !ruby/object:Gem::Version
130
- version: 1.9.3
158
+ version: '2.2'
131
159
  required_rubygems_version: !ruby/object:Gem::Requirement
132
160
  requirements:
133
161
  - - ">="
134
162
  - !ruby/object:Gem::Version
135
163
  version: '0'
136
164
  requirements: []
137
- rubyforge_project:
138
- rubygems_version: 2.6.10
139
- signing_key:
165
+ rubygems_version: 3.3.15
166
+ signing_key:
140
167
  specification_version: 4
141
168
  summary: Entity-relationship diagram for your Rails models.
142
169
  test_files: