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,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,9 @@
1
+ require 'dm-visualizer'
2
+
3
+ require 'spec_helper'
4
+
5
+ describe DataMapper::Visualizer do
6
+ it "should define a VERSION constant" do
7
+ DataMapper::Visualizer.const_defined?('VERSION').should == true
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Helpers
2
+ module Project
3
+ PROJECTS_DIR = File.expand_path(File.join(File.dirname(__FILE__),'projects'))
4
+
5
+ def project_dir(name)
6
+ File.join(PROJECTS_DIR,name)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ require 'blog/user'
2
+ require 'blog/post'
3
+ require 'blog/comment'
@@ -0,0 +1,17 @@
1
+ require 'blog/post'
2
+
3
+ require 'dm-core'
4
+
5
+ module Blog
6
+ class Comment
7
+
8
+ include DataMapper::Resource
9
+
10
+ property :id, Serial
11
+
12
+ property :body, Text
13
+
14
+ belongs_to :post
15
+
16
+ end
17
+ 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
@@ -0,0 +1,17 @@
1
+ require 'blog/post'
2
+
3
+ require 'dm-core'
4
+
5
+ module Blog
6
+ class User
7
+
8
+ include DataMapper::Resource
9
+
10
+ property :id, Serial
11
+
12
+ property :name, String
13
+
14
+ has 0..n, :posts
15
+
16
+ end
17
+ end
@@ -0,0 +1,11 @@
1
+ class Comment
2
+
3
+ include DataMapper::Resource
4
+
5
+ property :id, Serial
6
+
7
+ property :body, Text
8
+
9
+ belongs_to :post
10
+
11
+ end