dm-visualizer 0.1.0
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/.gitignore +9 -0
- data/.specopts +1 -0
- data/.yardopts +1 -0
- data/ChangeLog.md +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +48 -0
- data/Rakefile +44 -0
- data/VERSION +1 -0
- data/dm-visualizer.gemspec +100 -0
- data/lib/dm-visualizer.rb +2 -0
- data/lib/dm-visualizer/graphviz.rb +168 -0
- data/lib/dm-visualizer/project.rb +315 -0
- data/lib/dm-visualizer/rake/graphviz_task.rb +67 -0
- data/lib/dm-visualizer/rake/rails/graphviz_task.rb +16 -0
- data/lib/dm-visualizer/rake/rails/tasks.rb +24 -0
- data/lib/dm-visualizer/rake/task.rb +34 -0
- data/lib/dm-visualizer/visualization.rb +204 -0
- data/spec/dm_visualizer_spec.rb +9 -0
- data/spec/helpers/project.rb +9 -0
- data/spec/helpers/projects/library/lib/blog.rb +3 -0
- data/spec/helpers/projects/library/lib/blog/comment.rb +17 -0
- data/spec/helpers/projects/library/lib/blog/post.rb +21 -0
- data/spec/helpers/projects/library/lib/blog/user.rb +17 -0
- data/spec/helpers/projects/rails/app/models/comment.rb +11 -0
- data/spec/helpers/projects/rails/app/models/post.rb +15 -0
- data/spec/helpers/projects/rails/app/models/user.rb +11 -0
- data/spec/project_examples.rb +19 -0
- data/spec/project_spec.rb +47 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/visualization_spec.rb +92 -0
- metadata +189 -0
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'dm-visualizer/rake/task'
|
2
|
+
require 'dm-visualizer/graphviz'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Visualizer
|
6
|
+
module Rake
|
7
|
+
class GraphVizTask < Task
|
8
|
+
|
9
|
+
# The relational diagram GraphViz visualizer
|
10
|
+
attr_reader :relational
|
11
|
+
|
12
|
+
# The schema diagram GraphViz visualizer
|
13
|
+
attr_reader :schema
|
14
|
+
|
15
|
+
#
|
16
|
+
# Creates a new `dm:doc:graphviz` task.
|
17
|
+
#
|
18
|
+
# @param [Hash] options
|
19
|
+
# Additional options.
|
20
|
+
#
|
21
|
+
# @yield [task]
|
22
|
+
# The given block will be passed the newly created task.
|
23
|
+
#
|
24
|
+
# @yieldparam [GraphVizTask] task
|
25
|
+
# The new GraphViz task.
|
26
|
+
#
|
27
|
+
# @see GraphViz.new
|
28
|
+
#
|
29
|
+
def initialize(options={})
|
30
|
+
@relational = GraphViz.new(options.merge(
|
31
|
+
:naming => :relational,
|
32
|
+
:file => 'doc/relational_diagram'
|
33
|
+
))
|
34
|
+
|
35
|
+
@schema = GraphViz.new(options.merge(
|
36
|
+
:naming => :schema,
|
37
|
+
:file => 'doc/schema_diagram'
|
38
|
+
))
|
39
|
+
|
40
|
+
super
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Defines the `dm:doc:graphviz` namespace.
|
45
|
+
#
|
46
|
+
def define
|
47
|
+
super do
|
48
|
+
namespace :graphviz do
|
49
|
+
desc 'Generates a GraphViz relational diagram of the DataMapper Models'
|
50
|
+
task :relational do
|
51
|
+
@relational.visualize!
|
52
|
+
end
|
53
|
+
|
54
|
+
desc 'Generates a GraphViz schema diagram of the DataMapper Models'
|
55
|
+
task :schema do
|
56
|
+
@schema.visualize!
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
task :graphviz => ['graphviz:relational', 'graphviz:schema']
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'dm-visualizer/rake/rails/tasks'
|
2
|
+
require 'dm-visualizer/rake/graphviz_task'
|
3
|
+
|
4
|
+
module DataMapper
|
5
|
+
module Visualizer
|
6
|
+
module Rake
|
7
|
+
module Rails
|
8
|
+
class GraphVizTask < Rake::GraphVizTask
|
9
|
+
|
10
|
+
include Tasks
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module DataMapper
|
2
|
+
module Visualizer
|
3
|
+
module Rake
|
4
|
+
module Rails
|
5
|
+
module Tasks
|
6
|
+
#
|
7
|
+
# Overrides the Rake `task` method to make sure every defined
|
8
|
+
# task depends on `dm:load_models`.
|
9
|
+
#
|
10
|
+
# @param [Array] arguments
|
11
|
+
# The arguments of the task.
|
12
|
+
#
|
13
|
+
def task(*arguments)
|
14
|
+
if arguments.first.kind_of?(Hash)
|
15
|
+
super(*arguments)
|
16
|
+
else
|
17
|
+
super(arguments.first => 'db:load_models')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Visualizer
|
5
|
+
module Rake
|
6
|
+
class Task < ::Rake::TaskLib
|
7
|
+
#
|
8
|
+
# Creates a new task.
|
9
|
+
#
|
10
|
+
# @yield [task]
|
11
|
+
# The given block will be passed the newly created task.
|
12
|
+
#
|
13
|
+
# @yieldparam [Task] task
|
14
|
+
# The new Task.
|
15
|
+
#
|
16
|
+
def initialize(options={})
|
17
|
+
yield self if block_given?
|
18
|
+
|
19
|
+
define()
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Defines a task within the `dm:doc` namespace.
|
24
|
+
#
|
25
|
+
def define(&block)
|
26
|
+
namespace :dm do
|
27
|
+
namespace(:doc,&block)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'dm-visualizer/project'
|
2
|
+
|
3
|
+
require 'dm-core'
|
4
|
+
|
5
|
+
module DataMapper
|
6
|
+
module Visualizer
|
7
|
+
#
|
8
|
+
# The base class for all visualizations.
|
9
|
+
#
|
10
|
+
class Visualization
|
11
|
+
|
12
|
+
# The inflector to use
|
13
|
+
Inflector = if Object.const_defined?('ActiveSupport')
|
14
|
+
ActiveSupport::Inflector
|
15
|
+
else
|
16
|
+
Extlib::Inflection
|
17
|
+
end
|
18
|
+
|
19
|
+
# The project that will be visualized
|
20
|
+
attr_reader :project
|
21
|
+
|
22
|
+
# Mapping of DataMapper repository names and their actual names.
|
23
|
+
attr_reader :repository_names
|
24
|
+
|
25
|
+
# Specifies which naming convention to use
|
26
|
+
# (`:relational` or `:schema`).
|
27
|
+
attr_accessor :naming
|
28
|
+
|
29
|
+
# Specifies whether to demodulize class names.
|
30
|
+
attr_accessor :full_names
|
31
|
+
|
32
|
+
#
|
33
|
+
# Initializes a new visualization.
|
34
|
+
#
|
35
|
+
# @param [Hash] options
|
36
|
+
# Additional options.
|
37
|
+
#
|
38
|
+
# @option options [Hash] :repository_names
|
39
|
+
# The actual names of the DataMapper repositories.
|
40
|
+
#
|
41
|
+
# @option options [String] :repository_name
|
42
|
+
# The actual name to use for the `:default` DataMappe repository.
|
43
|
+
#
|
44
|
+
# @option options [Symbol] :naming
|
45
|
+
# The naming convention to use. May be either `:relational` or
|
46
|
+
# `:schema`.
|
47
|
+
#
|
48
|
+
# @option options [Boolean] :full_names
|
49
|
+
# Specifies whether to demodulize class names.
|
50
|
+
#
|
51
|
+
def initialize(options={})
|
52
|
+
@project = Project.new(options)
|
53
|
+
|
54
|
+
@repository_names = {}
|
55
|
+
@naming = :relational
|
56
|
+
@full_names = false
|
57
|
+
|
58
|
+
if options[:repository_names]
|
59
|
+
options[:repository_names].each do |name,db_name|
|
60
|
+
@repository_names[name.to_sym] = db_name.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if options[:repository_name]
|
65
|
+
@database_names[:default] = options[:repository_name].to_s
|
66
|
+
end
|
67
|
+
|
68
|
+
if options[:naming]
|
69
|
+
@naming = options[:naming].to_sym
|
70
|
+
end
|
71
|
+
|
72
|
+
if options.has_key?(:full_names)
|
73
|
+
@full_names = options[:full_names]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# Returns the class name of a given object.
|
79
|
+
#
|
80
|
+
# @param [Class, Object] obj
|
81
|
+
# The object or class.
|
82
|
+
#
|
83
|
+
# @return [String]
|
84
|
+
# The class name of the object or class.
|
85
|
+
#
|
86
|
+
def class_name(obj)
|
87
|
+
name = if (obj.class == Class || obj.class == Module)
|
88
|
+
obj.name
|
89
|
+
else
|
90
|
+
obj.class.name
|
91
|
+
end
|
92
|
+
|
93
|
+
name = Inflector.demodulize(name) unless @full_names
|
94
|
+
|
95
|
+
return name
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Returns the name of a given property.
|
100
|
+
#
|
101
|
+
# @param [DataMapper::Property] property
|
102
|
+
# The property.
|
103
|
+
#
|
104
|
+
# @return [String]
|
105
|
+
# The property name.
|
106
|
+
#
|
107
|
+
def property_name(property)
|
108
|
+
property.name.to_s
|
109
|
+
end
|
110
|
+
|
111
|
+
#
|
112
|
+
# Returns the name the given foreign key.
|
113
|
+
#
|
114
|
+
# @param [Symbol] key
|
115
|
+
# The foreign key.
|
116
|
+
#
|
117
|
+
# @return [String]
|
118
|
+
# The foreign key name.
|
119
|
+
#
|
120
|
+
def foreign_key_name(key)
|
121
|
+
key = key.to_s
|
122
|
+
|
123
|
+
key.chomp!('_id') unless @naming == :schema
|
124
|
+
return key
|
125
|
+
end
|
126
|
+
|
127
|
+
#
|
128
|
+
# Returns the type name of a property.
|
129
|
+
#
|
130
|
+
# @param [DataMapper::Property] property
|
131
|
+
# The property.
|
132
|
+
#
|
133
|
+
# @return [String]
|
134
|
+
# The property type name.
|
135
|
+
#
|
136
|
+
def property_type_name(property)
|
137
|
+
class_name(property.type || property.class)
|
138
|
+
end
|
139
|
+
|
140
|
+
#
|
141
|
+
# Returns the repository name of a model.
|
142
|
+
#
|
143
|
+
# @param [DataMapper::Model] model
|
144
|
+
# The model.
|
145
|
+
#
|
146
|
+
# @return [String]
|
147
|
+
# The repository name.
|
148
|
+
#
|
149
|
+
def model_repository_name(model)
|
150
|
+
@repository_names[model.default_repository_name]
|
151
|
+
end
|
152
|
+
|
153
|
+
#
|
154
|
+
# Returns the name of a model.
|
155
|
+
#
|
156
|
+
# @param [DataMapper::Model] model
|
157
|
+
# The model.
|
158
|
+
#
|
159
|
+
# @return [String]
|
160
|
+
# The name of the model.
|
161
|
+
#
|
162
|
+
def model_name(model)
|
163
|
+
if @naming == :schema
|
164
|
+
name = model_repository_name(model)
|
165
|
+
storage_name = model.storage_names[:default]
|
166
|
+
storage_name ||= NamingConventions::Resource::UnderscoredAndPluralized.call(model.name)
|
167
|
+
|
168
|
+
if name
|
169
|
+
"#{name}.#{storage_name}"
|
170
|
+
else
|
171
|
+
storage_name
|
172
|
+
end
|
173
|
+
else
|
174
|
+
class_name(model)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Loads the project and visualizes it.
|
180
|
+
#
|
181
|
+
# @param [Array] arguments
|
182
|
+
# Additional arguments to pass to {#visualize}.
|
183
|
+
#
|
184
|
+
def visualize!(*arguments)
|
185
|
+
@project.load!
|
186
|
+
|
187
|
+
visualize(*arguments)
|
188
|
+
end
|
189
|
+
|
190
|
+
protected
|
191
|
+
|
192
|
+
#
|
193
|
+
# Default method which visualizes the DataMapper models, properties
|
194
|
+
# and relationships.
|
195
|
+
#
|
196
|
+
# @param [Project] project
|
197
|
+
# The project to visualize.
|
198
|
+
#
|
199
|
+
def visualize
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'blog/user'
|
2
|
+
|
3
|
+
require 'dm-core'
|
4
|
+
|
5
|
+
module Blog
|
6
|
+
class Post
|
7
|
+
|
8
|
+
include DataMapper::Resource
|
9
|
+
|
10
|
+
property :id, Serial
|
11
|
+
|
12
|
+
property :title, String
|
13
|
+
|
14
|
+
property :body, Text
|
15
|
+
|
16
|
+
belongs_to :user
|
17
|
+
|
18
|
+
has 0..n, :comments
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|