railroady 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,169 @@
1
+ = RailRoady
2
+
3
+ RailRoady generates models and controllers diagrams in DOT language for a
4
+ Rails application.
5
+
6
+ This is a patched version based on the original v0.5.0.
7
+
8
+ I (Peter Hoeg) am not trying to hijack Javier's project, but since he hasn't released any
9
+ new versions since May '08, I figured I'd better put one out in order to make
10
+ railroad work with rails v2.3.
11
+
12
+ = Usage
13
+
14
+ Run RailRoady on the Rails application's root directory. You can redirect its
15
+ output to a .dot file or pipe it to the dot or neato utilities to produce a
16
+ graphic. Model diagrams are intended to be processed using dot and
17
+ controller diagrams are best processed using neato.
18
+
19
+ railroad [options] command
20
+
21
+ == Options
22
+
23
+ Common options:
24
+ -b, --brief Generate compact diagram
25
+ (no attributes nor methods)
26
+ -s, --specify file1[,fileN] Specify given files only for the diagram
27
+ (can take a glob pattern)
28
+ -e, --exclude file1[,fileN] Exclude given files
29
+ (can take a glob pattern)
30
+ -i, --inheritance Include inheritance relations
31
+ -l, --label Add a label with diagram information
32
+ (type, date, migration, version)
33
+ -o, --output FILE Write diagram to file FILE
34
+ -v, --verbose Enable verbose output
35
+ (produce messages to STDOUT)
36
+
37
+ Models diagram options:
38
+ -a, --all Include all models
39
+ (not only ActiveRecord::Base derived)
40
+ --hide-magic Hide magic field names
41
+ --hide-types Hide attributes type
42
+ -j, --join Concentrate edges
43
+ -m, --modules Include modules
44
+ -p, --plugins-models Include plugins models
45
+ -t, --transitive Include transitive associations
46
+ (through inheritance)
47
+
48
+ Controllers diagram options:
49
+ --hide-public Hide public methods
50
+ --hide-protected Hide protected methods
51
+ --hide-private Hide private methods
52
+
53
+ Other options:
54
+ -h, --help Show this message
55
+ --version Show version and copyright
56
+
57
+ == Commands
58
+
59
+ -M, --models Generate models diagram
60
+ -C, --controllers Generate controllers diagram
61
+ -A, --aasm Generate "acts as state machine" diagram
62
+
63
+
64
+ == Examples
65
+
66
+ railroad -o models.dot -M
67
+ Produces a models diagram to the file 'models.dot'
68
+ railroad -a -i -o full_models.dot -M
69
+ Models diagram with all classes showing inheritance relations
70
+ railroad -M | dot -Tsvg > models.svg
71
+ Model diagram in SVG format
72
+ railroad -C | neato -Tpng > controllers.png
73
+ Controller diagram in PNG format
74
+ railroad -h
75
+ Shows usage help
76
+
77
+
78
+ = Processing DOT files
79
+
80
+ To produce a PNG image from model diagram generated by RailRoady you can
81
+ issue the following command:
82
+
83
+ dot -Tpng models.dot > models.png
84
+
85
+ If you want to do the same with a controller diagram, use neato instead of
86
+ dot:
87
+
88
+ neato -Tpng controllers.dot > controllers.png
89
+
90
+ If you want to produce SVG (vectorial, scalable, editable) files, you can do
91
+ the following:
92
+
93
+ dot -Tsvg models.dot > models.svg
94
+ neato -Tsvg controllers.dot > controllers.svg
95
+
96
+ Important: There is a bug in Graphviz tools when generating SVG files that
97
+ cause a text overflow. You can solve this problem editing (with a text
98
+ editor, not a graphical SVG editor) the file and replacing around line 12
99
+ "font-size:14.00;" by "font-size:11.00;", or by issuing the following command
100
+ (see "man sed"):
101
+
102
+ sed -i 's/font-size:14.00/font-size:11.00/g' file.svg
103
+
104
+ Note: For viewing and editing SVG there is an excellent opensource tool
105
+ called Inkscape (similar to Adobe Illustrator. For DOT processing you can
106
+ also use Omnigraffle (on Mac OS X).
107
+
108
+ = RailRoady as a rake task
109
+
110
+ (Thanks to Thomas Ritz, http://www.galaxy-ritz.de ,for the code.)
111
+
112
+ In your Rails application, put the following rake tasks into 'lib/task/diagrams.rake':
113
+
114
+ namespace :doc do
115
+ namespace :diagram do
116
+ task :models do
117
+ sh "railroad -i -l -a -m -M | dot -Tsvg | sed 's/font-size:14.00/font-size:11.00/g' > doc/models.svg"
118
+ end
119
+
120
+ task :controllers do
121
+ sh "railroad -i -l -C | neato -Tsvg | sed 's/font-size:14.00/font-size:11.00/g' > doc/controllers.svg"
122
+ end
123
+ end
124
+
125
+ task :diagrams => %w(diagram:models diagram:controllers)
126
+ end
127
+
128
+ Then, 'rake doc:diagrams' produces 'doc/models.svg' and 'doc/controllers.svg'.
129
+
130
+ = Requirements
131
+
132
+ RailRoady has been tested with the following Ruby and Rails versions
133
+
134
+ == Ruby
135
+ * 1.8.5
136
+ * 1.8.7
137
+
138
+ == Rails
139
+ * 1.1.6 to 1.2.3
140
+ * 2.3.2 to 2.3.5
141
+
142
+ There are no additional requirements (nevertheless, all your Rails application
143
+ requirements must be installed).
144
+
145
+ In order to view/export the DOT diagrams, you'll need the processing tools
146
+ from Graphviz.
147
+
148
+ = Website and Project Home
149
+
150
+ http://railroad.rubyforge.org
151
+
152
+ = License
153
+
154
+ RailRoady is distributed under the terms of the GNU General Public License
155
+ as published by the Free Software Foundation; either version 2 of the
156
+ License, or (at your option) any later version.
157
+
158
+ See LICENSE for details.
159
+
160
+ == Copyright
161
+
162
+ Copyright (c) 2007-2008 Javier Smaldone
163
+ Copyright (c) 2009 Peter Hoeg
164
+
165
+ See LICENSE for details.
166
+
167
+ == Authors
168
+
169
+ See AUTHORS for details.
@@ -0,0 +1,47 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "railroady"
8
+ gem.executables = "railroady"
9
+ gem.email = ['conmotto@gmail.com', 'tcrawley@gmail.com', 'peter@hoeg.com', 'p.hoeg@northwind.sg', 'javier@smaldone.com.ar']
10
+ gem.homepage = "http://github.com/preston/railroady"
11
+ gem.authors = ["Preston Lee", "Tobias Crawley", "Peter Hoeg", "Javier Smaldone"]
12
+ gem.summary = "A DOT diagram generator for Ruby on Rail applications."
13
+ gem.description = gem.summary
14
+ gem.files = FileList["[A-Z]*", "{autotest,bin,lib,spec,tasks}/**/*", ".document"]
15
+ gem.extra_rdoc_files = FileList["*.rdoc"]
16
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
+ end
18
+
19
+ rescue LoadError
20
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
21
+ end
22
+
23
+ require 'rspec'
24
+ require 'rspec/core/rake_task'
25
+ RSpec::Core::RakeTask.new(:spec) do |spec|
26
+ # spec.libs << 'lib' << 'rspec'
27
+ spec.pattern = FileList['rspec/**/*_spec.rb']
28
+ end
29
+
30
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
31
+ # spec.libs << 'lib' << 'rspec'
32
+ spec.pattern = 'rspec/**/*_spec.rb'
33
+ spec.rcov = true
34
+ end
35
+
36
+ task :default => :spec
37
+
38
+ require 'rake/rdoctask'
39
+ require 'railroady/version'
40
+ Rake::RDocTask.new do |rdoc|
41
+ rdoc.rdoc_dir = 'rdoc'
42
+ rdoc.title = "railroady #{RailRoady::VERSION::STRING}"
43
+ rdoc.rdoc_files.include('README*')
44
+ rdoc.rdoc_files.include('CHANGELOG*')
45
+ rdoc.rdoc_files.include('AUTHORS*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+ :minor: 9
3
+ :build:
4
+ :patch: 0
5
+ :major: 0
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # RailRoady - RoR diagrams generator
4
+ # http://github.com/preston/railroady
5
+ #
6
+ # RailRoady generates models and controllers diagrams in DOT language
7
+ # for a Rails v3 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
+ # Modification 2010 by Preston Lee.
17
+ #
18
+
19
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
20
+ require 'railroady'
21
+
22
+ APP_NAME = "railroady"
23
+ APP_HUMAN_NAME = "RailRoady"
24
+ # APP_VERSION = [RailRoady::VERSION::MAJOR, RailRoady::VERSION::MINOR, RailRoady::VERSION::PATCH]
25
+ APP_VERSION = RailRoady::VERSION::STRING
26
+ COPYRIGHT = "Copyright (C) 2007-2008 Javier Smaldone, 2009 Peter Hoeg, 2010 Preston Lee"
27
+
28
+ options = OptionsStruct.new({:app_name => APP_NAME, :app_human_name => APP_HUMAN_NAME, :app_version =>APP_VERSION, :copyright =>COPYRIGHT})
29
+
30
+ options.parse ARGV
31
+
32
+ # puts "OPTS!!!"
33
+ # puts options
34
+
35
+ old_dir = Dir.pwd
36
+
37
+ Dir.chdir(options.root) if options.root != ''
38
+
39
+ if options.command == 'models'
40
+ diagram = ModelsDiagram.new options
41
+ elsif options.command == 'controllers'
42
+ diagram = ControllersDiagram.new options
43
+ elsif options.command == 'aasm'
44
+ diagram = AasmDiagram.new(options)
45
+ else
46
+ STDERR.print "#{APP_HUMAN_NAME} v#{RailRoady::VERSION::STRING}\n" +
47
+ "Error: You must supply a command\n" +
48
+ " (try #{APP_NAME} -h)\n\n"
49
+ exit 1
50
+ end
51
+
52
+ diagram.process
53
+ diagram.generate
54
+
55
+ Dir.chdir(old_dir)
56
+
57
+ diagram.print
58
+
@@ -0,0 +1,5 @@
1
+ ['version', 'options_struct', 'models_diagram', 'controllers_diagram', 'aasm_diagram'].each { |f| require "railroady/#{f}" }
2
+
3
+ module RailRoady
4
+ require 'railroady/railtie' if defined?(Rails)
5
+ end
@@ -0,0 +1,109 @@
1
+ # RailRoady - 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
+ require 'railroady/app_diagram'
10
+
11
+ # Diagram for Acts As State Machine
12
+ class AasmDiagram < AppDiagram
13
+
14
+ def initialize(options = OptionsStruct.new)
15
+ #options.exclude.map! {|e| e = "app/models/" + e}
16
+ super options
17
+ @graph.diagram_type = 'Models'
18
+ # Processed habtm associations
19
+ @habtm = []
20
+ end
21
+
22
+ # Process model files
23
+ def generate
24
+ STDERR.print "Generating AASM diagram\n" if @options.verbose
25
+ get_files.each do |f|
26
+ process_class extract_class_name(f).constantize
27
+ end
28
+ end
29
+
30
+ def get_files(prefix ='')
31
+ files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << "app/models/**/*.rb")
32
+ files += Dir.glob("vendor/plugins/**/app/models/*.rb") if @options.plugins_models
33
+ files -= Dir.glob(@options.exclude)
34
+ files
35
+ end
36
+
37
+ private
38
+
39
+ # Load model classes
40
+ def load_classes
41
+ begin
42
+ disable_stdout
43
+ get_files.each {|m| require m }
44
+ enable_stdout
45
+ rescue LoadError
46
+ enable_stdout
47
+ print_error "model classes"
48
+ raise
49
+ end
50
+ end # load_classes
51
+
52
+ # Process a model class
53
+ def process_class(current_class)
54
+
55
+ STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
56
+
57
+ # Only interested in acts_as_state_machine models.
58
+ process_acts_as_state_machine_class(current_class) if current_class.respond_to?(:states)
59
+ process_aasm_class(current_class) if current_class.respond_to?(:aasm_states)
60
+ end # process_class
61
+
62
+ def process_acts_as_state_machine_class(current_class)
63
+ node_attribs = []
64
+ node_type = 'aasm'
65
+
66
+ STDERR.print "\t\tprocessing as acts_as_state_machine\n" if @options.verbose
67
+ current_class.states.each do |state_name|
68
+ state = current_class.read_inheritable_attribute(:states)[state_name]
69
+ node_shape = (current_class.initial_state === state_name) ? ", peripheries = 2" : ""
70
+ node_attribs << "#{current_class.name.downcase}_#{state_name} [label=#{state_name} #{node_shape}];"
71
+ end
72
+ @graph.add_node [node_type, current_class.name, node_attribs]
73
+
74
+ current_class.read_inheritable_attribute(:transition_table).each do |event_name, event|
75
+ event.each do |transition|
76
+ @graph.add_edge [
77
+ 'event',
78
+ current_class.name.downcase + "_" + transition.from.to_s,
79
+ current_class.name.downcase + "_" + transition.to.to_s,
80
+ event_name.to_s
81
+ ]
82
+ end
83
+ end
84
+ end
85
+
86
+ def process_aasm_class(current_class)
87
+ node_attribs = []
88
+ node_type = 'aasm'
89
+
90
+ STDERR.print "\t\tprocessing as aasm\n" if @options.verbose
91
+ current_class.aasm_states.each do |state|
92
+ node_shape = (current_class.aasm_initial_state === state.name) ? ", peripheries = 2" : ""
93
+ node_attribs << "#{current_class.name.downcase}_#{state.name} [label=#{state.name} #{node_shape}];"
94
+ end
95
+ @graph.add_node [node_type, current_class.name, node_attribs]
96
+
97
+ current_class.aasm_events.each do |event_name, event|
98
+ event.all_transitions.each do |transition|
99
+ @graph.add_edge [
100
+ 'event',
101
+ current_class.name.downcase + "_" + transition.from.to_s,
102
+ current_class.name.downcase + "_" + transition.to.to_s,
103
+ event_name.to_s
104
+ ]
105
+ end
106
+ end
107
+ end
108
+
109
+ end # class AasmDiagram
@@ -0,0 +1,113 @@
1
+ # RailRoady - 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
+ require 'railroady/diagram_graph'
8
+
9
+ # camelize and constantize methods brought over from active_support
10
+ class String
11
+ def camelize(first_letter_in_uppercase = true)
12
+ if first_letter_in_uppercase
13
+ self.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
14
+ else
15
+ self.first + self.camelize[1..-1]
16
+ end
17
+ end
18
+ def constantize
19
+ names = self.split('::')
20
+ names.shift if names.empty? || names.first.empty?
21
+
22
+ constant = Object
23
+ names.each do |name|
24
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
25
+ end
26
+ constant
27
+ end
28
+ end
29
+
30
+ # Root class for RailRoady diagrams
31
+ class AppDiagram
32
+
33
+ def initialize(options = OptionsStruct.new)
34
+ @options = options
35
+ @graph = DiagramGraph.new
36
+ @graph.show_label = @options.label
37
+ end
38
+
39
+
40
+ # Print diagram
41
+ def print
42
+ if @options.output
43
+ old_stdout = STDOUT.dup
44
+ begin
45
+ STDOUT.reopen(@options.output)
46
+ rescue
47
+ STDERR.print "Error: Cannot write diagram to #{@options.output}\n\n"
48
+ exit 2
49
+ end
50
+ end
51
+
52
+ if @options.xmi
53
+ STDERR.print "Generating XMI diagram\n" if @options.verbose
54
+ STDOUT.print @graph.to_xmi
55
+ else
56
+ STDERR.print "Generating DOT graph\n" if @options.verbose
57
+ STDOUT.print @graph.to_dot
58
+ end
59
+
60
+ if @options.output
61
+ STDOUT.reopen(old_stdout)
62
+ end
63
+ end # print
64
+
65
+ def process
66
+ load_environment
67
+ end
68
+
69
+ private
70
+
71
+ # Load Rails application's environment
72
+ def load_environment
73
+ STDERR.print "Loading application environment\n" if @options.verbose
74
+ begin
75
+ disable_stdout
76
+ l = File.join(Dir.pwd.to_s, 'config/environment')
77
+ require l
78
+ enable_stdout
79
+ rescue LoadError
80
+ enable_stdout
81
+ print_error "application environment"
82
+ raise
83
+ end
84
+ STDERR.print "Loading application classes as we go\n" if @options.verbose
85
+ end
86
+
87
+ # Prevents Rails application from writing to STDOUT
88
+ def disable_stdout
89
+ @old_stdout = STDOUT.dup
90
+ STDOUT.reopen(::RUBY_PLATFORM =~ /mswin/ ? "NUL" : "/dev/null")
91
+ end
92
+
93
+ # Restore STDOUT
94
+ def enable_stdout
95
+ STDOUT.reopen(@old_stdout)
96
+ end
97
+
98
+
99
+ # Print error when loading Rails application
100
+ def print_error(type)
101
+ STDERR.print "Error loading #{type}.\n (Are you running " +
102
+ "#{@options.app_name} on the aplication's root directory?)\n\n"
103
+ end
104
+
105
+ # Extract class name from filename
106
+ def extract_class_name(filename)
107
+ #filename.split('/')[2..-1].join('/').split('.').first.camelize
108
+ # Fixed by patch from ticket #12742
109
+ # File.basename(filename).chomp(".rb").camelize
110
+ filename.split('/')[2..-1].collect { |i| i.camelize }.join('::').chomp(".rb")
111
+ end
112
+
113
+ end # class AppDiagram