factorylabs-railroad 0.6.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/ChangeLog +85 -0
- data/History.txt +6 -0
- data/Manifest.txt +17 -0
- data/README.txt +145 -0
- data/Rakefile +15 -0
- data/bin/railroad +45 -0
- data/init.rb +0 -0
- data/lib/railroad.rb +11 -0
- data/lib/railroad/aasm_diagram.rb +79 -0
- data/lib/railroad/app_diagram.rb +86 -0
- data/lib/railroad/controllers_diagram.rb +81 -0
- data/lib/railroad/diagram_graph.rb +133 -0
- data/lib/railroad/models_diagram.rb +171 -0
- data/lib/railroad/options_struct.rb +169 -0
- data/tasks/diagrams.rake +18 -0
- metadata +79 -0
data/README.txt
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
= RailRoad
|
2
|
+
|
3
|
+
RailRoad generates models and controllers diagrams in DOT language for a
|
4
|
+
Rails application.
|
5
|
+
|
6
|
+
|
7
|
+
= Usage
|
8
|
+
|
9
|
+
Run RailRoad on the Rails application's root directory. You can redirect its
|
10
|
+
output to a .dot file or pipe it to the dot or neato utilities to produce a
|
11
|
+
graphic. Model diagrams are intended to be processed using dot and
|
12
|
+
controller diagrams are best processed using neato.
|
13
|
+
|
14
|
+
railroad [options] command
|
15
|
+
|
16
|
+
== Options
|
17
|
+
|
18
|
+
Common options:
|
19
|
+
-b, --brief Generate compact diagram
|
20
|
+
(no attributes nor methods)
|
21
|
+
-e, --exclude file1[,fileN] Exclude given files
|
22
|
+
-i, --inheritance Include inheritance relations
|
23
|
+
-l, --label Add a label with diagram information
|
24
|
+
(type, date, migration, version)
|
25
|
+
-o, --output FILE Write diagram to file FILE
|
26
|
+
-v, --verbose Enable verbose output
|
27
|
+
(produce messages to STDOUT)
|
28
|
+
|
29
|
+
Models diagram options:
|
30
|
+
-a, --all Include all models
|
31
|
+
(not only ActiveRecord::Base derived)
|
32
|
+
--hide-magic Hide magic field names
|
33
|
+
--hide-types Hide attributes type
|
34
|
+
-j, --join Concentrate edges
|
35
|
+
-m, --modules Include modules
|
36
|
+
-p, --plugins-models Include plugins models
|
37
|
+
-t, --transitive Include transitive associations
|
38
|
+
(through inheritance)
|
39
|
+
|
40
|
+
Controllers diagram options:
|
41
|
+
--hide-public Hide public methods
|
42
|
+
--hide-protected Hide protected methods
|
43
|
+
--hide-private Hide private methods
|
44
|
+
|
45
|
+
Other options:
|
46
|
+
-h, --help Show this message
|
47
|
+
--version Show version and copyright
|
48
|
+
|
49
|
+
== Commands
|
50
|
+
|
51
|
+
-M, --models Generate models diagram
|
52
|
+
-C, --controllers Generate controllers diagram
|
53
|
+
-A, --aasm Generate "acts as state machine" diagram
|
54
|
+
|
55
|
+
|
56
|
+
== Examples
|
57
|
+
|
58
|
+
railroad -o models.dot -M
|
59
|
+
Produces a models diagram to the file 'models.dot'
|
60
|
+
railroad -a -i -o full_models.dot -M
|
61
|
+
Models diagram with all classes showing inheritance relations
|
62
|
+
railroad -M | dot -Tsvg > models.svg
|
63
|
+
Model diagram in SVG format
|
64
|
+
railroad -C | neato -Tpng > controllers.png
|
65
|
+
Controller diagram in PNG format
|
66
|
+
railroad -h
|
67
|
+
Shows usage help
|
68
|
+
|
69
|
+
|
70
|
+
= Processing DOT files
|
71
|
+
|
72
|
+
To produce a PNG image from model diagram generated by RailRoad you can
|
73
|
+
issue the following command:
|
74
|
+
|
75
|
+
dot -Tpng models.dot > models.png
|
76
|
+
|
77
|
+
If you want to do the same with a controller diagram, use neato instead of
|
78
|
+
dot:
|
79
|
+
|
80
|
+
neato -Tpng controllers.dot > controllers.png
|
81
|
+
|
82
|
+
If you want to produce SVG (vectorial, scalable, editable) files, you can do
|
83
|
+
the following:
|
84
|
+
|
85
|
+
dot -Tsvg models.dot > models.svg
|
86
|
+
neato -Tsvg controllers.dot > controllers.svg
|
87
|
+
|
88
|
+
Important: There is a bug in Graphviz tools when generating SVG files that
|
89
|
+
cause a text overflow. You can solve this problem editing (with a text
|
90
|
+
editor, not a graphical SVG editor) the file and replacing around line 12
|
91
|
+
"font-size:14.00;" by "font-size:11.00;", or by issuing the following command
|
92
|
+
(see "man sed"):
|
93
|
+
|
94
|
+
sed -i 's/font-size:14.00/font-size:11.00/g' file.svg
|
95
|
+
|
96
|
+
Note: For viewing and editing SVG there is an excellent opensource tool
|
97
|
+
called Inkscape (similar to Adobe Illustrator. For DOT processing you can
|
98
|
+
also use Omnigraffle (on Mac OS X).
|
99
|
+
|
100
|
+
= RailRoad as a rake task
|
101
|
+
|
102
|
+
(Thanks to Thomas Ritz, http://www.galaxy-ritz.de ,for the code.)
|
103
|
+
|
104
|
+
In your Rails application, put the following rake tasks into 'lib/task/diagrams.rake':
|
105
|
+
|
106
|
+
namespace :doc do
|
107
|
+
namespace :diagram do
|
108
|
+
task :models do
|
109
|
+
sh "railroad -i -l -a -m -M | dot -Tsvg | sed 's/font-size:14.00/font-size:11.00/g' > doc/models.svg"
|
110
|
+
end
|
111
|
+
|
112
|
+
task :controllers do
|
113
|
+
sh "railroad -i -l -C | neato -Tsvg | sed 's/font-size:14.00/font-size:11.00/g' > doc/controllers.svg"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
task :diagrams => %w(diagram:models diagram:controllers)
|
118
|
+
end
|
119
|
+
|
120
|
+
Then, 'rake doc:diagrams' produces 'doc/models.svg' and 'doc/controllers.svg'.
|
121
|
+
|
122
|
+
= Requirements
|
123
|
+
|
124
|
+
RailRoad has been tested with Ruby 1.8.5 and Rails 1.1.6 to 1.2.3
|
125
|
+
applications. There is no additional requirements (nevertheless, all your
|
126
|
+
Rails application requirements must be installed).
|
127
|
+
|
128
|
+
In order to view/export the DOT diagrams, you'll need the processing tools
|
129
|
+
from Graphviz.
|
130
|
+
|
131
|
+
= Website and Project Home
|
132
|
+
|
133
|
+
http://railroad.rubyforge.org
|
134
|
+
|
135
|
+
= License
|
136
|
+
|
137
|
+
RailRoad is distributed under the terms of the GNU General Public License
|
138
|
+
as published by the Free Software Foundation; either version 2 of the
|
139
|
+
License, or (at your option) any later version.
|
140
|
+
|
141
|
+
= Author
|
142
|
+
|
143
|
+
Javier Smaldone
|
144
|
+
(javier -at- smaldone -dot- com -dot- ar, http://blog.smaldone.com.ar )
|
145
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'hoe'
|
5
|
+
require './lib/railroad.rb'
|
6
|
+
|
7
|
+
Hoe.new('railroad', APP_VERSION.join('.')) do |p|
|
8
|
+
p.rubyforge_name = 'railroad'
|
9
|
+
p.author = "Javier Smaldone"
|
10
|
+
p.email = "javier@smaldone.com.ar"
|
11
|
+
p.url = "http://railroad.rubyforge.org"
|
12
|
+
p.summary = "A DOT diagram generator for Ruby on Rail applications"
|
13
|
+
end
|
14
|
+
|
15
|
+
# vim: syntax=Ruby
|
data/bin/railroad
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# RailRoad - RoR diagrams generator
|
4
|
+
# http://railroad.rubyforge.org
|
5
|
+
#
|
6
|
+
# RailRoad generates models and controllers diagrams in DOT language
|
7
|
+
# for a Rails application.
|
8
|
+
#
|
9
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
10
|
+
#
|
11
|
+
# This program is free software; you can redistribute it and/or modify
|
12
|
+
# it under the terms of the GNU General Public License as published by
|
13
|
+
# the Free Software Foundation; either version 2 of the License, or
|
14
|
+
# (at your option) any later version.
|
15
|
+
#
|
16
|
+
|
17
|
+
$: << File.join(File.dirname(__FILE__), '../lib/')
|
18
|
+
require 'railroad'
|
19
|
+
|
20
|
+
options = OptionsStruct.new
|
21
|
+
|
22
|
+
options.parse ARGV
|
23
|
+
|
24
|
+
old_dir = Dir.pwd
|
25
|
+
|
26
|
+
Dir.chdir(options.root) if options.root != ''
|
27
|
+
|
28
|
+
if options.command == 'models'
|
29
|
+
diagram = ModelsDiagram.new options
|
30
|
+
elsif options.command == 'controllers'
|
31
|
+
diagram = ControllersDiagram.new options
|
32
|
+
elsif options.command == 'aasm'
|
33
|
+
diagram = AasmDiagram.new options
|
34
|
+
else
|
35
|
+
STDERR.print "Error: You must supply a command\n" +
|
36
|
+
" (try #{APP_NAME} -h)\n\n"
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
diagram.generate
|
41
|
+
|
42
|
+
Dir.chdir(old_dir)
|
43
|
+
|
44
|
+
diagram.print
|
45
|
+
|
data/init.rb
ADDED
File without changes
|
data/lib/railroad.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
APP_NAME = "railroad"
|
2
|
+
APP_HUMAN_NAME = "RailRoad"
|
3
|
+
APP_VERSION = [0,6,0]
|
4
|
+
COPYRIGHT = "Copyright (C) 2007-2008 Javier Smaldone"
|
5
|
+
|
6
|
+
require 'railroad/options_struct'
|
7
|
+
require 'railroad/diagram_graph'
|
8
|
+
require 'railroad/app_diagram'
|
9
|
+
require 'railroad/models_diagram'
|
10
|
+
require 'railroad/controllers_diagram'
|
11
|
+
require 'railroad/aasm_diagram'
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# RailRoad - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
# AASM code provided by Ana Nelson (http://ananelson.com/)
|
8
|
+
|
9
|
+
# Diagram for Acts As State Machine
|
10
|
+
class AasmDiagram < AppDiagram
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
#options.exclude.map! {|e| e = "app/models/" + e}
|
14
|
+
super options
|
15
|
+
@graph.diagram_type = 'Models'
|
16
|
+
# Processed habtm associations
|
17
|
+
@habtm = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Process model files
|
21
|
+
def generate
|
22
|
+
STDERR.print "Generating AASM diagram\n" if @options.verbose
|
23
|
+
files = Dir.glob("app/models/*.rb")
|
24
|
+
files += Dir.glob("vendor/plugins/**/app/models/*.rb") if @options.plugins_models
|
25
|
+
files -= @options.exclude
|
26
|
+
files.each do |f|
|
27
|
+
process_class extract_class_name('app/models/', f).constantize
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# Load model classes
|
34
|
+
def load_classes
|
35
|
+
begin
|
36
|
+
disable_stdout
|
37
|
+
files = Dir.glob("app/models/**/*.rb")
|
38
|
+
files += Dir.glob("vendor/plugins/**/app/models/*.rb") if @options.plugins_models
|
39
|
+
files -= @options.exclude
|
40
|
+
files.each {|m| require m }
|
41
|
+
enable_stdout
|
42
|
+
rescue LoadError
|
43
|
+
enable_stdout
|
44
|
+
print_error "model classes"
|
45
|
+
raise
|
46
|
+
end
|
47
|
+
end # load_classes
|
48
|
+
|
49
|
+
# Process a model class
|
50
|
+
def process_class(current_class)
|
51
|
+
|
52
|
+
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
53
|
+
|
54
|
+
# Only interested in acts_as_state_machine models.
|
55
|
+
return unless current_class.respond_to?'states'
|
56
|
+
|
57
|
+
node_attribs = []
|
58
|
+
node_type = 'aasm'
|
59
|
+
|
60
|
+
current_class.states.each do |state_name|
|
61
|
+
state = current_class.read_inheritable_attribute(:states)[state_name]
|
62
|
+
node_shape = (current_class.initial_state === state_name) ? ", peripheries = 2" : ""
|
63
|
+
node_attribs << "#{current_class.name.downcase}_#{state_name} [label=#{state_name} #{node_shape}];"
|
64
|
+
end
|
65
|
+
@graph.add_node [node_type, current_class.name, node_attribs]
|
66
|
+
|
67
|
+
current_class.read_inheritable_attribute(:transition_table).each do |event_name, event|
|
68
|
+
event.each do |transition|
|
69
|
+
@graph.add_edge [
|
70
|
+
'event',
|
71
|
+
current_class.name.downcase + "_" + transition.from.to_s,
|
72
|
+
current_class.name.downcase + "_" + transition.to.to_s,
|
73
|
+
event_name.to_s
|
74
|
+
]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end # process_class
|
78
|
+
|
79
|
+
end # class AasmDiagram
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# RailRoad - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
# Root class for RailRoad diagrams
|
8
|
+
class AppDiagram
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@options = options
|
12
|
+
@graph = DiagramGraph.new
|
13
|
+
@graph.show_label = @options.label
|
14
|
+
|
15
|
+
STDERR.print "Loading application environment\n" if @options.verbose
|
16
|
+
load_environment
|
17
|
+
|
18
|
+
STDERR.print "Loading application classes\n" if @options.verbose
|
19
|
+
load_classes
|
20
|
+
end
|
21
|
+
|
22
|
+
# Print diagram
|
23
|
+
def print
|
24
|
+
if @options.output
|
25
|
+
old_stdout = STDOUT.dup
|
26
|
+
begin
|
27
|
+
STDOUT.reopen(@options.output)
|
28
|
+
rescue
|
29
|
+
STDERR.print "Error: Cannot write diagram to #{@options.output}\n\n"
|
30
|
+
exit 2
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if @options.xmi
|
35
|
+
STDERR.print "Generating XMI diagram\n" if @options.verbose
|
36
|
+
STDOUT.print @graph.to_xmi
|
37
|
+
else
|
38
|
+
STDERR.print "Generating DOT graph\n" if @options.verbose
|
39
|
+
STDOUT.print @graph.to_dot
|
40
|
+
end
|
41
|
+
|
42
|
+
if @options.output
|
43
|
+
STDOUT.reopen(old_stdout)
|
44
|
+
end
|
45
|
+
end # print
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Prevents Rails application from writing to STDOUT
|
50
|
+
def disable_stdout
|
51
|
+
@old_stdout = STDOUT.dup
|
52
|
+
STDOUT.reopen(PLATFORM =~ /mswin/ ? "NUL" : "/dev/null")
|
53
|
+
end
|
54
|
+
|
55
|
+
# Restore STDOUT
|
56
|
+
def enable_stdout
|
57
|
+
STDOUT.reopen(@old_stdout)
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
# Print error when loading Rails application
|
62
|
+
def print_error(type)
|
63
|
+
STDERR.print "Error loading #{type}.\n (Are you running " +
|
64
|
+
"#{APP_NAME} on the aplication's root directory?)\n\n"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Load Rails application's environment
|
68
|
+
def load_environment
|
69
|
+
begin
|
70
|
+
disable_stdout
|
71
|
+
require "config/environment"
|
72
|
+
enable_stdout
|
73
|
+
rescue LoadError
|
74
|
+
enable_stdout
|
75
|
+
print_error "application environment"
|
76
|
+
raise
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Extract class name from filename
|
81
|
+
def extract_class_name(base, filename)
|
82
|
+
# this is will handle directory names as namespace names
|
83
|
+
filename.reverse.chomp(base.reverse).reverse.chomp(".rb").camelize
|
84
|
+
end
|
85
|
+
|
86
|
+
end # class AppDiagram
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# RailRoad - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
# RailRoad controllers diagram
|
8
|
+
class ControllersDiagram < AppDiagram
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
#options.exclude.map! {|e| "app/controllers/" + e}
|
12
|
+
super options
|
13
|
+
@graph.diagram_type = 'Controllers'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Process controller files
|
17
|
+
def generate
|
18
|
+
STDERR.print "Generating controllers diagram\n" if @options.verbose
|
19
|
+
|
20
|
+
files = Dir.glob("app/controllers/**/*_controller.rb") - @options.exclude
|
21
|
+
files << 'app/controllers/application.rb'
|
22
|
+
files.each do |f|
|
23
|
+
class_name = extract_class_name('app/controllers/', f)
|
24
|
+
# ApplicationController's file is 'application.rb'
|
25
|
+
class_name += 'Controller' if class_name == 'Application'
|
26
|
+
process_class class_name.constantize
|
27
|
+
end
|
28
|
+
end # generate
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
# Load controller classes
|
33
|
+
def load_classes
|
34
|
+
begin
|
35
|
+
disable_stdout
|
36
|
+
# ApplicationController must be loaded first
|
37
|
+
require "app/controllers/application.rb"
|
38
|
+
files = Dir.glob("app/controllers/**/*_controller.rb") - @options.exclude
|
39
|
+
files.each {|c| require c }
|
40
|
+
enable_stdout
|
41
|
+
rescue LoadError
|
42
|
+
enable_stdout
|
43
|
+
print_error "controller classes"
|
44
|
+
raise
|
45
|
+
end
|
46
|
+
end # load_classes
|
47
|
+
|
48
|
+
# Proccess a controller class
|
49
|
+
def process_class(current_class)
|
50
|
+
|
51
|
+
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
52
|
+
|
53
|
+
if @options.brief
|
54
|
+
@graph.add_node ['controller-brief', current_class.name]
|
55
|
+
elsif current_class.is_a? Class
|
56
|
+
# Collect controller's methods
|
57
|
+
node_attribs = {:public => [],
|
58
|
+
:protected => [],
|
59
|
+
:private => []}
|
60
|
+
current_class.public_instance_methods(false).sort.each { |m|
|
61
|
+
node_attribs[:public] << m
|
62
|
+
} unless @options.hide_public
|
63
|
+
current_class.protected_instance_methods(false).sort.each { |m|
|
64
|
+
node_attribs[:protected] << m
|
65
|
+
} unless @options.hide_protected
|
66
|
+
current_class.private_instance_methods(false).sort.each { |m|
|
67
|
+
node_attribs[:private] << m
|
68
|
+
} unless @options.hide_private
|
69
|
+
@graph.add_node ['controller', current_class.name, node_attribs]
|
70
|
+
elsif @options.modules && current_class.is_a?(Module)
|
71
|
+
@graph.add_node ['module', current_class.name]
|
72
|
+
end
|
73
|
+
|
74
|
+
# Generate the inheritance edge (only for ApplicationControllers)
|
75
|
+
if @options.inheritance &&
|
76
|
+
(ApplicationController.subclasses.include? current_class.name)
|
77
|
+
@graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
|
78
|
+
end
|
79
|
+
end # process_class
|
80
|
+
|
81
|
+
end # class ControllersDiagram
|