railroady 0.9.0

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.
@@ -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