nono-railroad 0.7.4

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/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