dm-visualizer 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,9 @@
1
+ doc
2
+ pkg
3
+ tmp/*
4
+ .DS_Store
5
+ .yardoc
6
+ *.db
7
+ *.log
8
+ *.swp
9
+ *~
@@ -0,0 +1 @@
1
+ --colour --format specdoc
@@ -0,0 +1 @@
1
+ --markup markdown --title 'dm-visualizer Documentation' --protected --files ChangeLog.md,LICENSE.txt
@@ -0,0 +1,9 @@
1
+ ### 0.1.0 / 2010-05-27
2
+
3
+ * Initial release:
4
+ * Safely loads the models of a project.
5
+ * Supports using [Gem Bundler](http://gembundler.com/).
6
+ * Generates GraphViz diagrams for a project.
7
+ * Provides Rake tasks for both Ruby libraries and Rails3 apps.
8
+ * Supports both DataMapper 0.10.2 and 1.0.0.
9
+
@@ -0,0 +1,22 @@
1
+
2
+ Copyright (c) 2010 Hal Brodigan
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ 'Software'), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
@@ -0,0 +1,48 @@
1
+ # dm-visualizer
2
+
3
+ * [github.com/postmodern/dm-visualizer](http://github.com/postmodern/dm-visualizer/)
4
+ * [github.com/postmodern/dm-visualizer/issues](http://github.com/postmodern/dm-visualizer/issues)
5
+ * Postmodern (postmodern.mod3 at gmail.com)
6
+
7
+ ## Description
8
+
9
+ DataMapper Visualizer is both a library and a command-line utility for
10
+ visualizing the Models, Properties and Relationships defined in a
11
+ DataMapper based Ruby project.
12
+
13
+ ## Features
14
+
15
+ * Safely loads the models of a project.
16
+ * Supports using [Gem Bundler](http://gembundler.com/).
17
+ * Generates GraphViz diagrams for a project.
18
+ * Provides Rake tasks for both Ruby libraries and Rails3 apps.
19
+ * Supports both DataMapper 0.10.2 and 1.0.0.
20
+
21
+ ## Examples
22
+
23
+ Add the `dm:doc:graphviz` rake task to a Ruby library:
24
+
25
+ require 'dm-visualizer/rake/graphviz_task'
26
+ DataMapper::Visualizer::Rake::GraphVizTask.new(
27
+ :include => ['lib'],
28
+ :require => ['my_library/models']
29
+ )
30
+
31
+ Add the `db:doc:graphviz` rake task to a Rails3 / [dm-rails](http://github.com/datamapper/dm-rails) app:
32
+
33
+ require 'dm-visualizer/rake/rails/graphviz_task'
34
+ DataMapper::Visualizer::Rake::Rails::GraphVizTask.new
35
+
36
+ ## Requirements
37
+
38
+ * [ruby-graphviz](http://rubygems.org/gems/ruby-graphviz) >= 0.9.10
39
+ * [dm-core](http://github.com/datamapper/dm-core) >= 0.10.2
40
+
41
+ ## Install
42
+
43
+ $ sudo gem install dm-visualizer
44
+
45
+ ## License
46
+
47
+ See {file:LICENSE.txt} for license information.
48
+
@@ -0,0 +1,44 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = 'dm-visualizer'
8
+ gem.license = 'MIT'
9
+ gem.summary = %Q{Visualizes the Models, Properties and Relationships defined in a DataMapper based Ruby project.}
10
+ gem.description = %Q{DataMapper Visualizer is both a library and a command-line utility for visualizing the Models, Properties and Relationships defined in a DataMapper based Ruby project.}
11
+ gem.email = 'postmodern.mod3@gmail.com'
12
+ gem.homepage = 'http://github.com/postmodern/dm-visualizer'
13
+ gem.authors = ['Postmodern']
14
+ gem.add_dependency 'ruby-graphviz', '>= 0.9.10'
15
+ gem.add_dependency 'dm-core', '>= 0.10.2'
16
+ gem.add_dependency 'thor', '>= 0.13.4'
17
+ gem.add_development_dependency 'rspec', '~> 1.3.0'
18
+ gem.add_development_dependency 'yard', '~> 0.5.3'
19
+ gem.has_rdoc = 'yard'
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
24
+ end
25
+
26
+ require 'spec/rake/spectask'
27
+ Spec::Rake::SpecTask.new(:spec) do |spec|
28
+ spec.libs += ['lib', 'spec']
29
+ spec.spec_files = FileList['spec/**/*_spec.rb']
30
+ spec.spec_opts = ['--options', '.specopts']
31
+ end
32
+
33
+ task :spec => :check_dependencies
34
+ task :default => :spec
35
+
36
+ begin
37
+ require 'yard'
38
+
39
+ YARD::Rake::YardocTask.new
40
+ rescue LoadError
41
+ task :yard do
42
+ abort "YARD is not available. In order to run yard, you must: gem install yard"
43
+ end
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,100 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{dm-visualizer}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Postmodern"]
12
+ s.date = %q{2010-05-27}
13
+ s.description = %q{DataMapper Visualizer is both a library and a command-line utility for visualizing the Models, Properties and Relationships defined in a DataMapper based Ruby project.}
14
+ s.email = %q{postmodern.mod3@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "ChangeLog.md",
17
+ "LICENSE.txt",
18
+ "README.md"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ ".specopts",
23
+ ".yardopts",
24
+ "ChangeLog.md",
25
+ "LICENSE.txt",
26
+ "README.md",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "dm-visualizer.gemspec",
30
+ "lib/dm-visualizer.rb",
31
+ "lib/dm-visualizer/graphviz.rb",
32
+ "lib/dm-visualizer/project.rb",
33
+ "lib/dm-visualizer/rake/graphviz_task.rb",
34
+ "lib/dm-visualizer/rake/rails/graphviz_task.rb",
35
+ "lib/dm-visualizer/rake/rails/tasks.rb",
36
+ "lib/dm-visualizer/rake/task.rb",
37
+ "lib/dm-visualizer/visualization.rb",
38
+ "spec/dm_visualizer_spec.rb",
39
+ "spec/helpers/project.rb",
40
+ "spec/helpers/projects/library/lib/blog.rb",
41
+ "spec/helpers/projects/library/lib/blog/comment.rb",
42
+ "spec/helpers/projects/library/lib/blog/post.rb",
43
+ "spec/helpers/projects/library/lib/blog/user.rb",
44
+ "spec/helpers/projects/rails/app/models/comment.rb",
45
+ "spec/helpers/projects/rails/app/models/post.rb",
46
+ "spec/helpers/projects/rails/app/models/user.rb",
47
+ "spec/project_examples.rb",
48
+ "spec/project_spec.rb",
49
+ "spec/spec_helper.rb",
50
+ "spec/visualization_spec.rb"
51
+ ]
52
+ s.has_rdoc = %q{yard}
53
+ s.homepage = %q{http://github.com/postmodern/dm-visualizer}
54
+ s.licenses = ["MIT"]
55
+ s.rdoc_options = ["--charset=UTF-8"]
56
+ s.require_paths = ["lib"]
57
+ s.rubygems_version = %q{1.3.7}
58
+ s.summary = %q{Visualizes the Models, Properties and Relationships defined in a DataMapper based Ruby project.}
59
+ s.test_files = [
60
+ "spec/project_spec.rb",
61
+ "spec/spec_helper.rb",
62
+ "spec/visualization_spec.rb",
63
+ "spec/project_examples.rb",
64
+ "spec/helpers/project.rb",
65
+ "spec/helpers/projects/library/lib/blog.rb",
66
+ "spec/helpers/projects/library/lib/blog/post.rb",
67
+ "spec/helpers/projects/library/lib/blog/user.rb",
68
+ "spec/helpers/projects/library/lib/blog/comment.rb",
69
+ "spec/helpers/projects/rails/app/models/post.rb",
70
+ "spec/helpers/projects/rails/app/models/user.rb",
71
+ "spec/helpers/projects/rails/app/models/comment.rb",
72
+ "spec/dm_visualizer_spec.rb"
73
+ ]
74
+
75
+ if s.respond_to? :specification_version then
76
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
77
+ s.specification_version = 3
78
+
79
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
80
+ s.add_runtime_dependency(%q<ruby-graphviz>, [">= 0.9.10"])
81
+ s.add_runtime_dependency(%q<dm-core>, [">= 0.10.2"])
82
+ s.add_runtime_dependency(%q<thor>, [">= 0.13.4"])
83
+ s.add_development_dependency(%q<rspec>, ["~> 1.3.0"])
84
+ s.add_development_dependency(%q<yard>, ["~> 0.5.3"])
85
+ else
86
+ s.add_dependency(%q<ruby-graphviz>, [">= 0.9.10"])
87
+ s.add_dependency(%q<dm-core>, [">= 0.10.2"])
88
+ s.add_dependency(%q<thor>, [">= 0.13.4"])
89
+ s.add_dependency(%q<rspec>, ["~> 1.3.0"])
90
+ s.add_dependency(%q<yard>, ["~> 0.5.3"])
91
+ end
92
+ else
93
+ s.add_dependency(%q<ruby-graphviz>, [">= 0.9.10"])
94
+ s.add_dependency(%q<dm-core>, [">= 0.10.2"])
95
+ s.add_dependency(%q<thor>, [">= 0.13.4"])
96
+ s.add_dependency(%q<rspec>, ["~> 1.3.0"])
97
+ s.add_dependency(%q<yard>, ["~> 0.5.3"])
98
+ end
99
+ end
100
+
@@ -0,0 +1,2 @@
1
+ require 'dm-visualizer/project'
2
+ require 'dm-visualizer/graphviz'
@@ -0,0 +1,168 @@
1
+ require 'dm-visualizer/visualization'
2
+
3
+ begin
4
+ require 'graphviz'
5
+ rescue Gem::LoadError => e
6
+ raise(e)
7
+ rescue ::LoadError
8
+ STDERR.puts "GraphViz not available. Install it with: gem install ruby-graphviz"
9
+ end
10
+
11
+ module DataMapper
12
+ module Visualizer
13
+ #
14
+ # Visualizes projects by generating a
15
+ # [GraphViz](http://www.graphviz.org/) diagram.
16
+ #
17
+ class GraphViz < Visualization
18
+
19
+ # The output file
20
+ attr_accessor :file
21
+
22
+ # The output file format (`:png`)
23
+ attr_accessor :format
24
+
25
+ # The colors to use
26
+ attr_reader :colors
27
+
28
+ # The labels to use
29
+ attr_reader :labels
30
+
31
+ #
32
+ # Creates a new GraphViz object.
33
+ #
34
+ # @param [Hash] options
35
+ # Additional options.
36
+ #
37
+ # @option options [String] :file
38
+ # The output file path.
39
+ #
40
+ # @option options [Symbol] :format (:png)
41
+ # The format of the generated graph.
42
+ #
43
+ # @option options [Hash] :colors
44
+ # The colors to use for `:one_to_many` and `:one_to_one`
45
+ # relationship edges.
46
+ #
47
+ # @option options [Hash] :labels
48
+ # The labels to use for `:one_to_many` and `:one_to_one`
49
+ # relationship edges.
50
+ #
51
+ def initialize(options={})
52
+ super(options)
53
+
54
+ @format = :png
55
+
56
+ @colors = {
57
+ :one_to_many => 'blue',
58
+ :one_to_one => 'red',
59
+ :inheritence => 'cyan'
60
+ }
61
+ @labels = {
62
+ :one_to_many => '1:m',
63
+ :one_to_one => '1:1'
64
+ }
65
+
66
+ if options[:file]
67
+ @file = File.expand_path(options[:file])
68
+ end
69
+
70
+ if options[:format]
71
+ @format = options[:format].to_sym
72
+ end
73
+
74
+ if options[:colors]
75
+ options[:colors].each do |name,value|
76
+ @colors[name.to_sym] = value.to_s
77
+ end
78
+ end
79
+
80
+ if options[:labels]
81
+ options[:labels].each do |name,value|
82
+ @labels[name.to_sym] = value.to_s
83
+ end
84
+ end
85
+ end
86
+
87
+ #
88
+ # The full output path.
89
+ #
90
+ # @return [String]
91
+ # The full output path, including file extension.
92
+ #
93
+ def path
94
+ "#{@file}.#{@format}"
95
+ end
96
+
97
+ protected
98
+
99
+ #
100
+ # Generates a GraphViz diagram for a project.
101
+ #
102
+ # @param [String] path
103
+ # The path to save the graph image to.
104
+ #
105
+ def visualize
106
+ graph = ::GraphViz.new(:G, :type => :digraph)
107
+
108
+ # Create node for each model
109
+ project.each_model do |model|
110
+ properties = project.each_property(model).map do |property|
111
+ "#{property_name(property)}: #{property_type_name(property)}"
112
+ end
113
+
114
+ foreign_keys = project.each_foreign_key(model).map do |key,model|
115
+ "#{foreign_key_name(key)}: #{model_name(model)}"
116
+ end
117
+
118
+ columns = (properties + foreign_keys)
119
+ label = "{ #{model_name(model)} | #{columns.join("\n")} }"
120
+
121
+ graph.add_node(
122
+ model_name(model),
123
+ :shape => 'record',
124
+ :label => label
125
+ )
126
+ end
127
+
128
+ # Connect model nodes together by relationship
129
+ project.each_relationship do |relationship,model|
130
+ source_node = graph.get_node(model_name(model))
131
+ target_node = graph.get_node(model_name(relationship.target_model))
132
+
133
+ case relationship
134
+ when DataMapper::Associations::OneToMany::Relationship
135
+ graph.add_edge(
136
+ source_node,
137
+ target_node,
138
+ :color => @colors[:one_to_many],
139
+ :label => " #{@labels[:one_to_many]}"
140
+ )
141
+ when DataMapper::Associations::OneToOne::Relationship
142
+ graph.add_edge(
143
+ source_node,
144
+ target_node,
145
+ :color => @colors[:one_to_one],
146
+ :label => " #{@labels[:one_to_one]}"
147
+ )
148
+ end
149
+ end
150
+
151
+ # Connect model nodes by inheritence
152
+ project.each_model_inheritence do |model,ancestor|
153
+ source_node = graph.get_node(model_name(ancestor))
154
+ target_node = graph.get_node(model_name(model))
155
+
156
+ graph.add_edge(
157
+ source_node,
158
+ target_node,
159
+ :color => @colors[:inheritence]
160
+ )
161
+ end
162
+
163
+ graph.output(@format => self.path)
164
+ end
165
+
166
+ end
167
+ end
168
+ end
@@ -0,0 +1,315 @@
1
+ require 'set'
2
+ require 'dm-core'
3
+
4
+ require 'enumerator'
5
+
6
+ module DataMapper
7
+ module Visualizer
8
+ #
9
+ # Defines the paths and directories to load for a DataMapper project.
10
+ #
11
+ class Project
12
+
13
+ # Specifies which Bundler groups to activate.
14
+ attr_reader :bundle
15
+
16
+ # The directories to include
17
+ attr_reader :include_dirs
18
+
19
+ # The paths to require
20
+ attr_reader :require_paths
21
+
22
+ # The path glob patterns to require
23
+ attr_reader :require_globs
24
+
25
+ #
26
+ # Creates a new project.
27
+ #
28
+ # @param [Hash] options
29
+ # Additional options.
30
+ #
31
+ # @option options [Array] :include
32
+ # The directories to include into the `$LOAD_PATH` global variable.
33
+ #
34
+ # @option options [Boolean, Array] :bundle
35
+ # Specifies which groups of dependencies to activate using Bundler.
36
+ #
37
+ # @option options [Array] :require
38
+ # The paths to require.
39
+ #
40
+ # @option options [Array] :require_all
41
+ # The path globs to require.
42
+ #
43
+ def initialize(options={})
44
+ @bundle = nil
45
+ @include_dirs = Set[]
46
+ @require_paths = Set[]
47
+ @require_globs = Set[]
48
+
49
+ if options[:include]
50
+ options[:include].each do |dir|
51
+ @include_dirs << File.expand_path(dir)
52
+ end
53
+ end
54
+
55
+ if options[:bundle]
56
+ @bundle = Set[]
57
+
58
+ options[:bundle].each do |group|
59
+ @bundle << group.to_sym
60
+ end
61
+ end
62
+
63
+ if options[:require]
64
+ @require_paths += options[:require]
65
+ end
66
+
67
+ if options[:require_all]
68
+ @require_globs += options[:require_all]
69
+ end
70
+ end
71
+
72
+ #
73
+ # Activates dependencies of the project using Bundler.
74
+ #
75
+ # @return [true]
76
+ #
77
+ def bundle!
78
+ unless File.file?('Gemfile')
79
+ log "Gemfile is missing or not a valid file."
80
+ end
81
+
82
+ begin
83
+ require 'bundler'
84
+ rescue LoadError => e
85
+ log "Gemfile exists, but bundler is not installed"
86
+ log "Run `gem install bundler` to install bundler."
87
+ end
88
+
89
+ begin
90
+ Bundler.setup(*@bundle)
91
+ rescue Bundler::BundleError => e
92
+ log e.message
93
+ log "Run `bundle install` to install missing gems"
94
+ end
95
+
96
+ return true
97
+ end
98
+
99
+ #
100
+ # Activates the project by adding it's include directories to the
101
+ # `$LOAD_PATH` global variable.
102
+ #
103
+ # @return [true]
104
+ #
105
+ def activate!
106
+ @include_dirs.each do |dir|
107
+ $LOAD_PATH << dir if File.directory?(dir)
108
+ end
109
+
110
+ # use Bundler if a Gemfile is present
111
+ bundle! if (@bundle && File.file?('Gemfile'))
112
+
113
+ return true
114
+ end
115
+
116
+ #
117
+ # De-activates the project by removing it's include directories to the
118
+ # `$LOAD_PATH` global variable.
119
+ #
120
+ # @return [true]
121
+ #
122
+ def deactivate!
123
+ $LOAD_PATH.reject! { |dir| @include_dirs.include?(dir) }
124
+ return true
125
+ end
126
+
127
+ #
128
+ # Attempts to load all of the projects files.
129
+ #
130
+ # @return [true]
131
+ #
132
+ def load!
133
+ activate!
134
+
135
+ @require_paths.each do |path|
136
+ begin
137
+ require path
138
+ rescue LoadError => e
139
+ log "dm-visualizer: unable to load #{path}"
140
+ log "dm-visualizer: #{e.message}"
141
+ end
142
+ end
143
+
144
+ @require_globs.each do |glob|
145
+ @include_dirs.each do |dir|
146
+ Dir[File.join(dir,glob)].each do |path|
147
+ relative_path = path[(dir.length + 1)..-1]
148
+
149
+ begin
150
+ require relative_path
151
+ rescue LoadError => e
152
+ log "dm-visualizer: unable to load #{relative_path} from #{dir}"
153
+ log "dm-visualizer: #{e.message}"
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ deactivate!
160
+ return true
161
+ end
162
+
163
+ #
164
+ # Enumerates over each DataMapper Model loaded from the project.
165
+ #
166
+ # @yield [model]
167
+ # The given block will be passed every model registered with
168
+ # DataMapper.
169
+ #
170
+ # @yieldparam [DataMapper::Model]
171
+ # A model loaded from the project.
172
+ #
173
+ # @return [Enumerator]
174
+ # If no block is given, an Enumerator object will be returned.
175
+ #
176
+ def each_model(&block)
177
+ DataMapper::Model.descendants.each(&block)
178
+ end
179
+
180
+ #
181
+ # Enumerates over each DataMapper Model loaded from the project,
182
+ # and their direct ancestors.
183
+ #
184
+ # @yield [model, direct_ancestor]
185
+ # The given block will be passed every model and their immediate
186
+ # ancestor.
187
+ #
188
+ # @yieldparam [DataMapper::Model] model
189
+ # The model.
190
+ #
191
+ # @yieldparam [DataMapper::Model] direct_ancestor
192
+ # The first ancestor of the model.
193
+ #
194
+ # @return [Enumerator]
195
+ # If no block is given, an Enumerator object will be returned.
196
+ #
197
+ def each_model_inheritence
198
+ unless block_given?
199
+ return Enumerator.new(self,:each_model_inheritence)
200
+ end
201
+
202
+ each_model do |model|
203
+ direct_ancestor = model.ancestors[1]
204
+
205
+ if direct_ancestor.class == Class
206
+ yield model, direct_ancestor
207
+ end
208
+ end
209
+ end
210
+
211
+ #
212
+ # Enumerates over each DataMapper property from a given model.
213
+ #
214
+ # @param [DataMapper::Model] model
215
+ # The given model.
216
+ #
217
+ # @yield [property]
218
+ # The given block will be passed every property from the given
219
+ # model.
220
+ #
221
+ # @yieldparam [DataMapper::Property] property
222
+ # The property.
223
+ #
224
+ # @return [Enumerator]
225
+ # If no block is given, an Enumerator object will be returned.
226
+ #
227
+ def each_property(model)
228
+ unless block_given?
229
+ return Enumerator.new(self,:each_property,model)
230
+ end
231
+
232
+ model.properties.each do |property|
233
+ yield property
234
+ end
235
+ end
236
+
237
+ #
238
+ # Enumerates over every foreign-key in a given model.
239
+ #
240
+ # @param [DataMapper::Model] model
241
+ # The given model.
242
+ #
243
+ # @yield [foreign_key, foreign_model]
244
+ # The given block will be passed every foreign-key and the model
245
+ # that the foreign-key will reference.
246
+ #
247
+ # @yieldparam [String] foreign_key
248
+ # The name of the foreign-key.
249
+ #
250
+ # @yieldparam [DataMapper::Model] foreign_model
251
+ # The model that the foreign-key references.
252
+ #
253
+ # @return [Enumerator]
254
+ # If no block is given, an Enumerator object will be returned.
255
+ #
256
+ def each_foreign_key(model)
257
+ unless block_given?
258
+ return Enumerator.new(self,:each_foreign_key,model)
259
+ end
260
+
261
+ model.relationships.each_value do |relationship|
262
+ next if relationship.respond_to?(:through)
263
+
264
+ case relationship
265
+ when Associations::ManyToOne::Relationship,
266
+ Associations::OneToOne::Relationship
267
+ yield relationship.child_key.first.name,
268
+ relationship.parent_model
269
+ end
270
+ end
271
+ end
272
+
273
+ #
274
+ # Enumerates over each DataMapper relationship between each model.
275
+ #
276
+ # @yield [relationship,model]
277
+ # The given block will be passed every relationship from every
278
+ # model registered with DataMapper.
279
+ #
280
+ # @yieldparam [DataMapper::Relationship] relationship
281
+ # The relationship.
282
+ #
283
+ # @yieldparam [DataMapper::Model] model
284
+ # The model that the relationship belongs to.
285
+ #
286
+ # @return [Enumerator]
287
+ # If no block is given, an Enumerator object will be returned.
288
+ #
289
+ def each_relationship
290
+ return Enumerator.new(self,:each_relationship) unless block_given?
291
+
292
+ each_model do |model|
293
+ model.relationships.each_value do |relationship|
294
+ unless relationship.respond_to?(:through)
295
+ yield relationship, model
296
+ end
297
+ end
298
+ end
299
+ end
300
+
301
+ protected
302
+
303
+ #
304
+ # Prints a message to `STDERR`.
305
+ #
306
+ # @param [String] message
307
+ # The message to print.
308
+ #
309
+ def log(message)
310
+ STDERR.puts "dm-visualizer: #{message}"
311
+ end
312
+
313
+ end
314
+ end
315
+ end