rails-erd 1.5.2 → 1.7.2

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