railroady 1.5.3 → 1.6.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.
- 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
|