rails-erd 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
7
+ - 4
8
8
  - 0
9
- version: 0.3.0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Rolf Timmermans
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-10-03 00:00:00 +02:00
17
+ date: 2010-10-12 00:00:00 +02:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -28,8 +28,7 @@ dependencies:
28
28
  segments:
29
29
  - 3
30
30
  - 0
31
- - 0
32
- version: 3.0.0
31
+ version: "3.0"
33
32
  type: :runtime
34
33
  version_requirements: *id001
35
34
  - !ruby/object:Gem::Dependency
@@ -57,8 +56,8 @@ dependencies:
57
56
  segments:
58
57
  - 0
59
58
  - 9
60
- - 17
61
- version: 0.9.17
59
+ - 18
60
+ version: 0.9.18
62
61
  type: :runtime
63
62
  version_requirements: *id003
64
63
  - !ruby/object:Gem::Dependency
@@ -82,27 +81,28 @@ extensions: []
82
81
 
83
82
  extra_rdoc_files:
84
83
  - LICENSE
85
- - README.rdoc
84
+ - README.md
86
85
  files:
87
86
  - .gitignore
88
87
  - CHANGES.rdoc
89
88
  - Gemfile
90
89
  - Gemfile.lock
91
90
  - LICENSE
92
- - README.rdoc
91
+ - README.md
93
92
  - Rakefile
94
93
  - VERSION
95
94
  - lib/rails-erd.rb
96
95
  - lib/rails_erd.rb
97
- - lib/rails_erd/attribute.rb
98
96
  - lib/rails_erd/diagram.rb
99
97
  - lib/rails_erd/diagram/graphviz.rb
100
98
  - lib/rails_erd/diagram/templates/node.erb
101
99
  - lib/rails_erd/domain.rb
102
- - lib/rails_erd/entity.rb
100
+ - lib/rails_erd/domain/attribute.rb
101
+ - lib/rails_erd/domain/entity.rb
102
+ - lib/rails_erd/domain/relationship.rb
103
+ - lib/rails_erd/domain/relationship/cardinality.rb
104
+ - lib/rails_erd/domain/specialization.rb
103
105
  - lib/rails_erd/railtie.rb
104
- - lib/rails_erd/relationship.rb
105
- - lib/rails_erd/relationship/cardinality.rb
106
106
  - lib/rails_erd/tasks.rake
107
107
  - rails-erd.gemspec
108
108
  - test/test_helper.rb
@@ -114,6 +114,7 @@ files:
114
114
  - test/unit/graphviz_test.rb
115
115
  - test/unit/rake_task_test.rb
116
116
  - test/unit/relationship_test.rb
117
+ - test/unit/specialization_test.rb
117
118
  has_rdoc: true
118
119
  homepage: http://rails-erd.rubyforge.org/
119
120
  licenses: []
@@ -156,3 +157,4 @@ test_files:
156
157
  - test/unit/graphviz_test.rb
157
158
  - test/unit/rake_task_test.rb
158
159
  - test/unit/relationship_test.rb
160
+ - test/unit/specialization_test.rb
data/README.rdoc DELETED
@@ -1,51 +0,0 @@
1
- = Rails ERD - Generate Entity-Relationship Diagrams for Rails applications
2
-
3
- {Rails ERD}[http://rails-erd.rubyforge.org/] is a Rails plugin that allows
4
- you to easily generate a diagram based on your Active Record models. The
5
- diagram gives an overview of how your models are related. Having a diagram
6
- that describes your models is perfect documentation for your application.
7
-
8
- The second goal of Rails ERD is to provide you with a tool to inspect your
9
- application's domain model. If you don't like the default output, it is very
10
- easy to use the API to build your own diagrams.
11
-
12
- Rails ERD was created specifically for Rails 3. It uses Active Record's
13
- built-in reflection capabilities to figure out how your models are associated.
14
-
15
- == Preview
16
-
17
- Here's an example entity-relationship diagram that was generated by Rails ERD:
18
-
19
- http://rails-erd.rubyforge.org/examples/event-forms.png
20
-
21
- == Learn more
22
-
23
- Homepage:
24
- http://rails-erd.rubyforge.org/
25
-
26
- Diagram gallery:
27
- http://rails-erd.rubyforge.org/gallery.html
28
-
29
- Installation instructions:
30
- http://rails-erd.rubyforge.org/install.html
31
-
32
- Internal API documentation:
33
- http://rails-erd.rubyforge.org/doc/
34
-
35
- Source code at Github:
36
- http://github.com/voormedia/rails-erd
37
-
38
- == About Rails ERD
39
-
40
- Author: Rolf Timmermans (r.timmermans <i>at</i> voormedia.com)
41
-
42
- Copyright 2010 Voormedia B.V.
43
-
44
- == License
45
-
46
- Rails ERD is released under the MIT license. See the LICENSE.
47
-
48
- == Credits
49
-
50
- Rails ERD depends on the Ruby-Graphviz library to generate diagrams:
51
- http://github.com/glejeune/Ruby-Graphviz/
@@ -1,95 +0,0 @@
1
- # -*- encoding: utf-8
2
- module RailsERD
3
- # Describes an entity's attribute. Attributes correspond directly to
4
- # database columns.
5
- class Attribute
6
- TIMESTAMP_NAMES = %w{created_at created_on updated_at updated_on} # @private :nodoc:
7
-
8
- class << self
9
- def from_model(domain, model) # @private :nodoc:
10
- model.arel_table.columns.collect { |column| Attribute.new(domain, model, column) }.sort
11
- end
12
- end
13
-
14
- attr_reader :column # @private :nodoc:
15
-
16
- def initialize(domain, model, column) # @private :nodoc:
17
- @domain, @model, @column = domain, model, column
18
- end
19
-
20
- # The name of the attribute, equal to the column name.
21
- def name
22
- column.name
23
- end
24
-
25
- # The type of the attribute, equal to the Rails migration type. Can be any
26
- # of +:string+, +:integer+, +:boolean+, +:text+, etc.
27
- def type
28
- column.type
29
- end
30
-
31
- # Returns +true+ if this attribute has no special meaning, that is, if it
32
- # is not a primary key, foreign key, or timestamp.
33
- def regular?
34
- !primary_key? and !foreign_key? and !timestamp?
35
- end
36
-
37
- # Returns +true+ if this attribute is mandatory. Mandatory attributes
38
- # either have a presence validation (+validates_presence_of+), or have a
39
- # <tt>NOT NULL</tt> database constraint.
40
- def mandatory?
41
- !column.null or @model.validators_on(name).map(&:kind).include?(:presence)
42
- end
43
-
44
- # Returns +true+ if this attribute is the primary key of the entity.
45
- def primary_key?
46
- @model.arel_table.primary_key == name
47
- end
48
-
49
- # Returns +true+ if this attribute is used as a foreign key for any
50
- # relationship.
51
- def foreign_key?
52
- @domain.relationships_for(@model).map(&:associations).flatten.map(&:primary_key_name).include?(name)
53
- end
54
-
55
- # Returns +true+ if this attribute is one of the standard 'magic' Rails
56
- # timestamp columns, being +created_at+, +updated_at+, +created_on+ or
57
- # +updated_on+.
58
- def timestamp?
59
- TIMESTAMP_NAMES.include? name
60
- end
61
-
62
- def <=>(other) # @private :nodoc:
63
- name <=> other.name
64
- end
65
-
66
- def inspect # @private :nodoc:
67
- "#<#{self.class.name}:0x%.14x @column=#{name.inspect} @type=#{type.inspect}>" % (object_id << 1)
68
- end
69
-
70
- def to_s # @private :nodoc:
71
- name
72
- end
73
-
74
- # Returns a description of the attribute type. If the attribute has
75
- # a non-standard limit or if it is mandatory, this information is included.
76
- #
77
- # Example output:
78
- # <tt>:integer</tt>:: integer
79
- # <tt>:string, :limit => 255</tt>:: string
80
- # <tt>:string, :limit => 128</tt>:: string (128)
81
- # <tt>:boolean, :null => false</tt>:: boolean *
82
- def type_description
83
- type.to_s.tap do |desc|
84
- desc << " (#{limit})" if limit
85
- desc << " ∗" if mandatory? # Add a hair space + low asterisk (Unicode characters).
86
- end
87
- end
88
-
89
- # Returns any non-standard limit for this attribute. If a column has no
90
- # limit or uses a default database limit, this method returns +nil+.
91
- def limit
92
- column.limit if column.limit != @model.connection.native_database_types[type][:limit]
93
- end
94
- end
95
- end
@@ -1,73 +0,0 @@
1
- module RailsERD
2
- # Entities represent your Active Record models. Entities may be connected
3
- # to other entities.
4
- class Entity
5
- class << self
6
- def from_models(domain, models) # @private :nodoc:
7
- models.collect { |model| new domain, model }.sort
8
- end
9
- end
10
-
11
- # The domain in which this entity resides.
12
- attr_reader :domain
13
-
14
- # The Active Record model that this entity corresponds to.
15
- attr_reader :model
16
-
17
- def initialize(domain, model) # @private :nodoc:
18
- @domain, @model = domain, model
19
- end
20
-
21
- # Returns an array of attributes for this entity.
22
- def attributes
23
- @attributes ||= Attribute.from_model @domain, @model
24
- end
25
-
26
- # Returns an array of all relationships that this entity has with other
27
- # entities in the domain model.
28
- def relationships
29
- @domain.relationships_for(@model)
30
- end
31
-
32
- # Returns the parent entity, if this entity is a descendant.
33
- def parent
34
- @domain.entity_for(@model.superclass) if descendant?
35
- end
36
-
37
- # Returns +true+ if this entity has any relationships with other models,
38
- # +false+ otherwise.
39
- def connected?
40
- relationships.any?
41
- end
42
-
43
- # Returns +true+ if this entity has no relationships with any other models,
44
- # +false+ otherwise. Opposite of +connected?+.
45
- def disconnected?
46
- relationships.none?
47
- end
48
-
49
- # Returns +true+ if this entity descends from another entity, and is
50
- # represented in the same table as its parent.
51
- def descendant?
52
- !@model.descends_from_active_record?
53
- end
54
-
55
- # Returns the name of this entity, which is the class name of the
56
- # corresponding model.
57
- def name
58
- model.name
59
- end
60
-
61
- def inspect # @private :nodoc:
62
- "#<#{self.class}:0x%.14x @model=#{name}>" % (object_id << 1)
63
- end
64
-
65
- def to_s # @private :nodoc:
66
- name
67
- end
68
-
69
- def <=>(other) # @private :nodoc:
70
- self.name <=> other.name
71
- end
72
- end
73
- end
@@ -1,177 +0,0 @@
1
- require "rails_erd/relationship/cardinality"
2
-
3
- module RailsERD
4
- # Describes a relationship between two entities. A relationship is detected
5
- # based on Active Record associations. One relationship may represent more
6
- # than one association, however. Related associations are grouped together.
7
- # Associations are related if they share the same foreign key, or the same
8
- # join table in the case of many-to-many associations.
9
- class Relationship
10
- N = Cardinality::N
11
-
12
- class << self
13
- def from_associations(domain, associations) # @private :nodoc:
14
- assoc_groups = associations.group_by { |assoc| association_identity(assoc) }
15
- assoc_groups.collect { |_, assoc_group| Relationship.new(domain, assoc_group.to_a) }
16
- end
17
-
18
- private
19
-
20
- def association_identity(assoc)
21
- identifier = assoc.options[:join_table] || assoc.primary_key_name.to_s
22
- Set[identifier, assoc.active_record, assoc.klass]
23
- end
24
- end
25
-
26
- # The domain in which this relationship is defined.
27
- attr_reader :domain
28
-
29
- # The source entity. It corresponds to the model that has defined a
30
- # +has_one+ or +has_many+ association with the other model.
31
- attr_reader :source
32
-
33
- # The destination entity. It corresponds to the model that has defined
34
- # a +belongs_to+ association with the other model.
35
- attr_reader :destination
36
-
37
- delegate :one_to_one?, :one_to_many?, :many_to_many?, :source_optional?,
38
- :destination_optional?, :to => :cardinality
39
-
40
- def initialize(domain, associations) # @private :nodoc:
41
- @domain = domain
42
- @reverse_associations, @forward_associations = *unless any_habtm?(associations)
43
- associations.partition(&:belongs_to?)
44
- else
45
- # Many-to-many associations don't have a clearly defined direction.
46
- # We sort by name and use the first model as the source.
47
- source = associations.first.active_record
48
- associations.partition { |association| association.active_record == source }
49
- end
50
-
51
- assoc = @forward_associations.first || @reverse_associations.first
52
- @source, @destination = @domain.entity_for(assoc.active_record), @domain.entity_for(assoc.klass)
53
- @source, @destination = @destination, @source if assoc.belongs_to?
54
- end
55
-
56
- # Returns all Active Record association objects that describe this
57
- # relationship.
58
- def associations
59
- @forward_associations + @reverse_associations
60
- end
61
-
62
- # Returns the cardinality of this relationship.
63
- def cardinality
64
- @cardinality ||= begin
65
- reverse_max = any_habtm?(associations) ? N : 1
66
- forward_range = associations_range(@source.model, @forward_associations, N)
67
- reverse_range = associations_range(@destination.model, @reverse_associations, reverse_max)
68
- Cardinality.new(reverse_range, forward_range)
69
- end
70
- end
71
-
72
- # Indicates if a relationship is indirect, that is, if it is defined
73
- # through other relationships. Indirect relationships are created in
74
- # Rails with <tt>has_many :through</tt> or <tt>has_one :through</tt>
75
- # association macros.
76
- def indirect?
77
- !@forward_associations.empty? and @forward_associations.all?(&:through_reflection)
78
- end
79
-
80
- # Indicates whether or not the relationship is defined by two inverse
81
- # associations (e.g. a +has_many+ and a corresponding +belongs_to+
82
- # association).
83
- def mutual?
84
- @forward_associations.any? and @reverse_associations.any?
85
- end
86
-
87
- # Indicates whether or not this relationship connects an entity with itself.
88
- def recursive?
89
- @source == @destination
90
- end
91
-
92
- # Indicates whether the destination cardinality class of this relationship
93
- # is equal to one. This is +true+ for one-to-one relationships only.
94
- def to_one?
95
- cardinality.cardinality_class[1] == 1
96
- end
97
-
98
- # Indicates whether the destination cardinality class of this relationship
99
- # is equal to infinity. This is +true+ for one-to-many or
100
- # many-to-many relationships only.
101
- def to_many?
102
- cardinality.cardinality_class[1] != 1
103
- end
104
-
105
- # Indicates whether the source cardinality class of this relationship
106
- # is equal to one. This is +true+ for one-to-one or
107
- # one-to-many relationships only.
108
- def one_to?
109
- cardinality.cardinality_class[0] == 1
110
- end
111
-
112
- # Indicates whether the source cardinality class of this relationship
113
- # is equal to infinity. This is +true+ for many-to-many relationships only.
114
- def many_to?
115
- cardinality.cardinality_class[0] != 1
116
- end
117
-
118
- # The strength of a relationship is equal to the number of associations
119
- # that describe it.
120
- def strength
121
- associations.size
122
- end
123
-
124
- def inspect # @private :nodoc:
125
- "#<#{self.class}:0x%.14x @source=#{source} @destination=#{destination}>" % (object_id << 1)
126
- end
127
-
128
- def <=>(other) # @private :nodoc:
129
- (source.name <=> other.source.name).nonzero? or (destination.name <=> other.destination.name)
130
- end
131
-
132
- private
133
-
134
- def associations_range(model, associations, absolute_max)
135
- # The minimum of the range is the maximum value of each association
136
- # minimum. If there is none, it is zero by definition. The reasoning is
137
- # that from all associations, if only one has a required minimum, then
138
- # this side of the relationship has a cardinality of at least one.
139
- min = associations.map { |assoc| association_minimum(model, assoc) }.max || 0
140
-
141
- # The maximum of the range is the maximum value of each association
142
- # maximum. If there is none, it is equal to the absolute maximum. If
143
- # only one association has a high cardinality on this side, the
144
- # relationship itself has the same maximum cardinality.
145
- max = associations.map { |assoc| association_maximum(model, assoc) }.max || absolute_max
146
-
147
- min..max
148
- end
149
-
150
- def association_minimum(model, association)
151
- minimum = association_validators(:presence, model, association).any? ||
152
- foreign_key_required?(model, association) ? 1 : 0
153
- length_validators = association_validators(:length, model, association)
154
- length_validators.map { |v| v.options[:minimum] }.compact.max or minimum
155
- end
156
-
157
- def association_maximum(model, association)
158
- maximum = association.collection? ? N : 1
159
- length_validators = association_validators(:length, model, association)
160
- length_validators.map { |v| v.options[:maximum] }.compact.min or maximum
161
- end
162
-
163
- def association_validators(kind, model, association)
164
- model.validators_on(association.name).select { |v| v.kind == kind }
165
- end
166
-
167
- def any_habtm?(associations)
168
- associations.any? { |association| association.macro == :has_and_belongs_to_many }
169
- end
170
-
171
- def foreign_key_required?(model, association)
172
- if association.belongs_to?
173
- key = model.arel_table.columns.find { |column| column.name == association.primary_key_name } and !key.null
174
- end
175
- end
176
- end
177
- end