geert 0.0.1
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 +5 -0
- data/.gitignore +21 -0
- data/README.rdoc +87 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/bin/geert +3 -0
- data/geert.gemspec +64 -0
- data/lib/geert/association.rb +49 -0
- data/lib/geert/cli.rb +53 -0
- data/lib/geert/model.rb +39 -0
- data/lib/geert/project.rb +32 -0
- data/lib/geert.rb +11 -0
- data/sample-erd.png +0 -0
- data/spec/geert_spec.rb +7 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +9 -0
- metadata +90 -0
data/.document
ADDED
data/.gitignore
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
= Geert: "Geert's an Enterprise Entity Relation Tracker"
|
2
|
+
|
3
|
+
Find missing foreign keys in ActiveRecord and create a migration to add them.
|
4
|
+
|
5
|
+
== Usage
|
6
|
+
|
7
|
+
Go to your Rails application and type the command:
|
8
|
+
|
9
|
+
geert
|
10
|
+
|
11
|
+
And you'll get all the possible migrations you can have for your application.
|
12
|
+
Run "geert -h" for all possible options.
|
13
|
+
|
14
|
+
== A note of caution
|
15
|
+
|
16
|
+
Foreign key constraints have a real impact on your application. Geert can't
|
17
|
+
always see the difference between the desired and unwanted foreign keys.
|
18
|
+
It does try to get the proper type of constraint (restrict, nullify or delete),
|
19
|
+
but that might not be what you want. A properly tested application will help
|
20
|
+
you.
|
21
|
+
|
22
|
+
== Generating an ERD
|
23
|
+
|
24
|
+
See a sample of the generated ERD here, based on Webistrano:
|
25
|
+
|
26
|
+
http://github.com/finalist/geert/blob/master/sample-erd.png
|
27
|
+
|
28
|
+
Click on raw for full size. Can't link directly, because github will show
|
29
|
+
it directly, which is rather awkward.
|
30
|
+
|
31
|
+
If you run on a Mac, this is really easy. You'll might have to sacrifice a
|
32
|
+
database for it, and you'll need at least graphviz and Sequel Pro.
|
33
|
+
|
34
|
+
* Run geert
|
35
|
+
* Migrate your database, apply all foreign keys for the best effect.
|
36
|
+
* Open the database in Sequel Pro
|
37
|
+
* Select: File -> Export -> Graphviz dotfile
|
38
|
+
* Save the dotfile
|
39
|
+
* In the console:
|
40
|
+
|
41
|
+
dot -Tsvg your_database.dot > your_database.svg
|
42
|
+
|
43
|
+
* If you have librsvg installed, you can also generate a png file:
|
44
|
+
|
45
|
+
dot -Tsvg your_database.dot | rsvg-convert -o your_database.png
|
46
|
+
|
47
|
+
You can find these applications here:
|
48
|
+
|
49
|
+
* Sequel Pro: http://sequelpro.com
|
50
|
+
* Graphviz: http://graphviz.org
|
51
|
+
* librsvg: sudo port install librsvg (warning, has a lot of X11 dependencies)
|
52
|
+
|
53
|
+
|
54
|
+
== Installation
|
55
|
+
|
56
|
+
To install geert:
|
57
|
+
|
58
|
+
gem install geert --source http://gemcutter.org
|
59
|
+
|
60
|
+
It requires the foreigner gem as well, so please install that into your
|
61
|
+
project, before running the "geert" command.
|
62
|
+
|
63
|
+
In Rails < 3, edit config/environment.rb:
|
64
|
+
|
65
|
+
config.gem "matthuhiggins-foreigner", :lib => "foreigner", :source => "http://gemcutter.org"
|
66
|
+
|
67
|
+
In Rails 3, edit your Gemfile:
|
68
|
+
|
69
|
+
gem "matthuhiggins-foreigner", :require_as => "foreigner"
|
70
|
+
|
71
|
+
See http://github.com/matthuhiggins/foreigner for more info about foreigner.
|
72
|
+
|
73
|
+
|
74
|
+
== Note on Patches/Pull Requests
|
75
|
+
|
76
|
+
* Fork the project.
|
77
|
+
* Make your feature addition or bug fix.
|
78
|
+
* Add tests for it. This is important so I don't break it in a future version
|
79
|
+
unintentionally.
|
80
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have
|
81
|
+
your own version, that is fine but bump version in a commit by itself I can
|
82
|
+
ignore when I pull)
|
83
|
+
* Send me a pull request. Bonus points for topic branches.
|
84
|
+
|
85
|
+
== Copyright
|
86
|
+
|
87
|
+
Copyright (c) 2009 Iain Hecker. Released under the MIT License.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "geert"
|
8
|
+
gem.summary = %Q{Geert's a Enterprise Entity Relation Tracker}
|
9
|
+
gem.description = %Q{Find foreign keys in ActiveRecord and create a migration to add them}
|
10
|
+
gem.email = "iain@iain.nl"
|
11
|
+
gem.homepage = "http://github.com/finalist/geert"
|
12
|
+
gem.authors = ["Iain Hecker"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
14
|
+
gem.add_runtime_dependency "matthuhiggins-foreigner"
|
15
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
16
|
+
end
|
17
|
+
Jeweler::GemcutterTasks.new
|
18
|
+
rescue LoadError
|
19
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
20
|
+
end
|
21
|
+
|
22
|
+
require 'spec/rake/spectask'
|
23
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
24
|
+
spec.libs << 'lib' << 'spec'
|
25
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
26
|
+
end
|
27
|
+
|
28
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
29
|
+
spec.libs << 'lib' << 'spec'
|
30
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
31
|
+
spec.rcov = true
|
32
|
+
end
|
33
|
+
|
34
|
+
task :spec => :check_dependencies
|
35
|
+
|
36
|
+
task :default => :spec
|
37
|
+
|
38
|
+
require 'rake/rdoctask'
|
39
|
+
Rake::RDocTask.new do |rdoc|
|
40
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
41
|
+
|
42
|
+
rdoc.rdoc_dir = 'rdoc'
|
43
|
+
rdoc.title = "geert #{version}"
|
44
|
+
rdoc.rdoc_files.include('README*')
|
45
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/bin/geert
ADDED
data/geert.gemspec
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{geert}
|
8
|
+
s.version = "0.0.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Iain Hecker"]
|
12
|
+
s.date = %q{2009-11-19}
|
13
|
+
s.default_executable = %q{geert}
|
14
|
+
s.description = %q{Find foreign keys in ActiveRecord and create a migration to add them}
|
15
|
+
s.email = %q{iain@iain.nl}
|
16
|
+
s.executables = ["geert"]
|
17
|
+
s.extra_rdoc_files = [
|
18
|
+
"README.rdoc"
|
19
|
+
]
|
20
|
+
s.files = [
|
21
|
+
".document",
|
22
|
+
".gitignore",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"bin/geert",
|
27
|
+
"geert.gemspec",
|
28
|
+
"lib/geert.rb",
|
29
|
+
"lib/geert/association.rb",
|
30
|
+
"lib/geert/cli.rb",
|
31
|
+
"lib/geert/model.rb",
|
32
|
+
"lib/geert/project.rb",
|
33
|
+
"sample-erd.png",
|
34
|
+
"spec/geert_spec.rb",
|
35
|
+
"spec/spec.opts",
|
36
|
+
"spec/spec_helper.rb"
|
37
|
+
]
|
38
|
+
s.homepage = %q{http://github.com/finalist/geert}
|
39
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
40
|
+
s.require_paths = ["lib"]
|
41
|
+
s.rubygems_version = %q{1.3.5}
|
42
|
+
s.summary = %q{Geert's a Enterprise Entity Relation Tracker}
|
43
|
+
s.test_files = [
|
44
|
+
"spec/geert_spec.rb",
|
45
|
+
"spec/spec_helper.rb"
|
46
|
+
]
|
47
|
+
|
48
|
+
if s.respond_to? :specification_version then
|
49
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
50
|
+
s.specification_version = 3
|
51
|
+
|
52
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
53
|
+
s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
|
54
|
+
s.add_runtime_dependency(%q<matthuhiggins-foreigner>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
57
|
+
s.add_dependency(%q<matthuhiggins-foreigner>, [">= 0"])
|
58
|
+
end
|
59
|
+
else
|
60
|
+
s.add_dependency(%q<rspec>, [">= 1.2.9"])
|
61
|
+
s.add_dependency(%q<matthuhiggins-foreigner>, [">= 0"])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Geert
|
2
|
+
|
3
|
+
class Association
|
4
|
+
|
5
|
+
attr_reader :reflection, :model
|
6
|
+
|
7
|
+
def exclude?
|
8
|
+
polymorphic? or uses_polymorphic?
|
9
|
+
end
|
10
|
+
|
11
|
+
def migration
|
12
|
+
"add_foreign_key :#{source}, :#{target}, #{options_string}" unless exclude?
|
13
|
+
end
|
14
|
+
|
15
|
+
def polymorphic?
|
16
|
+
reflection.options[:polymorphic]
|
17
|
+
end
|
18
|
+
|
19
|
+
def uses_polymorphic?
|
20
|
+
model.associations.select(&:polymorphic?).map(&:column).include?(column)
|
21
|
+
end
|
22
|
+
|
23
|
+
def column
|
24
|
+
reflection.primary_key_name
|
25
|
+
end
|
26
|
+
|
27
|
+
def source
|
28
|
+
model.table_name
|
29
|
+
end
|
30
|
+
|
31
|
+
def target
|
32
|
+
reflection.table_name
|
33
|
+
end
|
34
|
+
|
35
|
+
def options
|
36
|
+
{:column => column}
|
37
|
+
end
|
38
|
+
|
39
|
+
def options_string
|
40
|
+
options.inspect.gsub(/\A\{(.*)\}\z/, '\\1')
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(reflection, model)
|
44
|
+
@reflection, @model = reflection, model
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
data/lib/geert/cli.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require File.dirname(__FILE__) + '/project'
|
3
|
+
|
4
|
+
module Geert
|
5
|
+
|
6
|
+
class CLI
|
7
|
+
|
8
|
+
def self.execute(stdout, arguments=[])
|
9
|
+
|
10
|
+
parser = OptionParser.new do |opts|
|
11
|
+
|
12
|
+
opts.banner = <<-BANNER.gsub(/^ +/,'')
|
13
|
+
Find foreign keys in ActiveRecord and create a migration to add them.
|
14
|
+
|
15
|
+
Go to your Rails directory, or optionally provide the path to it.
|
16
|
+
|
17
|
+
Please remember to read the readme, for further instructions.
|
18
|
+
|
19
|
+
Usage: geert [options] [DIRECTORY]
|
20
|
+
e.g. geert ~/projects/myapp
|
21
|
+
BANNER
|
22
|
+
|
23
|
+
opts.separator ""
|
24
|
+
|
25
|
+
opts.on(nil, "--readme", "Show the Readme.") do
|
26
|
+
stdout.puts File.read(File.dirname(__FILE__) + '/../../README.rdoc')
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-h", "--help", "Show this help message.") do
|
31
|
+
stdout.puts opts
|
32
|
+
exit
|
33
|
+
end
|
34
|
+
|
35
|
+
opts.parse!(arguments)
|
36
|
+
|
37
|
+
directory = arguments[-1] || Dir.pwd
|
38
|
+
|
39
|
+
unless File.exist?(File.join(directory, "config", "environment.rb"))
|
40
|
+
stdout.puts "Error: #{directory} is not a valid Rails application.\n\n"
|
41
|
+
stdout.puts opts; exit
|
42
|
+
end
|
43
|
+
|
44
|
+
require File.dirname(__FILE__) + '/../geert'
|
45
|
+
puts Geert.migration(directory)
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/geert/model.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Geert
|
2
|
+
|
3
|
+
class Model
|
4
|
+
|
5
|
+
attr_reader :model
|
6
|
+
|
7
|
+
def initialize(model)
|
8
|
+
@model = model
|
9
|
+
end
|
10
|
+
|
11
|
+
def usable?
|
12
|
+
activerecord? && reflections.any?
|
13
|
+
end
|
14
|
+
|
15
|
+
def migration
|
16
|
+
associations.map(&:migration).compact.join("\n") if usable?
|
17
|
+
end
|
18
|
+
|
19
|
+
def associations
|
20
|
+
@associations ||= reflections.map { |reflection| Association.new(reflection, self) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def table_name
|
24
|
+
model.table_name
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def activerecord?
|
30
|
+
model.ancestors.include?(ActiveRecord::Base)
|
31
|
+
end
|
32
|
+
|
33
|
+
def reflections
|
34
|
+
@reflection ||= model.reflect_on_all_associations(:belongs_to)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Geert
|
2
|
+
|
3
|
+
class Project
|
4
|
+
|
5
|
+
attr_reader :path
|
6
|
+
|
7
|
+
def initialize(path)
|
8
|
+
@path = path
|
9
|
+
load_rails
|
10
|
+
end
|
11
|
+
|
12
|
+
def migration
|
13
|
+
models.map(&:migration).select(&:present?).join("\n\n")
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def models
|
19
|
+
model_files.map { |file| Model.new(file.camelize.constantize) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_rails
|
23
|
+
require File.join(path, 'config', 'environment')
|
24
|
+
end
|
25
|
+
|
26
|
+
def model_files
|
27
|
+
Dir.glob("#{path}/app/models/*.rb").map { |file| File.basename(file, ".rb") }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/lib/geert.rb
ADDED
data/sample-erd.png
ADDED
Binary file
|
data/spec/geert_spec.rb
ADDED
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: geert
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Iain Hecker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-11-19 00:00:00 +01:00
|
13
|
+
default_executable: geert
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: matthuhiggins-foreigner
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: Find foreign keys in ActiveRecord and create a migration to add them
|
36
|
+
email: iain@iain.nl
|
37
|
+
executables:
|
38
|
+
- geert
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.rdoc
|
43
|
+
files:
|
44
|
+
- .document
|
45
|
+
- .gitignore
|
46
|
+
- README.rdoc
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- bin/geert
|
50
|
+
- geert.gemspec
|
51
|
+
- lib/geert.rb
|
52
|
+
- lib/geert/association.rb
|
53
|
+
- lib/geert/cli.rb
|
54
|
+
- lib/geert/model.rb
|
55
|
+
- lib/geert/project.rb
|
56
|
+
- sample-erd.png
|
57
|
+
- spec/geert_spec.rb
|
58
|
+
- spec/spec.opts
|
59
|
+
- spec/spec_helper.rb
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://github.com/finalist/geert
|
62
|
+
licenses: []
|
63
|
+
|
64
|
+
post_install_message:
|
65
|
+
rdoc_options:
|
66
|
+
- --charset=UTF-8
|
67
|
+
require_paths:
|
68
|
+
- lib
|
69
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0"
|
80
|
+
version:
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.5
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Geert's a Enterprise Entity Relation Tracker
|
88
|
+
test_files:
|
89
|
+
- spec/geert_spec.rb
|
90
|
+
- spec/spec_helper.rb
|