railroady 1.1.2 → 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.
@@ -1,56 +1,61 @@
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
10
4
  class AppDiagram
11
-
12
5
  def initialize(options = OptionsStruct.new)
13
6
  @options = options
14
7
  @graph = DiagramGraph.new
15
8
  @graph.show_label = @options.label
16
9
  @graph.alphabetize = @options.alphabetize
17
10
  end
18
-
19
11
 
20
12
  # Print diagram
21
13
  def print
22
14
  if @options.output
23
- old_stdout = STDOUT.dup
15
+ old_stdout = $stdout.dup
24
16
  begin
25
- STDOUT.reopen(@options.output)
17
+ $stdout.reopen(@options.output)
26
18
  rescue
27
- STDERR.print "Error: Cannot write diagram to #{@options.output}\n\n"
19
+ $stderr.print "Error: Cannot write diagram to #{@options.output}\n\n"
28
20
  exit 2
29
21
  end
30
22
  end
31
-
32
- if @options.xmi
33
- STDERR.print "Generating XMI diagram\n" if @options.verbose
34
- STDOUT.print @graph.to_xmi
23
+
24
+ if @options.xmi
25
+ $stderr.print "Generating XMI diagram\n" if @options.verbose
26
+ $stdout.print @graph.to_xmi
35
27
  else
36
- STDERR.print "Generating DOT graph\n" if @options.verbose
37
- STDOUT.print @graph.to_dot
28
+ $stderr.print "Generating DOT graph\n" if @options.verbose
29
+ $stdout.print @graph.to_dot
38
30
  end
39
31
 
40
- if @options.output
41
- STDOUT.reopen(old_stdout)
42
- end
43
- end # print
32
+ $stdout.reopen(old_stdout) if @options.output
33
+ end
44
34
 
45
35
  def process
46
36
  load_environment
47
37
  end
48
38
 
49
- private
50
-
39
+ # get all engines
40
+ def engines
41
+ engines = []
42
+
43
+ if defined?(Rails)
44
+ engines = if Rails::Application::Railties.respond_to?(:engines)
45
+ Rails::Application::Railties.engines
46
+ else
47
+ # rails 4 way of getting engines
48
+ Rails::Engine.subclasses.map(&:instance)
49
+ end
50
+ end
51
+ engines
52
+ end
53
+
54
+ private
55
+
51
56
  # Load Rails application's environment
52
57
  def load_environment
53
- STDERR.print "Loading application environment\n" if @options.verbose
58
+ $stderr.print "Loading application environment\n" if @options.verbose
54
59
  begin
55
60
  disable_stdout
56
61
  l = File.join(Dir.pwd.to_s, @options.config_file)
@@ -58,37 +63,35 @@ class AppDiagram
58
63
  enable_stdout
59
64
  rescue LoadError
60
65
  enable_stdout
61
- print_error "application environment"
66
+ print_error 'application environment'
62
67
  raise
63
68
  end
64
- STDERR.print "Loading application classes as we go\n" if @options.verbose
69
+ $stderr.print "Loading application classes as we go\n" if @options.verbose
65
70
  end
66
71
 
67
72
  # Prevents Rails application from writing to STDOUT
68
73
  def disable_stdout
69
- @old_stdout = STDOUT.dup
70
- #via Tomas Matousek, http://www.ruby-forum.com/topic/205887
71
- STDOUT.reopen(::RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/? "NUL" : "/dev/null")
74
+ @old_stdout = $stdout.dup
75
+ # via Tomas Matousek, http://www.ruby-forum.com/topic/205887
76
+ $stdout.reopen(::RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ ? 'NUL' : '/dev/null')
72
77
  end
73
78
 
74
- # Restore STDOUT
79
+ # Restore STDOUT
75
80
  def enable_stdout
76
- STDOUT.reopen(@old_stdout)
81
+ $stdout.reopen(@old_stdout)
77
82
  end
78
83
 
79
-
80
84
  # Print error when loading Rails application
81
85
  def print_error(type)
82
- STDERR.print "Error loading #{type}.\n (Are you running " +
83
- "#{@options.app_name} on the aplication's root directory?)\n\n"
86
+ $stderr.print "Error loading #{type}.\n (Are you running " \
87
+ "#{@options.app_name} on the application's root directory?)\n\n"
84
88
  end
85
89
 
86
90
  # Extract class name from filename
87
91
  def extract_class_name(filename)
88
- #filename.split('/')[2..-1].join('/').split('.').first.camelize
92
+ # filename.split('/')[2..-1].join('/').split('.').first.camelize
89
93
  # Fixed by patch from ticket #12742
90
94
  # File.basename(filename).chomp(".rb").camelize
91
- filename.split('/')[2..-1].collect { |i| i.camelize }.join('::').chomp(".rb")
95
+ filename.split('/')[2..-1].collect(&:camelize).join('::').chomp('.rb')
92
96
  end
93
-
94
- end # class AppDiagram
97
+ end
@@ -1,27 +1,20 @@
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
10
4
  class ControllersDiagram < AppDiagram
11
-
12
5
  # as of Rails 2.3 the file is no longer application.rb but instead
13
6
  # application_controller.rb
14
7
  APP_CONTROLLER = File.exist?('app/controllers/application.rb') ? 'app/controllers/application.rb' : 'app/controllers/application_controller.rb'
15
8
 
16
9
  def initialize(options = OptionsStruct.new)
17
- #options.exclude.map! {|e| "app/controllers/" + e}
10
+ # options.exclude.map! {|e| "app/controllers/" + e}
18
11
  super options
19
12
  @graph.diagram_type = 'Controllers'
20
13
  end
21
14
 
22
15
  # Process controller files
23
16
  def generate
24
- STDERR.print "Generating controllers diagram\n" if @options.verbose
17
+ $stderr.print "Generating controllers diagram\n" if @options.verbose
25
18
  files = get_files
26
19
  # only add APP_CONTROLLER if it isn't already included from the glob above
27
20
  files << APP_CONTROLLER unless files.include? APP_CONTROLLER
@@ -32,54 +25,67 @@ class ControllersDiagram < AppDiagram
32
25
  begin
33
26
  process_class class_name.constantize
34
27
  rescue Exception
35
- STDERR.print "Warning: exception #{$!} raised while trying to load controller class #{f}"
28
+ $stderr.print "Warning: exception #{$ERROR_INFO} raised while trying to load controller class #{f}"
36
29
  end
37
- end
38
- end # generate
30
+ end
31
+ end
39
32
 
40
- def get_files(prefix ='')
41
- files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << "app/controllers/**/*_controller.rb")
33
+ def get_files(prefix = '')
34
+ files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << 'app/controllers/**/*_controller.rb')
35
+ files += engine_files if @options.engine_controllers
42
36
  files -= Dir.glob(@options.exclude)
43
37
  files
44
38
  end
45
39
 
40
+ def engine_files
41
+ engines.collect { |engine| Dir.glob("#{engine.root}/app/controllers/**/*_controller.rb") }.flatten
42
+ end
43
+
44
+ def extract_class_name(filename)
45
+ filename.match(%r{.*/controllers/(.*).rb$})[1].camelize
46
+ end
47
+
46
48
  private
49
+
47
50
  # Load controller classes
48
51
  def load_classes
49
- begin
50
- disable_stdout
51
- # ApplicationController must be loaded first
52
- require APP_CONTROLLER
53
- get_files.each {|c| require "./#{c}" }
54
- enable_stdout
55
- rescue LoadError
56
- enable_stdout
57
- print_error "controller classes"
58
- raise
59
- end
60
- end # load_classes
52
+ disable_stdout
53
+ # ApplicationController must be loaded first
54
+ require APP_CONTROLLER
55
+ get_files.each { |c| require "./#{c}" }
56
+ enable_stdout
57
+ rescue LoadError
58
+ enable_stdout
59
+ print_error 'controller classes'
60
+ raise
61
+ end
61
62
 
62
63
  # Proccess a controller class
63
64
  def process_class(current_class)
64
-
65
- STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
65
+ $stderr.print "\tProcessing #{current_class}\n" if @options.verbose
66
66
 
67
67
  if @options.brief
68
68
  @graph.add_node ['controller-brief', current_class.name]
69
- elsif current_class.is_a? Class
69
+ elsif current_class.is_a? Class
70
70
  # Collect controller's methods
71
- node_attribs = {:public => [],
72
- :protected => [],
73
- :private => []}
74
- current_class.public_instance_methods(false).sort.each { |m|
75
- node_attribs[:public] << m
76
- } unless @options.hide_public
77
- current_class.protected_instance_methods(false).sort.each { |m|
78
- node_attribs[:protected] << m
79
- } unless @options.hide_protected
80
- current_class.private_instance_methods(false).sort.each { |m|
81
- node_attribs[:private] << m
82
- } unless @options.hide_private
71
+ node_attribs = { public: [],
72
+ protected: [],
73
+ private: [] }
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
83
89
  @graph.add_node ['controller', current_class.name, node_attribs]
84
90
  elsif @options.modules && current_class.is_a?(Module)
85
91
  @graph.add_node ['module', current_class.name]
@@ -89,10 +95,9 @@ class ControllersDiagram < AppDiagram
89
95
  if @options.inheritance && (transitive_subclasses_of(ApplicationController).include? current_class)
90
96
  @graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
91
97
  end
92
- end # process_class
98
+ end
93
99
 
94
100
  def transitive_subclasses_of(klass)
95
- klass.subclasses | klass.subclasses.map {|subklass| transitive_subclasses_of(subklass)}.flatten
101
+ klass.subclasses | klass.subclasses.map { |subklass| transitive_subclasses_of(subklass) }.flatten
96
102
  end
97
-
98
- end # class ControllersDiagram
103
+ end
@@ -1,12 +1,7 @@
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
1
+ # frozen_string_literal: true
6
2
 
7
-
8
- # RailRoady diagram structure
9
3
  class DiagramGraph
4
+ attr_writer :diagram_type, :show_label, :alphabetize
10
5
 
11
6
  def initialize
12
7
  @diagram_type = ''
@@ -24,91 +19,81 @@ class DiagramGraph
24
19
  @edges << edge
25
20
  end
26
21
 
27
- def diagram_type= (type)
28
- @diagram_type = type
29
- end
30
-
31
- def show_label= (value)
32
- @show_label = value
33
- end
34
-
35
- def alphabetize= (flag)
36
- @alphabetize = flag
37
- end
38
-
39
-
40
22
  # Generate DOT graph
41
23
  def to_dot
42
- return dot_header +
43
- @nodes.map{|n| dot_node n[0], n[1], n[2]}.join +
44
- @edges.map{|e| dot_edge e[0], e[1], e[2], e[3]}.join +
45
- dot_footer
24
+ dot_header +
25
+ @nodes.map { |n| dot_node n[0], n[1], n[2], n[3] }.join +
26
+ @edges.map { |e| dot_edge e[0], e[1], e[2], e[3] }.join +
27
+ dot_footer
46
28
  end
47
29
 
48
30
  # Generate XMI diagram (not yet implemented)
49
31
  def to_xmi
50
- STDERR.print "Sorry. XMI output not yet implemented.\n\n"
51
- return ""
32
+ $stderr.print "Sorry. XMI output not yet implemented.\n\n"
33
+ ''
52
34
  end
53
35
 
54
36
  private
55
37
 
56
38
  # Build DOT diagram header
57
39
  def dot_header
58
- result = "digraph #{@diagram_type.downcase}_diagram {\n" +
59
- "\tgraph[overlap=false, splines=true]\n"
40
+ result = "digraph #{@diagram_type.downcase}_diagram {\n" \
41
+ "\tgraph[overlap=false, splines=true, bgcolor=\"none\"]\n"
60
42
  result += dot_label if @show_label
61
- return result
43
+ result
62
44
  end
63
45
 
64
46
  # Build DOT diagram footer
65
47
  def dot_footer
66
- return "}\n"
48
+ "}\n"
67
49
  end
68
50
 
69
51
  # Build diagram label
70
52
  def dot_label
71
- return "\t_diagram_info [shape=\"plaintext\", " +
72
- "label=\"#{@diagram_type} diagram\\l" +
73
- "Date: #{Time.now.strftime "%b %d %Y - %H:%M"}\\l" +
74
- (defined?(ActiveRecord::Migrator) ? "Migration version: " +
75
- "#{ActiveRecord::Migrator.current_version}\\l" : "") +
76
- "Generated by #{APP_HUMAN_NAME} #{APP_VERSION}\\l"+
77
- "http://railroady.prestonlee.com" +
53
+ "\t_diagram_info [shape=\"plaintext\", " \
54
+ "label=\"#{@diagram_type} diagram\\l" \
55
+ "Date: #{Time.now.strftime '%b %d %Y - %H:%M'}\\l" +
56
+ (if defined?(ActiveRecord::Migrator)
57
+ 'Migration version: ' \
58
+ "#{Rails.logger.silence { ActiveRecord::Migrator.current_version }}\\l"
59
+ else
60
+ ''
61
+ end) +
62
+ "Generated by #{APP_HUMAN_NAME} #{APP_VERSION}\\l" + 'http://railroady.prestonlee.com' \
78
63
  "\\l\", fontsize=13]\n"
79
64
  end
80
65
 
81
66
  # Build a DOT graph node
82
- def dot_node(type, name, attributes=nil)
67
+ def dot_node(type, name, attributes = nil, custom_options = '')
83
68
  case type
84
- when 'model'
85
- options = 'shape=Mrecord, label="{' + name + '|'
86
- options += attributes.sort_by { |s| @alphabetize ? s : nil }.join('\l')
87
- options += '\l}"'
88
- when 'model-brief'
89
- options = ''
90
- when 'class'
91
- options = 'shape=record, label="{' + name + '|}"'
92
- when 'class-brief'
93
- options = 'shape=box'
94
- when 'controller'
95
- options = 'shape=Mrecord, label="{' + name + '|'
96
- public_methods = attributes[:public].sort_by { |s| @alphabetize ? s : nil }.join('\l')
97
- protected_methods = attributes[:protected].sort_by { |s| @alphabetize ? s : nil }.join('\l')
98
- private_methods = attributes[:private].sort_by { |s| @alphabetize ? s : nil }.join('\l')
99
- options += public_methods + '\l|' + protected_methods + '\l|' +
100
- private_methods + '\l'
101
- options += '}"'
102
- when 'controller-brief'
103
- options = ''
104
- when 'module'
105
- options = 'shape=box, style=dotted, label="' + name + '"'
106
- when 'aasm'
107
- # Return subgraph format
108
- return "subgraph cluster_#{name.downcase} {\n\tlabel = #{quote(name)}\n\t#{attributes.join("\n ")}}"
109
- end # case
110
- return "\t#{quote(name)} [#{options}]\n"
111
- 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
112
97
 
113
98
  # Build a DOT graph edge
114
99
  def dot_edge(type, from, to, name = '')
@@ -116,23 +101,25 @@ class DiagramGraph
116
101
  edge_color = '"#%02X%02X%02X"' % [rand(255), rand(255), rand(255)]
117
102
  suffix = ", dir=both color=#{edge_color}"
118
103
  case type
119
- when 'one-one'
120
- options += "arrowtail=odot, arrowhead=dot" + suffix
121
- when 'one-many'
122
- options += "arrowtail=odot, arrowhead=crow" + suffix
123
- when 'many-many'
124
- options += "arrowtail=crow, arrowhead=crow" + suffix
125
- when 'is-a'
126
- options += 'arrowhead="none", arrowtail="onormal"'
127
- when 'event'
128
- options += "fontsize=10"
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'
129
117
  end
130
- return "\t#{quote(from)} -> #{quote(to)} [#{options}]\n"
131
- end # dot_edge
118
+ "\t#{quote(from)} -> #{quote(to)} [#{options}]\n"
119
+ end
132
120
 
133
121
  # Quotes a class name
134
122
  def quote(name)
135
- '"' + name.to_s + '"'
123
+ "\"#{name}\""
136
124
  end
137
-
138
- end # class DiagramGraph
125
+ end