datamappify 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -13,7 +13,6 @@ Brought to you by [Envato](http://envato.com) and [Wuit](http://wuit.com).
13
13
  ### Todo
14
14
 
15
15
  * Add tests
16
- * Remove the dependency of the `auto_migrate` plugin
17
16
  * Possibly refactor `add_index` to be part of the `property` definition (as seen in the [DataMapper](http://datamapper.org/) library)
18
17
 
19
18
  ## Why?
@@ -36,14 +35,15 @@ Basically, it -
36
35
  2. `schema.rb` is automatically updated according to the model properties.
37
36
  3. Automatically 'migrates' the database according to the updated schema file.
38
37
 
39
- ## Dependencies
38
+ ## Installation
40
39
 
41
- To use Datamappify, you will need the following libraries.
40
+ gem install datamappify
42
41
 
43
- * ActiveRecord
44
- * [auto_migrations](http://github.com/pjhyett/auto_migrations)
42
+ Don't forget to include the library in your `Gemfile`:
45
43
 
46
- ## Usages
44
+ gem 'datamappify'
45
+
46
+ ## Usage
47
47
 
48
48
  Here's an example to get you started:
49
49
 
data/Rakefile CHANGED
@@ -4,12 +4,12 @@ begin
4
4
  require 'jeweler'
5
5
  Jeweler::Tasks.new do |s|
6
6
  s.name = "datamappify"
7
- s.version = "0.1.0"
8
7
  s.summary = "Turn ActiveRecord into DataMapper (sort of)!"
9
8
  s.description = "ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches."
10
9
  s.email = "ifredwu@gmail.com"
11
10
  s.homepage = "http://github.com/fredwu/datamappify"
12
11
  s.authors = ["Fred Wu"]
12
+ s.require_paths = ["lib", "vendor/auto_migrations/lib"]
13
13
  s.add_dependency("activerecord")
14
14
  end
15
15
  Jeweler::GemcutterTasks.new
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/datamappify.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{datamappify}
8
- s.version = "0.1.0"
8
+ s.version = "0.2.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Fred Wu"]
12
- s.date = %q{2010-08-04}
12
+ s.date = %q{2010-08-26}
13
13
  s.description = %q{ActiveRecord is without doubt the de facto ORM library for Rails and many Ruby web frameworks. Many developers however, do not like database migrations and prefer to use DSL for data mapping. Datamappify is created with the sole purpose of getting rid of the DB migration headaches.}
14
14
  s.email = %q{ifredwu@gmail.com}
15
15
  s.extra_rdoc_files = [
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
  "MIT-LICENSE",
21
21
  "README.md",
22
22
  "Rakefile",
23
+ "VERSION",
23
24
  "datamappify.gemspec",
24
25
  "lib/datamappify.rb",
25
26
  "lib/datamappify/associations.rb",
@@ -27,13 +28,21 @@ Gem::Specification.new do |s|
27
28
  "lib/datamappify/fake/column.rb",
28
29
  "lib/datamappify/fake/connection.rb",
29
30
  "lib/datamappify/fake/index.rb",
31
+ "lib/datamappify/railtie.rb",
30
32
  "lib/datamappify/resource.rb",
31
33
  "lib/datamappify/schema_dumper.rb",
32
- "lib/tasks/datamappify.rake"
34
+ "lib/tasks/datamappify.rake",
35
+ "vendor/auto_migrations/MIT-LICENSE",
36
+ "vendor/auto_migrations/README",
37
+ "vendor/auto_migrations/Rakefile",
38
+ "vendor/auto_migrations/init.rb",
39
+ "vendor/auto_migrations/lib/auto_migrations.rb",
40
+ "vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake",
41
+ "vendor/auto_migrations/test/auto_migrations_test.rb"
33
42
  ]
34
43
  s.homepage = %q{http://github.com/fredwu/datamappify}
35
44
  s.rdoc_options = ["--charset=UTF-8"]
36
- s.require_paths = ["lib"]
45
+ s.require_paths = ["lib", "vendor/auto_migrations/lib"]
37
46
  s.rubygems_version = %q{1.3.7}
38
47
  s.summary = %q{Turn ActiveRecord into DataMapper (sort of)!}
39
48
 
@@ -0,0 +1,8 @@
1
+ module Datamappify
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load File.expand_path("../../tasks/datamappify.rake", __FILE__)
5
+ load File.expand_path("../../../vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake", __FILE__)
6
+ end
7
+ end
8
+ end
data/lib/datamappify.rb CHANGED
@@ -1,10 +1,12 @@
1
- raise "Please install the AutoMigrations plugin from http://github.com/pjhyett/auto_migrations" unless defined?(AutoMigrations.run)
1
+ raise "ActiveRecord is not present!" unless defined?(ActiveRecord)
2
2
 
3
+ require 'auto_migrations'
3
4
  require 'datamappify/associations'
4
5
  require 'datamappify/collection'
5
6
  require 'datamappify/fake/column'
6
7
  require 'datamappify/fake/connection'
7
8
  require 'datamappify/fake/index'
9
+ require 'datamappify/railtie'
8
10
  require 'datamappify/resource'
9
11
  require 'datamappify/schema_dumper'
10
12
 
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007 PJ Hyett
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,46 @@
1
+ == AutoMigrations
2
+
3
+ Forget migrations, auto-migrate!
4
+
5
+
6
+ == Usage
7
+
8
+ Write out your schema (or use an existing one)
9
+
10
+ $ cat db/schema.rb
11
+
12
+ ActiveRecord::Schema.define do
13
+
14
+ create_table :posts do |t|
15
+ t.string :title
16
+ t.text :body
17
+ t.timestamps
18
+ end
19
+
20
+ end
21
+
22
+ $ rake db:auto:migrate
23
+
24
+ Created posts table
25
+
26
+ ...a few days later
27
+
28
+ $ cat db/schema.rb
29
+
30
+ ActiveRecord::Schema.define do
31
+
32
+ create_table :posts do |t|
33
+ t.string :title
34
+ t.text :content
35
+ t.timestamps
36
+ end
37
+
38
+ end
39
+
40
+ $ rake db:auto:migrate
41
+ -- add_column("posts", :content, :text)
42
+ -> 0.0307s
43
+ -- remove_column("posts", "body")
44
+ -> 0.0311s
45
+
46
+ * PJ Hyett [ pjhyett@gmail.com ]
@@ -0,0 +1,24 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the auto_migrations plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ desc 'Generate documentation for the auto_migrations plugin.'
16
+ Rake::RDocTask.new(:rdoc) do |rdoc|
17
+ files = ['README', 'LICENSE', 'lib/**/*.rb']
18
+ rdoc.rdoc_files.add(files)
19
+ rdoc.main = "README" # page to start on
20
+ rdoc.title = "auto_migrations"
21
+ rdoc.template = File.exists?(t="/Users/chris/ruby/projects/err/rock/template.rb") ? t : "/var/www/rock/template.rb"
22
+ rdoc.rdoc_dir = 'doc' # rdoc output folder
23
+ rdoc.options << '--inline-source'
24
+ end
@@ -0,0 +1,2 @@
1
+ require 'auto_migrations'
2
+ ActiveRecord::Migration.send :include, AutoMigrations
@@ -0,0 +1,178 @@
1
+ module AutoMigrations
2
+
3
+ def self.run
4
+ # Turn off schema_info code for auto-migration
5
+ class << ActiveRecord::Schema
6
+ alias :old_define :define
7
+ attr_accessor :version
8
+ def define(info={}, &block) @version = Time.now.utc.strftime("%Y%m%d%H%M%S"); instance_eval(&block) end
9
+ end
10
+
11
+ load(Rails.root.join('db', 'schema.rb'))
12
+ ActiveRecord::Migration.drop_unused_tables
13
+ ActiveRecord::Migration.drop_unused_indexes
14
+ ActiveRecord::Migration.update_schema_version(ActiveRecord::Schema.version) if ActiveRecord::Schema.version
15
+
16
+ class << ActiveRecord::Schema
17
+ alias :define :old_define
18
+ end
19
+ end
20
+
21
+ def self.schema_to_migration(with_reset = false)
22
+ schema_in = File.read(Rails.root.join("db", "schema.rb"))
23
+ schema_in.gsub!(/#(.)+\n/, '')
24
+ schema_in.sub!(/ActiveRecord::Schema.define(.+)do[ ]?\n/, '')
25
+ schema_in.gsub!(/^/, ' ')
26
+ schema = "class InitialSchema < ActiveRecord::Migration\n def self.up\n"
27
+ schema += " # We're resetting the migrations database...\n" +
28
+ " drop_table :schema_migrations\n" +
29
+ " initialize_schema_migrations_table\n\n" if with_reset
30
+ schema += schema_in
31
+ schema << "\n def self.down\n"
32
+ schema << (ActiveRecord::Base.connection.tables - %w(schema_info schema_migrations)).map do |table|
33
+ " drop_table :#{table}\n"
34
+ end.join
35
+ schema << " end\nend\n"
36
+ migration_file = Rails.root.join("db", "migrate", "001_initial_schema.rb")
37
+ File.open(migration_file, "w") { |f| f << schema }
38
+ puts "Migration created at db/migrate/001_initial_schema.rb"
39
+ end
40
+
41
+ def self.included(base)
42
+ base.extend ClassMethods
43
+ class << base
44
+ cattr_accessor :tables_in_schema, :indexes_in_schema
45
+ self.tables_in_schema, self.indexes_in_schema = [], []
46
+ alias_method_chain :method_missing, :auto_migration
47
+ end
48
+ end
49
+
50
+ module ClassMethods
51
+
52
+ def method_missing_with_auto_migration(method, *args, &block)
53
+ case method
54
+ when :create_table
55
+ auto_create_table(method, *args, &block)
56
+ when :add_index
57
+ auto_add_index(method, *args, &block)
58
+ else
59
+ method_missing_without_auto_migration(method, *args, &block)
60
+ end
61
+ end
62
+
63
+ def auto_create_table(method, *args, &block)
64
+ table_name = args.shift.to_s
65
+ options = args.pop || {}
66
+
67
+ (self.tables_in_schema ||= []) << table_name
68
+
69
+ # Table doesn't exist, create it
70
+ unless ActiveRecord::Base.connection.tables.include?(table_name)
71
+ return method_missing_without_auto_migration(method, *[table_name, options], &block)
72
+ end
73
+
74
+ # Grab database columns
75
+ fields_in_db = ActiveRecord::Base.connection.columns(table_name).inject({}) do |hash, column|
76
+ hash[column.name] = column
77
+ hash
78
+ end
79
+
80
+ # Grab schema columns (lifted from active_record/connection_adapters/abstract/schema_statements.rb)
81
+ table_definition = ActiveRecord::ConnectionAdapters::TableDefinition.new(ActiveRecord::Base.connection)
82
+ primary_key = options[:primary_key] || "id"
83
+ table_definition.primary_key(primary_key) unless options[:id] == false
84
+ yield table_definition
85
+ fields_in_schema = table_definition.columns.inject({}) do |hash, column|
86
+ hash[column.name.to_s] = column
87
+ hash
88
+ end
89
+
90
+ # Add fields to db new to schema
91
+ (fields_in_schema.keys - fields_in_db.keys).each do |field|
92
+ column = fields_in_schema[field]
93
+ options = {:limit => column.limit, :precision => column.precision, :scale => column.scale}
94
+ options[:default] = column.default.to_s if !column.default.nil?
95
+ options[:null] = column.null if !column.null.nil?
96
+ add_column table_name, column.name, column.type.to_sym, options
97
+ end
98
+
99
+ # Remove fields from db no longer in schema
100
+ (fields_in_db.keys - fields_in_schema.keys & fields_in_db.keys).each do |field|
101
+ column = fields_in_db[field]
102
+ remove_column table_name, column.name
103
+ end
104
+
105
+ (fields_in_schema.keys & fields_in_db.keys).each do |field|
106
+ if field != primary_key #ActiveRecord::Base.get_primary_key(table_name)
107
+ changed = false # flag
108
+ new_type = fields_in_schema[field].type.to_sym
109
+ new_attr = {}
110
+
111
+ # First, check if the field type changed
112
+ if fields_in_schema[field].type.to_sym != fields_in_db[field].type.to_sym
113
+ changed = true
114
+ end
115
+
116
+ # Special catch for precision/scale, since *both* must be specified together
117
+ # Always include them in the attr struct, but they'll only get applied if changed = true
118
+ new_attr[:precision] = fields_in_schema[field][:precision]
119
+ new_attr[:scale] = fields_in_schema[field][:scale]
120
+
121
+ # Next, iterate through our extended attributes, looking for any differences
122
+ # This catches stuff like :null, :precision, etc
123
+ fields_in_schema[field].each_pair do |att,value|
124
+ next if att == :type or att == :base or att == :name # special cases
125
+ if !value.nil? && value != fields_in_db[field].send(att)
126
+ new_attr[att] = value
127
+ changed = true
128
+ end
129
+ end
130
+
131
+ # Change the column if applicable
132
+ change_column table_name, field, new_type, new_attr if changed
133
+ end
134
+ end
135
+ end
136
+
137
+ def auto_add_index(method, *args, &block)
138
+ table_name = args.shift.to_s
139
+ fields = Array(args.shift).map(&:to_s)
140
+ options = args.shift
141
+
142
+ index_name = options[:name] if options
143
+ index_name ||= ActiveRecord::Base.connection.index_name(table_name, :column => fields)
144
+
145
+ (self.indexes_in_schema ||= []) << index_name
146
+
147
+ unless ActiveRecord::Base.connection.indexes(table_name).detect { |i| i.name == index_name }
148
+ method_missing_without_auto_migration(method, *[table_name, fields, options], &block)
149
+ end
150
+ end
151
+
152
+ def drop_unused_tables
153
+ (ActiveRecord::Base.connection.tables - tables_in_schema - %w(schema_info schema_migrations)).each do |table|
154
+ drop_table table
155
+ end
156
+ end
157
+
158
+ def drop_unused_indexes
159
+ tables_in_schema.each do |table_name|
160
+ indexes_in_db = ActiveRecord::Base.connection.indexes(table_name).map(&:name)
161
+ (indexes_in_db - indexes_in_schema & indexes_in_db).each do |index_name|
162
+ remove_index table_name, :name => index_name
163
+ end
164
+ end
165
+ end
166
+
167
+ def update_schema_version(version)
168
+ ActiveRecord::Base.connection.update("INSERT INTO schema_migrations VALUES ('#{version}')")
169
+
170
+ schema_file = Rails.root.join("db", "schema.rb")
171
+ schema = File.read(schema_file)
172
+ schema.sub!(/:version => \d+/, ":version => #{version}")
173
+ File.open(schema_file, "w") { |f| f << schema }
174
+ end
175
+
176
+ end
177
+
178
+ end
@@ -0,0 +1,20 @@
1
+ namespace :db do
2
+ namespace :auto do
3
+ desc "Use schema.rb to auto-migrate"
4
+ task :migrate => :environment do
5
+ AutoMigrations.run
6
+ end
7
+ end
8
+
9
+ namespace :schema do
10
+ desc "Create migration from schema.rb"
11
+ task :to_migration => :environment do
12
+ AutoMigrations.schema_to_migration
13
+ end
14
+
15
+ desc "Create migration from schema.rb and reset migrations log"
16
+ task :to_migration_with_reset => :environment do
17
+ AutoMigrations.schema_to_migration(true)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ require 'test/unit'
2
+
3
+ class AutoMigrationsTest < Test::Unit::TestCase
4
+ # Replace this with your real tests.
5
+ def test_this_plugin
6
+ flunk
7
+ end
8
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 0.1.0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Fred Wu
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-04 00:00:00 +10:00
17
+ date: 2010-08-26 00:00:00 +10:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -43,6 +43,7 @@ files:
43
43
  - MIT-LICENSE
44
44
  - README.md
45
45
  - Rakefile
46
+ - VERSION
46
47
  - datamappify.gemspec
47
48
  - lib/datamappify.rb
48
49
  - lib/datamappify/associations.rb
@@ -50,9 +51,17 @@ files:
50
51
  - lib/datamappify/fake/column.rb
51
52
  - lib/datamappify/fake/connection.rb
52
53
  - lib/datamappify/fake/index.rb
54
+ - lib/datamappify/railtie.rb
53
55
  - lib/datamappify/resource.rb
54
56
  - lib/datamappify/schema_dumper.rb
55
57
  - lib/tasks/datamappify.rake
58
+ - vendor/auto_migrations/MIT-LICENSE
59
+ - vendor/auto_migrations/README
60
+ - vendor/auto_migrations/Rakefile
61
+ - vendor/auto_migrations/init.rb
62
+ - vendor/auto_migrations/lib/auto_migrations.rb
63
+ - vendor/auto_migrations/lib/tasks/auto_migrations_tasks.rake
64
+ - vendor/auto_migrations/test/auto_migrations_test.rb
56
65
  has_rdoc: true
57
66
  homepage: http://github.com/fredwu/datamappify
58
67
  licenses: []
@@ -62,6 +71,7 @@ rdoc_options:
62
71
  - --charset=UTF-8
63
72
  require_paths:
64
73
  - lib
74
+ - vendor/auto_migrations/lib
65
75
  required_ruby_version: !ruby/object:Gem::Requirement
66
76
  none: false
67
77
  requirements: