railroady 1.5.3 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +1 -1
- data/AUTHORS.rdoc +1 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +16 -14
- data/bin/railroady +4 -2
- data/lib/railroady.rb +9 -1
- data/lib/railroady/aasm_diagram.rb +15 -46
- data/lib/railroady/app_diagram.rb +16 -22
- data/lib/railroady/controllers_diagram.rb +23 -23
- data/lib/railroady/diagram_graph.rb +54 -60
- data/lib/railroady/models_diagram.rb +39 -41
- data/lib/railroady/options_struct.rb +12 -16
- data/lib/railroady/railtie.rb +3 -0
- data/lib/railroady/version.rb +3 -1
- data/railroady.gemspec +8 -7
- data/tasks/railroady.rake +2 -2
- metadata +13 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e60172ea20b64daead4e5a040e50c92e411a0ea0824d4bb6836978d16ce7cf82
|
4
|
+
data.tar.gz: d1fb29719573215458dfb3cacf01d0d96a5b98a479accd0688ddd4cab231f5ca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 458f52b7f8f07b1abae06ee141a4a098f67e8882b1087383d4cfee6d642d2f766cb2937037ee39e87a1c68aadce9321c9c208470423fa8982d17b8bbd0a15f48
|
7
|
+
data.tar.gz: 9d8e33334f7727d5f7049446416328f91f2221d3d8ee261300e44c7507174b4610bab7c447d3511c773bc962dcc73661711493a069a2132bbbd67e06783417f0
|
data/.travis.yml
CHANGED
data/AUTHORS.rdoc
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,26 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
railroady (1.
|
4
|
+
railroady (1.6.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
activesupport (
|
9
|
+
activesupport (6.1.4)
|
10
10
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
-
i18n (
|
12
|
-
minitest (
|
13
|
-
tzinfo (~>
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
i18n (>= 1.6, < 2)
|
12
|
+
minitest (>= 5.1)
|
13
|
+
tzinfo (~> 2.0)
|
14
|
+
zeitwerk (~> 2.3)
|
15
|
+
concurrent-ruby (1.1.9)
|
16
|
+
i18n (1.8.10)
|
17
|
+
concurrent-ruby (~> 1.0)
|
18
|
+
minitest (5.14.4)
|
19
|
+
rake (13.0.6)
|
20
|
+
tzinfo (2.0.4)
|
21
|
+
concurrent-ruby (~> 1.0)
|
22
|
+
zeitwerk (2.4.2)
|
21
23
|
|
22
24
|
PLATFORMS
|
23
|
-
|
25
|
+
x86_64-darwin-20
|
24
26
|
|
25
27
|
DEPENDENCIES
|
26
28
|
activesupport
|
@@ -30,4 +32,4 @@ DEPENDENCIES
|
|
30
32
|
rake
|
31
33
|
|
32
34
|
BUNDLED WITH
|
33
|
-
|
35
|
+
2.2.22
|
data/bin/railroady
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
# RailRoady - RoR diagrams generator
|
4
5
|
# http://github.com/preston/railroady
|
@@ -25,7 +26,8 @@ APP_HUMAN_NAME = 'RailRoady'
|
|
25
26
|
APP_VERSION = RailRoady::VERSION
|
26
27
|
COPYRIGHT = 'Copyright (C) 2007-2008 Javier Smaldone, 2009 Peter Hoeg, 2010-2015 Preston Lee'
|
27
28
|
|
28
|
-
options = OptionsStruct.new(app_name: APP_NAME, app_human_name: APP_HUMAN_NAME, app_version: APP_VERSION,
|
29
|
+
options = OptionsStruct.new(app_name: APP_NAME, app_human_name: APP_HUMAN_NAME, app_version: APP_VERSION,
|
30
|
+
copyright: COPYRIGHT)
|
29
31
|
|
30
32
|
options.parse ARGV
|
31
33
|
|
@@ -44,7 +46,7 @@ when 'controllers'
|
|
44
46
|
when 'aasm'
|
45
47
|
diagram = AasmDiagram.new(options)
|
46
48
|
else
|
47
|
-
|
49
|
+
$stderr.print "#{APP_HUMAN_NAME} v#{APP_VERSION}\n" \
|
48
50
|
"Error: You must supply a command\n" \
|
49
51
|
" (try #{APP_NAME} -h)\n\n"
|
50
52
|
exit 1
|
data/lib/railroady.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'railroady/version'
|
4
|
+
require 'railroady/options_struct'
|
5
|
+
require 'railroady/models_diagram'
|
6
|
+
require 'railroady/controllers_diagram'
|
7
|
+
require 'railroady/aasm_diagram'
|
8
|
+
|
9
|
+
# This is the RailRoady module
|
10
|
+
# TODO: documentation
|
3
11
|
module RailRoady
|
4
12
|
require 'railroady/railtie' if defined?(Rails)
|
5
13
|
end
|
@@ -1,10 +1,4 @@
|
|
1
|
-
#
|
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/)
|
1
|
+
# frozen_string_literal: true
|
8
2
|
|
9
3
|
require 'railroady/app_diagram'
|
10
4
|
|
@@ -20,18 +14,17 @@ class AasmDiagram < AppDiagram
|
|
20
14
|
|
21
15
|
# Process model files
|
22
16
|
def generate
|
23
|
-
|
17
|
+
$stderr.print "Generating AASM diagram\n" if @options.verbose
|
24
18
|
get_files.each do |f|
|
25
19
|
process_class extract_class_name(f).constantize
|
26
20
|
end
|
27
21
|
end
|
28
22
|
|
29
23
|
def get_files(prefix = '')
|
30
|
-
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix
|
24
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob("#{prefix}app/models/**/*.rb")
|
31
25
|
files += Dir.glob('vendor/plugins/**/app/models/*.rb') if @options.plugins_models
|
32
|
-
files
|
33
|
-
|
34
|
-
files
|
26
|
+
files - Dir.glob("#{prefix}app/models/concerns/**/*.rb") unless @options.include_concerns
|
27
|
+
Dir.glob(@options.exclude)
|
35
28
|
end
|
36
29
|
|
37
30
|
private
|
@@ -45,49 +38,25 @@ class AasmDiagram < AppDiagram
|
|
45
38
|
enable_stdout
|
46
39
|
print_error 'model classes'
|
47
40
|
raise
|
48
|
-
end
|
41
|
+
end
|
49
42
|
|
50
43
|
# Process a model class
|
51
44
|
def process_class(current_class)
|
52
|
-
|
45
|
+
$stderr.print "\tProcessing #{current_class}\n" if @options.verbose
|
53
46
|
|
54
|
-
# Only interested in
|
55
|
-
process_acts_as_state_machine_class(current_class) if current_class.respond_to?(:states)
|
47
|
+
# Only interested in aasm models.
|
56
48
|
process_aasm_class(current_class) if current_class.respond_to?(:aasm_states) || current_class.respond_to?(:aasm)
|
57
|
-
end # process_class
|
58
|
-
|
59
|
-
def process_acts_as_state_machine_class(current_class)
|
60
|
-
node_attribs = []
|
61
|
-
node_type = 'aasm'
|
62
|
-
|
63
|
-
STDERR.print "\t\tprocessing as acts_as_state_machine\n" if @options.verbose
|
64
|
-
current_class.aasm.states.each do |state_name|
|
65
|
-
node_shape = (current_class.aasm.initial_state == state_name) ? ', peripheries = 2' : ''
|
66
|
-
node_attribs << "#{current_class.name.downcase}_#{state_name} [label=#{state_name} #{node_shape}];"
|
67
|
-
end
|
68
|
-
@graph.add_node [node_type, current_class.name, node_attribs]
|
69
|
-
|
70
|
-
current_class.aasm.events.each do |event|
|
71
|
-
event_name = event.name
|
72
|
-
event.transitions.each do |transition|
|
73
|
-
@graph.add_edge [
|
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
|
-
]
|
79
|
-
end
|
80
|
-
end
|
81
49
|
end
|
82
50
|
|
83
51
|
def process_aasm_class(current_class)
|
84
52
|
node_attribs = []
|
85
53
|
node_type = 'aasm'
|
54
|
+
diagram_friendly_class_name = current_class.name.downcase.gsub(/[^a-z0-9\-_]+/i, '_')
|
86
55
|
|
87
|
-
|
56
|
+
$stderr.print "\t\tprocessing as aasm\n" if @options.verbose
|
88
57
|
current_class.aasm.states.each do |state|
|
89
|
-
node_shape =
|
90
|
-
node_attribs << "#{
|
58
|
+
node_shape = current_class.aasm.initial_state == state.name ? ', peripheries = 2' : ''
|
59
|
+
node_attribs << "#{diagram_friendly_class_name}_#{state.name} [label=#{state.name} #{node_shape}];"
|
91
60
|
end
|
92
61
|
@graph.add_node [node_type, current_class.name, node_attribs]
|
93
62
|
|
@@ -95,11 +64,11 @@ class AasmDiagram < AppDiagram
|
|
95
64
|
event.transitions.each do |transition|
|
96
65
|
@graph.add_edge [
|
97
66
|
'event',
|
98
|
-
|
99
|
-
|
67
|
+
"#{diagram_friendly_class_name}_#{transition.from}",
|
68
|
+
"#{diagram_friendly_class_name}_#{transition.to}",
|
100
69
|
event.name.to_s
|
101
70
|
]
|
102
71
|
end
|
103
72
|
end
|
104
73
|
end
|
105
|
-
end
|
74
|
+
end
|
@@ -1,9 +1,3 @@
|
|
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
1
|
require 'railroady/diagram_graph'
|
8
2
|
|
9
3
|
# Root class for RailRoady diagrams
|
@@ -18,25 +12,25 @@ class AppDiagram
|
|
18
12
|
# Print diagram
|
19
13
|
def print
|
20
14
|
if @options.output
|
21
|
-
old_stdout =
|
15
|
+
old_stdout = $stdout.dup
|
22
16
|
begin
|
23
|
-
|
17
|
+
$stdout.reopen(@options.output)
|
24
18
|
rescue
|
25
|
-
|
19
|
+
$stderr.print "Error: Cannot write diagram to #{@options.output}\n\n"
|
26
20
|
exit 2
|
27
21
|
end
|
28
22
|
end
|
29
23
|
|
30
24
|
if @options.xmi
|
31
|
-
|
32
|
-
|
25
|
+
$stderr.print "Generating XMI diagram\n" if @options.verbose
|
26
|
+
$stdout.print @graph.to_xmi
|
33
27
|
else
|
34
|
-
|
35
|
-
|
28
|
+
$stderr.print "Generating DOT graph\n" if @options.verbose
|
29
|
+
$stdout.print @graph.to_dot
|
36
30
|
end
|
37
31
|
|
38
|
-
|
39
|
-
end
|
32
|
+
$stdout.reopen(old_stdout) if @options.output
|
33
|
+
end
|
40
34
|
|
41
35
|
def process
|
42
36
|
load_environment
|
@@ -61,7 +55,7 @@ class AppDiagram
|
|
61
55
|
|
62
56
|
# Load Rails application's environment
|
63
57
|
def load_environment
|
64
|
-
|
58
|
+
$stderr.print "Loading application environment\n" if @options.verbose
|
65
59
|
begin
|
66
60
|
disable_stdout
|
67
61
|
l = File.join(Dir.pwd.to_s, @options.config_file)
|
@@ -72,24 +66,24 @@ class AppDiagram
|
|
72
66
|
print_error 'application environment'
|
73
67
|
raise
|
74
68
|
end
|
75
|
-
|
69
|
+
$stderr.print "Loading application classes as we go\n" if @options.verbose
|
76
70
|
end
|
77
71
|
|
78
72
|
# Prevents Rails application from writing to STDOUT
|
79
73
|
def disable_stdout
|
80
|
-
@old_stdout =
|
74
|
+
@old_stdout = $stdout.dup
|
81
75
|
# via Tomas Matousek, http://www.ruby-forum.com/topic/205887
|
82
|
-
|
76
|
+
$stdout.reopen(::RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ ? 'NUL' : '/dev/null')
|
83
77
|
end
|
84
78
|
|
85
79
|
# Restore STDOUT
|
86
80
|
def enable_stdout
|
87
|
-
|
81
|
+
$stdout.reopen(@old_stdout)
|
88
82
|
end
|
89
83
|
|
90
84
|
# Print error when loading Rails application
|
91
85
|
def print_error(type)
|
92
|
-
|
86
|
+
$stderr.print "Error loading #{type}.\n (Are you running " \
|
93
87
|
"#{@options.app_name} on the application's root directory?)\n\n"
|
94
88
|
end
|
95
89
|
|
@@ -100,4 +94,4 @@ class AppDiagram
|
|
100
94
|
# File.basename(filename).chomp(".rb").camelize
|
101
95
|
filename.split('/')[2..-1].collect(&:camelize).join('::').chomp('.rb')
|
102
96
|
end
|
103
|
-
end
|
97
|
+
end
|
@@ -1,9 +1,3 @@
|
|
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
1
|
require 'railroady/app_diagram'
|
8
2
|
|
9
3
|
# RailRoady controllers diagram
|
@@ -20,7 +14,7 @@ class ControllersDiagram < AppDiagram
|
|
20
14
|
|
21
15
|
# Process controller files
|
22
16
|
def generate
|
23
|
-
|
17
|
+
$stderr.print "Generating controllers diagram\n" if @options.verbose
|
24
18
|
files = get_files
|
25
19
|
# only add APP_CONTROLLER if it isn't already included from the glob above
|
26
20
|
files << APP_CONTROLLER unless files.include? APP_CONTROLLER
|
@@ -31,10 +25,10 @@ class ControllersDiagram < AppDiagram
|
|
31
25
|
begin
|
32
26
|
process_class class_name.constantize
|
33
27
|
rescue Exception
|
34
|
-
|
28
|
+
$stderr.print "Warning: exception #{$ERROR_INFO} raised while trying to load controller class #{f}"
|
35
29
|
end
|
36
30
|
end
|
37
|
-
end
|
31
|
+
end
|
38
32
|
|
39
33
|
def get_files(prefix = '')
|
40
34
|
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << 'app/controllers/**/*_controller.rb')
|
@@ -48,7 +42,7 @@ class ControllersDiagram < AppDiagram
|
|
48
42
|
end
|
49
43
|
|
50
44
|
def extract_class_name(filename)
|
51
|
-
filename.match(
|
45
|
+
filename.match(%r{.*/controllers/(.*).rb$})[1].camelize
|
52
46
|
end
|
53
47
|
|
54
48
|
private
|
@@ -64,11 +58,11 @@ class ControllersDiagram < AppDiagram
|
|
64
58
|
enable_stdout
|
65
59
|
print_error 'controller classes'
|
66
60
|
raise
|
67
|
-
end
|
61
|
+
end
|
68
62
|
|
69
63
|
# Proccess a controller class
|
70
64
|
def process_class(current_class)
|
71
|
-
|
65
|
+
$stderr.print "\tProcessing #{current_class}\n" if @options.verbose
|
72
66
|
|
73
67
|
if @options.brief
|
74
68
|
@graph.add_node ['controller-brief', current_class.name]
|
@@ -77,15 +71,21 @@ class ControllersDiagram < AppDiagram
|
|
77
71
|
node_attribs = { public: [],
|
78
72
|
protected: [],
|
79
73
|
private: [] }
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
74
|
+
unless @options.hide_public
|
75
|
+
current_class.public_instance_methods(false).sort.each do |m|
|
76
|
+
node_attribs[:public] << m
|
77
|
+
end
|
78
|
+
end
|
79
|
+
unless @options.hide_protected
|
80
|
+
current_class.protected_instance_methods(false).sort.each do |m|
|
81
|
+
node_attribs[:protected] << m
|
82
|
+
end
|
83
|
+
end
|
84
|
+
unless @options.hide_private
|
85
|
+
current_class.private_instance_methods(false).sort.each do |m|
|
86
|
+
node_attribs[:private] << m
|
87
|
+
end
|
88
|
+
end
|
89
89
|
@graph.add_node ['controller', current_class.name, node_attribs]
|
90
90
|
elsif @options.modules && current_class.is_a?(Module)
|
91
91
|
@graph.add_node ['module', current_class.name]
|
@@ -95,9 +95,9 @@ class ControllersDiagram < AppDiagram
|
|
95
95
|
if @options.inheritance && (transitive_subclasses_of(ApplicationController).include? current_class)
|
96
96
|
@graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
|
97
97
|
end
|
98
|
-
end
|
98
|
+
end
|
99
99
|
|
100
100
|
def transitive_subclasses_of(klass)
|
101
101
|
klass.subclasses | klass.subclasses.map { |subklass| transitive_subclasses_of(subklass) }.flatten
|
102
102
|
end
|
103
|
-
end
|
103
|
+
end
|
@@ -1,11 +1,8 @@
|
|
1
|
-
#
|
2
|
-
# http://railroad.rubyforge.org
|
3
|
-
#
|
4
|
-
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
-
# See COPYING for more details
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
|
-
# RailRoady diagram structure
|
8
3
|
class DiagramGraph
|
4
|
+
attr_writer :diagram_type, :show_label, :alphabetize
|
5
|
+
|
9
6
|
def initialize
|
10
7
|
@diagram_type = ''
|
11
8
|
@show_label = false
|
@@ -22,12 +19,6 @@ class DiagramGraph
|
|
22
19
|
@edges << edge
|
23
20
|
end
|
24
21
|
|
25
|
-
attr_writer :diagram_type
|
26
|
-
|
27
|
-
attr_writer :show_label
|
28
|
-
|
29
|
-
attr_writer :alphabetize
|
30
|
-
|
31
22
|
# Generate DOT graph
|
32
23
|
def to_dot
|
33
24
|
dot_header +
|
@@ -38,7 +29,7 @@ class DiagramGraph
|
|
38
29
|
|
39
30
|
# Generate XMI diagram (not yet implemented)
|
40
31
|
def to_xmi
|
41
|
-
|
32
|
+
$stderr.print "Sorry. XMI output not yet implemented.\n\n"
|
42
33
|
''
|
43
34
|
end
|
44
35
|
|
@@ -62,8 +53,12 @@ class DiagramGraph
|
|
62
53
|
"\t_diagram_info [shape=\"plaintext\", " \
|
63
54
|
"label=\"#{@diagram_type} diagram\\l" \
|
64
55
|
"Date: #{Time.now.strftime '%b %d %Y - %H:%M'}\\l" +
|
65
|
-
(defined?(ActiveRecord::Migrator)
|
66
|
-
|
56
|
+
(if defined?(ActiveRecord::Migrator)
|
57
|
+
'Migration version: ' \
|
58
|
+
"#{Rails.logger.silence { ActiveRecord::Migrator.current_version }}\\l"
|
59
|
+
else
|
60
|
+
''
|
61
|
+
end) +
|
67
62
|
"Generated by #{APP_HUMAN_NAME} #{APP_VERSION}\\l" + 'http://railroady.prestonlee.com' \
|
68
63
|
"\\l\", fontsize=13]\n"
|
69
64
|
end
|
@@ -71,35 +66,34 @@ class DiagramGraph
|
|
71
66
|
# Build a DOT graph node
|
72
67
|
def dot_node(type, name, attributes = nil, custom_options = '')
|
73
68
|
case type
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
end # dot_node
|
69
|
+
when 'model'
|
70
|
+
options = "shape=Mrecord, label=\"{#{name}|"
|
71
|
+
options += attributes.sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
72
|
+
options += '\l}"'
|
73
|
+
when 'model-brief'
|
74
|
+
options = ''
|
75
|
+
when 'class'
|
76
|
+
options = "shape=record, label=\"{#{name}|}\""
|
77
|
+
when 'class-brief'
|
78
|
+
options = 'shape=box'
|
79
|
+
when 'controller'
|
80
|
+
options = "shape=Mrecord, label=\"{#{name}|"
|
81
|
+
public_methods = attributes[:public].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
82
|
+
protected_methods = attributes[:protected].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
83
|
+
private_methods = attributes[:private].sort_by { |s| @alphabetize ? s : nil }.join('\l')
|
84
|
+
options += "#{public_methods}\\l|#{protected_methods}\\l|#{private_methods}\\l"
|
85
|
+
options += '}"'
|
86
|
+
when 'controller-brief'
|
87
|
+
options = ''
|
88
|
+
when 'module'
|
89
|
+
options = "shape=box, style=dotted, label=\"#{name}\""
|
90
|
+
when 'aasm'
|
91
|
+
# Return subgraph format
|
92
|
+
return "subgraph cluster_#{name.downcase.gsub(/[^a-z0-9\-_]+/i, '_')} {\n\tlabel = #{quote(name)}\n\t#{attributes.join("\n ")}}"
|
93
|
+
end
|
94
|
+
options = [options, custom_options].compact.reject(&:empty?).join(', ')
|
95
|
+
"\t#{quote(name)} [#{options}]\n"
|
96
|
+
end
|
103
97
|
|
104
98
|
# Build a DOT graph edge
|
105
99
|
def dot_edge(type, from, to, name = '')
|
@@ -107,25 +101,25 @@ class DiagramGraph
|
|
107
101
|
edge_color = '"#%02X%02X%02X"' % [rand(255), rand(255), rand(255)]
|
108
102
|
suffix = ", dir=both color=#{edge_color}"
|
109
103
|
case type
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
104
|
+
when 'one-one'
|
105
|
+
options += "arrowtail=odot, arrowhead=dot#{suffix}"
|
106
|
+
when 'one-many'
|
107
|
+
options += "arrowtail=odot, arrowhead=crow#{suffix}"
|
108
|
+
when 'many-many'
|
109
|
+
options += "arrowtail=crow, arrowhead=crow#{suffix}"
|
110
|
+
when 'belongs-to'
|
111
|
+
# following http://guides.rubyonrails.org/association_basics.html#the-belongs-to-association
|
112
|
+
options += "arrowtail=none, arrowhead=normal#{suffix}"
|
113
|
+
when 'is-a'
|
114
|
+
options += 'arrowhead="none", arrowtail="onormal"'
|
115
|
+
when 'event'
|
116
|
+
options += 'fontsize=10'
|
123
117
|
end
|
124
118
|
"\t#{quote(from)} -> #{quote(to)} [#{options}]\n"
|
125
|
-
end
|
119
|
+
end
|
126
120
|
|
127
121
|
# Quotes a class name
|
128
122
|
def quote(name)
|
129
|
-
|
123
|
+
"\"#{name}\""
|
130
124
|
end
|
131
|
-
end
|
125
|
+
end
|
@@ -1,9 +1,3 @@
|
|
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
1
|
require 'railroady/app_diagram'
|
8
2
|
|
9
3
|
# RailRoady models diagram
|
@@ -17,20 +11,20 @@ class ModelsDiagram < AppDiagram
|
|
17
11
|
|
18
12
|
# Process model files
|
19
13
|
def generate
|
20
|
-
|
14
|
+
warn 'Generating models diagram' if @options.verbose
|
21
15
|
get_files.each do |f|
|
22
16
|
begin
|
23
17
|
process_class extract_class_name(f).constantize
|
24
|
-
rescue
|
25
|
-
|
18
|
+
rescue NoMethodError
|
19
|
+
warn "Warning: exception #{$ERROR_INFO} raised while trying to load model class #{f}"
|
26
20
|
end
|
27
21
|
end
|
28
22
|
end
|
29
23
|
|
30
24
|
def get_files(prefix = '')
|
31
|
-
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix
|
25
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob("#{prefix}app/models/**/*.rb")
|
32
26
|
files += Dir.glob('vendor/plugins/**/app/models/*.rb') if @options.plugins_models
|
33
|
-
files -= Dir.glob(prefix
|
27
|
+
files -= Dir.glob("#{prefix}app/models/concerns/**/*.rb") unless @options.include_concerns
|
34
28
|
files += engine_files if @options.engine_models
|
35
29
|
files -= Dir.glob(@options.exclude)
|
36
30
|
files
|
@@ -41,17 +35,19 @@ class ModelsDiagram < AppDiagram
|
|
41
35
|
end
|
42
36
|
|
43
37
|
def extract_class_name(filename)
|
44
|
-
filename_was
|
38
|
+
filename_was = filename
|
39
|
+
class_name = nil
|
45
40
|
|
46
41
|
filename = "app/models/#{filename.split('app/models')[1]}"
|
47
42
|
|
48
43
|
while filename.split('/').length > 2
|
49
44
|
begin
|
50
|
-
class_name = filename.match(
|
45
|
+
class_name = filename.match(%r{.*/models/(.*).rb$})[1]
|
46
|
+
class_name = class_name.camelize
|
47
|
+
# class_name = class_name.from 2 if class_name.start_with? '::'
|
51
48
|
class_name.constantize
|
52
|
-
|
53
49
|
break
|
54
|
-
rescue
|
50
|
+
rescue NoMethodError
|
55
51
|
class_name = nil
|
56
52
|
filename_end = filename.split('/')[2..-1]
|
57
53
|
filename_end.shift
|
@@ -60,15 +56,16 @@ class ModelsDiagram < AppDiagram
|
|
60
56
|
end
|
61
57
|
|
62
58
|
if class_name.nil?
|
63
|
-
filename_was.match(
|
59
|
+
filename_was.match(%r{.*/models/(.*).rb$})[1].camelize
|
64
60
|
else
|
61
|
+
warn class_name
|
65
62
|
class_name
|
66
63
|
end
|
67
64
|
end
|
68
65
|
|
69
66
|
# Process a model class
|
70
67
|
def process_class(current_class)
|
71
|
-
|
68
|
+
warn "Processing #{current_class}" if @options.verbose
|
72
69
|
|
73
70
|
generated =
|
74
71
|
if defined?(CouchRest::Model::Base) && current_class.new.is_a?(CouchRest::Model::Base)
|
@@ -85,13 +82,14 @@ class ModelsDiagram < AppDiagram
|
|
85
82
|
process_basic_module(current_class)
|
86
83
|
end
|
87
84
|
|
85
|
+
warn generated
|
88
86
|
if @options.inheritance && generated && include_inheritance?(current_class)
|
89
87
|
@graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
|
90
88
|
end
|
91
|
-
end
|
89
|
+
end
|
92
90
|
|
93
91
|
def include_inheritance?(current_class)
|
94
|
-
|
92
|
+
warn current_class.superclass if @options.verbose
|
95
93
|
(defined?(ActiveRecord::Base) ? current_class.superclass != ActiveRecord::Base : true) &&
|
96
94
|
(defined?(CouchRest::Model::Base) ? current_class.superclass != CouchRest::Model::Base : true) &&
|
97
95
|
(current_class.superclass != Object)
|
@@ -121,16 +119,16 @@ class ModelsDiagram < AppDiagram
|
|
121
119
|
if @options.hide_magic
|
122
120
|
# From patch #13351
|
123
121
|
# http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
|
124
|
-
magic_fields = %w
|
125
|
-
magic_fields << current_class.table_name
|
126
|
-
content_columns = current_class.content_columns.
|
122
|
+
magic_fields = %w[created_at created_on updated_at updated_on lock_version type id position parent_id lft rgt quote template]
|
123
|
+
magic_fields << "#{current_class.table_name}_count" if current_class.respond_to? 'table_name'
|
124
|
+
content_columns = current_class.content_columns.reject { |c| magic_fields.include? c.name }
|
127
125
|
else
|
128
126
|
content_columns = current_class.columns
|
129
127
|
end
|
130
128
|
|
131
129
|
content_columns.each do |a|
|
132
130
|
content_column = a.name
|
133
|
-
content_column +=
|
131
|
+
content_column += " :#{a.sql_type.to_s}" unless @options.hide_types
|
134
132
|
node_attribs << content_column
|
135
133
|
end
|
136
134
|
end
|
@@ -141,7 +139,7 @@ class ModelsDiagram < AppDiagram
|
|
141
139
|
if @options.inheritance && ! @options.transitive
|
142
140
|
superclass_associations = current_class.superclass.reflect_on_all_associations
|
143
141
|
|
144
|
-
associations = associations.
|
142
|
+
associations = associations.reject { |a| superclass_associations.include? a }
|
145
143
|
# This doesn't works!
|
146
144
|
# associations -= current_class.superclass.reflect_on_all_associations
|
147
145
|
end
|
@@ -167,13 +165,13 @@ class ModelsDiagram < AppDiagram
|
|
167
165
|
# From patch #13351
|
168
166
|
# http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
|
169
167
|
magic_fields =
|
170
|
-
%w
|
171
|
-
props = props.
|
168
|
+
%w[created_at created_on updated_at updated_on lock_version _type _id position parent_id lft rgt quote template]
|
169
|
+
props = props.reject { |c| magic_fields.include?(c.name.to_s) }
|
172
170
|
end
|
173
171
|
|
174
172
|
props.each do |a|
|
175
173
|
prop = a.name.to_s
|
176
|
-
prop +=
|
174
|
+
prop += " :#{a.class.name.split('::').last}" unless @options.hide_types
|
177
175
|
node_attribs << prop
|
178
176
|
end
|
179
177
|
end
|
@@ -205,8 +203,8 @@ class ModelsDiagram < AppDiagram
|
|
205
203
|
if @options.hide_magic
|
206
204
|
# From patch #13351
|
207
205
|
# http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
|
208
|
-
magic_fields = %w
|
209
|
-
content_columns = content_columns.
|
206
|
+
magic_fields = %w[created_at created_on updated_at updated_on lock_version _type _id position parent_id lft rgt quote template]
|
207
|
+
content_columns = content_columns.reject { |c| magic_fields.include?(c.name) }
|
210
208
|
end
|
211
209
|
|
212
210
|
content_columns.each do |a|
|
@@ -251,8 +249,8 @@ class ModelsDiagram < AppDiagram
|
|
251
249
|
content_columns = current_class.properties
|
252
250
|
|
253
251
|
if @options.hide_magic
|
254
|
-
magic_fields = %w
|
255
|
-
content_columns = content_columns.
|
252
|
+
magic_fields = %w[created_at updated_at type _id _rev]
|
253
|
+
content_columns = content_columns.reject { |c| magic_fields.include?(c.name) }
|
256
254
|
end
|
257
255
|
|
258
256
|
content_columns.each do |a|
|
@@ -269,11 +267,10 @@ class ModelsDiagram < AppDiagram
|
|
269
267
|
|
270
268
|
# Process a model association
|
271
269
|
def process_association(class_name, assoc)
|
272
|
-
|
273
|
-
|
270
|
+
warn "- Processing model association #{assoc.name}" if @options.verbose
|
274
271
|
# Skip "belongs_to" associations
|
275
|
-
macro = assoc.
|
276
|
-
return if %w
|
272
|
+
macro = assoc.methods.to_s
|
273
|
+
return if %w[belongs_to referenced_in].include?(macro) && !@options.show_belongs_to
|
277
274
|
|
278
275
|
# Skip "through" associations
|
279
276
|
through = assoc.options.include?(:through)
|
@@ -299,29 +296,30 @@ class ModelsDiagram < AppDiagram
|
|
299
296
|
if class_name.include?('::') && !assoc_class_name.include?('::')
|
300
297
|
assoc_class_name = class_name.split('::')[0..-2].push(assoc_class_name).join('::')
|
301
298
|
end
|
302
|
-
assoc_class_name.gsub
|
299
|
+
assoc_class_name = assoc_class_name.gsub(/^::/, '')
|
303
300
|
|
304
|
-
if %w
|
301
|
+
if %w[has_one references_one embeds_one].include?(macro)
|
305
302
|
assoc_type = 'one-one'
|
306
303
|
elsif macro == 'has_many' && (!assoc.options[:through]) ||
|
307
|
-
%w
|
304
|
+
%w[references_many embeds_many].include?(macro)
|
308
305
|
assoc_type = 'one-many'
|
309
306
|
elsif macro == 'belongs_to'
|
310
307
|
assoc_type = 'belongs-to'
|
311
308
|
else # habtm or has_many, :through
|
312
309
|
# Add FAKE associations too in order to understand mistakes
|
313
310
|
return if @habtm.include? [assoc_class_name, class_name, assoc_name]
|
311
|
+
|
314
312
|
assoc_type = 'many-many'
|
315
313
|
@habtm << [class_name, assoc_class_name, assoc_name]
|
316
314
|
end
|
317
315
|
# from patch #12384
|
318
316
|
# @graph.add_edge [assoc_type, class_name, assoc.class_name, assoc_name]
|
319
317
|
@graph.add_edge [assoc_type, class_name, assoc_class_name, assoc_name]
|
320
|
-
end
|
318
|
+
end
|
321
319
|
|
322
320
|
# Process a DataMapper relationship
|
323
321
|
def process_datamapper_relationship(class_name, relation)
|
324
|
-
|
322
|
+
warn "- Processing DataMapper model relationship #{relation.name}" if @options.verbose
|
325
323
|
|
326
324
|
# Skip "belongs_to" relationships
|
327
325
|
dm_type = relation.class.to_s.split('::')[-2]
|
@@ -354,4 +352,4 @@ class ModelsDiagram < AppDiagram
|
|
354
352
|
|
355
353
|
@graph.add_edge [rel_type, class_name, assoc_class_name, assoc_name]
|
356
354
|
end
|
357
|
-
end
|
355
|
+
end
|
@@ -1,8 +1,4 @@
|
|
1
|
-
#
|
2
|
-
# http://railroad.rubyforge.org
|
3
|
-
#
|
4
|
-
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
-
# See COPYING for more details
|
1
|
+
# frozen_string_literal: true
|
6
2
|
|
7
3
|
require 'ostruct'
|
8
4
|
|
@@ -40,7 +36,7 @@ class OptionsStruct < OpenStruct
|
|
40
36
|
config_file: 'config/environment',
|
41
37
|
app_name: 'railroady', app_human_name: 'Railroady', app_version: '', copyright: '' }
|
42
38
|
super(init_options.merge(args))
|
43
|
-
end
|
39
|
+
end
|
44
40
|
|
45
41
|
def parse(args)
|
46
42
|
@opt_parser = OptionParser.new do |opts|
|
@@ -138,11 +134,11 @@ class OptionsStruct < OpenStruct
|
|
138
134
|
opts.separator ''
|
139
135
|
opts.separator 'Other options:'
|
140
136
|
opts.on('-h', '--help', 'Show this message') do
|
141
|
-
|
137
|
+
$stdout.print "#{opts}\n"
|
142
138
|
exit
|
143
139
|
end
|
144
140
|
opts.on('--version', 'Show version and copyright') do
|
145
|
-
|
141
|
+
$stdout.print "#{app_human_name} version #{app_version}\n\n" \
|
146
142
|
"#{copyright}\nThis is free software; see the source " \
|
147
143
|
"for copying conditions.\n\n"
|
148
144
|
exit
|
@@ -154,7 +150,7 @@ class OptionsStruct < OpenStruct
|
|
154
150
|
opts.separator 'Commands (you must supply one of these):'
|
155
151
|
opts.on('-M', '--models', 'Generate models diagram') do |_c|
|
156
152
|
if command != ''
|
157
|
-
|
153
|
+
$stderr.print "Error: Can only generate one diagram type\n\n"
|
158
154
|
exit 1
|
159
155
|
else
|
160
156
|
self.command = 'models'
|
@@ -162,16 +158,16 @@ class OptionsStruct < OpenStruct
|
|
162
158
|
end
|
163
159
|
opts.on('-C', '--controllers', 'Generate controllers diagram') do |_c|
|
164
160
|
if command != ''
|
165
|
-
|
161
|
+
$stderr.print "Error: Can only generate one diagram type\n\n"
|
166
162
|
exit 1
|
167
163
|
else
|
168
164
|
self.command = 'controllers'
|
169
165
|
end
|
170
166
|
end
|
171
167
|
# From Ana Nelson's patch
|
172
|
-
opts.on('-A', '--aasm',
|
168
|
+
opts.on('-A', '--aasm', 'Generate "acts as state machine" diagram') do |_c|
|
173
169
|
if command == 'controllers'
|
174
|
-
|
170
|
+
$stderr.print "Error: Can only generate one diagram type\n\n"
|
175
171
|
exit 1
|
176
172
|
else
|
177
173
|
self.command = 'aasm'
|
@@ -180,7 +176,7 @@ class OptionsStruct < OpenStruct
|
|
180
176
|
opts.separator ''
|
181
177
|
opts.separator 'For bug reporting and additional information, please see:'
|
182
178
|
opts.separator 'http://railroad.rubyforge.org/'
|
183
|
-
end
|
179
|
+
end
|
184
180
|
|
185
181
|
begin
|
186
182
|
@opt_parser.parse!(args)
|
@@ -193,12 +189,12 @@ class OptionsStruct < OpenStruct
|
|
193
189
|
rescue OptionParser::MissingArgument
|
194
190
|
option_error 'Missing argument'
|
195
191
|
end
|
196
|
-
end
|
192
|
+
end
|
197
193
|
|
198
194
|
private
|
199
195
|
|
200
196
|
def option_error(msg)
|
201
|
-
|
197
|
+
$stderr.print "Error: #{msg}\n\n #{@opt_parser}\n"
|
202
198
|
exit 1
|
203
199
|
end
|
204
|
-
end
|
200
|
+
end
|
data/lib/railroady/railtie.rb
CHANGED
data/lib/railroady/version.rb
CHANGED
data/railroady.gemspec
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
#
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'railroady/version'
|
5
6
|
|
@@ -7,9 +8,9 @@ Gem::Specification.new do |spec|
|
|
7
8
|
spec.name = 'railroady'
|
8
9
|
spec.version = RailRoady::VERSION
|
9
10
|
spec.authors = ['Preston Lee', 'Tobias Crawley', 'Peter Hoeg', 'Javier Smaldone']
|
10
|
-
spec.description = "Ruby on Rails
|
11
|
-
spec.email = [
|
12
|
-
spec.summary = 'Ruby on Rails
|
11
|
+
spec.description = "Ruby on Rails model and controller UML class diagram generator. Originally based on the 'railroad' plugin and contributions of many others. (`brew install graphviz` before use!)"
|
12
|
+
spec.email = %w[preston.lee@prestonlee.com tcrawley@gmail.com peter@hoeg.com p.hoeg@northwind.sg javier@smaldone.com.ar]
|
13
|
+
spec.summary = 'Ruby on Rails model and controller UML class diagram generator.'
|
13
14
|
spec.homepage = 'http://github.com/preston/railroady'
|
14
15
|
spec.license = 'GPLv2'
|
15
16
|
|
@@ -18,8 +19,8 @@ Gem::Specification.new do |spec|
|
|
18
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
20
|
spec.require_paths = ['lib']
|
20
21
|
|
22
|
+
spec.add_development_dependency 'activesupport'
|
21
23
|
spec.add_development_dependency 'bundler'
|
22
|
-
spec.add_development_dependency 'rake'
|
23
24
|
spec.add_development_dependency 'minitest'
|
24
|
-
spec.add_development_dependency '
|
25
|
+
spec.add_development_dependency 'rake'
|
25
26
|
end
|
data/tasks/railroady.rake
CHANGED
@@ -54,7 +54,7 @@ namespace :diagram do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
namespace :models do
|
57
|
-
desc '
|
57
|
+
desc 'Generates brief and complete class diagrams for all models.'
|
58
58
|
task all: ['diagram:setup:create_new_doc_folder_if_needed', 'diagram:models:complete', 'diagram:models:brief']
|
59
59
|
|
60
60
|
desc 'Generates a class diagram for all models.'
|
@@ -87,7 +87,7 @@ namespace :diagram do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
namespace :controllers do
|
90
|
-
desc '
|
90
|
+
desc 'Generates brief and complete class diagrams for all controllers.'
|
91
91
|
task all: ['diagram:setup:create_new_doc_folder_if_needed', 'diagram:controllers:complete', 'diagram:controllers:brief']
|
92
92
|
|
93
93
|
desc 'Generates a class diagram for all controllers.'
|
metadata
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: railroady
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Preston Lee
|
8
8
|
- Tobias Crawley
|
9
9
|
- Peter Hoeg
|
10
10
|
- Javier Smaldone
|
11
|
-
autorequire:
|
11
|
+
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date:
|
14
|
+
date: 2021-07-30 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
|
-
name:
|
17
|
+
name: activesupport
|
18
18
|
requirement: !ruby/object:Gem::Requirement
|
19
19
|
requirements:
|
20
20
|
- - ">="
|
@@ -28,7 +28,7 @@ dependencies:
|
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '0'
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
31
|
+
name: bundler
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|
33
33
|
requirements:
|
34
34
|
- - ">="
|
@@ -56,7 +56,7 @@ dependencies:
|
|
56
56
|
- !ruby/object:Gem::Version
|
57
57
|
version: '0'
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
|
-
name:
|
59
|
+
name: rake
|
60
60
|
requirement: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
62
|
- - ">="
|
@@ -69,9 +69,9 @@ dependencies:
|
|
69
69
|
- - ">="
|
70
70
|
- !ruby/object:Gem::Version
|
71
71
|
version: '0'
|
72
|
-
description: Ruby on Rails
|
73
|
-
|
74
|
-
|
72
|
+
description: Ruby on Rails model and controller UML class diagram generator. Originally
|
73
|
+
based on the 'railroad' plugin and contributions of many others. (`brew install
|
74
|
+
graphviz` before use!)
|
75
75
|
email:
|
76
76
|
- preston.lee@prestonlee.com
|
77
77
|
- tcrawley@gmail.com
|
@@ -126,7 +126,7 @@ homepage: http://github.com/preston/railroady
|
|
126
126
|
licenses:
|
127
127
|
- GPLv2
|
128
128
|
metadata: {}
|
129
|
-
post_install_message:
|
129
|
+
post_install_message:
|
130
130
|
rdoc_options: []
|
131
131
|
require_paths:
|
132
132
|
- lib
|
@@ -141,11 +141,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
141
|
- !ruby/object:Gem::Version
|
142
142
|
version: '0'
|
143
143
|
requirements: []
|
144
|
-
|
145
|
-
|
146
|
-
signing_key:
|
144
|
+
rubygems_version: 3.2.25
|
145
|
+
signing_key:
|
147
146
|
specification_version: 4
|
148
|
-
summary: Ruby on Rails
|
147
|
+
summary: Ruby on Rails model and controller UML class diagram generator.
|
149
148
|
test_files:
|
150
149
|
- test/file_fixture/app/controllers/application_controller.rb
|
151
150
|
- test/file_fixture/app/controllers/dummy1_controller.rb
|