railroady 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +7 -0
- data/AUTHORS.rdoc +17 -0
- data/CHANGELOG.rdoc +110 -0
- data/LICENSE.rdoc +340 -0
- data/README.rdoc +169 -0
- data/Rakefile +47 -0
- data/VERSION.yml +5 -0
- data/bin/railroady +58 -0
- data/lib/railroady.rb +5 -0
- data/lib/railroady/aasm_diagram.rb +109 -0
- data/lib/railroady/app_diagram.rb +113 -0
- data/lib/railroady/controllers_diagram.rb +95 -0
- data/lib/railroady/diagram_graph.rb +130 -0
- data/lib/railroady/models_diagram.rb +146 -0
- data/lib/railroady/options_struct.rb +178 -0
- data/lib/railroady/railtie.rb +13 -0
- data/lib/railroady/version.rb +14 -0
- data/tasks/railroady.rake +62 -0
- metadata +92 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
# RailRoady - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
require 'railroady/app_diagram'
|
8
|
+
|
9
|
+
# RailRoady controllers diagram
|
10
|
+
class ControllersDiagram < AppDiagram
|
11
|
+
|
12
|
+
# as of Rails 2.3 the file is no longer application.rb but instead
|
13
|
+
# application_controller.rb
|
14
|
+
APP_CONTROLLER = File.exist?('app/controllers/application.rb') ? 'app/controllers/application.rb' : 'app/controllers/application_controller.rb'
|
15
|
+
|
16
|
+
def initialize(options = OptionsStruct.new)
|
17
|
+
#options.exclude.map! {|e| "app/controllers/" + e}
|
18
|
+
super options
|
19
|
+
@graph.diagram_type = 'Controllers'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Process controller files
|
23
|
+
def generate
|
24
|
+
STDERR.print "Generating controllers diagram\n" if @options.verbose
|
25
|
+
files = get_files
|
26
|
+
# only add APP_CONTROLLER if it isn't already included from the glob above
|
27
|
+
files << APP_CONTROLLER unless files.include? APP_CONTROLLER
|
28
|
+
files.each do |f|
|
29
|
+
class_name = extract_class_name(f)
|
30
|
+
# ApplicationController's file is 'application.rb' in Rails < 2.3
|
31
|
+
class_name += 'Controller' if class_name == 'Application'
|
32
|
+
begin
|
33
|
+
process_class class_name.constantize
|
34
|
+
rescue Exception
|
35
|
+
STDERR.print "Warning: exception #{$!} raised while trying to load controller class #{f}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end # generate
|
39
|
+
|
40
|
+
def get_files(prefix ='')
|
41
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << "app/controllers/**/*_controller.rb")
|
42
|
+
files -= Dir.glob(@options.exclude)
|
43
|
+
files
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
# Load controller classes
|
48
|
+
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
|
61
|
+
|
62
|
+
# Proccess a controller class
|
63
|
+
def process_class(current_class)
|
64
|
+
|
65
|
+
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
66
|
+
|
67
|
+
if @options.brief
|
68
|
+
@graph.add_node ['controller-brief', current_class.name]
|
69
|
+
elsif current_class.is_a? Class
|
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
|
83
|
+
@graph.add_node ['controller', current_class.name, node_attribs]
|
84
|
+
elsif @options.modules && current_class.is_a?(Module)
|
85
|
+
@graph.add_node ['module', current_class.name]
|
86
|
+
end
|
87
|
+
|
88
|
+
# Generate the inheritance edge (only for ApplicationControllers)
|
89
|
+
if @options.inheritance &&
|
90
|
+
(ApplicationController.subclasses.include? current_class.name)
|
91
|
+
@graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
|
92
|
+
end
|
93
|
+
end # process_class
|
94
|
+
|
95
|
+
end # class ControllersDiagram
|
@@ -0,0 +1,130 @@
|
|
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
|
+
|
8
|
+
# RailRoady diagram structure
|
9
|
+
class DiagramGraph
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@diagram_type = ''
|
13
|
+
@show_label = false
|
14
|
+
@nodes = []
|
15
|
+
@edges = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_node(node)
|
19
|
+
@nodes << node
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_edge(edge)
|
23
|
+
@edges << edge
|
24
|
+
end
|
25
|
+
|
26
|
+
def diagram_type= (type)
|
27
|
+
@diagram_type = type
|
28
|
+
end
|
29
|
+
|
30
|
+
def show_label= (value)
|
31
|
+
@show_label = value
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
# Generate DOT graph
|
36
|
+
def to_dot
|
37
|
+
return dot_header +
|
38
|
+
@nodes.map{|n| dot_node n[0], n[1], n[2]}.join +
|
39
|
+
@edges.map{|e| dot_edge e[0], e[1], e[2], e[3]}.join +
|
40
|
+
dot_footer
|
41
|
+
end
|
42
|
+
|
43
|
+
# Generate XMI diagram (not yet implemented)
|
44
|
+
def to_xmi
|
45
|
+
STDERR.print "Sorry. XMI output not yet implemented.\n\n"
|
46
|
+
return ""
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# Build DOT diagram header
|
52
|
+
def dot_header
|
53
|
+
result = "digraph #{@diagram_type.downcase}_diagram {\n" +
|
54
|
+
"\tgraph[overlap=false, splines=true]\n"
|
55
|
+
result += dot_label if @show_label
|
56
|
+
return result
|
57
|
+
end
|
58
|
+
|
59
|
+
# Build DOT diagram footer
|
60
|
+
def dot_footer
|
61
|
+
return "}\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
# Build diagram label
|
65
|
+
def dot_label
|
66
|
+
return "\t_diagram_info [shape=\"plaintext\", " +
|
67
|
+
"label=\"#{@diagram_type} diagram\\l" +
|
68
|
+
"Date: #{Time.now.strftime "%b %d %Y - %H:%M"}\\l" +
|
69
|
+
"Migration version: " +
|
70
|
+
"#{ActiveRecord::Migrator.current_version}\\l" +
|
71
|
+
"Generated by #{APP_HUMAN_NAME} #{APP_VERSION}"+
|
72
|
+
"\\l\", fontsize=14]\n"
|
73
|
+
end
|
74
|
+
|
75
|
+
# Build a DOT graph node
|
76
|
+
def dot_node(type, name, attributes=nil)
|
77
|
+
case type
|
78
|
+
when 'model'
|
79
|
+
options = 'shape=Mrecord, label="{' + name + '|'
|
80
|
+
options += attributes.join('\l')
|
81
|
+
options += '\l}"'
|
82
|
+
when 'model-brief'
|
83
|
+
options = ''
|
84
|
+
when 'class'
|
85
|
+
options = 'shape=record, label="{' + name + '|}"'
|
86
|
+
when 'class-brief'
|
87
|
+
options = 'shape=box'
|
88
|
+
when 'controller'
|
89
|
+
options = 'shape=Mrecord, label="{' + name + '|'
|
90
|
+
public_methods = attributes[:public].join('\l')
|
91
|
+
protected_methods = attributes[:protected].join('\l')
|
92
|
+
private_methods = attributes[:private].join('\l')
|
93
|
+
options += public_methods + '\l|' + protected_methods + '\l|' +
|
94
|
+
private_methods + '\l'
|
95
|
+
options += '}"'
|
96
|
+
when 'controller-brief'
|
97
|
+
options = ''
|
98
|
+
when 'module'
|
99
|
+
options = 'shape=box, style=dotted, label="' + name + '"'
|
100
|
+
when 'aasm'
|
101
|
+
# Return subgraph format
|
102
|
+
return "subgraph cluster_#{name.downcase} {\n\tlabel = #{quote(name)}\n\t#{attributes.join("\n ")}}"
|
103
|
+
end # case
|
104
|
+
return "\t#{quote(name)} [#{options}]\n"
|
105
|
+
end # dot_node
|
106
|
+
|
107
|
+
# Build a DOT graph edge
|
108
|
+
def dot_edge(type, from, to, name = '')
|
109
|
+
options = name != '' ? "label=\"#{name}\", " : ''
|
110
|
+
case type
|
111
|
+
when 'one-one'
|
112
|
+
options += 'arrowtail=odot, arrowhead=dot, dir=both'
|
113
|
+
when 'one-many'
|
114
|
+
options += 'arrowtail=odot, arrowhead=crow, dir=both'
|
115
|
+
when 'many-many'
|
116
|
+
options += 'arrowtail=crow, arrowhead=crow, dir=both'
|
117
|
+
when 'is-a'
|
118
|
+
options += 'arrowhead="none", arrowtail="onormal"'
|
119
|
+
when 'event'
|
120
|
+
options += "fontsize=10"
|
121
|
+
end
|
122
|
+
return "\t#{quote(from)} -> #{quote(to)} [#{options}]\n"
|
123
|
+
end # dot_edge
|
124
|
+
|
125
|
+
# Quotes a class name
|
126
|
+
def quote(name)
|
127
|
+
'"' + name.to_s + '"'
|
128
|
+
end
|
129
|
+
|
130
|
+
end # class DiagramGraph
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# RailRoady - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
require 'railroady/app_diagram'
|
8
|
+
|
9
|
+
# RailRoady models diagram
|
10
|
+
class ModelsDiagram < AppDiagram
|
11
|
+
|
12
|
+
def initialize(options = OptionsStruct.new)
|
13
|
+
#options.exclude.map! {|e| "app/models/" + e}
|
14
|
+
super options
|
15
|
+
@graph.diagram_type = 'Models'
|
16
|
+
# Processed habtm associations
|
17
|
+
@habtm = []
|
18
|
+
end
|
19
|
+
|
20
|
+
# Process model files
|
21
|
+
def generate
|
22
|
+
STDERR.print "Generating models diagram\n" if @options.verbose
|
23
|
+
get_files.each do |f|
|
24
|
+
begin
|
25
|
+
process_class extract_class_name(f).constantize
|
26
|
+
rescue Exception
|
27
|
+
STDERR.print "Warning: exception #{$!} raised while trying to load model class #{f}\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def get_files(prefix ='')
|
34
|
+
files = !@options.specify.empty? ? Dir.glob(@options.specify) : Dir.glob(prefix << "app/models/**/*.rb")
|
35
|
+
files += Dir.glob("vendor/plugins/**/app/models/*.rb") if @options.plugins_models
|
36
|
+
files -= Dir.glob(@options.exclude)
|
37
|
+
files
|
38
|
+
end
|
39
|
+
|
40
|
+
# Process a model class
|
41
|
+
def process_class(current_class)
|
42
|
+
|
43
|
+
STDERR.print "\tProcessing #{current_class}\n" if @options.verbose
|
44
|
+
|
45
|
+
generated = false
|
46
|
+
|
47
|
+
# Is current_clas derived from ActiveRecord::Base?
|
48
|
+
if current_class.respond_to?'reflect_on_all_associations'
|
49
|
+
|
50
|
+
|
51
|
+
node_attribs = []
|
52
|
+
if @options.brief || current_class.abstract_class?
|
53
|
+
node_type = 'model-brief'
|
54
|
+
else
|
55
|
+
node_type = 'model'
|
56
|
+
|
57
|
+
# Collect model's content columns
|
58
|
+
|
59
|
+
content_columns = current_class.content_columns
|
60
|
+
|
61
|
+
if @options.hide_magic
|
62
|
+
# From patch #13351
|
63
|
+
# http://wiki.rubyonrails.org/rails/pages/MagicFieldNames
|
64
|
+
magic_fields = [
|
65
|
+
"created_at", "created_on", "updated_at", "updated_on",
|
66
|
+
"lock_version", "type", "id", "position", "parent_id", "lft",
|
67
|
+
"rgt", "quote", "template"
|
68
|
+
]
|
69
|
+
magic_fields << current_class.table_name + "_count" if current_class.respond_to? 'table_name'
|
70
|
+
content_columns = current_class.content_columns.select {|c| ! magic_fields.include? c.name}
|
71
|
+
else
|
72
|
+
content_columns = current_class.content_columns
|
73
|
+
end
|
74
|
+
|
75
|
+
content_columns.each do |a|
|
76
|
+
content_column = a.name
|
77
|
+
content_column += ' :' + a.type.to_s unless @options.hide_types
|
78
|
+
node_attribs << content_column
|
79
|
+
end
|
80
|
+
end
|
81
|
+
@graph.add_node [node_type, current_class.name, node_attribs]
|
82
|
+
generated = true
|
83
|
+
# Process class associations
|
84
|
+
associations = current_class.reflect_on_all_associations
|
85
|
+
if @options.inheritance && ! @options.transitive
|
86
|
+
superclass_associations = current_class.superclass.reflect_on_all_associations
|
87
|
+
|
88
|
+
associations = associations.select{|a| ! superclass_associations.include? a}
|
89
|
+
# This doesn't works!
|
90
|
+
# associations -= current_class.superclass.reflect_on_all_associations
|
91
|
+
end
|
92
|
+
associations.each do |a|
|
93
|
+
process_association current_class.name, a
|
94
|
+
end
|
95
|
+
elsif @options.all && (current_class.is_a? Class)
|
96
|
+
# Not ActiveRecord::Base model
|
97
|
+
node_type = @options.brief ? 'class-brief' : 'class'
|
98
|
+
@graph.add_node [node_type, current_class.name]
|
99
|
+
generated = true
|
100
|
+
elsif @options.modules && (current_class.is_a? Module)
|
101
|
+
@graph.add_node ['module', current_class.name]
|
102
|
+
end
|
103
|
+
|
104
|
+
# Only consider meaningful inheritance relations for generated classes
|
105
|
+
if @options.inheritance && generated &&
|
106
|
+
(current_class.superclass != ActiveRecord::Base) &&
|
107
|
+
(current_class.superclass != Object)
|
108
|
+
@graph.add_edge ['is-a', current_class.superclass.name, current_class.name]
|
109
|
+
end
|
110
|
+
|
111
|
+
end # process_class
|
112
|
+
|
113
|
+
# Process a model association
|
114
|
+
def process_association(class_name, assoc)
|
115
|
+
|
116
|
+
STDERR.print "\t\tProcessing model association #{assoc.name.to_s}\n" if @options.verbose
|
117
|
+
|
118
|
+
# Skip "belongs_to" associations
|
119
|
+
return if assoc.macro.to_s == 'belongs_to' && !@options.show_belongs_to
|
120
|
+
|
121
|
+
# Only non standard association names needs a label
|
122
|
+
|
123
|
+
# from patch #12384
|
124
|
+
# if assoc.class_name == assoc.name.to_s.singularize.camelize
|
125
|
+
assoc_class_name = (assoc.class_name.respond_to? 'underscore') ? assoc.class_name.underscore.singularize.camelize : assoc.class_name
|
126
|
+
if assoc_class_name == assoc.name.to_s.singularize.camelize
|
127
|
+
assoc_name = ''
|
128
|
+
else
|
129
|
+
assoc_name = assoc.name.to_s
|
130
|
+
end
|
131
|
+
|
132
|
+
if ['has_one', 'belongs_to'].include? assoc.macro.to_s
|
133
|
+
assoc_type = 'one-one'
|
134
|
+
elsif assoc.macro.to_s == 'has_many' && (! assoc.options[:through])
|
135
|
+
assoc_type = 'one-many'
|
136
|
+
else # habtm or has_many, :through
|
137
|
+
return if @habtm.include? [assoc.class_name, class_name, assoc_name]
|
138
|
+
assoc_type = 'many-many'
|
139
|
+
@habtm << [class_name, assoc.class_name, assoc_name]
|
140
|
+
end
|
141
|
+
# from patch #12384
|
142
|
+
# @graph.add_edge [assoc_type, class_name, assoc.class_name, assoc_name]
|
143
|
+
@graph.add_edge [assoc_type, class_name, assoc_class_name, assoc_name]
|
144
|
+
end # process_association
|
145
|
+
|
146
|
+
end # class ModelsDiagram
|
@@ -0,0 +1,178 @@
|
|
1
|
+
# RailRoady - RoR diagrams generator
|
2
|
+
# http://railroad.rubyforge.org
|
3
|
+
#
|
4
|
+
# Copyright 2007-2008 - Javier Smaldone (http://www.smaldone.com.ar)
|
5
|
+
# See COPYING for more details
|
6
|
+
|
7
|
+
require 'ostruct'
|
8
|
+
|
9
|
+
# RailRoady command line options parser
|
10
|
+
class OptionsStruct < OpenStruct
|
11
|
+
|
12
|
+
require 'optparse'
|
13
|
+
|
14
|
+
def initialize(args={})
|
15
|
+
init_options = { :all => false,
|
16
|
+
:brief => false,
|
17
|
+
:specify => [],
|
18
|
+
:exclude => [],
|
19
|
+
:inheritance => false,
|
20
|
+
:join => false,
|
21
|
+
:label => false,
|
22
|
+
:modules => false,
|
23
|
+
:hide_magic => false,
|
24
|
+
:hide_types => false,
|
25
|
+
:hide_public => false,
|
26
|
+
:hide_protected => false,
|
27
|
+
:hide_private => false,
|
28
|
+
:plugins_models => false,
|
29
|
+
:root => '',
|
30
|
+
:show_belongs_to => false,
|
31
|
+
:transitive => false,
|
32
|
+
:verbose => false,
|
33
|
+
:xmi => false,
|
34
|
+
:command => '',
|
35
|
+
:app_name => 'railroady', :app_human_name => 'Railroady', :app_version =>'', :copyright =>'' }
|
36
|
+
super(init_options.merge(args))
|
37
|
+
end # initialize
|
38
|
+
|
39
|
+
def parse(args)
|
40
|
+
@opt_parser = OptionParser.new do |opts|
|
41
|
+
opts.banner = "Usage: #{self.app_name} [options] command"
|
42
|
+
opts.separator ""
|
43
|
+
opts.separator "Common options:"
|
44
|
+
opts.on("-b", "--brief", "Generate compact diagram",
|
45
|
+
" (no attributes nor methods)") do |b|
|
46
|
+
self.brief = b
|
47
|
+
end
|
48
|
+
opts.on("-s", "--specify file1[,fileN]", Array, "Specify only given files") do |list|
|
49
|
+
self.specify = list
|
50
|
+
end
|
51
|
+
opts.on("-e", "--exclude file1[,fileN]", Array, "Exclude given files") do |list|
|
52
|
+
self.exclude = list
|
53
|
+
end
|
54
|
+
opts.on("-i", "--inheritance", "Include inheritance relations") do |i|
|
55
|
+
self.inheritance = i
|
56
|
+
end
|
57
|
+
opts.on("-l", "--label", "Add a label with diagram information",
|
58
|
+
" (type, date, migration, version)") do |l|
|
59
|
+
self.label = l
|
60
|
+
end
|
61
|
+
opts.on("-o", "--output FILE", "Write diagram to file FILE") do |f|
|
62
|
+
self.output = f
|
63
|
+
end
|
64
|
+
opts.on("-r", "--root PATH", "Set PATH as the application root") do |r|
|
65
|
+
self.root = r
|
66
|
+
end
|
67
|
+
opts.on("-v", "--verbose", "Enable verbose output",
|
68
|
+
" (produce messages to STDOUT)") do |v|
|
69
|
+
self.verbose = v
|
70
|
+
end
|
71
|
+
opts.on("-x", "--xmi", "Produce XMI instead of DOT",
|
72
|
+
" (for UML tools)") do |x|
|
73
|
+
self.xmi = x
|
74
|
+
end
|
75
|
+
opts.separator ""
|
76
|
+
opts.separator "Models diagram options:"
|
77
|
+
opts.on("-a", "--all", "Include all models",
|
78
|
+
" (not only ActiveRecord::Base derived)") do |a|
|
79
|
+
self.all = a
|
80
|
+
end
|
81
|
+
opts.on("--show-belongs_to", "Show belongs_to associations") do |s|
|
82
|
+
self.show_belongs_to = s
|
83
|
+
end
|
84
|
+
opts.on("--hide-magic", "Hide magic field names") do |h|
|
85
|
+
self.hide_magic = h
|
86
|
+
end
|
87
|
+
opts.on("--hide-types", "Hide attributes type") do |h|
|
88
|
+
self.hide_types = h
|
89
|
+
end
|
90
|
+
opts.on("-j", "--join", "Concentrate edges") do |j|
|
91
|
+
self.join = j
|
92
|
+
end
|
93
|
+
opts.on("-m", "--modules", "Include modules") do |m|
|
94
|
+
self.modules = m
|
95
|
+
end
|
96
|
+
opts.on("-p", "--plugins-models", "Include plugins models") do |p|
|
97
|
+
self.plugins_models = p
|
98
|
+
end
|
99
|
+
opts.on("-t", "--transitive", "Include transitive associations",
|
100
|
+
"(through inheritance)") do |t|
|
101
|
+
self.transitive = t
|
102
|
+
end
|
103
|
+
opts.separator ""
|
104
|
+
opts.separator "Controllers diagram options:"
|
105
|
+
opts.on("--hide-public", "Hide public methods") do |h|
|
106
|
+
self.hide_public = h
|
107
|
+
end
|
108
|
+
opts.on("--hide-protected", "Hide protected methods") do |h|
|
109
|
+
self.hide_protected = h
|
110
|
+
end
|
111
|
+
opts.on("--hide-private", "Hide private methods") do |h|
|
112
|
+
self.hide_private = h
|
113
|
+
end
|
114
|
+
opts.separator ""
|
115
|
+
opts.separator "Other options:"
|
116
|
+
opts.on("-h", "--help", "Show this message") do
|
117
|
+
STDOUT.print "#{opts}\n"
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
opts.on("--version", "Show version and copyright") do
|
121
|
+
STDOUT.print"#{self.app_human_name} version #{self.app_version}\n\n" +
|
122
|
+
"#{self.copyright}\nThis is free software; see the source " +
|
123
|
+
"for copying conditions.\n\n"
|
124
|
+
exit
|
125
|
+
end
|
126
|
+
opts.separator ""
|
127
|
+
opts.separator "Commands (you must supply one of these):"
|
128
|
+
opts.on("-M", "--models", "Generate models diagram") do |c|
|
129
|
+
if self.command != ''
|
130
|
+
STDERR.print "Error: Can only generate one diagram type\n\n"
|
131
|
+
exit 1
|
132
|
+
else
|
133
|
+
self.command = 'models'
|
134
|
+
end
|
135
|
+
end
|
136
|
+
opts.on("-C", "--controllers", "Generate controllers diagram") do |c|
|
137
|
+
if self.command != ''
|
138
|
+
STDERR.print "Error: Can only generate one diagram type\n\n"
|
139
|
+
exit 1
|
140
|
+
else
|
141
|
+
self.command = 'controllers'
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# From Ana Nelson's patch
|
145
|
+
opts.on("-A", "--aasm", "Generate \"acts as state machine\" diagram") do |c|
|
146
|
+
if self.command == 'controllers'
|
147
|
+
STDERR.print "Error: Can only generate one diagram type\n\n"
|
148
|
+
exit 1
|
149
|
+
else
|
150
|
+
self.command = 'aasm'
|
151
|
+
end
|
152
|
+
end
|
153
|
+
opts.separator ""
|
154
|
+
opts.separator "For bug reporting and additional information, please see:"
|
155
|
+
opts.separator "http://railroad.rubyforge.org/"
|
156
|
+
end # do
|
157
|
+
|
158
|
+
begin
|
159
|
+
@opt_parser.parse!(args)
|
160
|
+
rescue OptionParser::AmbiguousOption
|
161
|
+
option_error "Ambiguous option"
|
162
|
+
rescue OptionParser::InvalidOption
|
163
|
+
option_error "Invalid option"
|
164
|
+
rescue OptionParser::InvalidArgument
|
165
|
+
option_error "Invalid argument"
|
166
|
+
rescue OptionParser::MissingArgument
|
167
|
+
option_error "Missing argument"
|
168
|
+
end
|
169
|
+
end # parse
|
170
|
+
|
171
|
+
private
|
172
|
+
|
173
|
+
def option_error(msg)
|
174
|
+
STDERR.print "Error: #{msg}\n\n #{@opt_parser}\n"
|
175
|
+
exit 1
|
176
|
+
end
|
177
|
+
|
178
|
+
end # class OptionsStruct
|