rails-erd 1.4.7 → 1.6.1

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
2
  SHA1:
3
- metadata.gz: e10c973dc76bbb05773bc6920678cc060878c740
4
- data.tar.gz: 42af4a884c51e266b993d255a49e2647c2d4e368
3
+ metadata.gz: 16bfef1b79087e3017df7723bef8cf286df5a812
4
+ data.tar.gz: 7162f90b6dce224a0ec89693e7d307fbc15a9b45
5
5
  SHA512:
6
- metadata.gz: 9dbb498dd6dbfb15a243d3957e5172ab0fb6ffb54c39ba5ba4aac13ea7fb8a38d2272e07fd6b8b67651e39ed842620757b387c23cd77f4325d1736e3e5706efe
7
- data.tar.gz: ca3b2a15e3db16434341e6d8c2b439b0a97fcfd9ed0304b5eaf07d1e571b11d82ff44a0ffc6fbd352d0dbae8eb7c380b98beaef57d3ffe16ced26a7f4cbf4b81
6
+ metadata.gz: 34e2582512bfe6313f626d4de969eebc328415c97456b1cd151df3e19d75e55cc0b65a9ded7ba0c363d3708072d001266d96657e2a8669ee6a7c4ca7b0cc3ee0
7
+ data.tar.gz: 16ddf4ba4c7d640a4c139905fe6f238f76c70cf20712c467ebb9bf9075f0ee6603c0c532114b86bd0e66f7d275f5ae0200802e91c8978a469c6e39208dd3c709
data/README.md CHANGED
@@ -2,11 +2,11 @@ Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
2
2
  ========================================================================
3
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)
4
4
 
5
- [Rails ERD](http://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.
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
 
7
7
  The second goal of Rails ERD is to provide you with a tool to inspect your application's domain model. If you don't like the default output, it is very easy to use the API to build your own diagrams.
8
8
 
9
- Rails ERD was created specifically for Rails and works on versions 3.0-4.2. It uses Active Record's built-in reflection capabilities to figure out how your models are associated.
9
+ Rails ERD was created specifically for Rails and works on versions 3.0-5.0. It uses Active Record's built-in reflection capabilities to figure out how your models are associated.
10
10
 
11
11
 
12
12
  Preview
@@ -14,34 +14,34 @@ Preview
14
14
 
15
15
  Here's an example entity-relationship diagram that was generated by Rails ERD:
16
16
 
17
- ![Entity-Relationship Diagram](http://voormedia.github.io/rails-erd/images/entity-relationship-diagram.png)
17
+ ![Entity-Relationship Diagram](https://voormedia.github.io/rails-erd/images/entity-relationship-diagram.png)
18
18
 
19
- Browse the [gallery](http://voormedia.github.io/rails-erd/gallery.html) for more example diagrams.
19
+ Browse the [gallery](https://voormedia.github.io/rails-erd/gallery.html) for more example diagrams.
20
20
 
21
21
 
22
22
  Requirements
23
23
  ---------------
24
24
 
25
25
  * Ruby 1.9.3+
26
- * ActiveRecord 3.x
26
+ * ActiveRecord 3.x - 5.0.x
27
27
 
28
28
  Getting started
29
29
  ---------------
30
30
 
31
- See the [installation instructions](http://voormedia.github.io/rails-erd/install.html) for a complete description of how to install Rails ERD. Here's a summary:
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?](http://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
+ * Add <tt>gem 'rails-erd', group: :development</tt> to your application's Gemfile
36
36
 
37
37
  * Run <tt>bundle exec erd</tt>
38
38
 
39
39
  ### Configuration
40
40
 
41
41
 
42
- Rails ERD has the ability to be configured via the command line or through the use of a YAML file with configuration options set. It will look for this file first at `~/.erdconfig` and then `./.erdconfig` (which will override any settings in `~/.erdconfig`). The format of the file is as follows (shown here with the default settings used if no `.erdconfig` is found). More information on [customization options](http://voormedia.github.io/rails-erd/customise.html) can be found in Rails ERD's project documentation.
42
+ Rails ERD has the ability to be configured via the command line or through the use of a YAML file with configuration options set. It will look for this file first at `~/.erdconfig` and then `./.erdconfig` (which will override any settings in `~/.erdconfig`). The format of the file is as follows (shown here with the default settings used if no `.erdconfig` is found). More information on [customization options](https://voormedia.github.io/rails-erd/customise.html) can be found in Rails ERD's project documentation.
43
43
 
44
- ```
44
+ ```yaml
45
45
  attributes:
46
46
  - content
47
47
  - foreign_key
@@ -60,14 +60,22 @@ warn: true
60
60
  title: sample title
61
61
  exclude: null
62
62
  only: null
63
+ only_recursion_depth: null
63
64
  prepend_primary: false
65
+ cluster: false
66
+ splines: spline
64
67
  ```
65
68
 
69
+ Auto generation
70
+ ---------------
71
+
72
+ * Run <tt>bundle exec rails g erd:install</tt>
73
+ * Run <tt>bundle exec rails db:migrate</tt>, then the diagram is generated
66
74
 
67
75
  Learn more
68
76
  ----------
69
77
 
70
- More information can be found on [Rails ERD's project homepage](http://voormedia.github.io/rails-erd/).
78
+ More information can be found on [Rails ERD's project homepage](https://voormedia.github.io/rails-erd/).
71
79
 
72
80
  If you wish to extend or customise Rails ERD, take a look at the [API documentation](http://rubydoc.info/github/voormedia/rails-erd/frames).
73
81
 
@@ -2,5 +2,5 @@
2
2
  # NOTE: are sensitive to local FS writes, and besides -- it's just not proper
3
3
  # NOTE: to have a dev-mode tool do its thing in production.
4
4
  if Rails.env.development?
5
- Erd.load_tasks
5
+ RailsERD.load_tasks
6
6
  end
data/lib/rails_erd.rb CHANGED
@@ -51,9 +51,21 @@ module RailsERD
51
51
  :title, true,
52
52
  :exclude, nil,
53
53
  :only, nil,
54
- :prepend_primary, false
54
+ :only_recursion_depth, nil,
55
+ :prepend_primary, false,
56
+ :cluster, false,
55
57
  ]
56
58
  end
59
+
60
+ def loaded_tasks=(val); @loaded_tasks = val; end
61
+ def loaded_tasks; return @loaded_tasks; end
62
+
63
+ def load_tasks
64
+ return if(self.loaded_tasks)
65
+ self.loaded_tasks = true
66
+
67
+ Dir[File.join(File.dirname(__FILE__), 'tasks', '**/*.rake')].each { |rake| load rake }
68
+ end
57
69
  end
58
70
 
59
71
  module Inspectable # @private :nodoc:
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
@@ -49,6 +50,11 @@ Choice.options do
49
50
  desc "Filter to only include listed models in diagram."
50
51
  end
51
52
 
53
+ option :only_recursion_depth do
54
+ long "--only_recursion_depth=INTEGER"
55
+ desc "Recurses into relations specified by --only upto a depth N."
56
+ end
57
+
52
58
  option :exclude do
53
59
  long "--exclude"
54
60
  desc "Filter to exclude listed models in diagram."
@@ -64,6 +70,16 @@ Choice.options do
64
70
  desc "Ensure primary key is at start of attribute list"
65
71
  end
66
72
 
73
+ option :cluster do
74
+ long "--cluster"
75
+ desc "Display models in subgraphs based on their namespace."
76
+ end
77
+
78
+ option :splines do
79
+ long "--splines=SPLINE_TYPE"
80
+ desc "Control how edges are represented. See http://www.graphviz.org/doc/info/attrs.html#d:splines for values."
81
+ end
82
+
67
83
  separator ""
68
84
  separator "Output options:"
69
85
 
@@ -110,6 +126,12 @@ Choice.options do
110
126
  exit
111
127
  end
112
128
  end
129
+
130
+ option :config_file do
131
+ short "-c"
132
+ long "--config=FILENAME"
133
+ desc "Configuration file to use"
134
+ end
113
135
  end
114
136
 
115
137
  module RailsERD
@@ -128,6 +150,9 @@ module RailsERD
128
150
  opts[key.to_sym] = value
129
151
  end
130
152
  end
153
+ if options[:config_file] && options[:config_file] != ''
154
+ RailsERD.options = RailsERD.default_options.merge(Config.load(options[:config_file]))
155
+ end
131
156
  new(path, options).start
132
157
  end
133
158
  end
@@ -149,9 +174,17 @@ module RailsERD
149
174
 
150
175
  def load_application
151
176
  $stderr.puts "Loading application in '#{File.basename(path)}'..."
152
- # TODO: Add support for different kinds of environment.
153
- require "#{path}/config/environment"
154
- Rails.application.eager_load!
177
+ begin
178
+ environment_path = "#{path}/config/environment.rb"
179
+ require environment_path
180
+ rescue ::LoadError
181
+ puts "Please create a file in '#{environment_path}' that loads your application environment."
182
+ raise
183
+ end
184
+ if defined? Rails
185
+ Rails.application.eager_load!
186
+ Rails.application.config.eager_load_namespaces.each(&:eager_load!) if Rails.application.config.respond_to?(:eager_load_namespaces)
187
+ end
155
188
  rescue TypeError
156
189
  end
157
190
 
@@ -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
@@ -63,8 +67,10 @@ module RailsERD
63
67
  # [<string>]
64
68
  when :only, :exclude
65
69
  Array(value).join(",").split(",").map { |v| v.strip }
70
+
66
71
  # true | false
67
- when :disconnected, :indirect, :inheritance, :markup, :polymorphism, :warn
72
+ when :disconnected, :indirect, :inheritance, :markup, :polymorphism,
73
+ :warn, :cluster
68
74
  !!value
69
75
 
70
76
  # nil | <string>
@@ -7,7 +7,7 @@ module RailsERD
7
7
  # and (optionally) +save+.
8
8
  #
9
9
  # As an example, a diagram class that generates code that can be used with
10
- # yUML (http://yuml.me) can be as simple as:
10
+ # yUML (https://yuml.me) can be as simple as:
11
11
  #
12
12
  # require "rails_erd/diagram"
13
13
  #
@@ -124,6 +124,13 @@ module RailsERD
124
124
  # internally by Diagram#create.
125
125
  def generate
126
126
  instance_eval(&callbacks[:setup])
127
+ if options.only_recursion_depth.present?
128
+ depth = options.only_recursion_depth.to_s.to_i
129
+ options[:only].dup.each do |class_name|
130
+ options[:only]+= recurse_into_relationships(@domain.entity_by_name(class_name), depth)
131
+ end
132
+ options[:only].uniq!
133
+ end
127
134
 
128
135
  filtered_entities.each do |entity|
129
136
  instance_exec entity, filtered_attributes(entity), &callbacks[:each_entity]
@@ -138,6 +145,26 @@ module RailsERD
138
145
  end
139
146
  end
140
147
 
148
+ def recurse_into_relationships(entity, max_level, current_level = 0)
149
+ return [] unless entity
150
+ return [] if max_level == current_level
151
+
152
+ relationships = entity.relationships.reject{|r| r.indirect? || r.recursive?}
153
+
154
+ relationships.map do |relationship|
155
+ other_entitiy = if relationship.source == entity
156
+ relationship.destination
157
+ else
158
+ relationship.source
159
+ end
160
+ if other_entitiy and !other_entitiy.generalized?
161
+ [other_entitiy.name] + recurse_into_relationships(other_entitiy, max_level, current_level + 1)
162
+ else
163
+ []
164
+ end
165
+ end.flatten.uniq
166
+ end
167
+
141
168
  def save
142
169
  instance_eval(&callbacks[:save])
143
170
  end
@@ -150,8 +177,8 @@ module RailsERD
150
177
 
151
178
  def filtered_entities
152
179
  @domain.entities.reject { |entity|
153
- options.exclude.present? && entity.model && [options.exclude].flatten.map(&:to_sym).include?(entity.name.to_sym) or
154
- options.only.present? && entity.model && ![options.only].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
+ options[:only].present? && entity.model && ![options[:only]].flatten.map(&:to_sym).include?(entity.name.to_sym) or
155
182
  !options.inheritance && entity.specialized? or
156
183
  !options.polymorphism && entity.generalized? or
157
184
  !options.disconnected && entity.disconnected?
@@ -62,7 +62,8 @@ module RailsERD
62
62
  concentrate: true,
63
63
  labelloc: :t,
64
64
  fontsize: 13,
65
- fontname: FONTS[:bold]
65
+ fontname: FONTS[:bold],
66
+ splines: 'spline'
66
67
  }
67
68
 
68
69
  # Default node attributes.
@@ -85,6 +86,11 @@ module RailsERD
85
86
  labeldistance: 1.8,
86
87
  }
87
88
 
89
+ # Default cluster attributes.
90
+ CLUSTER_ATTRIBUTES = {
91
+ margin: "10,10"
92
+ }
93
+
88
94
  module Simple
89
95
  def entity_style(entity, attributes)
90
96
  {}.tap do |options|
@@ -188,6 +194,9 @@ module RailsERD
188
194
  # Title of the graph itself.
189
195
  graph[:label] = "#{title}\\n\\n" if title
190
196
 
197
+ # Style of splines
198
+ graph[:splines] = options.splines unless options.splines.nil?
199
+
191
200
  # Setup notation options.
192
201
  extend self.class.const_get(options.notation.to_s.capitalize.to_sym)
193
202
  end
@@ -210,7 +219,16 @@ module RailsERD
210
219
  end
211
220
 
212
221
  each_entity do |entity, attributes|
213
- draw_node entity.name, entity_options(entity, attributes)
222
+ if options[:cluster] && entity.namespace
223
+ cluster_name = "cluster_#{entity.namespace}"
224
+ cluster_options = CLUSTER_ATTRIBUTES.merge(label: entity.namespace)
225
+ cluster = graph.get_graph(cluster_name) ||
226
+ graph.add_graph(cluster_name, cluster_options)
227
+
228
+ draw_cluster_node cluster, entity.name, entity_options(entity, attributes)
229
+ else
230
+ draw_node entity.name, entity_options(entity, attributes)
231
+ end
214
232
  end
215
233
 
216
234
  each_specialization do |specialization|
@@ -233,15 +251,19 @@ module RailsERD
233
251
  private
234
252
 
235
253
  def node_exists?(name)
236
- !!graph.get_node(escape_name(name))
254
+ !!graph.search_node(escape_name(name))
237
255
  end
238
256
 
239
257
  def draw_node(name, options)
240
258
  graph.add_nodes escape_name(name), options
241
259
  end
242
260
 
261
+ def draw_cluster_node(cluster, name, options)
262
+ cluster.add_nodes escape_name(name), options
263
+ end
264
+
243
265
  def draw_edge(from, to, options)
244
- graph.add_edges graph.get_node(escape_name(from)), graph.get_node(escape_name(to)), options if node_exists?(from) and node_exists?(to)
266
+ graph.add_edges graph.search_node(escape_name(from)), graph.search_node(escape_name(to)), options if node_exists?(from) and node_exists?(to)
245
267
  end
246
268
 
247
269
  def escape_name(name)
@@ -288,7 +310,12 @@ module RailsERD
288
310
  end
289
311
 
290
312
  def read_template(type)
291
- 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
292
319
  end
293
320
  end
294
321
  end
@@ -1,4 +1,4 @@
1
- <% if options.orientation == :vertical %>{<% end %>
1
+ <% if options.orientation == :horizontal %>{<% end %>
2
2
  <table border="0" align="center" cellspacing="0.5" cellpadding="0" width="<%= NODE_WIDTH + 4 %>">
3
3
  <tr><td align="center" valign="bottom" width="<%= NODE_WIDTH %>"><font face="<%= FONTS[:bold] %>" point-size="11"><%= entity.name %></font></td></tr>
4
4
  </table>
@@ -11,4 +11,4 @@
11
11
  </table>
12
12
  <% else %>
13
13
  <% end %>
14
- <% if options.orientation == :vertical %>}<% end %>
14
+ <% if options.orientation == :horizontal %>}<% end %>
@@ -1,4 +1,4 @@
1
- <% if options.orientation == :vertical %>{<% end %><%= entity.name %><% if attributes.any? %>
1
+ <% if options.orientation == :horizontal %>{<% end %><%= entity.name %><% if attributes.any? %>
2
2
  |<% attributes.each do |attribute| %><%=
3
3
  attribute %> (<%= attribute.type_description %>)
4
- <% end %><% end %><% if options.orientation == :vertical %>}<% end %>
4
+ <% end %><% end %><% if options.orientation == :horizontal %>}<% 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.
@@ -140,8 +146,7 @@ module RailsERD
140
146
  association.check_validity!
141
147
 
142
148
  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"
149
+ check_polymorphic_association_validity(association)
145
150
  else
146
151
  entity_name = association.klass.name # Raises NameError if the associated class cannot be found.
147
152
  entity_by_name(entity_name) or raise "model #{entity_name} exists, but is not included in domain"
@@ -150,6 +155,17 @@ module RailsERD
150
155
  warn "Ignoring invalid association #{association_description(association)} (#{e.message})"
151
156
  end
152
157
 
158
+ def check_polymorphic_association_validity(association)
159
+ entity_name = association.class_name
160
+ entity = entity_by_name(entity_name)
161
+
162
+ if entity || (entity && entity.generalized?)
163
+ return entity
164
+ else
165
+ raise("polymorphic interface #{entity_name} does not exist")
166
+ end
167
+ end
168
+
153
169
  def association_description(association)
154
170
  "#{association.name.inspect} on #{association.active_record}"
155
171
  end
@@ -92,6 +92,10 @@ module RailsERD
92
92
  @children ||= domain.specializations_by_entity_name(name).map(&:specialized)
93
93
  end
94
94
 
95
+ def namespace
96
+ $1 if name.match(/(.*)::.*/)
97
+ end
98
+
95
99
  def to_s # @private :nodoc:
96
100
  name
97
101
  end
@@ -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,7 @@ module RailsERD
30
30
  end
31
31
 
32
32
  def abstract_from_models(domain, models)
33
- models.select(&:abstract_class?).collect(&:descendants).flatten.collect { |model|
33
+ models.select(&:abstract_class?).collect(&:direct_descendants).flatten.collect { |model|
34
34
  new(domain, domain.entity_by_name(model.superclass.name), domain.entity_by_name(model.name))
35
35
  }
36
36
  end
@@ -1,15 +1,31 @@
1
+ require 'graphviz/utils'
2
+
1
3
  def say(message)
2
4
  puts message unless Rake.application.options.silent
3
5
  end
4
6
 
5
7
  namespace :erd do
8
+ task :check_dependencies do
9
+ include GraphViz::Utils
10
+ unless find_executable("dot", nil)
11
+ raise "Unable to find GraphViz's \"dot\" executable. Please " \
12
+ "visit https://voormedia.github.io/rails-erd/install.html for installation instructions."
13
+ end
14
+ end
15
+
6
16
  task :options do
7
17
  (RailsERD.options.keys.map(&:to_s) & ENV.keys).each do |option|
8
18
  RailsERD.options[option.to_sym] = case ENV[option]
9
19
  when "true", "yes" then true
10
20
  when "false", "no" then false
11
21
  when /,/ then ENV[option].split(/\s*,\s*/)
12
- else ENV[option].to_sym
22
+ when /^\d+$/ then ENV[option].to_i
23
+ else
24
+ if option == 'only'
25
+ [ENV[option]]
26
+ else
27
+ ENV[option].to_sym
28
+ end
13
29
  end
14
30
  end
15
31
  end
@@ -21,6 +37,10 @@ namespace :erd do
21
37
  say "Loading code in search of Active Record models..."
22
38
  begin
23
39
  Rails.application.eager_load!
40
+
41
+ if Rails.application.respond_to?(:config) && !Rails.application.config.nil?
42
+ Rails.application.config.eager_load_namespaces.each(&:eager_load!) if Rails.application.config.respond_to?(:eager_load_namespaces)
43
+ end
24
44
  rescue Exception => err
25
45
  if Rake.application.options.trace
26
46
  raise
@@ -34,7 +54,7 @@ namespace :erd do
34
54
  raise "Active Record was not loaded." unless defined? ActiveRecord
35
55
  end
36
56
 
37
- task :generate => [:options, :load_models] do
57
+ task :generate => [:check_dependencies, :options, :load_models] do
38
58
  say "Generating Entity-Relationship Diagram for #{ActiveRecord::Base.descendants.length} models..."
39
59
 
40
60
  require "rails_erd/diagram/graphviz"
@@ -1,4 +1,4 @@
1
1
  module RailsERD
2
- VERSION = "1.4.7"
2
+ VERSION = "1.6.1"
3
3
  BANNER = "RailsERD #{VERSION}"
4
4
  end
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
 
@@ -48,10 +53,34 @@ class ActiveSupport::TestCase
48
53
  ActiveRecord::Base.clear_cache!
49
54
  end
50
55
 
56
+ def create_module_model(full_name,*args,&block)
57
+ superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
58
+
59
+ names = full_name.split('::')
60
+
61
+ parent_module = names[0..-1].inject(Object) do |parent,child|
62
+ parent = parent.const_set(child.to_sym, Module.new)
63
+ end
64
+
65
+ parent_module ||= Object
66
+ name = names.last
67
+
68
+ columns = args.first || {}
69
+ klass = parent_module.const_set name.to_sym, Class.new(superklass)
70
+ konstant = parent_module.const_get(name.to_sym)
71
+
72
+ if superklass == ActiveRecord::Base || superklass.abstract_class?
73
+ create_table konstant.table_name, columns, konstant.primary_key rescue nil
74
+ end
75
+ klass.class_eval(&block) if block_given?
76
+ konstant
77
+ end
78
+
51
79
  def create_model(name, *args, &block)
52
80
  superklass = args.first.kind_of?(Class) ? args.shift : ActiveRecord::Base
53
81
  columns = args.first || {}
54
82
  klass = Object.const_set name.to_sym, Class.new(superklass)
83
+
55
84
  if superklass == ActiveRecord::Base || superklass.abstract_class?
56
85
  create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key rescue nil
57
86
  end
@@ -143,18 +172,64 @@ class ActiveSupport::TestCase
143
172
  RailsERD.options = RailsERD.default_options.merge(Config.load)
144
173
  end
145
174
 
175
+ def name_to_object_symbol_pairs(name)
176
+ parts = name.to_s.split('::')
177
+
178
+ return [] if parts.first == '' || parts.count == 0
179
+
180
+ parts[1..-1].inject([[Object, parts.first.to_sym]]) do |pairs,string|
181
+ last_parent, last_child = pairs.last
182
+ # Fixes for Rails 6. No idea if this is actually correct as I can't decipher what the heck is going on in this
183
+ # code.
184
+ if last_child == :ActiveRecord || last_child == :primary
185
+ break []
186
+ end
187
+
188
+ break pairs unless last_parent.const_defined?(last_child)
189
+
190
+ next_parent = last_parent.const_get(last_child)
191
+ next_child = string.to_sym
192
+ pairs << [next_parent, next_child]
193
+ end
194
+ end
195
+
196
+ def remove_fully_qualified_constant(name)
197
+ pairs = name_to_object_symbol_pairs(name)
198
+ pairs.reverse.each do |parent, child|
199
+ parent.send(:remove_const,child) if parent.const_defined?(child)
200
+ end
201
+ end
202
+
146
203
  def reset_domain
147
204
  if defined? ActiveRecord
148
205
  ActiveRecord::Base.descendants.each do |model|
206
+ next if model.name == "ActiveRecord::InternalMetadata"
149
207
  model.reset_column_information
150
- Object.send :remove_const, model.name.to_sym if Object.const_defined? model.name.to_sym
208
+ remove_fully_qualified_constant(model.name)
151
209
  end
152
- ActiveRecord::Base.connection.tables.each do |table|
210
+
211
+ tables_and_views.each do |table|
153
212
  ActiveRecord::Base.connection.drop_table table
154
213
  end
155
- ActiveRecord::Base.direct_descendants.clear
214
+
215
+ if ActiveRecord.version >= Gem::Version.new("6.0.0.rc1")
216
+ cv = ActiveSupport::DescendantsTracker.class_variable_get(:@@direct_descendants)
217
+ cv.delete(ActiveRecord::Base)
218
+ ActiveSupport::DescendantsTracker.class_variable_set(:@@direct_descendants, cv)
219
+ else
220
+ ActiveRecord::Base.direct_descendants.clear
221
+ end
222
+
156
223
  ActiveSupport::Dependencies::Reference.clear!
157
224
  ActiveRecord::Base.clear_cache!
158
225
  end
159
226
  end
227
+
228
+ def tables_and_views
229
+ if ActiveRecord::VERSION::MAJOR >= 5
230
+ ActiveRecord::Base.connection.data_sources
231
+ else
232
+ ActiveRecord::Base.connection.tables
233
+ end
234
+ end
160
235
  end
@@ -3,8 +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
7
- define_method :native_database_types do
6
+ ActiveRecord::Base.connection.singleton_class.class_eval do
7
+ undef :native_database_types
8
+ define_method(:native_database_types) do
8
9
  super().tap do |types|
9
10
  types[type][:limit] = new_limit
10
11
  end
@@ -12,8 +13,9 @@ class AttributeTest < ActiveSupport::TestCase
12
13
  end
13
14
  yield
14
15
  ensure
15
- ActiveRecord::Base.connection.class_eval do
16
- define_method :native_database_types do
16
+ ActiveRecord::Base.connection.singleton_class.class_eval do
17
+ undef :native_database_types
18
+ define_method(:native_database_types) do
17
19
  super()
18
20
  end
19
21
  end
@@ -222,14 +224,14 @@ class AttributeTest < ActiveSupport::TestCase
222
224
  test "limit should return nil if there is no limit" do
223
225
  create_model "Foo"
224
226
  add_column :foos, :my_txt, :text
225
- assert_equal nil, create_attribute(Foo, "my_txt").limit
227
+ assert_nil create_attribute(Foo, "my_txt").limit
226
228
  end
227
229
 
228
230
  test "limit should return nil if equal to standard database limit" do
229
231
  with_native_limit :string, 456 do
230
232
  create_model "Foo"
231
233
  add_column :foos, :my_str, :string, :limit => 456
232
- assert_equal nil, create_attribute(Foo, "my_str").limit
234
+ assert_nil create_attribute(Foo, "my_str").limit
233
235
  end
234
236
  end
235
237
 
@@ -250,7 +252,7 @@ class AttributeTest < ActiveSupport::TestCase
250
252
  test "limit should return nil for decimal columns if equal to standard database limit" do
251
253
  create_model "Foo"
252
254
  add_column :foos, :num, :decimal
253
- assert_equal nil, create_attribute(Foo, "num").limit
255
+ assert_nil create_attribute(Foo, "num").limit
254
256
  end
255
257
 
256
258
  test "limit should return nil if type is unsupported by rails" do
@@ -260,19 +262,19 @@ class AttributeTest < ActiveSupport::TestCase
260
262
  add_column "foos", "a", "REAL"
261
263
  end
262
264
  end
263
- assert_equal nil, create_attribute(Foo, "a").limit
265
+ assert_nil create_attribute(Foo, "a").limit
264
266
  end
265
267
 
266
268
  test "limit should return nil for oddball column types that misuse the limit attribute" do
267
- create_model "Business", :location => :integer
268
- attribute = create_attribute(Business, "location")
269
- attribute.column.class_eval do
270
- define_method :limit do
269
+ create_model "Business", :location => :integer do
270
+ define_singleton_method :limit do
271
271
  # https://github.com/voormedia/rails-erd/issues/21
272
272
  { :srid => 4326, :type => "point", :geographic => true }
273
273
  end
274
274
  end
275
- assert_equal nil, attribute.limit
275
+
276
+ attribute = create_attribute(Business, "location")
277
+ assert_nil attribute.limit
276
278
  end
277
279
 
278
280
  test "scale should return scale for decimal columns if nonstandard" do
@@ -284,7 +286,7 @@ class AttributeTest < ActiveSupport::TestCase
284
286
  test "scale should return nil for decimal columns if equal to standard database limit" do
285
287
  create_model "Foo"
286
288
  add_column :foos, :num, :decimal
287
- assert_equal nil, create_attribute(Foo, "num").scale
289
+ assert_nil create_attribute(Foo, "num").scale
288
290
  end
289
291
 
290
292
  test "scale should return zero for decimal columns if left to default setting when specifying precision" do
@@ -300,17 +302,16 @@ class AttributeTest < ActiveSupport::TestCase
300
302
  add_column "foos", "a", "REAL"
301
303
  end
302
304
  end
303
- assert_equal nil, create_attribute(Foo, "a").scale
305
+ assert_nil create_attribute(Foo, "a").scale
304
306
  end
305
307
 
306
308
  test "scale should return nil for oddball column types that misuse the scale attribute" do
307
- create_model "Kobold", :size => :integer
308
- attribute = create_attribute(Kobold, "size")
309
- attribute.column.class_eval do
309
+ create_model "Kobold", :size => :integer do
310
310
  define_method :scale do
311
311
  1..5
312
312
  end
313
313
  end
314
- assert_equal nil, attribute.scale
314
+ attribute = create_attribute(Kobold, "size")
315
+ assert_nil attribute.scale
315
316
  end
316
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")
@@ -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
@@ -186,6 +194,15 @@ class DomainTest < ActiveSupport::TestCase
186
194
  assert_equal [Domain::Specialization] * 3, Domain.generate.specializations.collect(&:class)
187
195
  end
188
196
 
197
+ test "specializations should return specializations in domain model once for descendants of abstract class" do
198
+ create_model "Thing" do
199
+ self.abstract_class = true
200
+ end
201
+ create_model "Beverage", Thing, :type => :string
202
+ create_model "Beer", Beverage
203
+ assert_equal [Domain::Specialization], Domain.generate.specializations.collect(&:class)
204
+ end
205
+
189
206
  # Erroneous associations ===================================================
190
207
  test "relationships should omit bad has_many associations" do
191
208
  create_model "Foo" do
@@ -216,7 +233,7 @@ class DomainTest < ActiveSupport::TestCase
216
233
  output = collect_stdout do
217
234
  Domain.generate.relationships
218
235
  end
219
- assert_match /Ignoring invalid association :flabs on Foo/, output
236
+ assert_match(/Ignoring invalid association :flabs on Foo/, output)
220
237
  end
221
238
 
222
239
  test "relationships should output a warning when an association to model outside domain is encountered" do
@@ -227,7 +244,7 @@ class DomainTest < ActiveSupport::TestCase
227
244
  output = collect_stdout do
228
245
  Domain.new([Foo]).relationships
229
246
  end
230
- assert_match /model Bar exists, but is not included in domain/, output
247
+ assert_match(/model Bar exists, but is not included in domain/, output)
231
248
  end
232
249
 
233
250
  test "relationships should output a warning when an association to a non existent generalization is encountered" do
@@ -240,7 +257,7 @@ class DomainTest < ActiveSupport::TestCase
240
257
  output = collect_stdout do
241
258
  Domain.generate.relationships
242
259
  end
243
- assert_match /polymorphic interface FooBar does not exist/, output
260
+ assert_match(/polymorphic interface FooBar does not exist/, output)
244
261
  end
245
262
 
246
263
  test "relationships should not warn when a bad association is encountered if warnings are disabled" do
@@ -264,6 +281,6 @@ class DomainTest < ActiveSupport::TestCase
264
281
  output = collect_stdout do
265
282
  Domain.generate.entities
266
283
  end
267
- assert_match /Ignoring invalid model Foo \(table foos does not exist\)/, output
284
+ assert_match(/Ignoring invalid model Foo \(table foos does not exist\)/, output)
268
285
  end
269
286
  end
@@ -249,4 +249,30 @@ class EntityTest < ActiveSupport::TestCase
249
249
  assert_equal [domain.entity_by_name("Galleon"), domain.entity_by_name("Stronghold")],
250
250
  domain.entity_by_name("Defensible").children
251
251
  end
252
+
253
+ # Namespace ===================================================================
254
+ test "namespace should return nil for models outside modules" do
255
+ create_module_model "Plane"
256
+ assert_nil create_entity(Plane).namespace
257
+ end
258
+
259
+ test "namespace should return the module name for single-module models" do
260
+ create_module_model "Saw::Plane"
261
+ assert_equal "Saw", create_entity(Saw::Plane).namespace
262
+ end
263
+
264
+ test "namespace should return the module path if more than one module" do
265
+ create_module_model "Augur::Chisel::Saw::Plane"
266
+ assert_equal "Augur::Chisel::Saw", create_entity(Augur::Chisel::Saw::Plane).namespace
267
+ end
268
+
269
+ test "namespace defaults to nil" do
270
+ create_model "Foo"
271
+ assert_nil create_entity(Foo).namespace
272
+ end
273
+
274
+ test "namespace returns appropriate modules" do
275
+ entity = Domain::Entity.new(Domain.new, "Foo::Bar::Qux")
276
+ assert_equal "Foo::Bar", entity.namespace
277
+ end
252
278
  end
@@ -106,6 +106,7 @@ class GraphvizTest < ActiveSupport::TestCase
106
106
  begin
107
107
  GraphViz.class_eval do
108
108
  alias_method :old_output_and_errors_from_command, :output_and_errors_from_command
109
+ undef :output_and_errors_from_command
109
110
  def output_and_errors_from_command(*args); raise end
110
111
  end
111
112
  assert_nothing_raised do
@@ -113,6 +114,7 @@ class GraphvizTest < ActiveSupport::TestCase
113
114
  end
114
115
  ensure
115
116
  GraphViz.class_eval do
117
+ undef :output_and_errors_from_command
116
118
  alias_method :output_and_errors_from_command, :old_output_and_errors_from_command
117
119
  end
118
120
  end
@@ -137,7 +139,7 @@ class GraphvizTest < ActiveSupport::TestCase
137
139
 
138
140
  test "create should not create output if there are no connected models" do
139
141
  Diagram::Graphviz.create rescue nil
140
- assert !File.exists?("erd.png")
142
+ assert !File.exist?("erd.png")
141
143
  end
142
144
 
143
145
  test "create should abort and complain if there are no connected models" do
@@ -147,7 +149,7 @@ class GraphvizTest < ActiveSupport::TestCase
147
149
  rescue => e
148
150
  message = e.message
149
151
  end
150
- assert_match /No entities found/, message
152
+ assert_match(/No entities found/, message)
151
153
  end
152
154
 
153
155
  test "create should abort and complain if output directory does not exist" do
@@ -160,7 +162,7 @@ class GraphvizTest < ActiveSupport::TestCase
160
162
  message = e.message
161
163
  end
162
164
 
163
- assert_match /Output directory 'does_not_exist' does not exist/, message
165
+ assert_match(/Output directory 'does_not_exist' does not exist/, message)
164
166
  end
165
167
 
166
168
  test "create should not fail when reserved words are used as node names" do
@@ -184,6 +186,16 @@ class GraphvizTest < ActiveSupport::TestCase
184
186
  assert_equal '"Domain model\n\n"', diagram.graph.graph[:label].to_s
185
187
  end
186
188
 
189
+ test "generate should add default value for splines attribute" do
190
+ create_simple_domain
191
+ assert_equal '"spline"', diagram.graph.graph[:splines].to_s
192
+ end
193
+
194
+ test "generate should add set value for splines attribute" do
195
+ create_simple_domain
196
+ assert_equal '"ortho"', diagram(splines: 'ortho').graph.graph[:splines].to_s
197
+ end
198
+
187
199
  test "generate should add title with application name to graph" do
188
200
  begin
189
201
  Object::Quux = Module.new
@@ -226,7 +238,7 @@ class GraphvizTest < ActiveSupport::TestCase
226
238
  belongs_to :bar
227
239
  end
228
240
  create_model "Bar"
229
- assert_equal %Q("Bar"), find_dot_node(diagram, "m_Bar")[:label].to_gv
241
+ assert_equal %Q("{Bar}"), find_dot_node(diagram, "m_Bar")[:label].to_gv
230
242
  end
231
243
 
232
244
  test "generate should add attributes to entity html labels" do
@@ -244,7 +256,7 @@ class GraphvizTest < ActiveSupport::TestCase
244
256
  belongs_to :bar
245
257
  end
246
258
  create_model "Bar", :column => :string, :column_two => :boolean
247
- assert_equal %Q("Bar|column (string)\\ncolumn_two (boolean)\\n"), find_dot_node(diagram, "m_Bar")[:label].to_gv
259
+ assert_equal %Q("{Bar|column (string)\\ncolumn_two (boolean)\\n}"), find_dot_node(diagram, "m_Bar")[:label].to_gv
248
260
  end
249
261
 
250
262
  test "generate should not add any attributes to entity labels if attributes is set to false" do
@@ -255,50 +267,58 @@ class GraphvizTest < ActiveSupport::TestCase
255
267
  assert_no_match %r{contents}, find_dot_node(diagram(:attributes => false), "m_Jar")[:label].to_gv
256
268
  end
257
269
 
258
- test "node html labels should have direction reversing braces for vertical orientation" do
270
+ test "node html labels should have direction reversing braces for horizontal orientation" do
259
271
  RailsERD.options.markup = true
260
272
  create_model "Book", :author => :references do
261
273
  belongs_to :author
262
274
  end
263
275
  create_model "Author", :name => :string
264
- assert_match %r(\A<\{\s*<.*\|.*>\s*\}>\Z)m, find_dot_node(diagram(:orientation => :vertical), "m_Author")[:label].to_gv
276
+ assert_match %r(\A<\{\s*<.*\|.*>\s*\}>\Z)m, find_dot_node(diagram(:orientation => :horizontal), "m_Author")[:label].to_gv
265
277
  end
266
278
 
267
- test "node html labels should not have direction reversing braces for horizontal orientation" do
279
+ test "node html labels should not have direction reversing braces for vertical orientation" do
268
280
  RailsERD.options.markup = true
269
281
  create_model "Book", :author => :references do
270
282
  belongs_to :author
271
283
  end
272
284
  create_model "Author", :name => :string
273
- assert_match %r(\A<\s*<.*\|.*>\s*>\Z)m, find_dot_node(diagram(:orientation => :horizontal), "m_Author")[:label].to_gv
285
+ assert_match %r(\A<\s*<.*\|.*>\s*>\Z)m, find_dot_node(diagram(:orientation => :vertical), "m_Author")[:label].to_gv
274
286
  end
275
287
 
276
- test "node record labels should have direction reversing braces for vertical orientation" do
288
+ test "node record labels should have direction reversing braces for horizontal orientation" do
277
289
  RailsERD.options.markup = false
278
290
  create_model "Book", :author => :references do
279
291
  belongs_to :author
280
292
  end
281
293
  create_model "Author", :name => :string
282
- assert_match %r(\A"\{\w+|.*\}"\Z)m, find_dot_node(diagram(:orientation => :vertical), "m_Author")[:label].to_gv
294
+ assert_match %r(\A"\{\w+\|.*\}"\Z)m, find_dot_node(diagram(:orientation => :horizontal), "m_Author")[:label].to_gv
283
295
  end
284
296
 
285
- test "node record labels should not have direction reversing braces for horizontal orientation" do
297
+ test "node record labels should not have direction reversing braces for vertical orientation" do
286
298
  RailsERD.options.markup = false
287
299
  create_model "Book", :author => :references do
288
300
  belongs_to :author
289
301
  end
290
302
  create_model "Author", :name => :string
291
- assert_match %r(\A"\w+|.*"\Z)m, find_dot_node(diagram(:orientation => :horizontal), "m_Author")[:label].to_gv
303
+ assert_match %r(\A"\w+\|.*"\Z)m, find_dot_node(diagram(:orientation => :vertical), "m_Author")[:label].to_gv
292
304
  end
293
305
 
294
306
  test "generate should create edge for each relationship" do
295
- create_model "Foo", :bar => :references do
296
- belongs_to :bar
297
- end
298
- create_model "Bar", :foo => :references do
299
- belongs_to :foo
307
+ # TODO: Once we drop Rails 3.2 support, we _should_ be able to drop the
308
+ # :respond_to? check
309
+ #
310
+ if respond_to? :skip
311
+ skip("multiple edges between the same objects can cause segfaults in some versions of Graphviz")
312
+
313
+ create_model "Foo", :bar => :references do
314
+ belongs_to :bar
315
+ end
316
+ create_model "Bar", :foo => :references do
317
+ belongs_to :foo
318
+ end
319
+
320
+ assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
300
321
  end
301
- assert_equal [["m_Bar", "m_Foo"], ["m_Foo", "m_Bar"]], find_dot_node_pairs(diagram).sort
302
322
  end
303
323
 
304
324
  test "generate should create edge to polymorphic entity if polymorphism is true" do
@@ -20,6 +20,7 @@ class RakeTaskTest < ActiveSupport::TestCase
20
20
  Object::Quux = Module.new
21
21
  Object::Quux::Application = Class.new
22
22
  Object::Rails = Struct.new(:application).new(Object::Quux::Application.new)
23
+
23
24
  Rails.class_eval do
24
25
  define_method :backtrace_cleaner do
25
26
  ActiveSupport::BacktraceCleaner.new.tap do |cleaner|
@@ -40,7 +41,7 @@ class RakeTaskTest < ActiveSupport::TestCase
40
41
 
41
42
  test "generate task should not create output if there are no connected models" do
42
43
  Rake::Task["erd:generate"].execute rescue nil
43
- assert !File.exists?("erd.dot")
44
+ assert !File.exist?("erd.dot")
44
45
  end
45
46
 
46
47
  test "generate task should eager load application environment" do
@@ -100,12 +101,13 @@ class RakeTaskTest < ActiveSupport::TestCase
100
101
  rescue => e
101
102
  message = e.message
102
103
  end
103
- assert_match /#{Regexp.escape(<<-MSG.strip).gsub("xxx", ".*?")}/, message
104
+ assert_match(/#{Regexp.escape(<<-MSG.strip).gsub("xxx", ".*?")}/, message
104
105
  Loading models failed!
105
106
  Error occurred while loading application: FooBar (RuntimeError)
106
107
  test/unit/rake_task_test.rb:#{l1}:in `xxx'
107
108
  test/unit/rake_task_test.rb:#{l2}:in `xxx'
108
109
  MSG
110
+ )
109
111
  end
110
112
 
111
113
  test "generate task should reraise if application could not be loaded and trace option is enabled" do
@@ -171,4 +173,22 @@ Error occurred while loading application: FooBar (RuntimeError)
171
173
  Rake::Task["erd:options"].execute
172
174
  assert_equal %w[content timestamps], RailsERD.options.attributes
173
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
174
194
  end
metadata CHANGED
@@ -1,14 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-erd
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.7
4
+ version: 1.6.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rolf Timmermans
8
- autorequire:
8
+ - Kerri Miller
9
+ autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
- date: 2016-04-19 00:00:00.000000000 Z
12
+ date: 2021-02-16 00:00:00.000000000 Z
12
13
  dependencies:
13
14
  - !ruby/object:Gem::Dependency
14
15
  name: activerecord
@@ -16,28 +17,28 @@ dependencies:
16
17
  requirements:
17
18
  - - ">="
18
19
  - !ruby/object:Gem::Version
19
- version: '3.2'
20
+ version: '4.2'
20
21
  type: :runtime
21
22
  prerelease: false
22
23
  version_requirements: !ruby/object:Gem::Requirement
23
24
  requirements:
24
25
  - - ">="
25
26
  - !ruby/object:Gem::Version
26
- version: '3.2'
27
+ version: '4.2'
27
28
  - !ruby/object:Gem::Dependency
28
29
  name: activesupport
29
30
  requirement: !ruby/object:Gem::Requirement
30
31
  requirements:
31
32
  - - ">="
32
33
  - !ruby/object:Gem::Version
33
- version: '3.2'
34
+ version: '4.2'
34
35
  type: :runtime
35
36
  prerelease: false
36
37
  version_requirements: !ruby/object:Gem::Requirement
37
38
  requirements:
38
39
  - - ">="
39
40
  - !ruby/object:Gem::Version
40
- version: '3.2'
41
+ version: '4.2'
41
42
  - !ruby/object:Gem::Dependency
42
43
  name: ruby-graphviz
43
44
  requirement: !ruby/object:Gem::Requirement
@@ -66,10 +67,39 @@ dependencies:
66
67
  - - "~>"
67
68
  - !ruby/object:Gem::Version
68
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'
69
98
  description: Automatically generate an entity-relationship diagram (ERD) for your
70
99
  Rails models.
71
100
  email:
72
101
  - r.timmermans@voormedia.com
102
+ - kerrizor@kerrizor.com
73
103
  executables:
74
104
  - erd
75
105
  extensions: []
@@ -117,7 +147,7 @@ homepage: https://github.com/voormedia/rails-erd
117
147
  licenses:
118
148
  - MIT
119
149
  metadata: {}
120
- post_install_message:
150
+ post_install_message:
121
151
  rdoc_options: []
122
152
  require_paths:
123
153
  - lib
@@ -125,16 +155,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
125
155
  requirements:
126
156
  - - ">="
127
157
  - !ruby/object:Gem::Version
128
- version: 1.9.3
158
+ version: '2.2'
129
159
  required_rubygems_version: !ruby/object:Gem::Requirement
130
160
  requirements:
131
161
  - - ">="
132
162
  - !ruby/object:Gem::Version
133
163
  version: '0'
134
164
  requirements: []
135
- rubyforge_project:
136
- rubygems_version: 2.4.6
137
- signing_key:
165
+ rubyforge_project:
166
+ rubygems_version: 2.6.14
167
+ signing_key:
138
168
  specification_version: 4
139
169
  summary: Entity-relationship diagram for your Rails models.
140
170
  test_files:
@@ -152,4 +182,3 @@ test_files:
152
182
  - test/unit/rake_task_test.rb
153
183
  - test/unit/relationship_test.rb
154
184
  - test/unit/specialization_test.rb
155
- has_rdoc: