nono-railroad 0.7.4

Sign up to get free protection for your applications and to get access to all the features.
data/Manifest.txt ADDED
@@ -0,0 +1,17 @@
1
+ COPYING
2
+ ChangeLog
3
+ History.txt
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ bin/railroad
8
+ init.rb
9
+ lib/railroad.rb
10
+ lib/railroad/aasm_diagram.rb
11
+ lib/railroad/app_diagram.rb
12
+ lib/railroad/controllers_diagram.rb
13
+ lib/railroad/diagram_graph.rb
14
+ lib/railroad/models_diagram.rb
15
+ lib/railroad/options_struct.rb
16
+ railroad.gemspec
17
+ tasks/diagrams.rake
data/README.txt ADDED
@@ -0,0 +1,139 @@
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
+ -c, --class-map file1,MyClass1[,fileN,MyClassN]
23
+ Map files to classes they contain
24
+ -i, --inheritance Include inheritance relations
25
+ -l, --label Add a label with diagram information
26
+ (type, date, migration, version)
27
+ -o, --output FILE Write diagram to file FILE
28
+ -v, --verbose Enable verbose output
29
+ (produce messages to STDOUT)
30
+
31
+ Models diagram options:
32
+ -a, --all Include all models
33
+ (not only ActiveRecord::Base derived)
34
+ --hide-magic Hide magic field names
35
+ --hide-types Hide attributes type
36
+ -j, --join Concentrate edges
37
+ -m, --modules Include modules
38
+ -p, --plugins-models Include plugins models
39
+ -y, --libraries Include application library
40
+ -t, --transitive Include transitive associations
41
+ (through inheritance)
42
+
43
+ Controllers diagram options:
44
+ --hide-public Hide public methods
45
+ --hide-protected Hide protected methods
46
+ --hide-private Hide private methods
47
+
48
+ Other options:
49
+ -h, --help Show this message
50
+ --version Show version and copyright
51
+
52
+ == Commands
53
+
54
+ -M, --models Generate models diagram
55
+ -C, --controllers Generate controllers diagram
56
+ -A, --aasm Generate "acts as state machine" diagram
57
+
58
+
59
+ == Examples
60
+
61
+ railroad -o models.dot -M
62
+ Produces a models diagram to the file 'models.dot'
63
+ railroad -a -i -o full_models.dot -M
64
+ Models diagram with all classes showing inheritance relations
65
+ railroad -M | dot -Tsvg > models.svg
66
+ Model diagram in SVG format
67
+ railroad -C | neato -Tpng > controllers.png
68
+ Controller diagram in PNG format
69
+ railroad -h
70
+ Shows usage help
71
+
72
+
73
+ = Processing DOT files
74
+
75
+ To produce a PNG image from model diagram generated by RailRoad you can
76
+ issue the following command:
77
+
78
+ dot -Tpng models.dot > models.png
79
+
80
+ If you want to do the same with a controller diagram, use neato instead of
81
+ dot:
82
+
83
+ neato -Tpng controllers.dot > controllers.png
84
+
85
+ If you want to produce SVG (vectorial, scalable, editable) files, you can do
86
+ the following:
87
+
88
+ dot -Tsvg models.dot > models.svg
89
+ neato -Tsvg controllers.dot > controllers.svg
90
+
91
+ Important: There is a bug in Graphviz tools when generating SVG files that
92
+ cause a text overflow. You can solve this problem editing (with a text
93
+ editor, not a graphical SVG editor) the file and replacing around line 12
94
+ "font-size:14.00;" by "font-size:11.00;", or by issuing the following command
95
+ (see "man sed"):
96
+
97
+ sed -i 's/font-size:14.00/font-size:11.00/g' file.svg
98
+ sed -i 's/font-size:14.00/font-size:11px/g' file.svg # alternative
99
+
100
+ Note: For viewing and editing SVG there is an excellent opensource tool
101
+ called Inkscape (similar to Adobe Illustrator. For DOT processing you can
102
+ also use Omnigraffle (on Mac OS X).
103
+
104
+ = RailRoad as a rake task
105
+
106
+ See tasks/diagrams.rake
107
+
108
+ = Requirements
109
+
110
+ RailRoad has been tested with Ruby 1.8.5 and Rails 1.1.6 to 1.2.3
111
+ applications. There is no additional requirements (nevertheless, all your
112
+ Rails application requirements must be installed).
113
+
114
+ In order to view/export the DOT diagrams, you'll need the processing tools
115
+ from Graphviz.
116
+
117
+ = Website and Project Home
118
+
119
+ http://railroad.rubyforge.org
120
+
121
+ = License
122
+
123
+ RailRoad is distributed under the terms of the GNU General Public License
124
+ as published by the Free Software Foundation; either version 2 of the
125
+ License, or (at your option) any later version.
126
+
127
+ = Author
128
+
129
+ Javier Smaldone
130
+ (javier -at- smaldone -dot- com -dot- ar, http://blog.smaldone.com.ar )
131
+
132
+ == Contributors
133
+
134
+ Thomas Ritz http://www.galaxy-ritz.de
135
+ Tien Dung http://github.com/tiendung
136
+ Factory Design Labs http://github.com/factorylabs
137
+ Mike Mondragon http://github.com/monde
138
+ Tero Tilus http://github.com/terotil
139
+ Bruno Michel http://github.com/nono
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,7,4]
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,110 @@
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 {|file| get_model_class(file) }
41
+ enable_stdout
42
+ rescue LoadError
43
+ enable_stdout
44
+ print_error "model classes"
45
+ raise
46
+ end
47
+ end # load_classes
48
+
49
+ # This method is taken from the annotate models gem
50
+ # http://github.com/ctran/annotate_models/tree/master
51
+ #
52
+ # Retrieve the classes belonging to the model names we're asked to process
53
+ # Check for namespaced models in subdirectories as well as models
54
+ # in subdirectories without namespacing.
55
+ def get_model_class(file)
56
+ model = file.sub(/^.*app\/models\//, '').sub(/\.rb$/, '').camelize
57
+ parts = model.split('::')
58
+ begin
59
+ parts.inject(Object) {|klass, part| klass.const_get(part) }
60
+ rescue LoadError
61
+ Object.const_get(parts.last)
62
+ end
63
+ end
64
+
65
+ # Process a model class
66
+ def process_class(current_class)
67
+
68
+ STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
69
+
70
+ states = nil
71
+ if current_class.respond_to? 'states'
72
+ states = current_class.states
73
+ initial = current_class.initial_state
74
+ events = current_class.read_inheritable_attribute(:transition_table)
75
+ elsif current_class.respond_to? 'aasm_states'
76
+ states = current_class.aasm_states.map { |s| s.name }
77
+ initial = current_class.aasm_initial_state
78
+ events = current_class.aasm_events
79
+ end
80
+
81
+ # Only interested in acts_as_state_machine models.
82
+ return if states.nil? || states.empty?
83
+
84
+ node_attribs = []
85
+ node_type = 'aasm'
86
+
87
+ states.each do |state_name|
88
+ node_shape = (initial === state_name) ? ", peripheries = 2" : ""
89
+ node_attribs << "#{current_class.name.downcase}_#{state_name} [label=#{state_name} #{node_shape}];"
90
+ end
91
+ @graph.add_node [node_type, current_class.name, node_attribs]
92
+
93
+ events.each do |event_name, event|
94
+ if !event.respond_to?('each')
95
+ def event.each(&blk)
96
+ @transitions.each { |t| blk.call(t) }
97
+ end
98
+ end
99
+ event.each do |transition|
100
+ @graph.add_edge [
101
+ 'event',
102
+ current_class.name.downcase + "_" + transition.from.to_s,
103
+ current_class.name.downcase + "_" + transition.to.to_s,
104
+ event_name.to_s
105
+ ]
106
+ end
107
+ end
108
+ end # process_class
109
+
110
+ 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,98 @@
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.each do |f|
22
+ class_name = extract_class_name('app/controllers/', f)
23
+ process_class class_name.constantize
24
+ end
25
+ end # generate
26
+
27
+ private
28
+
29
+ # Load controller classes
30
+ def load_classes
31
+ begin
32
+ disable_stdout
33
+ files = Dir.glob("app/controllers/**/*_controller.rb") - @options.exclude
34
+ files.each {|file| get_controller_class(file) }
35
+ enable_stdout
36
+ rescue LoadError
37
+ enable_stdout
38
+ print_error "controller classes"
39
+ raise
40
+ end
41
+ end # load_classes
42
+
43
+ # This method is taken from the annotate models gem
44
+ # http://github.com/ctran/annotate_models/tree/master
45
+ #
46
+ # Retrieve the classes belonging to the controller names we're asked to process
47
+ # Check for namespaced controllers in subdirectories as well as controllers
48
+ # in subdirectories without namespacing.
49
+ def get_controller_class(file)
50
+ model = file.sub(/^.*app\/controllers\//, '').sub(/\.rb$/, '').camelize
51
+ parts = model.split('::')
52
+ begin
53
+ parts.inject(Object) {|klass, part| klass.const_get(part) }
54
+ rescue LoadError
55
+ Object.const_get(parts.last)
56
+ end
57
+ end
58
+
59
+ # Proccess a controller class
60
+ def process_class(current_class)
61
+
62
+ STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
63
+
64
+ if @options.brief
65
+ @graph.add_node ['controller-brief', current_class.name]
66
+ elsif current_class.is_a? Class
67
+ # Collect controller's methods
68
+ node_attribs = {:public => [],
69
+ :protected => [],
70
+ :private => []}
71
+ current_class.public_instance_methods(false).sort.each { |m|
72
+ process_method(node_attribs[:public], m)
73
+ } unless @options.hide_public
74
+ current_class.protected_instance_methods(false).sort.each { |m|
75
+ process_method(node_attribs[:protected], m)
76
+ } unless @options.hide_protected
77
+ current_class.private_instance_methods(false).sort.each { |m|
78
+ process_method(node_attribs[:private], m)
79
+ } unless @options.hide_private
80
+ @graph.add_node ['controller', current_class.name, node_attribs]
81
+ elsif @options.modules && current_class.is_a?(Module)
82
+ @graph.add_node ['module', current_class.name]
83
+ end
84
+
85
+ # Generate the inheritance edge (only for ApplicationControllers)
86
+ if @options.inheritance &&
87
+ (ApplicationController.subclasses.include? current_class.name)
88
+ @graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
89
+ end
90
+ end # process_class
91
+
92
+ # Process a method
93
+ def process_method(attribs, method)
94
+ return if @options.hide_underscore && method[0..0] == '_'
95
+ attribs << method
96
+ end
97
+
98
+ end # class ControllersDiagram