railroady 1.3.0 → 1.3.1
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.
- checksums.yaml +4 -4
- data/Guardfile +0 -1
- data/Rakefile +5 -5
- data/bin/railroady +6 -7
- data/lib/railroady.rb +2 -2
- data/lib/railroady/aasm_diagram.rb +24 -29
- data/lib/railroady/app_diagram.rb +16 -23
- data/lib/railroady/controllers_diagram.rb +33 -40
- data/lib/railroady/diagram_graph.rb +45 -55
- data/lib/railroady/models_diagram.rb +37 -56
- data/lib/railroady/options_struct.rb +99 -103
- data/lib/railroady/railtie.rb +4 -5
- data/lib/railroady/version.rb +1 -1
- data/railroady.gemspec +12 -13
- data/tasks/railroady.rake +20 -29
- data/test/file_fixture/app/controllers/application_controller.rb +1 -1
- data/test/lib/railroady/aasm_diagram_spec.rb +14 -16
- data/test/lib/railroady/app_diagram_spec.rb +1 -2
- data/test/lib/railroady/controllers_diagram_spec.rb +16 -19
- data/test/lib/railroady/core_ext_spec.rb +2 -2
- data/test/lib/railroady/diagram_graph_spec.rb +6 -2
- data/test/lib/railroady/models_diagram_spec.rb +18 -20
- data/test/spec_helper.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c445e74b5659404f61ab558a1bf02f496d7b34c
|
4
|
+
data.tar.gz: f5a44d738815114e732b44c650129ff6870a710f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fe0e9ecb631a4482179083fd47cbe75316ea3cfa39c48e6df315a802108336d6dba8b9ff94670125be8cc2486a7846a00d8e50b75aa8b7a0aa24b2f83fe6751
|
7
|
+
data.tar.gz: 4df37c87884a01dca2859f2ba244652c4c58099abddc9907d30d31dddfcd0ece044fd05c8a3de07497a8a9c8b93bb95f7e938b607599823196434d1f5a1c484b
|
data/Guardfile
CHANGED
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
#!/usr/bin/env rake
|
2
|
-
require
|
3
|
-
|
2
|
+
require 'bundler/gem_tasks'
|
3
|
+
|
4
4
|
require 'rake/testtask'
|
5
|
-
|
5
|
+
|
6
6
|
Rake::TestTask.new do |t|
|
7
7
|
t.libs << 'lib/railroady'
|
8
8
|
t.test_files = FileList['test/lib/railroady/*_spec.rb']
|
9
9
|
t.verbose = true
|
10
10
|
end
|
11
|
-
|
12
|
-
task :
|
11
|
+
|
12
|
+
task default: :test
|
data/bin/railroady
CHANGED
@@ -19,13 +19,13 @@
|
|
19
19
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
20
20
|
require 'railroady'
|
21
21
|
|
22
|
-
APP_NAME =
|
23
|
-
APP_HUMAN_NAME =
|
22
|
+
APP_NAME = 'railroady'
|
23
|
+
APP_HUMAN_NAME = 'RailRoady'
|
24
24
|
# APP_VERSION = [RailRoady::VERSION::MAJOR, RailRoady::VERSION::MINOR, RailRoady::VERSION::PATCH]
|
25
25
|
APP_VERSION = RailRoady::VERSION
|
26
|
-
COPYRIGHT =
|
26
|
+
COPYRIGHT = 'Copyright (C) 2007-2008 Javier Smaldone, 2009 Peter Hoeg, 2010 Preston Lee'
|
27
27
|
|
28
|
-
options = OptionsStruct.new(
|
28
|
+
options = OptionsStruct.new(app_name: APP_NAME, app_human_name: APP_HUMAN_NAME, app_version: APP_VERSION, copyright: COPYRIGHT)
|
29
29
|
|
30
30
|
options.parse ARGV
|
31
31
|
|
@@ -44,8 +44,8 @@ when 'controllers'
|
|
44
44
|
when 'aasm'
|
45
45
|
diagram = AasmDiagram.new(options)
|
46
46
|
else
|
47
|
-
STDERR.print "#{APP_HUMAN_NAME} v#{APP_VERSION}\n"
|
48
|
-
"Error: You must supply a command\n"
|
47
|
+
STDERR.print "#{APP_HUMAN_NAME} v#{APP_VERSION}\n" \
|
48
|
+
"Error: You must supply a command\n" \
|
49
49
|
" (try #{APP_NAME} -h)\n\n"
|
50
50
|
exit 1
|
51
51
|
end
|
@@ -56,4 +56,3 @@ diagram.generate
|
|
56
56
|
Dir.chdir(old_dir)
|
57
57
|
|
58
58
|
diagram.print
|
59
|
-
|
data/lib/railroady.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
|
1
|
+
%w(version options_struct models_diagram controllers_diagram aasm_diagram).each { |f| require "railroady/#{f}" }
|
2
2
|
|
3
3
|
module RailRoady
|
4
4
|
require 'railroady/railtie' if defined?(Rails)
|
5
|
-
end
|
5
|
+
end
|
@@ -10,9 +10,8 @@ require 'railroady/app_diagram'
|
|
10
10
|
|
11
11
|
# Diagram for Acts As State Machine
|
12
12
|
class AasmDiagram < AppDiagram
|
13
|
-
|
14
13
|
def initialize(options = OptionsStruct.new)
|
15
|
-
#options.exclude.map! {|e| e = "app/models/" + e}
|
14
|
+
# options.exclude.map! {|e| e = "app/models/" + e}
|
16
15
|
super options
|
17
16
|
@graph.diagram_type = 'Models'
|
18
17
|
# Processed habtm associations
|
@@ -27,10 +26,10 @@ class AasmDiagram < AppDiagram
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
def get_files(prefix ='')
|
31
|
-
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix +
|
32
|
-
files += Dir.glob(
|
33
|
-
files -= Dir.glob(prefix +
|
29
|
+
def get_files(prefix = '')
|
30
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix + 'app/models/**/*.rb')
|
31
|
+
files += Dir.glob('vendor/plugins/**/app/models/*.rb') if @options.plugins_models
|
32
|
+
files -= Dir.glob(prefix + 'app/models/concerns/**/*.rb') unless @options.include_concerns
|
34
33
|
files -= Dir.glob(@options.exclude)
|
35
34
|
files
|
36
35
|
end
|
@@ -39,20 +38,17 @@ class AasmDiagram < AppDiagram
|
|
39
38
|
|
40
39
|
# Load model classes
|
41
40
|
def load_classes
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
raise
|
50
|
-
end
|
41
|
+
disable_stdout
|
42
|
+
get_files.each { |m| require m }
|
43
|
+
enable_stdout
|
44
|
+
rescue LoadError
|
45
|
+
enable_stdout
|
46
|
+
print_error 'model classes'
|
47
|
+
raise
|
51
48
|
end # load_classes
|
52
49
|
|
53
50
|
# Process a model class
|
54
51
|
def process_class(current_class)
|
55
|
-
|
56
52
|
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
57
53
|
|
58
54
|
# Only interested in acts_as_state_machine models.
|
@@ -67,7 +63,7 @@ class AasmDiagram < AppDiagram
|
|
67
63
|
STDERR.print "\t\tprocessing as acts_as_state_machine\n" if @options.verbose
|
68
64
|
current_class.states.each do |state_name|
|
69
65
|
state = current_class.read_inheritable_attribute(:states)[state_name]
|
70
|
-
node_shape = (current_class.initial_state
|
66
|
+
node_shape = (current_class.initial_state == state_name) ? ', peripheries = 2' : ''
|
71
67
|
node_attribs << "#{current_class.name.downcase}_#{state_name} [label=#{state_name} #{node_shape}];"
|
72
68
|
end
|
73
69
|
@graph.add_node [node_type, current_class.name, node_attribs]
|
@@ -75,11 +71,11 @@ class AasmDiagram < AppDiagram
|
|
75
71
|
current_class.read_inheritable_attribute(:transition_table).each do |event_name, event|
|
76
72
|
event.each do |transition|
|
77
73
|
@graph.add_edge [
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
74
|
+
'event',
|
75
|
+
current_class.name.downcase + '_' + transition.from.to_s,
|
76
|
+
current_class.name.downcase + '_' + transition.to.to_s,
|
77
|
+
event_name.to_s
|
78
|
+
]
|
83
79
|
end
|
84
80
|
end
|
85
81
|
end
|
@@ -90,7 +86,7 @@ class AasmDiagram < AppDiagram
|
|
90
86
|
|
91
87
|
STDERR.print "\t\tprocessing as aasm\n" if @options.verbose
|
92
88
|
current_class.aasm.states.each do |state|
|
93
|
-
node_shape = (current_class.aasm.initial_state
|
89
|
+
node_shape = (current_class.aasm.initial_state == state.name) ? ', peripheries = 2' : ''
|
94
90
|
node_attribs << "#{current_class.name.downcase}_#{state.name} [label=#{state.name} #{node_shape}];"
|
95
91
|
end
|
96
92
|
@graph.add_node [node_type, current_class.name, node_attribs]
|
@@ -98,13 +94,12 @@ class AasmDiagram < AppDiagram
|
|
98
94
|
current_class.aasm.events.each do |event_name, event|
|
99
95
|
event.transitions.each do |transition|
|
100
96
|
@graph.add_edge [
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
97
|
+
'event',
|
98
|
+
current_class.name.downcase + '_' + transition.from.to_s,
|
99
|
+
current_class.name.downcase + '_' + transition.to.to_s,
|
100
|
+
event_name.to_s
|
101
|
+
]
|
106
102
|
end
|
107
103
|
end
|
108
104
|
end
|
109
|
-
|
110
105
|
end # class AasmDiagram
|
@@ -8,14 +8,12 @@ require 'railroady/diagram_graph'
|
|
8
8
|
|
9
9
|
# Root class for RailRoady diagrams
|
10
10
|
class AppDiagram
|
11
|
-
|
12
11
|
def initialize(options = OptionsStruct.new)
|
13
12
|
@options = options
|
14
13
|
@graph = DiagramGraph.new
|
15
14
|
@graph.show_label = @options.label
|
16
15
|
@graph.alphabetize = @options.alphabetize
|
17
16
|
end
|
18
|
-
|
19
17
|
|
20
18
|
# Print diagram
|
21
19
|
def print
|
@@ -28,18 +26,16 @@ class AppDiagram
|
|
28
26
|
exit 2
|
29
27
|
end
|
30
28
|
end
|
31
|
-
|
32
|
-
if @options.xmi
|
33
|
-
|
34
|
-
|
29
|
+
|
30
|
+
if @options.xmi
|
31
|
+
STDERR.print "Generating XMI diagram\n" if @options.verbose
|
32
|
+
STDOUT.print @graph.to_xmi
|
35
33
|
else
|
36
|
-
|
37
|
-
|
34
|
+
STDERR.print "Generating DOT graph\n" if @options.verbose
|
35
|
+
STDOUT.print @graph.to_dot
|
38
36
|
end
|
39
37
|
|
40
|
-
if @options.output
|
41
|
-
STDOUT.reopen(old_stdout)
|
42
|
-
end
|
38
|
+
STDOUT.reopen(old_stdout) if @options.output
|
43
39
|
end # print
|
44
40
|
|
45
41
|
def process
|
@@ -49,7 +45,7 @@ class AppDiagram
|
|
49
45
|
# get all engines
|
50
46
|
def engines
|
51
47
|
engines = []
|
52
|
-
|
48
|
+
|
53
49
|
if defined?(Rails)
|
54
50
|
engines = if Rails::Application::Railties.respond_to?(:engines)
|
55
51
|
Rails::Application::Railties.engines
|
@@ -61,9 +57,8 @@ class AppDiagram
|
|
61
57
|
engines
|
62
58
|
end
|
63
59
|
|
60
|
+
private
|
64
61
|
|
65
|
-
private
|
66
|
-
|
67
62
|
# Load Rails application's environment
|
68
63
|
def load_environment
|
69
64
|
STDERR.print "Loading application environment\n" if @options.verbose
|
@@ -74,7 +69,7 @@ class AppDiagram
|
|
74
69
|
enable_stdout
|
75
70
|
rescue LoadError
|
76
71
|
enable_stdout
|
77
|
-
print_error
|
72
|
+
print_error 'application environment'
|
78
73
|
raise
|
79
74
|
end
|
80
75
|
STDERR.print "Loading application classes as we go\n" if @options.verbose
|
@@ -83,28 +78,26 @@ class AppDiagram
|
|
83
78
|
# Prevents Rails application from writing to STDOUT
|
84
79
|
def disable_stdout
|
85
80
|
@old_stdout = STDOUT.dup
|
86
|
-
#via Tomas Matousek, http://www.ruby-forum.com/topic/205887
|
87
|
-
STDOUT.reopen(::RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw
|
81
|
+
# via Tomas Matousek, http://www.ruby-forum.com/topic/205887
|
82
|
+
STDOUT.reopen(::RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ ? 'NUL' : '/dev/null')
|
88
83
|
end
|
89
84
|
|
90
|
-
# Restore STDOUT
|
85
|
+
# Restore STDOUT
|
91
86
|
def enable_stdout
|
92
87
|
STDOUT.reopen(@old_stdout)
|
93
88
|
end
|
94
89
|
|
95
|
-
|
96
90
|
# Print error when loading Rails application
|
97
91
|
def print_error(type)
|
98
|
-
STDERR.print "Error loading #{type}.\n (Are you running "
|
92
|
+
STDERR.print "Error loading #{type}.\n (Are you running " \
|
99
93
|
"#{@options.app_name} on the aplication's root directory?)\n\n"
|
100
94
|
end
|
101
95
|
|
102
96
|
# Extract class name from filename
|
103
97
|
def extract_class_name(filename)
|
104
|
-
#filename.split('/')[2..-1].join('/').split('.').first.camelize
|
98
|
+
# filename.split('/')[2..-1].join('/').split('.').first.camelize
|
105
99
|
# Fixed by patch from ticket #12742
|
106
100
|
# File.basename(filename).chomp(".rb").camelize
|
107
|
-
filename.split('/')[2..-1].collect
|
101
|
+
filename.split('/')[2..-1].collect(&:camelize).join('::').chomp('.rb')
|
108
102
|
end
|
109
|
-
|
110
103
|
end # class AppDiagram
|
@@ -8,13 +8,12 @@ require 'railroady/app_diagram'
|
|
8
8
|
|
9
9
|
# RailRoady controllers diagram
|
10
10
|
class ControllersDiagram < AppDiagram
|
11
|
-
|
12
11
|
# as of Rails 2.3 the file is no longer application.rb but instead
|
13
12
|
# application_controller.rb
|
14
13
|
APP_CONTROLLER = File.exist?('app/controllers/application.rb') ? 'app/controllers/application.rb' : 'app/controllers/application_controller.rb'
|
15
14
|
|
16
15
|
def initialize(options = OptionsStruct.new)
|
17
|
-
#options.exclude.map! {|e| "app/controllers/" + e}
|
16
|
+
# options.exclude.map! {|e| "app/controllers/" + e}
|
18
17
|
super options
|
19
18
|
@graph.diagram_type = 'Controllers'
|
20
19
|
end
|
@@ -32,66 +31,61 @@ class ControllersDiagram < AppDiagram
|
|
32
31
|
begin
|
33
32
|
process_class class_name.constantize
|
34
33
|
rescue Exception
|
35
|
-
STDERR.print "Warning: exception #{
|
34
|
+
STDERR.print "Warning: exception #{$ERROR_INFO} raised while trying to load controller class #{f}"
|
36
35
|
end
|
37
|
-
end
|
36
|
+
end
|
38
37
|
end # generate
|
39
38
|
|
40
|
-
def get_files(prefix ='')
|
41
|
-
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix <<
|
42
|
-
files +=
|
39
|
+
def get_files(prefix = '')
|
40
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << 'app/controllers/**/*_controller.rb')
|
41
|
+
files += engine_files if @options.engine_controllers
|
43
42
|
files -= Dir.glob(@options.exclude)
|
44
43
|
files
|
45
44
|
end
|
46
|
-
|
47
|
-
def
|
48
|
-
engines.collect { |engine| Dir.glob("#{engine.root
|
45
|
+
|
46
|
+
def engine_files
|
47
|
+
engines.collect { |engine| Dir.glob("#{engine.root}/app/controllers/**/*_controller.rb") }.flatten
|
49
48
|
end
|
50
|
-
|
49
|
+
|
51
50
|
def extract_class_name(filename)
|
52
|
-
|
53
|
-
filename.split('/')[controller_index..-1].collect { |i| i.camelize }.join('::').chomp(".rb")
|
51
|
+
filename.match(/.*\/controllers\/(.*).rb$/)[1].camelize
|
54
52
|
end
|
55
53
|
|
56
|
-
|
57
|
-
|
58
54
|
private
|
55
|
+
|
59
56
|
# Load controller classes
|
60
57
|
def load_classes
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
raise
|
71
|
-
end
|
58
|
+
disable_stdout
|
59
|
+
# ApplicationController must be loaded first
|
60
|
+
require APP_CONTROLLER
|
61
|
+
get_files.each { |c| require "./#{c}" }
|
62
|
+
enable_stdout
|
63
|
+
rescue LoadError
|
64
|
+
enable_stdout
|
65
|
+
print_error 'controller classes'
|
66
|
+
raise
|
72
67
|
end # load_classes
|
73
68
|
|
74
69
|
# Proccess a controller class
|
75
70
|
def process_class(current_class)
|
76
|
-
|
77
71
|
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
78
72
|
|
79
73
|
if @options.brief
|
80
74
|
@graph.add_node ['controller-brief', current_class.name]
|
81
|
-
elsif current_class.is_a? Class
|
75
|
+
elsif current_class.is_a? Class
|
82
76
|
# Collect controller's methods
|
83
|
-
node_attribs = {:
|
84
|
-
|
85
|
-
|
86
|
-
current_class.public_instance_methods(false).sort.each
|
77
|
+
node_attribs = { public: [],
|
78
|
+
protected: [],
|
79
|
+
private: [] }
|
80
|
+
current_class.public_instance_methods(false).sort.each do |m|
|
87
81
|
node_attribs[:public] << m
|
88
|
-
|
89
|
-
current_class.protected_instance_methods(false).sort.each
|
82
|
+
end unless @options.hide_public
|
83
|
+
current_class.protected_instance_methods(false).sort.each do |m|
|
90
84
|
node_attribs[:protected] << m
|
91
|
-
|
92
|
-
current_class.private_instance_methods(false).sort.each
|
93
|
-
node_attribs[:private] << m
|
94
|
-
|
85
|
+
end unless @options.hide_protected
|
86
|
+
current_class.private_instance_methods(false).sort.each do |m|
|
87
|
+
node_attribs[:private] << m
|
88
|
+
end unless @options.hide_private
|
95
89
|
@graph.add_node ['controller', current_class.name, node_attribs]
|
96
90
|
elsif @options.modules && current_class.is_a?(Module)
|
97
91
|
@graph.add_node ['module', current_class.name]
|
@@ -104,7 +98,6 @@ class ControllersDiagram < AppDiagram
|
|
104
98
|
end # process_class
|
105
99
|
|
106
100
|
def transitive_subclasses_of(klass)
|
107
|
-
klass.subclasses | klass.subclasses.map {|subklass| transitive_subclasses_of(subklass)}.flatten
|
101
|
+
klass.subclasses | klass.subclasses.map { |subklass| transitive_subclasses_of(subklass) }.flatten
|
108
102
|
end
|
109
|
-
|
110
103
|
end # class ControllersDiagram
|
@@ -4,10 +4,8 @@
|
|
4
4
|
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
5
|
# See COPYING for more details
|
6
6
|
|
7
|
-
|
8
7
|
# RailRoady diagram structure
|
9
8
|
class DiagramGraph
|
10
|
-
|
11
9
|
def initialize
|
12
10
|
@diagram_type = ''
|
13
11
|
@show_label = false
|
@@ -24,90 +22,83 @@ class DiagramGraph
|
|
24
22
|
@edges << edge
|
25
23
|
end
|
26
24
|
|
27
|
-
|
28
|
-
@diagram_type = type
|
29
|
-
end
|
25
|
+
attr_writer :diagram_type
|
30
26
|
|
31
|
-
|
32
|
-
@show_label = value
|
33
|
-
end
|
34
|
-
|
35
|
-
def alphabetize= (flag)
|
36
|
-
@alphabetize = flag
|
37
|
-
end
|
27
|
+
attr_writer :show_label
|
38
28
|
|
29
|
+
attr_writer :alphabetize
|
39
30
|
|
40
31
|
# Generate DOT graph
|
41
32
|
def to_dot
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
33
|
+
dot_header +
|
34
|
+
@nodes.map { |n| dot_node n[0], n[1], n[2], n[3] }.join +
|
35
|
+
@edges.map { |e| dot_edge e[0], e[1], e[2], e[3] }.join +
|
36
|
+
dot_footer
|
46
37
|
end
|
47
38
|
|
48
39
|
# Generate XMI diagram (not yet implemented)
|
49
40
|
def to_xmi
|
50
|
-
|
51
|
-
|
41
|
+
STDERR.print "Sorry. XMI output not yet implemented.\n\n"
|
42
|
+
''
|
52
43
|
end
|
53
44
|
|
54
45
|
private
|
55
46
|
|
56
47
|
# Build DOT diagram header
|
57
48
|
def dot_header
|
58
|
-
result = "digraph #{@diagram_type.downcase}_diagram {\n"
|
59
|
-
"\tgraph[overlap=false, splines=true]\n"
|
49
|
+
result = "digraph #{@diagram_type.downcase}_diagram {\n" \
|
50
|
+
"\tgraph[overlap=false, splines=true, bgcolor=\"none\"]\n"
|
60
51
|
result += dot_label if @show_label
|
61
|
-
|
52
|
+
result
|
62
53
|
end
|
63
54
|
|
64
55
|
# Build DOT diagram footer
|
65
56
|
def dot_footer
|
66
|
-
|
57
|
+
"}\n"
|
67
58
|
end
|
68
59
|
|
69
60
|
# Build diagram label
|
70
61
|
def dot_label
|
71
|
-
|
72
|
-
"label=\"#{@diagram_type} diagram\\l"
|
73
|
-
"Date: #{Time.now.strftime
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
"http://railroady.prestonlee.com" +
|
62
|
+
"\t_diagram_info [shape=\"plaintext\", " \
|
63
|
+
"label=\"#{@diagram_type} diagram\\l" \
|
64
|
+
"Date: #{Time.now.strftime '%b %d %Y - %H:%M'}\\l" +
|
65
|
+
(defined?(ActiveRecord::Migrator) ? 'Migration version: ' \
|
66
|
+
"#{ActiveRecord::Migrator.current_version}\\l" : '') +
|
67
|
+
"Generated by #{APP_HUMAN_NAME} #{APP_VERSION}\\l" + 'http://railroady.prestonlee.com' \
|
78
68
|
"\\l\", fontsize=13]\n"
|
79
69
|
end
|
80
70
|
|
81
71
|
# Build a DOT graph node
|
82
|
-
def dot_node(type, name, attributes=nil)
|
72
|
+
def dot_node(type, name, attributes = nil, custom_options = '')
|
83
73
|
case type
|
84
74
|
when 'model'
|
85
|
-
|
86
|
-
|
87
|
-
|
75
|
+
options = 'shape=Mrecord, label="{' + name + '|'
|
76
|
+
options += attributes.sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
77
|
+
options += '\l}"'
|
88
78
|
when 'model-brief'
|
89
|
-
|
79
|
+
options = ''
|
90
80
|
when 'class'
|
91
|
-
|
81
|
+
options = 'shape=record, label="{' + name + '|}"'
|
92
82
|
when 'class-brief'
|
93
|
-
|
83
|
+
options = 'shape=box'
|
94
84
|
when 'controller'
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
85
|
+
options = 'shape=Mrecord, label="{' + name + '|'
|
86
|
+
public_methods = attributes[:public].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
87
|
+
protected_methods = attributes[:protected].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
88
|
+
private_methods = attributes[:private].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
89
|
+
options += public_methods + '\l|' + protected_methods + '\l|' +
|
90
|
+
private_methods + '\l'
|
91
|
+
options += '}"'
|
102
92
|
when 'controller-brief'
|
103
|
-
|
93
|
+
options = ''
|
104
94
|
when 'module'
|
105
|
-
|
95
|
+
options = 'shape=box, style=dotted, label="' + name + '"'
|
106
96
|
when 'aasm'
|
107
|
-
|
108
|
-
|
97
|
+
# Return subgraph format
|
98
|
+
return "subgraph cluster_#{name.downcase} {\n\tlabel = #{quote(name)}\n\t#{attributes.join("\n ")}}"
|
109
99
|
end # case
|
110
|
-
|
100
|
+
options = [options, custom_options].compact.join(', ')
|
101
|
+
"\t#{quote(name)} [#{options}]\n"
|
111
102
|
end # dot_node
|
112
103
|
|
113
104
|
# Build a DOT graph edge
|
@@ -117,22 +108,21 @@ class DiagramGraph
|
|
117
108
|
suffix = ", dir=both color=#{edge_color}"
|
118
109
|
case type
|
119
110
|
when 'one-one'
|
120
|
-
|
111
|
+
options += 'arrowtail=odot, arrowhead=dot' + suffix
|
121
112
|
when 'one-many'
|
122
|
-
|
113
|
+
options += 'arrowtail=odot, arrowhead=crow' + suffix
|
123
114
|
when 'many-many'
|
124
|
-
|
115
|
+
options += 'arrowtail=crow, arrowhead=crow' + suffix
|
125
116
|
when 'is-a'
|
126
|
-
|
117
|
+
options += 'arrowhead="none", arrowtail="onormal"'
|
127
118
|
when 'event'
|
128
|
-
|
119
|
+
options += 'fontsize=10'
|
129
120
|
end
|
130
|
-
|
121
|
+
"\t#{quote(from)} -> #{quote(to)} [#{options}]\n"
|
131
122
|
end # dot_edge
|
132
123
|
|
133
124
|
# Quotes a class name
|
134
125
|
def quote(name)
|
135
126
|
'"' + name.to_s + '"'
|
136
127
|
end
|
137
|
-
|
138
128
|
end # class DiagramGraph
|