railroady 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,6 +1,6 @@
1
1
  = RailRoady
2
2
 
3
- RailRoady generates Rails 3 model (AcitveRecord, Mongoid) and controller UML diagrams as cross-platform .svg files, as well as in the DOT language.
3
+ RailRoady generates Rails 3 model (AcitveRecord, Mongoid, Datamapper) and controller UML diagrams as cross-platform .svg files, as well as in the DOT language.
4
4
 
5
5
  Code is based on the original "railroad" gem, patched and maintained over the years. Lineage can be traced via GitHub.
6
6
 
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
1
  ---
2
2
  :major: 1
3
3
  :minor: 0
4
- :patch: 6
4
+ :patch: 7
5
5
  :build:
@@ -26,7 +26,7 @@ class ModelsDiagram < AppDiagram
26
26
  end
27
27
 
28
28
  end
29
- end
29
+ end
30
30
 
31
31
  def get_files(prefix ='')
32
32
  files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << "app/models/**/*.rb")
@@ -38,34 +38,37 @@ class ModelsDiagram < AppDiagram
38
38
  # Process a model class
39
39
  def process_class(current_class)
40
40
  STDERR.puts "Processing #{current_class}" if @options.verbose
41
-
42
- generated = if defined?(Mongoid::Document) && current_class.new.is_a?(Mongoid::Document)
43
- process_mongoid_model(current_class)
44
- elsif current_class.respond_to?'reflect_on_all_associations'
45
- process_active_record_model(current_class)
46
- elsif @options.all && (current_class.is_a? Class)
47
- process_basic_class(current_class)
48
- elsif @options.modules && (current_class.is_a? Module)
49
- process_basic_module(current_class)
50
- end
41
+
42
+ generated =
43
+ if defined?(Mongoid::Document) && current_class.new.is_a?(Mongoid::Document)
44
+ process_mongoid_model(current_class)
45
+ elsif defined?(DataMapper::Resource) && current_class.new.is_a?(DataMapper::Resource)
46
+ process_datamapper_model(current_class)
47
+ elsif current_class.respond_to?'reflect_on_all_associations'
48
+ process_active_record_model(current_class)
49
+ elsif @options.all && (current_class.is_a? Class)
50
+ process_basic_class(current_class)
51
+ elsif @options.modules && (current_class.is_a? Module)
52
+ process_basic_module(current_class)
53
+ end
51
54
 
52
55
  if @options.inheritance && generated && include_inheritance?(current_class)
53
56
  @graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
54
- end
55
-
57
+ end
58
+
56
59
  end # process_class
57
-
60
+
58
61
  def include_inheritance?(current_class)
59
62
  (defined?(ActiveRecord::Base) && current_class.superclass != ActiveRecord::Base) &&
60
63
  (current_class.superclass != Object)
61
64
  end
62
-
65
+
63
66
  def process_basic_class(current_class)
64
67
  node_type = @options.brief ? 'class-brief' : 'class'
65
68
  @graph.add_node [node_type, current_class.name]
66
69
  true
67
70
  end
68
-
71
+
69
72
  def process_basic_module(current_class)
70
73
  @graph.add_node ['module', current_class.name]
71
74
  false
@@ -86,15 +89,15 @@ class ModelsDiagram < AppDiagram
86
89
  # http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
87
90
  magic_fields = [
88
91
  "created_at", "created_on", "updated_at", "updated_on",
89
- "lock_version", "type", "id", "position", "parent_id", "lft",
92
+ "lock_version", "type", "id", "position", "parent_id", "lft",
90
93
  "rgt", "quote", "template"
91
94
  ]
92
- magic_fields << current_class.table_name + "_count" if current_class.respond_to? 'table_name'
95
+ magic_fields << current_class.table_name + "_count" if current_class.respond_to? 'table_name'
93
96
  content_columns = current_class.content_columns.select {|c| ! magic_fields.include? c.name}
94
97
  else
95
98
  content_columns = current_class.content_columns
96
99
  end
97
-
100
+
98
101
  content_columns.each do |a|
99
102
  content_column = a.name
100
103
  content_column += ' :' + a.type.to_s unless @options.hide_types
@@ -102,27 +105,69 @@ class ModelsDiagram < AppDiagram
102
105
  end
103
106
  end
104
107
  @graph.add_node [node_type, current_class.name, node_attribs]
105
-
108
+
106
109
  # Process class associations
107
110
  associations = current_class.reflect_on_all_associations
108
111
  if @options.inheritance && ! @options.transitive
109
112
  superclass_associations = current_class.superclass.reflect_on_all_associations
110
-
111
- associations = associations.select{|a| ! superclass_associations.include? a}
113
+
114
+ associations = associations.select{|a| ! superclass_associations.include? a}
112
115
  # This doesn't works!
113
116
  # associations -= current_class.superclass.reflect_on_all_associations
114
117
  end
115
-
118
+
116
119
  associations.each do |a|
117
120
  process_association current_class.name, a
118
121
  end
119
-
122
+
120
123
  true
121
124
  end
122
-
125
+
126
+ def process_datamapper_model(current_class)
127
+ node_attribs = []
128
+ if @options.brief #|| current_class.abstract_class?
129
+ node_type = 'model-brief'
130
+ else
131
+ node_type = 'model'
132
+
133
+ # Collect model's properties
134
+ props = current_class.properties.sort_by(&:name)
135
+
136
+ if @options.hide_magic
137
+ # From patch #13351
138
+ # http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
139
+ magic_fields =
140
+ ["created_at", "created_on", "updated_at", "updated_on", "lock_version", "_type", "_id",
141
+ "position", "parent_id", "lft", "rgt", "quote", "template"]
142
+ props = props.select {|c| !magic_fields.include?(c.name.to_s) }
143
+ end
144
+
145
+ props.each do |a|
146
+ prop = a.name.to_s
147
+ prop += ' :' + a.class.name.split('::').last unless @options.hide_types
148
+ node_attribs << prop
149
+ end
150
+ end
151
+ @graph.add_node [node_type, current_class.name, node_attribs]
152
+
153
+ # Process relationships
154
+ relationships = current_class.relationships
155
+
156
+ # TODO: Manage inheritance
157
+
158
+ relationships.each do |a|
159
+ process_datamapper_relationship current_class.name, a
160
+ end
161
+
162
+ true
163
+ end
164
+
165
+
166
+
167
+
123
168
  def process_mongoid_model(current_class)
124
169
  node_attribs = []
125
-
170
+
126
171
  if @options.brief
127
172
  node_type = 'model-brief'
128
173
  else
@@ -141,31 +186,31 @@ class ModelsDiagram < AppDiagram
141
186
  ]
142
187
  content_columns = content_columns.select {|c| !magic_fields.include?(c.name) }
143
188
  end
144
-
189
+
145
190
  content_columns.each do |a|
146
191
  content_column = a.name
147
192
  content_column += " :#{a.type}" unless @options.hide_types
148
193
  node_attribs << content_column
149
194
  end
150
195
  end
151
-
196
+
152
197
  @graph.add_node [node_type, current_class.name, node_attribs]
153
-
198
+
154
199
  # Process class associations
155
200
  associations = current_class.relations.values
156
-
201
+
157
202
  if @options.inheritance && !@options.transitive &&
158
203
  current_class.superclass.respond_to?(:relations)
159
204
  associations -= current_class.superclass.relations.values
160
205
  end
161
-
206
+
162
207
  associations.each do |a|
163
208
  process_association current_class.name, a
164
209
  end
165
-
210
+
166
211
  true
167
212
  end
168
-
213
+
169
214
 
170
215
  # Process a model association
171
216
  def process_association(class_name, assoc)
@@ -175,21 +220,21 @@ class ModelsDiagram < AppDiagram
175
220
  macro = assoc.macro.to_s
176
221
  return if %w[belongs_to referenced_in].include?(macro) && !@options.show_belongs_to
177
222
 
178
- #TODO:
223
+ #TODO:
179
224
  # FAIL: assoc.methods.include?(:class_name)
180
225
  # FAIL: assoc.responds_to?(:class_name)
181
226
  assoc_class_name = assoc.class_name rescue nil
182
227
  assoc_class_name ||= assoc.name.to_s.underscore.singularize.camelize
183
-
228
+
184
229
  # Only non standard association names needs a label
185
-
230
+
186
231
  # from patch #12384
187
232
  # if assoc.class_name == assoc.name.to_s.singularize.camelize
188
233
  if assoc_class_name == assoc.name.to_s.singularize.camelize
189
234
  assoc_name = ''
190
235
  else
191
236
  assoc_name = assoc.name.to_s
192
- end
237
+ end
193
238
 
194
239
  # Patch from "alpack" to support classes in a non-root module namespace. See: http://disq.us/yxl1v
195
240
  if class_name.include?("::") && !assoc_class_name.include?("::")
@@ -207,9 +252,45 @@ class ModelsDiagram < AppDiagram
207
252
  return if @habtm.include? [assoc_class_name, class_name, assoc_name]
208
253
  assoc_type = 'many-many'
209
254
  @habtm << [class_name, assoc_class_name, assoc_name]
210
- end
211
- # from patch #12384
255
+ end
256
+ # from patch #12384
212
257
  # @graph.add_edge [assoc_type, class_name, assoc.class_name, assoc_name]
213
- @graph.add_edge [assoc_type, class_name, assoc_class_name, assoc_name]
258
+ @graph.add_edge [assoc_type, class_name, assoc_class_name, assoc_name]
214
259
  end # process_association
215
260
  end # class ModelsDiagram
261
+
262
+ # Process a DataMapper relationship
263
+ def process_datamapper_relationship(class_name, relation)
264
+ STDERR.puts "- Processing DataMapper model relationship #{relation.name.to_s}" if @options.verbose
265
+
266
+ # Skip "belongs_to" relationships
267
+ dm_type = relation.class.to_s.split('::')[-2]
268
+ return if dm_type == 'ManyToOne' && !@options.show_belongs_to
269
+
270
+ dm_parent_model = relation.parent_model.to_s
271
+ dm_child_model = relation.child_model.to_s
272
+
273
+ assoc_class_name = ''
274
+ # Get the assoc_class_name
275
+ if dm_parent_model.eql?(class_name)
276
+ assoc_class_name = dm_child_model
277
+ else
278
+ assoc_class_name = dm_parent_model
279
+ end
280
+
281
+ # Only non standard association names needs a label
282
+ assoc_name = ''
283
+ if !(relation.name.to_s.singularize.camelize.eql?(assoc_class_name.split('::').last))
284
+ assoc_name = relation.name.to_s
285
+ end
286
+
287
+ # TO BE IMPROVED
288
+ rel_type = 'many-many' # default value for ManyToOne and ManyToMany
289
+ if dm_type == 'OneToOne'
290
+ rel_type = 'one-one'
291
+ elsif dm_type == 'OneToMany'
292
+ rel_type = 'one-many'
293
+ end
294
+
295
+ @graph.add_edge [rel_type, class_name, assoc_class_name, assoc_name ]
296
+ end
data/tasks/railroady.rake CHANGED
@@ -7,22 +7,27 @@
7
7
  #
8
8
  # Author: Preston Lee, http://railroady.prestonlee.com
9
9
 
10
- # Returns an absolute path for the following file.
11
- def format
12
- @@DIAGRAM_FORMAT ||= 'svg'
13
- end
10
+ # wrap helper methods so they don't conflict w/ methods on Object
11
+ module RailRoady
12
+ class RakeHelpers
13
+ def self.format
14
+ @@DIAGRAM_FORMAT ||= 'svg'
15
+ end
14
16
 
15
- def full_path(name = 'test.txt')
16
- f = File.join(Rails.root.to_s.gsub(' ', '\ '), 'doc', name)
17
- f.to_s
17
+ # Returns an absolute path for the following file.
18
+ def self.full_path(name = 'test.txt')
19
+ f = File.join(Rails.root.to_s.gsub(' ', '\ '), 'doc', name)
20
+ f.to_s
21
+ end
22
+ end
18
23
  end
19
24
 
20
25
  namespace :diagram do
21
26
 
22
- @MODELS_ALL = full_path("models_complete.#{format}").freeze
23
- @MODELS_BRIEF = full_path("models_brief.#{format}").freeze
24
- @CONTROLLERS_ALL = full_path("controllers_complete.#{format}").freeze
25
- @CONTROLLERS_BRIEF = full_path("controllers_brief.#{format}").freeze
27
+ @MODELS_ALL = RailRoady::RakeHelpers.full_path("models_complete.#{RailRoady::RakeHelpers.format}").freeze
28
+ @MODELS_BRIEF = RailRoady::RakeHelpers.full_path("models_brief.#{RailRoady::RakeHelpers.format}").freeze
29
+ @CONTROLLERS_ALL = RailRoady::RakeHelpers.full_path("controllers_complete.#{RailRoady::RakeHelpers.format}").freeze
30
+ @CONTROLLERS_BRIEF = RailRoady::RakeHelpers.full_path("controllers_brief.#{RailRoady::RakeHelpers.format}").freeze
26
31
 
27
32
  namespace :models do
28
33
 
@@ -30,14 +35,14 @@ namespace :diagram do
30
35
  task :complete do
31
36
  f = @MODELS_ALL
32
37
  puts "Generating #{f}"
33
- sh "railroady -ilamM | dot -T#{format} > #{f}"
38
+ sh "railroady -ilamM | dot -T#{RailRoady::RakeHelpers.format} > #{f}"
34
39
  end
35
40
 
36
41
  desc 'Generates an abbreviated class diagram for all models.'
37
42
  task :brief do
38
43
  f = @MODELS_BRIEF
39
44
  puts "Generating #{f}"
40
- sh "railroady -bilamM | dot -T#{format} > #{f}"
45
+ sh "railroady -bilamM | dot -T#{RailRoady::RakeHelpers.format} > #{f}"
41
46
  end
42
47
 
43
48
  end
@@ -48,14 +53,14 @@ namespace :diagram do
48
53
  task :complete do
49
54
  f = @CONTROLLERS_ALL
50
55
  puts "Generating #{f}"
51
- sh "railroady -ilC | neato -T#{format} > #{f}"
56
+ sh "railroady -ilC | neato -T#{RailRoady::RakeHelpers.format} > #{f}"
52
57
  end
53
58
 
54
59
  desc 'Generates an abbreviated class diagram for all controllers.'
55
60
  task :brief do
56
61
  f = @CONTROLLERS_BRIEF
57
62
  puts "Generating #{f}"
58
- sh "railroady -bilC | neato -T#{format} > #{f}"
63
+ sh "railroady -bilC | neato -T#{RailRoady::RakeHelpers.format} > #{f}"
59
64
  end
60
65
 
61
66
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: railroady
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 6
10
- version: 1.0.6
9
+ - 7
10
+ version: 1.0.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Preston Lee
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2012-02-03 00:00:00 +05:30
21
+ date: 2012-02-28 00:00:00 +05:30
22
22
  default_executable: railroady
23
23
  dependencies: []
24
24