rails-erd 0.4.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES.rdoc CHANGED
@@ -1,3 +1,21 @@
1
+ === 1.0.0:
2
+
3
+ * The internal API is now stable and will be backwards compatible until
4
+ the next major version.
5
+ * Added experimental command line interface (erd). The CLI still requires a
6
+ Rails application to be present, but it may one day support other kinds of
7
+ applications.
8
+ * Crow's foot notation (also known as the Information Engineering notation)
9
+ can be used by adding 'notation=crowsfoot' to the 'rake erd' command
10
+ (contributed by Jeremy Holland).
11
+ * Filter models by using the only or exclude options (only=ModelOne,ModelTwo
12
+ or exclude=ModelThree,ModelFour) from the command line (contributed by
13
+ Milovan Zogovic).
14
+ * Process column types that are unsupported by Rails (contributed by Erik
15
+ Gustavson).
16
+ * Ignore custom limit/scale attributes that cannot be converted to an integer
17
+ (reported by Adam St. John).
18
+
1
19
  === 0.4.5:
2
20
 
3
21
  * Display more helpful error message when the application models could not be
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2011 Voormedia B.V.
1
+ Copyright (c) 2010-2012 Voormedia B.V.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -31,11 +31,11 @@ Getting started
31
31
  See the [installation instructions](http://rails-erd.rubyforge.org/install.html)
32
32
  for a complete description of how to install Rails ERD. Here's a summary:
33
33
 
34
- * Install Graphviz 2.22+ with Pango and Cairo support ([how?](http://rails-erd.rubyforge.org/install.html))
34
+ * Install Graphviz 2.22+ ([how?](http://rails-erd.rubyforge.org/install.html))
35
35
 
36
36
  * Add <tt>gem "rails-erd"</tt> to your application's Gemfile
37
37
 
38
- * Run <tt>rake erd</tt>
38
+ * Run <tt>bundle exec erd</tt>
39
39
 
40
40
 
41
41
  Learn more
@@ -51,7 +51,7 @@ About Rails ERD
51
51
 
52
52
  Rails ERD was created by Rolf Timmermans (r.timmermans *at* voormedia.com)
53
53
 
54
- Copyright 2010-2011 Voormedia - [www.voormedia.com](http://www.voormedia.com/)
54
+ Copyright 2010-2012 Voormedia - [www.voormedia.com](http://www.voormedia.com/)
55
55
 
56
56
 
57
57
  License
data/Rakefile CHANGED
@@ -1,54 +1,65 @@
1
- # encoding: utf-8
2
- require "jeweler"
1
+ require "bundler"
3
2
  require "rake/testtask"
4
3
 
5
- Jeweler::Tasks.new do |spec|
6
- spec.name = "rails-erd"
7
- spec.rubyforge_project = "rails-erd"
8
- spec.summary = "Entity-relationship diagram for your Rails models."
9
- spec.description = "Automatically generate an entity-relationship diagram (ERD) for your Rails models."
10
-
11
- spec.authors = ["Rolf Timmermans"]
12
- spec.email = "r.timmermans@voormedia.com"
13
- spec.homepage = "http://rails-erd.rubyforge.org/"
14
-
15
- # Don't bundle examples or website in gem.
16
- excluded = Dir["{examples,site}/**/*"]
17
- spec.files -= excluded
18
- spec.test_files -= excluded
19
- end
20
-
21
- Jeweler::GemcutterTasks.new
22
-
23
- Jeweler::RubyforgeTasks.new do |rubyforge|
24
- rubyforge.doc_task = "rdoc"
25
- rubyforge.remote_doc_path = "doc"
26
- end
4
+ Bundler::GemHelper.install_tasks
27
5
 
28
6
  Rake::TestTask.new do |test|
29
- test.pattern = "test/unit/**/*_test.rb"
7
+ test.test_files = FileList["test/**/*_test.rb"]
30
8
  end
31
9
 
32
10
  task :default => :test
33
11
 
34
- begin
35
- require "hanna/rdoctask"
36
- Rake::RDocTask.new do |rdoc|
37
- rdoc.rdoc_files = %w{CHANGES.rdoc LICENSE} + Dir["lib/**/*.rb"]
38
- rdoc.title = "Rails ERD – API Documentation"
39
- rdoc.rdoc_dir = "rdoc"
40
- rdoc.main = "RailsERD"
41
- end
42
- rescue LoadError
43
- end
44
-
45
- desc "Generate diagrams for bundled examples"
46
- task :examples do
47
- require File.expand_path("examples/generate", File.dirname(__FILE__))
48
- end
49
-
50
- namespace :examples do
51
- task :sfdp do
52
- require File.expand_path("examples/sfdp", File.dirname(__FILE__))
53
- end
54
- end
12
+ # # encoding: utf-8
13
+ # require "jeweler"
14
+ # require "rake/testtask"
15
+ #
16
+ # Jeweler::Tasks.new do |spec|
17
+ # spec.name = "rails-erd"
18
+ # spec.rubyforge_project = "rails-erd"
19
+ # spec.summary = "Entity-relationship diagram for your Rails models."
20
+ # spec.description = "Automatically generate an entity-relationship diagram (ERD) for your Rails models."
21
+ #
22
+ # spec.authors = ["Rolf Timmermans"]
23
+ # spec.email = "r.timmermans@voormedia.com"
24
+ # spec.homepage = "http://rails-erd.rubyforge.org/"
25
+ #
26
+ # # Don't bundle examples or website in gem.
27
+ # excluded = Dir["{examples,site}/**/*"]
28
+ # spec.files -= excluded
29
+ # spec.test_files -= excluded
30
+ # end
31
+ #
32
+ # Jeweler::GemcutterTasks.new
33
+ #
34
+ # Jeweler::RubyforgeTasks.new do |rubyforge|
35
+ # rubyforge.doc_task = "rdoc"
36
+ # rubyforge.remote_doc_path = "doc"
37
+ # end
38
+ #
39
+ # Rake::TestTask.new do |test|
40
+ # test.pattern = "test/unit/**/*_test.rb"
41
+ # end
42
+ #
43
+ # task :default => :test
44
+ #
45
+ # begin
46
+ # require "hanna/rdoctask"
47
+ # Rake::RDocTask.new do |rdoc|
48
+ # rdoc.rdoc_files = %w{CHANGES.rdoc LICENSE} + Dir["lib/**/*.rb"]
49
+ # rdoc.title = "Rails ERD – API Documentation"
50
+ # rdoc.rdoc_dir = "rdoc"
51
+ # rdoc.main = "RailsERD"
52
+ # end
53
+ # rescue LoadError
54
+ # end
55
+ #
56
+ # desc "Generate diagrams for bundled examples"
57
+ # task :examples do
58
+ # require File.expand_path("examples/generate", File.dirname(__FILE__))
59
+ # end
60
+ #
61
+ # namespace :examples do
62
+ # task :sfdp do
63
+ # require File.expand_path("examples/sfdp", File.dirname(__FILE__))
64
+ # end
65
+ # end
data/bin/erd ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require "rails_erd/cli"
3
+
4
+ RailsERD::CLI.start
data/lib/rails_erd.rb CHANGED
@@ -50,7 +50,7 @@ module RailsERD
50
50
  self.options = ActiveSupport::OrderedOptions[
51
51
  :attributes, :content,
52
52
  :disconnected, true,
53
- :filename, "ERD",
53
+ :filename, "erd",
54
54
  :filetype, :pdf,
55
55
  :indirect, true,
56
56
  :inheritance, false,
@@ -59,6 +59,8 @@ module RailsERD
59
59
  :orientation, :horizontal,
60
60
  :polymorphism, false,
61
61
  :warn, true,
62
- :title, true
62
+ :title, true,
63
+ :exclude, nil,
64
+ :only, nil
63
65
  ]
64
66
  end
@@ -0,0 +1,149 @@
1
+ require "choice"
2
+
3
+ Choice.options do
4
+ separator ""
5
+ separator "Diagram options:"
6
+
7
+ option :title do
8
+ long "--title=TITLE"
9
+ desc "Replace default diagram title with a custom one."
10
+ end
11
+
12
+ option :notation do
13
+ long "--notation=STYLE"
14
+ desc "Diagram notation style, one of simple, bachman, uml or crowsfoot."
15
+ default "simple"
16
+ end
17
+
18
+ option :attributes do
19
+ long "--attributes=TYPE,..."
20
+ desc "Attribute groups to display: content, primary_keys, foreign_keys, timestamps and/or inheritance."
21
+ default "content"
22
+ end
23
+
24
+ option :orientation do
25
+ long "--orientation=ORIENTATION"
26
+ desc "Orientation of diagram, either horizontal (default) or vertical."
27
+ default "orientation"
28
+ end
29
+
30
+ option :inheritance do
31
+ long "--inheritance"
32
+ desc "Display (single table) inheritance relationships."
33
+ end
34
+
35
+ option :polymorphism do
36
+ long "--polymorphism"
37
+ desc "Display polymorphic relationships."
38
+ end
39
+
40
+ option :no_indirect do
41
+ long "--direct"
42
+ desc "Omit indirect relationships (through other entities)."
43
+ end
44
+
45
+ option :no_disconnected do
46
+ long "--connected"
47
+ desc "Omit entities without relationships."
48
+ end
49
+
50
+ separator ""
51
+ separator "Output options:"
52
+
53
+ option :filename do
54
+ long "--filename=FILENAME"
55
+ desc "Basename of the output diagram."
56
+ default "erd"
57
+ end
58
+
59
+ option :filetype do
60
+ long "--filetype=TYPE"
61
+ desc "Output file type. Available types depend on the diagram renderer."
62
+ default "pdf"
63
+ end
64
+
65
+ option :no_markup do
66
+ long "--no-markup"
67
+ desc "Disable markup for enhanced compatibility of .dot output with other applications."
68
+ end
69
+
70
+ option :open do
71
+ long "--open"
72
+ desc "Open the output file after it has been saved."
73
+ end
74
+
75
+ separator ""
76
+ separator "Common options:"
77
+
78
+ option :help do
79
+ long "--help"
80
+ desc "Display this help message."
81
+ end
82
+
83
+ option :debug do
84
+ long "--debug"
85
+ desc "Show stack traces when an error occurs."
86
+ end
87
+
88
+ option :version do
89
+ short "-v"
90
+ long "--version"
91
+ desc "Show version and quit."
92
+ action do
93
+ require "rails_erd/version"
94
+ $stderr.puts RailsERD::BANNER
95
+ exit
96
+ end
97
+ end
98
+ end
99
+
100
+ module RailsERD
101
+ class CLI
102
+ attr_reader :path, :options
103
+
104
+ class << self
105
+ def start
106
+ path = Choice.rest.first || Dir.pwd
107
+ options = Choice.choices.each_with_object({}) do |(key, value), opts|
108
+ if key.start_with? "no_"
109
+ opts[key.gsub("no_", "").to_sym] = !value
110
+ elsif value.to_s.include? ","
111
+ opts[key.to_sym] = value.split(",").map(&:to_sym)
112
+ else
113
+ opts[key.to_sym] = value
114
+ end
115
+ end
116
+ new(path, options).start
117
+ end
118
+ end
119
+
120
+ def initialize(path, options)
121
+ @path, @options = path, options
122
+ require "rails_erd/diagram/graphviz"
123
+ end
124
+
125
+ def start
126
+ load_application
127
+ create_diagram
128
+ rescue Exception => e
129
+ $stderr.puts "Failed: #{e.class}: #{e.message}"
130
+ $stderr.puts e.backtrace.map { |t| " from #{t}" } if options[:debug]
131
+ end
132
+
133
+ private
134
+
135
+ def load_application
136
+ $stderr.puts "Loading application in '#{File.basename(path)}'..."
137
+ # TODO: Add support for different kinds of environment.
138
+ require "#{path}/config/environment"
139
+ Rails.application.eager_load!
140
+ end
141
+
142
+ def create_diagram
143
+ $stderr.puts "Generating entity-relationship diagram for #{ActiveRecord::Base.descendants.length} models..."
144
+ file = RailsERD::Diagram::Graphviz.create(options)
145
+ $stderr.puts "Diagram saved to '#{file}'."
146
+ `open #{file}` if options[:open]
147
+ end
148
+ end
149
+ end
@@ -3,7 +3,7 @@ require "rails_erd/domain"
3
3
  module RailsERD
4
4
  # This class is an abstract class that will process a domain model and
5
5
  # allows easy creation of diagrams. To implement a new diagram type, derive
6
- # from this class and override +process_entity+, +process_relationship+,
6
+ # from this class and override +process_entity+, +process_relationship+,
7
7
  # and (optionally) +save+.
8
8
  #
9
9
  # As an example, a diagram class that generates code that can be used with
@@ -73,13 +73,13 @@ module RailsERD
73
73
  def create(options = {})
74
74
  new(Domain.generate(options), options).create
75
75
  end
76
-
76
+
77
77
  protected
78
-
78
+
79
79
  def setup(&block)
80
80
  callbacks[:setup] = block
81
81
  end
82
-
82
+
83
83
  def each_entity(&block)
84
84
  callbacks[:each_entity] = block
85
85
  end
@@ -91,7 +91,7 @@ module RailsERD
91
91
  def each_specialization(&block)
92
92
  callbacks[:each_specialization] = block
93
93
  end
94
-
94
+
95
95
  def save(&block)
96
96
  callbacks[:save] = block
97
97
  end
@@ -105,7 +105,7 @@ module RailsERD
105
105
 
106
106
  # The options that are used to create this diagram.
107
107
  attr_reader :options
108
-
108
+
109
109
  # The domain that this diagram represents.
110
110
  attr_reader :domain
111
111
 
@@ -113,13 +113,13 @@ module RailsERD
113
113
  def initialize(domain, options = {})
114
114
  @domain, @options = domain, RailsERD.options.merge(options)
115
115
  end
116
-
116
+
117
117
  # Generates and saves the diagram, returning the result of +save+.
118
118
  def create
119
119
  generate
120
120
  save
121
121
  end
122
-
122
+
123
123
  # Generates the diagram, but does not save the output. It is called
124
124
  # internally by Diagram#create.
125
125
  def generate
@@ -137,19 +137,21 @@ module RailsERD
137
137
  instance_exec relationship, &callbacks[:each_relationship]
138
138
  end
139
139
  end
140
-
140
+
141
141
  def save
142
142
  instance_eval &callbacks[:save]
143
143
  end
144
-
144
+
145
145
  private
146
-
146
+
147
147
  def callbacks
148
148
  @callbacks ||= self.class.send(:callbacks)
149
149
  end
150
-
150
+
151
151
  def filtered_entities
152
152
  @domain.entities.reject { |entity|
153
+ options.exclude && entity.model && [options.exclude].flatten.include?(entity.name.to_sym) or
154
+ options.only && entity.model && ![options.only].flatten.include?(entity.name.to_sym) or
153
155
  !options.inheritance && entity.specialized? or
154
156
  !options.polymorphism && entity.generalized? or
155
157
  !options.disconnected && entity.disconnected?
@@ -157,20 +159,20 @@ module RailsERD
157
159
  raise "No entities found; create your models first!" if entities.empty?
158
160
  end
159
161
  end
160
-
162
+
161
163
  def filtered_relationships
162
164
  @domain.relationships.reject { |relationship|
163
165
  !options.indirect && relationship.indirect?
164
166
  }
165
167
  end
166
-
168
+
167
169
  def filtered_specializations
168
170
  @domain.specializations.reject { |specialization|
169
171
  !options.inheritance && specialization.inheritance? or
170
172
  !options.polymorphism && specialization.polymorphic?
171
173
  }
172
174
  end
173
-
175
+
174
176
  def filtered_attributes(entity)
175
177
  entity.attributes.reject { |attribute|
176
178
  # Select attributes that satisfy the conditions in the :attributes option.
@@ -178,7 +180,7 @@ module RailsERD
178
180
  [*options.attributes].none? { |type| attribute.send(:"#{type.to_s.chomp('s')}?") }
179
181
  }
180
182
  end
181
-
183
+
182
184
  def warn(message)
183
185
  puts "Warning: #{message}" if options.warn
184
186
  end