rails-erd 1.4.7 → 1.6.1

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