rails-erd 0.4.1 → 0.4.3
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.
- data/CHANGES.rdoc +6 -0
- data/Gemfile +16 -12
- data/Gemfile.lock +26 -38
- data/Rakefile +0 -5
- data/VERSION +1 -1
- data/lib/rails_erd/domain.rb +24 -18
- data/lib/rails_erd/domain/attribute.rb +32 -14
- data/lib/rails_erd/domain/relationship.rb +28 -28
- data/rails-erd.gemspec +65 -49
- data/test/unit/attribute_test.rb +50 -14
- metadata +92 -11
- data/.gitignore +0 -10
data/CHANGES.rdoc
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
=== 0.4.3:
|
2
|
+
|
3
|
+
* Display the scale of decimal attributes when set. A decimal attribute with
|
4
|
+
precision 5 and scale 2 is now indicated with (5,2).
|
5
|
+
* Fixed deprecation warnings for edge Rails (upcoming 3.1).
|
6
|
+
|
1
7
|
=== 0.4.1:
|
2
8
|
|
3
9
|
* Fix processing of associations with class_name set to absolute module paths.
|
data/Gemfile
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
2
|
|
3
|
-
gem "
|
4
|
-
gem "
|
5
|
-
gem "
|
6
|
-
gem "rake"
|
7
|
-
gem "jeweler"
|
3
|
+
gem "activerecord", "~> 3.0"
|
4
|
+
gem "activesupport", "~> 3.0"
|
5
|
+
gem "ruby-graphviz", "~> 0.9.18"
|
8
6
|
|
9
|
-
|
10
|
-
gem "
|
11
|
-
|
7
|
+
group :development do
|
8
|
+
gem "rake"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.2"
|
11
|
+
|
12
|
+
platforms :ruby do
|
13
|
+
gem "sqlite3"
|
14
|
+
end
|
12
15
|
|
13
|
-
platforms :jruby do
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
platforms :jruby do
|
17
|
+
gem "jdbc-sqlite3"
|
18
|
+
gem "activerecord-jdbc-adapter"
|
19
|
+
gem "jruby-openssl", :require => false # Silence openssl warnings.
|
20
|
+
end
|
17
21
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,58 +1,46 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
rails-erd (0.4.0)
|
5
|
-
activerecord (~> 3.0)
|
6
|
-
activesupport (~> 3.0)
|
7
|
-
ruby-graphviz (~> 0.9.18)
|
8
|
-
|
9
1
|
GEM
|
10
2
|
remote: http://rubygems.org/
|
11
3
|
specs:
|
12
|
-
activemodel (3.0.
|
13
|
-
activesupport (= 3.0.
|
4
|
+
activemodel (3.0.3)
|
5
|
+
activesupport (= 3.0.3)
|
14
6
|
builder (~> 2.1.2)
|
15
|
-
i18n (~> 0.4
|
16
|
-
activerecord (3.0.
|
17
|
-
activemodel (= 3.0.
|
18
|
-
activesupport (= 3.0.
|
19
|
-
arel (~>
|
7
|
+
i18n (~> 0.4)
|
8
|
+
activerecord (3.0.3)
|
9
|
+
activemodel (= 3.0.3)
|
10
|
+
activesupport (= 3.0.3)
|
11
|
+
arel (~> 2.0.2)
|
20
12
|
tzinfo (~> 0.3.23)
|
21
|
-
activerecord-jdbc-adapter (1.
|
22
|
-
activesupport (3.0.
|
23
|
-
arel (
|
24
|
-
activesupport (~> 3.0.0)
|
13
|
+
activerecord-jdbc-adapter (1.1.1)
|
14
|
+
activesupport (3.0.3)
|
15
|
+
arel (2.0.7)
|
25
16
|
bouncy-castle-java (1.5.0145.2)
|
26
17
|
builder (2.1.2)
|
27
|
-
gemcutter (0.6.1)
|
28
18
|
git (1.2.5)
|
29
|
-
i18n (0.
|
30
|
-
jdbc-sqlite3 (3.6.
|
31
|
-
jeweler (1.
|
32
|
-
|
19
|
+
i18n (0.5.0)
|
20
|
+
jdbc-sqlite3 (3.6.14.2.056-java)
|
21
|
+
jeweler (1.5.2)
|
22
|
+
bundler (~> 1.0.0)
|
33
23
|
git (>= 1.2.5)
|
34
|
-
|
35
|
-
jruby-openssl (0.7.
|
24
|
+
rake
|
25
|
+
jruby-openssl (0.7.3)
|
36
26
|
bouncy-castle-java
|
37
|
-
json_pure (1.4.6)
|
38
27
|
rake (0.8.7)
|
39
|
-
ruby-graphviz (0.9.
|
40
|
-
|
41
|
-
|
42
|
-
sqlite3-ruby (1.3.1)
|
43
|
-
tzinfo (0.3.23)
|
28
|
+
ruby-graphviz (0.9.20)
|
29
|
+
sqlite3 (1.3.3)
|
30
|
+
tzinfo (0.3.24)
|
44
31
|
|
45
32
|
PLATFORMS
|
46
33
|
java
|
47
34
|
ruby
|
48
35
|
|
49
36
|
DEPENDENCIES
|
50
|
-
activerecord
|
51
|
-
activerecord-jdbc-adapter
|
52
|
-
activesupport
|
37
|
+
activerecord (~> 3.0)
|
38
|
+
activerecord-jdbc-adapter
|
39
|
+
activesupport (~> 3.0)
|
40
|
+
bundler (~> 1.0.0)
|
53
41
|
jdbc-sqlite3
|
54
|
-
jeweler
|
42
|
+
jeweler (~> 1.5.2)
|
55
43
|
jruby-openssl
|
56
|
-
rails-erd!
|
57
44
|
rake
|
58
|
-
|
45
|
+
ruby-graphviz (~> 0.9.18)
|
46
|
+
sqlite3
|
data/Rakefile
CHANGED
@@ -12,11 +12,6 @@ Jeweler::Tasks.new do |spec|
|
|
12
12
|
spec.email = "r.timmermans@voormedia.com"
|
13
13
|
spec.homepage = "http://rails-erd.rubyforge.org/"
|
14
14
|
|
15
|
-
spec.add_runtime_dependency "activerecord", "~> 3.0"
|
16
|
-
spec.add_runtime_dependency "activesupport", "~> 3.0"
|
17
|
-
spec.add_runtime_dependency "ruby-graphviz", "~> 0.9.18"
|
18
|
-
spec.add_development_dependency "sqlite3-ruby"
|
19
|
-
|
20
15
|
# Don't bundle examples or website in gem.
|
21
16
|
excluded = Dir["{examples,site}/**/*"]
|
22
17
|
spec.files -= excluded
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.4.
|
1
|
+
0.4.3
|
data/lib/rails_erd/domain.rb
CHANGED
@@ -26,11 +26,17 @@ module RailsERD
|
|
26
26
|
def generate(options = {})
|
27
27
|
new ActiveRecord::Base.descendants, options
|
28
28
|
end
|
29
|
+
|
30
|
+
# Returns the method name to retrieve the foreign key from an
|
31
|
+
# association reflection object.
|
32
|
+
def foreign_key_method_name # @private :nodoc:
|
33
|
+
@foreign_key_method_name ||= ActiveRecord::Reflection::AssociationReflection.method_defined?(:foreign_key) ? :foreign_key : :primary_key_name
|
34
|
+
end
|
29
35
|
end
|
30
|
-
|
36
|
+
|
31
37
|
extend Inspectable
|
32
38
|
inspection_attributes
|
33
|
-
|
39
|
+
|
34
40
|
# The options that are used to generate this domain model.
|
35
41
|
attr_reader :options
|
36
42
|
|
@@ -45,42 +51,42 @@ module RailsERD
|
|
45
51
|
def name
|
46
52
|
defined? Rails and Rails.application and Rails.application.class.parent.name
|
47
53
|
end
|
48
|
-
|
54
|
+
|
49
55
|
# Returns all entities of your domain model.
|
50
56
|
def entities
|
51
57
|
@entities ||= Entity.from_models(self, models)
|
52
58
|
end
|
53
|
-
|
59
|
+
|
54
60
|
# Returns all relationships in your domain model.
|
55
61
|
def relationships
|
56
62
|
@relationships ||= Relationship.from_associations(self, associations)
|
57
63
|
end
|
58
|
-
|
64
|
+
|
59
65
|
# Returns all specializations in your domain model.
|
60
66
|
def specializations
|
61
67
|
@specializations ||= Specialization.from_models(self, models)
|
62
68
|
end
|
63
|
-
|
69
|
+
|
64
70
|
# Returns a specific entity object for the given Active Record model.
|
65
71
|
def entity_by_name(name) # @private :nodoc:
|
66
72
|
entity_mapping[name]
|
67
73
|
end
|
68
|
-
|
74
|
+
|
69
75
|
# Returns an array of relationships for the given Active Record model.
|
70
76
|
def relationships_by_entity_name(name) # @private :nodoc:
|
71
77
|
relationships_mapping[name] or []
|
72
78
|
end
|
73
|
-
|
79
|
+
|
74
80
|
def specializations_by_entity_name(name)
|
75
81
|
specializations_mapping[name] or []
|
76
82
|
end
|
77
|
-
|
83
|
+
|
78
84
|
def warn(message) # @private :nodoc:
|
79
85
|
puts "Warning: #{message}" if options.warn
|
80
86
|
end
|
81
|
-
|
87
|
+
|
82
88
|
private
|
83
|
-
|
89
|
+
|
84
90
|
def entity_mapping
|
85
91
|
@entity_mapping ||= {}.tap do |mapping|
|
86
92
|
entities.each do |entity|
|
@@ -88,7 +94,7 @@ module RailsERD
|
|
88
94
|
end
|
89
95
|
end
|
90
96
|
end
|
91
|
-
|
97
|
+
|
92
98
|
def relationships_mapping
|
93
99
|
@relationships_mapping ||= {}.tap do |mapping|
|
94
100
|
relationships.each do |relationship|
|
@@ -97,7 +103,7 @@ module RailsERD
|
|
97
103
|
end
|
98
104
|
end
|
99
105
|
end
|
100
|
-
|
106
|
+
|
101
107
|
def specializations_mapping
|
102
108
|
@specializations_mapping ||= {}.tap do |mapping|
|
103
109
|
specializations.each do |specialization|
|
@@ -106,21 +112,21 @@ module RailsERD
|
|
106
112
|
end
|
107
113
|
end
|
108
114
|
end
|
109
|
-
|
115
|
+
|
110
116
|
def models
|
111
117
|
@models ||= @source_models.reject(&:abstract_class?).select { |model| check_model_validity(model) }
|
112
118
|
end
|
113
|
-
|
119
|
+
|
114
120
|
def associations
|
115
121
|
@associations ||= models.collect(&:reflect_on_all_associations).flatten.select { |assoc| check_association_validity(assoc) }
|
116
122
|
end
|
117
|
-
|
123
|
+
|
118
124
|
def check_model_validity(model)
|
119
125
|
model.table_exists? or raise "table #{model.table_name} does not exist"
|
120
126
|
rescue => e
|
121
127
|
warn "Ignoring invalid model #{model.name} (#{e.message})"
|
122
128
|
end
|
123
|
-
|
129
|
+
|
124
130
|
def check_association_validity(association)
|
125
131
|
# Raises an ActiveRecord::ActiveRecordError if the association is broken.
|
126
132
|
association.check_validity!
|
@@ -135,7 +141,7 @@ module RailsERD
|
|
135
141
|
rescue => e
|
136
142
|
warn "Ignoring invalid association #{association_description(association)} (#{e.message})"
|
137
143
|
end
|
138
|
-
|
144
|
+
|
139
145
|
def association_description(association)
|
140
146
|
"#{association.name.inspect} on #{association.active_record}"
|
141
147
|
end
|
@@ -1,4 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
|
3
|
+
#--
|
2
4
|
module RailsERD
|
3
5
|
class Domain
|
4
6
|
# Describes an entity's attribute. Attributes correspond directly to
|
@@ -11,49 +13,51 @@ module RailsERD
|
|
11
13
|
model.columns.collect { |column| new(domain, model, column) }.sort
|
12
14
|
end
|
13
15
|
end
|
14
|
-
|
16
|
+
|
15
17
|
extend Inspectable
|
16
18
|
inspection_attributes :name, :type
|
17
19
|
|
18
20
|
attr_reader :column # @private :nodoc:
|
19
|
-
|
21
|
+
|
20
22
|
def initialize(domain, model, column) # @private :nodoc:
|
21
23
|
@domain, @model, @column = domain, model, column
|
22
24
|
end
|
23
|
-
|
25
|
+
|
24
26
|
# The name of the attribute, equal to the column name.
|
25
27
|
def name
|
26
28
|
column.name
|
27
29
|
end
|
28
|
-
|
30
|
+
|
29
31
|
# The type of the attribute, equal to the Rails migration type. Can be any
|
30
32
|
# of +:string+, +:integer+, +:boolean+, +:text+, etc.
|
31
33
|
def type
|
32
34
|
column.type
|
33
35
|
end
|
34
|
-
|
36
|
+
|
35
37
|
# Returns +true+ if this attribute is a content column, that is, if it
|
36
38
|
# is not a primary key, foreign key, timestamp, or inheritance column.
|
37
39
|
def content?
|
38
40
|
!primary_key? and !foreign_key? and !timestamp? and !inheritance?
|
39
41
|
end
|
40
|
-
|
42
|
+
|
41
43
|
# Returns +true+ if this attribute is mandatory. Mandatory attributes
|
42
44
|
# either have a presence validation (+validates_presence_of+), or have a
|
43
45
|
# <tt>NOT NULL</tt> database constraint.
|
44
46
|
def mandatory?
|
45
47
|
!column.null or @model.validators_on(name).map(&:kind).include?(:presence)
|
46
48
|
end
|
47
|
-
|
49
|
+
|
48
50
|
# Returns +true+ if this attribute is the primary key of the entity.
|
49
51
|
def primary_key?
|
50
52
|
column.primary
|
51
53
|
end
|
52
|
-
|
54
|
+
|
53
55
|
# Returns +true+ if this attribute is used as a foreign key for any
|
54
56
|
# relationship.
|
55
57
|
def foreign_key?
|
56
|
-
@domain.relationships_by_entity_name(@model.name).map(&:associations).flatten.map
|
58
|
+
@domain.relationships_by_entity_name(@model.name).map(&:associations).flatten.map { |associaton|
|
59
|
+
associaton.send(Domain.foreign_key_method_name)
|
60
|
+
}.include?(name)
|
57
61
|
end
|
58
62
|
|
59
63
|
# Returns +true+ if this attribute is used for single table inheritance.
|
@@ -68,15 +72,15 @@ module RailsERD
|
|
68
72
|
def timestamp?
|
69
73
|
TIMESTAMP_NAMES.include? name
|
70
74
|
end
|
71
|
-
|
75
|
+
|
72
76
|
def <=>(other) # @private :nodoc:
|
73
77
|
name <=> other.name
|
74
78
|
end
|
75
|
-
|
79
|
+
|
76
80
|
def to_s # @private :nodoc:
|
77
81
|
name
|
78
82
|
end
|
79
|
-
|
83
|
+
|
80
84
|
# Returns a description of the attribute type. If the attribute has
|
81
85
|
# a non-standard limit or if it is mandatory, this information is included.
|
82
86
|
#
|
@@ -84,19 +88,33 @@ module RailsERD
|
|
84
88
|
# <tt>:integer</tt>:: integer
|
85
89
|
# <tt>:string, :limit => 255</tt>:: string
|
86
90
|
# <tt>:string, :limit => 128</tt>:: string (128)
|
91
|
+
# <tt>:decimal, :precision => 5, :scale => 2/tt>:: decimal (5,2)
|
87
92
|
# <tt>:boolean, :null => false</tt>:: boolean *
|
88
93
|
def type_description
|
89
94
|
type.to_s.tap do |desc|
|
90
|
-
desc << "
|
95
|
+
desc << " #{limit_description}" if limit_description
|
91
96
|
desc << " ∗" if mandatory? # Add a hair space + low asterisk (Unicode characters).
|
92
97
|
end
|
93
98
|
end
|
94
|
-
|
99
|
+
|
95
100
|
# Returns any non-standard limit for this attribute. If a column has no
|
96
101
|
# limit or uses a default database limit, this method returns +nil+.
|
97
102
|
def limit
|
98
103
|
column.limit if column.limit != @model.connection.native_database_types[type][:limit]
|
99
104
|
end
|
105
|
+
|
106
|
+
# Returns any non-standard scale for this attribute (decimal types only).
|
107
|
+
def scale
|
108
|
+
column.scale if column.scale != @model.connection.native_database_types[type][:scale]
|
109
|
+
end
|
110
|
+
|
111
|
+
# Returns a string that describes the limit for this attribute, such as
|
112
|
+
# +(128)+, or +(5,2)+ for decimal types. Returns nil if no non-standard
|
113
|
+
# limit was set.
|
114
|
+
def limit_description # @private :nodoc:
|
115
|
+
return "(#{limit},#{scale})" if limit and scale
|
116
|
+
return "(#{limit})" if limit
|
117
|
+
end
|
100
118
|
end
|
101
119
|
end
|
102
120
|
end
|
@@ -11,29 +11,29 @@ module RailsERD
|
|
11
11
|
# join table in the case of many-to-many associations.
|
12
12
|
class Relationship
|
13
13
|
N = Cardinality::N
|
14
|
-
|
14
|
+
|
15
15
|
class << self
|
16
16
|
def from_associations(domain, associations) # @private :nodoc:
|
17
17
|
assoc_groups = associations.group_by { |assoc| association_identity(assoc) }
|
18
18
|
assoc_groups.collect { |_, assoc_group| new(domain, assoc_group.to_a) }
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
private
|
22
|
-
|
22
|
+
|
23
23
|
def association_identity(association)
|
24
|
-
identifier = association.options[:join_table] || association.options[:through] || association.
|
24
|
+
identifier = association.options[:join_table] || association.options[:through] || association.send(Domain.foreign_key_method_name).to_s
|
25
25
|
Set[identifier, association_owner(association), association_target(association)]
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
def association_owner(association)
|
29
29
|
association.options[:as] ? association.options[:as].to_s.classify : association.active_record.name
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
def association_target(association)
|
33
33
|
association.options[:polymorphic] ? association.class_name : association.klass.name
|
34
34
|
end
|
35
35
|
end
|
36
|
-
|
36
|
+
|
37
37
|
extend Inspectable
|
38
38
|
inspection_attributes :source, :destination
|
39
39
|
|
@@ -43,14 +43,14 @@ module RailsERD
|
|
43
43
|
# The source entity. It corresponds to the model that has defined a
|
44
44
|
# +has_one+ or +has_many+ association with the other model.
|
45
45
|
attr_reader :source
|
46
|
-
|
46
|
+
|
47
47
|
# The destination entity. It corresponds to the model that has defined
|
48
48
|
# a +belongs_to+ association with the other model.
|
49
49
|
attr_reader :destination
|
50
|
-
|
50
|
+
|
51
51
|
delegate :one_to_one?, :one_to_many?, :many_to_many?, :source_optional?,
|
52
52
|
:destination_optional?, :to => :cardinality
|
53
|
-
|
53
|
+
|
54
54
|
def initialize(domain, associations) # @private :nodoc:
|
55
55
|
@domain = domain
|
56
56
|
@reverse_associations, @forward_associations = *unless any_habtm?(associations)
|
@@ -61,19 +61,19 @@ module RailsERD
|
|
61
61
|
source = associations.map(&:active_record).sort_by(&:name).first
|
62
62
|
associations.partition { |association| association.active_record != source }
|
63
63
|
end
|
64
|
-
|
64
|
+
|
65
65
|
assoc = @forward_associations.first || @reverse_associations.first
|
66
66
|
@source = @domain.entity_by_name(self.class.send(:association_owner, assoc))
|
67
67
|
@destination = @domain.entity_by_name(self.class.send(:association_target, assoc))
|
68
68
|
@source, @destination = @destination, @source if assoc.belongs_to?
|
69
69
|
end
|
70
|
-
|
70
|
+
|
71
71
|
# Returns all Active Record association objects that describe this
|
72
72
|
# relationship.
|
73
73
|
def associations
|
74
74
|
@forward_associations + @reverse_associations
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
# Returns the cardinality of this relationship.
|
78
78
|
def cardinality
|
79
79
|
@cardinality ||= begin
|
@@ -83,7 +83,7 @@ module RailsERD
|
|
83
83
|
Cardinality.new(reverse_range, forward_range)
|
84
84
|
end
|
85
85
|
end
|
86
|
-
|
86
|
+
|
87
87
|
# Indicates if a relationship is indirect, that is, if it is defined
|
88
88
|
# through other relationships. Indirect relationships are created in
|
89
89
|
# Rails with <tt>has_many :through</tt> or <tt>has_one :through</tt>
|
@@ -91,45 +91,45 @@ module RailsERD
|
|
91
91
|
def indirect?
|
92
92
|
!@forward_associations.empty? and @forward_associations.all?(&:through_reflection)
|
93
93
|
end
|
94
|
-
|
94
|
+
|
95
95
|
# Indicates whether or not the relationship is defined by two inverse
|
96
96
|
# associations (e.g. a +has_many+ and a corresponding +belongs_to+
|
97
97
|
# association).
|
98
98
|
def mutual?
|
99
99
|
@forward_associations.any? and @reverse_associations.any?
|
100
100
|
end
|
101
|
-
|
101
|
+
|
102
102
|
# Indicates whether or not this relationship connects an entity with itself.
|
103
103
|
def recursive?
|
104
104
|
@source == @destination
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
# Indicates whether the destination cardinality class of this relationship
|
108
108
|
# is equal to one. This is +true+ for one-to-one relationships only.
|
109
109
|
def to_one?
|
110
110
|
cardinality.cardinality_class[1] == 1
|
111
111
|
end
|
112
|
-
|
112
|
+
|
113
113
|
# Indicates whether the destination cardinality class of this relationship
|
114
114
|
# is equal to infinity. This is +true+ for one-to-many or
|
115
115
|
# many-to-many relationships only.
|
116
116
|
def to_many?
|
117
117
|
cardinality.cardinality_class[1] != 1
|
118
118
|
end
|
119
|
-
|
119
|
+
|
120
120
|
# Indicates whether the source cardinality class of this relationship
|
121
121
|
# is equal to one. This is +true+ for one-to-one or
|
122
122
|
# one-to-many relationships only.
|
123
123
|
def one_to?
|
124
124
|
cardinality.cardinality_class[0] == 1
|
125
125
|
end
|
126
|
-
|
126
|
+
|
127
127
|
# Indicates whether the source cardinality class of this relationship
|
128
128
|
# is equal to infinity. This is +true+ for many-to-many relationships only.
|
129
129
|
def many_to?
|
130
130
|
cardinality.cardinality_class[0] != 1
|
131
131
|
end
|
132
|
-
|
132
|
+
|
133
133
|
# The strength of a relationship is equal to the number of associations
|
134
134
|
# that describe it.
|
135
135
|
def strength
|
@@ -139,7 +139,7 @@ module RailsERD
|
|
139
139
|
def <=>(other) # @private :nodoc:
|
140
140
|
(source.name <=> other.source.name).nonzero? or (destination.name <=> other.destination.name)
|
141
141
|
end
|
142
|
-
|
142
|
+
|
143
143
|
private
|
144
144
|
|
145
145
|
def associations_range(associations, absolute_max)
|
@@ -157,7 +157,7 @@ module RailsERD
|
|
157
157
|
|
158
158
|
min..max
|
159
159
|
end
|
160
|
-
|
160
|
+
|
161
161
|
def association_minimum(association)
|
162
162
|
minimum = association_validators(:presence, association).any? ||
|
163
163
|
foreign_key_required?(association) ? 1 : 0
|
@@ -166,22 +166,22 @@ module RailsERD
|
|
166
166
|
end
|
167
167
|
|
168
168
|
def association_maximum(association)
|
169
|
-
maximum = association.collection? ? N : 1
|
169
|
+
maximum = association.collection? ? N : 1
|
170
170
|
length_validators = association_validators(:length, association)
|
171
171
|
length_validators.map { |v| v.options[:maximum] }.compact.min or maximum
|
172
172
|
end
|
173
|
-
|
173
|
+
|
174
174
|
def association_validators(kind, association)
|
175
175
|
association.active_record.validators_on(association.name).select { |v| v.kind == kind }
|
176
176
|
end
|
177
|
-
|
177
|
+
|
178
178
|
def any_habtm?(associations)
|
179
179
|
associations.any? { |association| association.macro == :has_and_belongs_to_many }
|
180
180
|
end
|
181
|
-
|
181
|
+
|
182
182
|
def foreign_key_required?(association)
|
183
183
|
if association.belongs_to?
|
184
|
-
column = association.active_record.columns_hash[association.
|
184
|
+
column = association.active_record.columns_hash[association.send(Domain.foreign_key_method_name)] and !column.null
|
185
185
|
end
|
186
186
|
end
|
187
187
|
end
|
data/rails-erd.gemspec
CHANGED
@@ -1,72 +1,70 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{rails-erd}
|
8
|
-
s.version = "0.4.
|
8
|
+
s.version = "0.4.3"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Rolf Timmermans"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-27}
|
13
13
|
s.description = %q{Automatically generate an entity-relationship diagram (ERD) for your Rails models.}
|
14
14
|
s.email = %q{r.timmermans@voormedia.com}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.md"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
".
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
"test/unit/specialization_test.rb"
|
20
|
+
"CHANGES.rdoc",
|
21
|
+
"Gemfile",
|
22
|
+
"Gemfile.lock",
|
23
|
+
"LICENSE",
|
24
|
+
"README.md",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/rails-erd.rb",
|
28
|
+
"lib/rails_erd.rb",
|
29
|
+
"lib/rails_erd/diagram.rb",
|
30
|
+
"lib/rails_erd/diagram/graphviz.rb",
|
31
|
+
"lib/rails_erd/diagram/templates/node.erb",
|
32
|
+
"lib/rails_erd/domain.rb",
|
33
|
+
"lib/rails_erd/domain/attribute.rb",
|
34
|
+
"lib/rails_erd/domain/entity.rb",
|
35
|
+
"lib/rails_erd/domain/relationship.rb",
|
36
|
+
"lib/rails_erd/domain/relationship/cardinality.rb",
|
37
|
+
"lib/rails_erd/domain/specialization.rb",
|
38
|
+
"lib/rails_erd/railtie.rb",
|
39
|
+
"lib/rails_erd/tasks.rake",
|
40
|
+
"rails-erd.gemspec",
|
41
|
+
"test/test_helper.rb",
|
42
|
+
"test/unit/attribute_test.rb",
|
43
|
+
"test/unit/cardinality_test.rb",
|
44
|
+
"test/unit/diagram_test.rb",
|
45
|
+
"test/unit/domain_test.rb",
|
46
|
+
"test/unit/entity_test.rb",
|
47
|
+
"test/unit/graphviz_test.rb",
|
48
|
+
"test/unit/rake_task_test.rb",
|
49
|
+
"test/unit/relationship_test.rb",
|
50
|
+
"test/unit/specialization_test.rb"
|
52
51
|
]
|
53
52
|
s.homepage = %q{http://rails-erd.rubyforge.org/}
|
54
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
55
53
|
s.require_paths = ["lib"]
|
56
54
|
s.rubyforge_project = %q{rails-erd}
|
57
55
|
s.rubygems_version = %q{1.3.7}
|
58
56
|
s.summary = %q{Entity-relationship diagram for your Rails models.}
|
59
57
|
s.test_files = [
|
60
58
|
"test/test_helper.rb",
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
59
|
+
"test/unit/attribute_test.rb",
|
60
|
+
"test/unit/cardinality_test.rb",
|
61
|
+
"test/unit/diagram_test.rb",
|
62
|
+
"test/unit/domain_test.rb",
|
63
|
+
"test/unit/entity_test.rb",
|
64
|
+
"test/unit/graphviz_test.rb",
|
65
|
+
"test/unit/rake_task_test.rb",
|
66
|
+
"test/unit/relationship_test.rb",
|
67
|
+
"test/unit/specialization_test.rb"
|
70
68
|
]
|
71
69
|
|
72
70
|
if s.respond_to? :specification_version then
|
@@ -77,18 +75,36 @@ Gem::Specification.new do |s|
|
|
77
75
|
s.add_runtime_dependency(%q<activerecord>, ["~> 3.0"])
|
78
76
|
s.add_runtime_dependency(%q<activesupport>, ["~> 3.0"])
|
79
77
|
s.add_runtime_dependency(%q<ruby-graphviz>, ["~> 0.9.18"])
|
80
|
-
s.add_development_dependency(%q<
|
78
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
79
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
80
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
81
|
+
s.add_development_dependency(%q<sqlite3>, [">= 0"])
|
82
|
+
s.add_development_dependency(%q<jdbc-sqlite3>, [">= 0"])
|
83
|
+
s.add_development_dependency(%q<activerecord-jdbc-adapter>, [">= 0"])
|
84
|
+
s.add_development_dependency(%q<jruby-openssl>, [">= 0"])
|
81
85
|
else
|
82
86
|
s.add_dependency(%q<activerecord>, ["~> 3.0"])
|
83
87
|
s.add_dependency(%q<activesupport>, ["~> 3.0"])
|
84
88
|
s.add_dependency(%q<ruby-graphviz>, ["~> 0.9.18"])
|
85
|
-
s.add_dependency(%q<
|
89
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
90
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
91
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
92
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
93
|
+
s.add_dependency(%q<jdbc-sqlite3>, [">= 0"])
|
94
|
+
s.add_dependency(%q<activerecord-jdbc-adapter>, [">= 0"])
|
95
|
+
s.add_dependency(%q<jruby-openssl>, [">= 0"])
|
86
96
|
end
|
87
97
|
else
|
88
98
|
s.add_dependency(%q<activerecord>, ["~> 3.0"])
|
89
99
|
s.add_dependency(%q<activesupport>, ["~> 3.0"])
|
90
100
|
s.add_dependency(%q<ruby-graphviz>, ["~> 0.9.18"])
|
91
|
-
s.add_dependency(%q<
|
101
|
+
s.add_dependency(%q<rake>, [">= 0"])
|
102
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
103
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
104
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
105
|
+
s.add_dependency(%q<jdbc-sqlite3>, [">= 0"])
|
106
|
+
s.add_dependency(%q<activerecord-jdbc-adapter>, [">= 0"])
|
107
|
+
s.add_dependency(%q<jruby-openssl>, [">= 0"])
|
92
108
|
end
|
93
109
|
end
|
94
110
|
|
data/test/unit/attribute_test.rb
CHANGED
@@ -18,18 +18,18 @@ class AttributeTest < ActiveSupport::TestCase
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def create_attribute(model, name)
|
23
23
|
Domain::Attribute.new(Domain.generate, model, model.columns_hash[name])
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
# Attribute ================================================================
|
27
27
|
test "column should return database column" do
|
28
28
|
create_model "Foo", :my_column => :string
|
29
29
|
assert_equal Foo.columns_hash["my_column"],
|
30
30
|
Domain::Attribute.from_model(Domain.new, Foo).reject(&:primary_key?).first.column
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
test "spaceship should sort attributes by name" do
|
34
34
|
create_model "Foo", :a => :string, :b => :string, :c => :string
|
35
35
|
a = create_attribute(Foo, "a")
|
@@ -37,18 +37,18 @@ class AttributeTest < ActiveSupport::TestCase
|
|
37
37
|
c = create_attribute(Foo, "c")
|
38
38
|
assert_equal [a, b, c], [c, a, b].sort
|
39
39
|
end
|
40
|
-
|
40
|
+
|
41
41
|
test "inspect should show column" do
|
42
42
|
create_model "Foo", :my_column => :string
|
43
43
|
assert_match %r{#<RailsERD::Domain::Attribute:.* @name="my_column" @type=:string>},
|
44
44
|
Domain::Attribute.new(Domain.new, Foo, Foo.columns_hash["my_column"]).inspect
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
test "type should return attribute type" do
|
48
48
|
create_model "Foo", :a => :binary
|
49
49
|
assert_equal :binary, create_attribute(Foo, "a").type
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
52
|
# Attribute properties =====================================================
|
53
53
|
test "mandatory should return false by default" do
|
54
54
|
create_model "Foo", :column => :string
|
@@ -111,21 +111,21 @@ class AttributeTest < ActiveSupport::TestCase
|
|
111
111
|
assert_equal [true] * 4, [create_attribute(Foo, "created_at"), create_attribute(Foo, "updated_at"),
|
112
112
|
create_attribute(Foo, "created_on"), create_attribute(Foo, "updated_on")].collect(&:timestamp?)
|
113
113
|
end
|
114
|
-
|
114
|
+
|
115
115
|
test "inheritance should return false by default" do
|
116
116
|
create_model "Foo", :type => :string, :alternative => :string do
|
117
117
|
set_inheritance_column :alternative
|
118
118
|
end
|
119
119
|
assert_equal false, create_attribute(Foo, "type").inheritance?
|
120
120
|
end
|
121
|
-
|
121
|
+
|
122
122
|
test "inheritance should return if this column is used for single table inheritance" do
|
123
123
|
create_model "Foo", :type => :string, :alternative => :string do
|
124
124
|
set_inheritance_column :alternative
|
125
125
|
end
|
126
126
|
assert_equal true, create_attribute(Foo, "alternative").inheritance?
|
127
127
|
end
|
128
|
-
|
128
|
+
|
129
129
|
test "content should return true by default" do
|
130
130
|
create_model "Foo", :my_first_column => :string
|
131
131
|
assert_equal true, create_attribute(Foo, "my_first_column").content?
|
@@ -138,7 +138,7 @@ class AttributeTest < ActiveSupport::TestCase
|
|
138
138
|
create_model "Case"
|
139
139
|
assert_equal [false] * 4, %w{id type created_at case_id}.map { |a| create_attribute(Book, a).content? }
|
140
140
|
end
|
141
|
-
|
141
|
+
|
142
142
|
# Type descriptions ========================================================
|
143
143
|
test "type_description should return short type description" do
|
144
144
|
create_model "Foo", :a => :binary
|
@@ -161,20 +161,26 @@ class AttributeTest < ActiveSupport::TestCase
|
|
161
161
|
assert_equal "string", create_attribute(Foo, "my_str").type_description
|
162
162
|
end
|
163
163
|
end
|
164
|
-
|
164
|
+
|
165
165
|
test "type_description should append hair space and low asterisk if field is mandatory" do
|
166
166
|
create_model "Foo", :a => :integer do
|
167
167
|
validates_presence_of :a
|
168
168
|
end
|
169
169
|
assert_equal "integer ∗", create_attribute(Foo, "a").type_description
|
170
170
|
end
|
171
|
-
|
171
|
+
|
172
|
+
test "type_description should return short type description with scale and precision for decimal types if nonstandard" do
|
173
|
+
create_model "Foo"
|
174
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
175
|
+
assert_equal "decimal (5,2)", create_attribute(Foo, "num").type_description
|
176
|
+
end
|
177
|
+
|
172
178
|
test "limit should return nil if there is no limit" do
|
173
179
|
create_model "Foo"
|
174
180
|
add_column :foos, :my_txt, :text
|
175
181
|
assert_equal nil, create_attribute(Foo, "my_txt").limit
|
176
182
|
end
|
177
|
-
|
183
|
+
|
178
184
|
test "limit should return nil if equal to standard database limit" do
|
179
185
|
with_native_limit :string, 456 do
|
180
186
|
create_model "Foo"
|
@@ -182,7 +188,7 @@ class AttributeTest < ActiveSupport::TestCase
|
|
182
188
|
assert_equal nil, create_attribute(Foo, "my_str").limit
|
183
189
|
end
|
184
190
|
end
|
185
|
-
|
191
|
+
|
186
192
|
test "limit should return limit if nonstandard" do
|
187
193
|
with_native_limit :string, 456 do
|
188
194
|
create_model "Foo"
|
@@ -190,4 +196,34 @@ class AttributeTest < ActiveSupport::TestCase
|
|
190
196
|
assert_equal 255, create_attribute(Foo, "my_str").limit
|
191
197
|
end
|
192
198
|
end
|
199
|
+
|
200
|
+
test "limit should return precision for decimal columns if nonstandard" do
|
201
|
+
create_model "Foo"
|
202
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
203
|
+
assert_equal 5, create_attribute(Foo, "num").limit
|
204
|
+
end
|
205
|
+
|
206
|
+
test "limit should return nil for decimal columns if equal to standard database limit" do
|
207
|
+
create_model "Foo"
|
208
|
+
add_column :foos, :num, :decimal
|
209
|
+
assert_equal nil, create_attribute(Foo, "num").limit
|
210
|
+
end
|
211
|
+
|
212
|
+
test "scale should return scale for decimal columns if nonstandard" do
|
213
|
+
create_model "Foo"
|
214
|
+
add_column :foos, :num, :decimal, :precision => 5, :scale => 2
|
215
|
+
assert_equal 2, create_attribute(Foo, "num").scale
|
216
|
+
end
|
217
|
+
|
218
|
+
test "scale should return nil for decimal columns if equal to standard database limit" do
|
219
|
+
create_model "Foo"
|
220
|
+
add_column :foos, :num, :decimal
|
221
|
+
assert_equal nil, create_attribute(Foo, "num").scale
|
222
|
+
end
|
223
|
+
|
224
|
+
test "scale should return zero for decimal columns if left to default setting when specifying precision" do
|
225
|
+
create_model "Foo"
|
226
|
+
add_column :foos, :num, :decimal, :precision => 5
|
227
|
+
assert_equal 0, create_attribute(Foo, "num").scale
|
228
|
+
end
|
193
229
|
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 4
|
8
|
-
-
|
9
|
-
version: 0.4.
|
8
|
+
- 3
|
9
|
+
version: 0.4.3
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Rolf Timmermans
|
@@ -14,12 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2011-01-27 00:00:00 +01:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activerecord
|
22
|
-
prerelease: false
|
23
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
23
|
none: false
|
25
24
|
requirements:
|
@@ -30,10 +29,10 @@ dependencies:
|
|
30
29
|
- 0
|
31
30
|
version: "3.0"
|
32
31
|
type: :runtime
|
32
|
+
prerelease: false
|
33
33
|
version_requirements: *id001
|
34
34
|
- !ruby/object:Gem::Dependency
|
35
35
|
name: activesupport
|
36
|
-
prerelease: false
|
37
36
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
37
|
none: false
|
39
38
|
requirements:
|
@@ -44,10 +43,10 @@ dependencies:
|
|
44
43
|
- 0
|
45
44
|
version: "3.0"
|
46
45
|
type: :runtime
|
46
|
+
prerelease: false
|
47
47
|
version_requirements: *id002
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: ruby-graphviz
|
50
|
-
prerelease: false
|
51
50
|
requirement: &id003 !ruby/object:Gem::Requirement
|
52
51
|
none: false
|
53
52
|
requirements:
|
@@ -59,10 +58,10 @@ dependencies:
|
|
59
58
|
- 18
|
60
59
|
version: 0.9.18
|
61
60
|
type: :runtime
|
61
|
+
prerelease: false
|
62
62
|
version_requirements: *id003
|
63
63
|
- !ruby/object:Gem::Dependency
|
64
|
-
name:
|
65
|
-
prerelease: false
|
64
|
+
name: rake
|
66
65
|
requirement: &id004 !ruby/object:Gem::Requirement
|
67
66
|
none: false
|
68
67
|
requirements:
|
@@ -72,7 +71,90 @@ dependencies:
|
|
72
71
|
- 0
|
73
72
|
version: "0"
|
74
73
|
type: :development
|
74
|
+
prerelease: false
|
75
75
|
version_requirements: *id004
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: bundler
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ~>
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
segments:
|
84
|
+
- 1
|
85
|
+
- 0
|
86
|
+
- 0
|
87
|
+
version: 1.0.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *id005
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: jeweler
|
93
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ~>
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
segments:
|
99
|
+
- 1
|
100
|
+
- 5
|
101
|
+
- 2
|
102
|
+
version: 1.5.2
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: *id006
|
106
|
+
- !ruby/object:Gem::Dependency
|
107
|
+
name: sqlite3
|
108
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
segments:
|
114
|
+
- 0
|
115
|
+
version: "0"
|
116
|
+
type: :development
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: *id007
|
119
|
+
- !ruby/object:Gem::Dependency
|
120
|
+
name: jdbc-sqlite3
|
121
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
122
|
+
none: false
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
segments:
|
127
|
+
- 0
|
128
|
+
version: "0"
|
129
|
+
type: :development
|
130
|
+
prerelease: false
|
131
|
+
version_requirements: *id008
|
132
|
+
- !ruby/object:Gem::Dependency
|
133
|
+
name: activerecord-jdbc-adapter
|
134
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
135
|
+
none: false
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
segments:
|
140
|
+
- 0
|
141
|
+
version: "0"
|
142
|
+
type: :development
|
143
|
+
prerelease: false
|
144
|
+
version_requirements: *id009
|
145
|
+
- !ruby/object:Gem::Dependency
|
146
|
+
name: jruby-openssl
|
147
|
+
requirement: &id010 !ruby/object:Gem::Requirement
|
148
|
+
none: false
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
segments:
|
153
|
+
- 0
|
154
|
+
version: "0"
|
155
|
+
type: :development
|
156
|
+
prerelease: false
|
157
|
+
version_requirements: *id010
|
76
158
|
description: Automatically generate an entity-relationship diagram (ERD) for your Rails models.
|
77
159
|
email: r.timmermans@voormedia.com
|
78
160
|
executables: []
|
@@ -83,7 +165,6 @@ extra_rdoc_files:
|
|
83
165
|
- LICENSE
|
84
166
|
- README.md
|
85
167
|
files:
|
86
|
-
- .gitignore
|
87
168
|
- CHANGES.rdoc
|
88
169
|
- Gemfile
|
89
170
|
- Gemfile.lock
|
@@ -120,8 +201,8 @@ homepage: http://rails-erd.rubyforge.org/
|
|
120
201
|
licenses: []
|
121
202
|
|
122
203
|
post_install_message:
|
123
|
-
rdoc_options:
|
124
|
-
|
204
|
+
rdoc_options: []
|
205
|
+
|
125
206
|
require_paths:
|
126
207
|
- lib
|
127
208
|
required_ruby_version: !ruby/object:Gem::Requirement
|