rails-erd 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGES.rdoc +4 -0
- data/LICENSE +19 -0
- data/README.rdoc +56 -0
- data/Rakefile +38 -0
- data/VERSION +1 -0
- data/lib/rails-erd.rb +1 -0
- data/lib/rails_erd.rb +38 -0
- data/lib/rails_erd/attribute.rb +74 -0
- data/lib/rails_erd/diagram.rb +88 -0
- data/lib/rails_erd/domain.rb +102 -0
- data/lib/rails_erd/entity.rb +50 -0
- data/lib/rails_erd/railtie.rb +7 -0
- data/lib/rails_erd/relationship.rb +85 -0
- data/lib/rails_erd/relationship/cardinality.rb +35 -0
- data/lib/rails_erd/tasks.rake +38 -0
- data/lib/rails_erd/templates/node.erb +13 -0
- data/test/test_helper.rb +72 -0
- data/test/unit/attribute_test.rb +144 -0
- data/test/unit/cardinality_test.rb +8 -0
- data/test/unit/diagram_test.rb +0 -0
- data/test/unit/domain_test.rb +125 -0
- data/test/unit/entity_test.rb +82 -0
- data/test/unit/relationship_test.rb +308 -0
- metadata +123 -0
@@ -0,0 +1,85 @@
|
|
1
|
+
module RailsERD
|
2
|
+
class Relationship
|
3
|
+
class << self
|
4
|
+
def from_associations(domain, associations) #:nodoc:
|
5
|
+
assoc_groups = associations.group_by { |assoc| association_identity(assoc) }
|
6
|
+
assoc_groups.collect { |_, assoc_group| Relationship.new(domain, assoc_group.to_a) }
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def association_identity(assoc)
|
12
|
+
identifier = assoc.options[:join_table] || assoc.primary_key_name.to_s
|
13
|
+
Set[identifier, assoc.active_record, assoc.klass]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Returns the domain in which this relationship is defined.
|
18
|
+
attr_reader :domain
|
19
|
+
|
20
|
+
# Returns the source entity. The source entity corresponds to the model
|
21
|
+
# that has defined a +has_one+ or +has_many+ association with the other
|
22
|
+
# model.
|
23
|
+
attr_reader :source
|
24
|
+
|
25
|
+
# Returns the destination entity. The destination entity corresponds to the
|
26
|
+
# model that has defined a +belongs_to+ association with the other model.
|
27
|
+
attr_reader :destination
|
28
|
+
|
29
|
+
def initialize(domain, associations) #:nodoc:
|
30
|
+
@domain = domain
|
31
|
+
@reverse_associations, @forward_associations = *associations.partition(&:belongs_to?)
|
32
|
+
|
33
|
+
assoc = @forward_associations.first || @reverse_associations.first
|
34
|
+
@source, @destination = @domain.entity_for(assoc.active_record), @domain.entity_for(assoc.klass)
|
35
|
+
@source, @destination = @destination, @source if assoc.belongs_to?
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns all +ActiveRecord+ association objects that describe this
|
39
|
+
# relationship.
|
40
|
+
def associations
|
41
|
+
@forward_associations + @reverse_associations
|
42
|
+
end
|
43
|
+
|
44
|
+
# Returns the cardinality of this relationship. The cardinality may be
|
45
|
+
# one of Cardinality::OneToOne, Cardinality::OneToMany, or
|
46
|
+
# Cardinality::ManyToMany.
|
47
|
+
def cardinality
|
48
|
+
@forward_associations.collect { |assoc| Cardinality.from_macro(assoc.macro) }.max or Cardinality::OneToMany
|
49
|
+
end
|
50
|
+
|
51
|
+
# Indicates if a relationship is indirect, that is, if it is defined
|
52
|
+
# through other relationships. Indirect relationships are created in
|
53
|
+
# Rails with <tt>has_many :through</tt> or <tt>has_one :through</tt>
|
54
|
+
# association macros.
|
55
|
+
def indirect?
|
56
|
+
@forward_associations.all?(&:through_reflection)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Indicates whether or not the relationship is defined by two inverse
|
60
|
+
# associations (e.g. a +has_many+ and a corresponding +belongs_to+
|
61
|
+
# association).
|
62
|
+
def mutual?
|
63
|
+
@forward_associations.any? and @reverse_associations.any?
|
64
|
+
end
|
65
|
+
|
66
|
+
# Indicates whether or not this relationship connects an entity with itself.
|
67
|
+
def recursive?
|
68
|
+
@source == @destination
|
69
|
+
end
|
70
|
+
|
71
|
+
# The strength of a relationship is equal to the number of associations
|
72
|
+
# that describe it.
|
73
|
+
def strength
|
74
|
+
associations.size
|
75
|
+
end
|
76
|
+
|
77
|
+
def inspect #:nodoc:
|
78
|
+
"#<#{self.class}:0x%.14x @source=#{source} @destination=#{destination}>" % (object_id << 1)
|
79
|
+
end
|
80
|
+
|
81
|
+
def <=>(other) #:nodoc:
|
82
|
+
(source.name <=> other.source.name).nonzero? or (destination.name <=> other.destination.name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RailsERD
|
2
|
+
class Relationship
|
3
|
+
class Cardinality
|
4
|
+
CARDINALITY_NAMES = %w{one_to_one one_to_many many_to_many} #:nodoc:
|
5
|
+
ORDER = {} #:nodoc:
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
def from_macro(macro) #:nodoc:
|
11
|
+
case macro
|
12
|
+
when :has_and_belongs_to_many then ManyToMany
|
13
|
+
when :has_many then OneToMany
|
14
|
+
when :has_one then OneToOne
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def <=>(other) #:nodoc:
|
19
|
+
ORDER[self] <=> ORDER[other]
|
20
|
+
end
|
21
|
+
|
22
|
+
CARDINALITY_NAMES.each do |cardinality|
|
23
|
+
define_method :"#{cardinality}?" do
|
24
|
+
type == cardinality
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
CARDINALITY_NAMES.each_with_index do |cardinality, i|
|
30
|
+
klass = Cardinality.const_set cardinality.camelize.to_sym, Class.new(Cardinality) { @@type = cardinality }
|
31
|
+
ORDER[klass] = i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
def say(message)
|
2
|
+
puts message unless Rake.application.options.silent
|
3
|
+
end
|
4
|
+
|
5
|
+
namespace :erd do
|
6
|
+
task :options do
|
7
|
+
(RailsERD.options.keys.map(&:to_s) & ENV.keys).each do |option|
|
8
|
+
RailsERD.options[option.to_sym] = case ENV[option]
|
9
|
+
when "true" then true
|
10
|
+
when "false" then false
|
11
|
+
else ENV[option].to_sym
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
task :load_models do
|
17
|
+
say "Loading ActiveRecord models..."
|
18
|
+
|
19
|
+
Rake::Task[:environment].invoke
|
20
|
+
Rails.application.config.paths.app.models.paths.each do |model_path|
|
21
|
+
Dir["#{model_path}/**/*.rb"].sort.each do |file|
|
22
|
+
require_dependency file
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
task :generate => [:options, :load_models] do
|
28
|
+
say "Generating ERD diagram..."
|
29
|
+
|
30
|
+
require "rails_erd/diagram"
|
31
|
+
diagram = RailsERD::Diagram.generate
|
32
|
+
|
33
|
+
say "Done! Saved diagram to #{diagram.file_name}."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
desc "Generate an Entity-Relationship Diagram based on your models"
|
38
|
+
task :erd => "erd:generate"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% if vertical? %>{<% end %>
|
2
|
+
<table border="0" align="center" cellspacing="0.5" cellpadding="0" width="<%= NODE_WIDTH + 4 %>">
|
3
|
+
<tr><td align="center" valign="bottom" width="<%= NODE_WIDTH %>"><font face="Arial Bold" point-size="11"><%= entity.name %></font></td></tr>
|
4
|
+
</table>|<% if attributes.any? %>
|
5
|
+
<table border="0" align="left" cellspacing="2" cellpadding="0" width="<%= NODE_WIDTH + 4 %>">
|
6
|
+
<% attributes.each do |attribute| %>
|
7
|
+
<tr>
|
8
|
+
<td align="left" width="<%= NODE_WIDTH %>" port="<%= attribute %>"><%= attribute %> <font face="Arial Italic" color="grey60"><%= attribute.type_description %></font></td>
|
9
|
+
</tr>
|
10
|
+
<% end %>
|
11
|
+
</table>
|
12
|
+
<% end %>
|
13
|
+
<% if vertical? %>}<% end %>
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "active_support/test_case"
|
3
|
+
|
4
|
+
require "rails_erd/domain"
|
5
|
+
|
6
|
+
require "rails"
|
7
|
+
require "active_record"
|
8
|
+
|
9
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
|
10
|
+
|
11
|
+
include RailsERD
|
12
|
+
|
13
|
+
class ActiveSupport::TestCase
|
14
|
+
teardown :reset_domain
|
15
|
+
|
16
|
+
def create_table(table, columns = {}, pk = nil)
|
17
|
+
opts = if pk then { :primary_key => pk } else { :id => false } end
|
18
|
+
ActiveRecord::Schema.define do
|
19
|
+
suppress_messages do
|
20
|
+
create_table table, opts do |t|
|
21
|
+
columns.each do |column, type|
|
22
|
+
t.send type, column
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def add_column(*args)
|
30
|
+
ActiveRecord::Schema.define do
|
31
|
+
suppress_messages do
|
32
|
+
add_column *args
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def create_model(name, columns = {}, &block)
|
38
|
+
klass = Object.const_set name.to_sym, Class.new(ActiveRecord::Base)
|
39
|
+
klass.class_eval(&block) if block_given?
|
40
|
+
create_table Object.const_get(name.to_sym).table_name, columns, Object.const_get(name.to_sym).primary_key rescue nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_models(*names)
|
44
|
+
names.each do |name|
|
45
|
+
create_model name
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def collect_stdout
|
50
|
+
stdout = $stdout
|
51
|
+
$stdout = StringIO.new
|
52
|
+
yield
|
53
|
+
$stdout.rewind
|
54
|
+
$stdout.read
|
55
|
+
ensure
|
56
|
+
$stdout = stdout
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def reset_domain
|
62
|
+
ActiveRecord::Base.descendants.each do |model|
|
63
|
+
Object.send :remove_const, model.name.to_sym
|
64
|
+
end
|
65
|
+
ActiveRecord::Base.connection.tables.each do |table|
|
66
|
+
ActiveRecord::Base.connection.drop_table table
|
67
|
+
end
|
68
|
+
ActiveRecord::Base.direct_descendants.clear
|
69
|
+
Arel::Relation.class_variable_set :@@connection_tables_primary_keys, {}
|
70
|
+
ActiveSupport::Dependencies::Reference.clear!
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
3
|
+
|
4
|
+
class AttributeTest < ActiveSupport::TestCase
|
5
|
+
def with_native_limit(type, new_limit)
|
6
|
+
ActiveRecord::Base.connection.class_eval do
|
7
|
+
define_method :native_database_types do
|
8
|
+
super().tap do |types|
|
9
|
+
types[type][:limit] = new_limit
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
ActiveRecord::Base.connection.class_eval do
|
16
|
+
define_method :native_database_types do
|
17
|
+
super()
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_attribute(model, name)
|
23
|
+
Attribute.new(Domain.generate, model, model.arel_table.attributes[name].column)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Attribute ================================================================
|
27
|
+
test "column should return database column" do
|
28
|
+
create_model "Foo", :my_column => :string
|
29
|
+
assert_equal Foo.arel_table.attributes["my_column"].column,
|
30
|
+
Attribute.from_model(Domain.new, Foo).reject(&:primary_key?).first.column
|
31
|
+
end
|
32
|
+
|
33
|
+
test "spaceship should sort attributes by name" do
|
34
|
+
create_model "Foo", :a => :string, :b => :string, :c => :string
|
35
|
+
a = Attribute.new(Domain.new, Foo, Foo.arel_table.attributes["a"].column)
|
36
|
+
b = Attribute.new(Domain.new, Foo, Foo.arel_table.attributes["b"].column)
|
37
|
+
c = Attribute.new(Domain.new, Foo, Foo.arel_table.attributes["c"].column)
|
38
|
+
assert_equal [a, b, c], [c, a, b].sort
|
39
|
+
end
|
40
|
+
|
41
|
+
test "inspect should show column" do
|
42
|
+
create_model "Foo", :my_column => :string
|
43
|
+
assert_match %r{#<RailsERD::Attribute:.* @column="my_column" @type=:string>},
|
44
|
+
Attribute.new(Domain.new, Foo, Foo.arel_table.attributes["my_column"].column).inspect
|
45
|
+
end
|
46
|
+
|
47
|
+
test "type should return attribute type" do
|
48
|
+
create_model "Foo", :a => :binary
|
49
|
+
assert_equal :binary, create_attribute(Foo, "a").type
|
50
|
+
end
|
51
|
+
|
52
|
+
# Attribute properties =====================================================
|
53
|
+
test "mandatory should return false by default" do
|
54
|
+
create_model "Foo", :column => :string
|
55
|
+
assert_equal false, create_attribute(Foo, "column").mandatory?
|
56
|
+
end
|
57
|
+
|
58
|
+
test "mandatory should return true if attribute has a presence validator" do
|
59
|
+
create_model "Foo", :column => :string do
|
60
|
+
validates :column, :presence => true
|
61
|
+
end
|
62
|
+
assert_equal true, create_attribute(Foo, "column").mandatory?
|
63
|
+
end
|
64
|
+
|
65
|
+
test "mandatory should return true if attribute has a not null constraint" do
|
66
|
+
create_model "Foo"
|
67
|
+
add_column :foos, :column, :string, :null => false, :default => ""
|
68
|
+
assert_equal true, create_attribute(Foo, "column").mandatory?
|
69
|
+
end
|
70
|
+
|
71
|
+
test "primary_key should return false by default" do
|
72
|
+
create_model "Bar", :my_key => :integer
|
73
|
+
assert_equal false, create_attribute(Bar, "my_key").primary_key?
|
74
|
+
end
|
75
|
+
|
76
|
+
test "primary_key should return true if column is used as primary key" do
|
77
|
+
create_model "Bar", :my_key => :integer do
|
78
|
+
set_primary_key :my_key
|
79
|
+
end
|
80
|
+
assert_equal true, create_attribute(Bar, "my_key").primary_key?
|
81
|
+
end
|
82
|
+
|
83
|
+
test "foreign_key should return false by default" do
|
84
|
+
create_model "Foo", :bar => :references
|
85
|
+
assert_equal false, create_attribute(Foo, "bar_id").foreign_key?
|
86
|
+
end
|
87
|
+
|
88
|
+
test "foreign_key should return true if it is used in an association" do
|
89
|
+
create_model "Foo", :bar => :references do
|
90
|
+
belongs_to :bar
|
91
|
+
end
|
92
|
+
create_model "Bar"
|
93
|
+
assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
|
94
|
+
end
|
95
|
+
|
96
|
+
test "foreign_key should return true if it is used in a remote association" do
|
97
|
+
create_model "Foo", :bar => :references
|
98
|
+
create_model "Bar" do
|
99
|
+
has_many :foos
|
100
|
+
end
|
101
|
+
assert_equal true, create_attribute(Foo, "bar_id").foreign_key?
|
102
|
+
end
|
103
|
+
|
104
|
+
test "timestamp should return false by default" do
|
105
|
+
create_model "Foo", :created => :datetime
|
106
|
+
assert_equal false, create_attribute(Foo, "created").timestamp?
|
107
|
+
end
|
108
|
+
|
109
|
+
test "timestamp should return true if it is named created_at/on or updated_at/on" do
|
110
|
+
create_model "Foo", :created_at => :string, :updated_at => :string, :created_on => :string, :updated_on => :string
|
111
|
+
assert_equal [true] * 4, [create_attribute(Foo, "created_at"), create_attribute(Foo, "updated_at"),
|
112
|
+
create_attribute(Foo, "created_on"), create_attribute(Foo, "updated_on")].collect(&:timestamp?)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Type descriptions ========================================================
|
116
|
+
test "type_description should return short type description" do
|
117
|
+
create_model "Foo", :a => :binary
|
118
|
+
assert_equal "blob", create_attribute(Foo, "a").type_description
|
119
|
+
end
|
120
|
+
|
121
|
+
test "type_description should return short type description without limit if standard" do
|
122
|
+
with_native_limit :string, 456 do
|
123
|
+
create_model "Foo"
|
124
|
+
add_column :foos, :my_str, :string, :limit => 255
|
125
|
+
ActiveRecord::Base.connection.native_database_types[:string]
|
126
|
+
assert_equal "str (255)", create_attribute(Foo, "my_str").type_description
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
test "type_description should return short type description with limit if nonstandard" do
|
131
|
+
with_native_limit :string, 456 do
|
132
|
+
create_model "Foo"
|
133
|
+
add_column :foos, :my_str, :string, :limit => 456
|
134
|
+
assert_equal "str", create_attribute(Foo, "my_str").type_description
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
test "type_description should append hair space and low asterisk if field is mandatory" do
|
139
|
+
create_model "Foo", :a => :integer do
|
140
|
+
validates_presence_of :a
|
141
|
+
end
|
142
|
+
assert_equal "int ∗", create_attribute(Foo, "a").type_description
|
143
|
+
end
|
144
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class CardinalityTest < ActiveSupport::TestCase
|
4
|
+
test "cardinalities should be sorted in order of maniness" do
|
5
|
+
assert_equal [Relationship::Cardinality::OneToOne, Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany],
|
6
|
+
[Relationship::Cardinality::OneToMany, Relationship::Cardinality::ManyToMany, Relationship::Cardinality::OneToOne].sort
|
7
|
+
end
|
8
|
+
end
|
File without changes
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path("../test_helper", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
class DomainTest < ActiveSupport::TestCase
|
4
|
+
# Domain ===================================================================
|
5
|
+
test "generate should return domain" do
|
6
|
+
assert_kind_of Domain, Domain.generate
|
7
|
+
end
|
8
|
+
|
9
|
+
test "name should return rails application name" do
|
10
|
+
Object::Quux = Module.new
|
11
|
+
Object::Quux::Application = Class.new Rails::Application
|
12
|
+
assert_equal "Quux", Domain.generate.name
|
13
|
+
end
|
14
|
+
|
15
|
+
test "name should return nil outside rails" do
|
16
|
+
assert_nil Domain.generate.name
|
17
|
+
end
|
18
|
+
|
19
|
+
# Entity processing ========================================================
|
20
|
+
test "entity_for should return associated entity for given model" do
|
21
|
+
create_model "Foo"
|
22
|
+
assert_equal Foo, Domain.generate.entity_for(Foo).model
|
23
|
+
end
|
24
|
+
|
25
|
+
test "entities should return domain entities" do
|
26
|
+
create_models "Foo", "Bar"
|
27
|
+
assert_equal [Entity] * 2, Domain.generate.entities.collect(&:class)
|
28
|
+
end
|
29
|
+
|
30
|
+
test "entities should return all domain entities sorted by name" do
|
31
|
+
create_models "Foo", "Bar", "Baz", "Qux"
|
32
|
+
assert_equal [Bar, Baz, Foo, Qux], Domain.generate.entities.collect(&:model)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Relationship processing ==================================================
|
36
|
+
test "relationships should return empty array for empty domain" do
|
37
|
+
assert_equal [], Domain.generate.relationships
|
38
|
+
end
|
39
|
+
|
40
|
+
test "relationships should return relationships in domain model" do
|
41
|
+
create_models "Baz", "Qux"
|
42
|
+
create_model "Foo", :bar => :references, :qux => :references do
|
43
|
+
belongs_to :bar
|
44
|
+
belongs_to :qux
|
45
|
+
end
|
46
|
+
create_model "Bar", :baz => :references do
|
47
|
+
belongs_to :baz
|
48
|
+
end
|
49
|
+
assert_equal [Relationship] * 3, Domain.generate.relationships.collect(&:class)
|
50
|
+
end
|
51
|
+
|
52
|
+
test "relationships should count mutual relationship as one" do
|
53
|
+
create_model "Foo", :bar => :references do
|
54
|
+
belongs_to :bar
|
55
|
+
end
|
56
|
+
create_model "Bar" do
|
57
|
+
has_many :foos
|
58
|
+
end
|
59
|
+
assert_equal [Relationship], Domain.generate.relationships.collect(&:class)
|
60
|
+
end
|
61
|
+
|
62
|
+
test "relationships should count relationship between same models with distinct foreign key seperately" do
|
63
|
+
create_model "Foo", :bar => :references, :special_bar => :references do
|
64
|
+
belongs_to :bar
|
65
|
+
end
|
66
|
+
create_model "Bar" do
|
67
|
+
has_many :foos, :foreign_key => :special_bar_id
|
68
|
+
end
|
69
|
+
assert_equal [Relationship] * 2, Domain.generate.relationships.collect(&:class)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Erroneous associations ===================================================
|
73
|
+
test "relationships should omit bad has_many associations" do
|
74
|
+
create_model "Foo" do
|
75
|
+
has_many :flabs
|
76
|
+
end
|
77
|
+
assert_equal [], Domain.generate(:suppress_warnings => true).relationships
|
78
|
+
end
|
79
|
+
|
80
|
+
test "relationships should omit bad has_many through association" do
|
81
|
+
create_model "Foo" do
|
82
|
+
has_many :flabs, :through => :bars
|
83
|
+
end
|
84
|
+
assert_equal [], Domain.generate(:suppress_warnings => true).relationships
|
85
|
+
end
|
86
|
+
|
87
|
+
test "relationships should omit association to model outside domain" do
|
88
|
+
create_model "Foo" do
|
89
|
+
has_many :bars
|
90
|
+
end
|
91
|
+
create_model "Bar", :foo => :references
|
92
|
+
assert_equal [], Domain.new([Foo], :suppress_warnings => true).relationships
|
93
|
+
end
|
94
|
+
|
95
|
+
test "relationships should output a warning when a bad association is encountered" do
|
96
|
+
create_model "Foo" do
|
97
|
+
has_many :flabs
|
98
|
+
end
|
99
|
+
output = collect_stdout do
|
100
|
+
Domain.generate.relationships
|
101
|
+
end
|
102
|
+
assert_match /Invalid association :flabs on Foo/, output
|
103
|
+
end
|
104
|
+
|
105
|
+
test "relationships should output a warning when an association to model outside domain is encountered" do
|
106
|
+
create_model "Foo" do
|
107
|
+
has_many :bars
|
108
|
+
end
|
109
|
+
create_model "Bar", :foo => :references
|
110
|
+
output = collect_stdout do
|
111
|
+
Domain.new([Foo]).relationships
|
112
|
+
end
|
113
|
+
assert_match /model Bar exists, but is not included in the domain/, output
|
114
|
+
end
|
115
|
+
|
116
|
+
test "relationships should suppress warnings when a bad association is encountered if warning suppression is enabled" do
|
117
|
+
create_model "Foo" do
|
118
|
+
has_many :flabs
|
119
|
+
end
|
120
|
+
output = collect_stdout do
|
121
|
+
Domain.generate(:suppress_warnings => true).relationships
|
122
|
+
end
|
123
|
+
assert_equal "", output
|
124
|
+
end
|
125
|
+
end
|