schemer 0.0.10 → 0.1.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/README.markdown +46 -17
- data/Rakefile +1 -26
- data/lib/schemer.rb +1 -56
- data/lib/schemer/active_record.rb +83 -0
- data/lib/schemer/sequel.rb +77 -0
- data/lib/schemer/tasks/schemer.rake +29 -5
- data/schemer.gemspec +25 -0
- data/test/{schemer_test.rb → active_record_test.rb} +15 -17
- data/test/sequel_test.rb +98 -0
- data/test/test_helper.rb +14 -0
- metadata +82 -15
- data/LICENSE +0 -19
- data/lib/schemer/migrator.rb +0 -18
- data/rails/init.rb +0 -3
data/README.markdown
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
Schemer
|
2
2
|
=======
|
3
3
|
|
4
|
-
On-the-fly
|
4
|
+
On-the-fly schema changes for very rapid prototyping, for ActiveRecord and
|
5
|
+
Sequel ORMs.
|
5
6
|
|
6
7
|
Description
|
7
8
|
-----------
|
8
9
|
|
9
|
-
Loosely define your schema in your
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
Loosely define your schema in your model and have it created and updated for
|
11
|
+
you without worrying about migrations.
|
12
|
+
|
13
|
+
Useful for when you want to play around with real data handling during
|
14
|
+
prototyping but you really don't care about keeping the data or how it's
|
15
|
+
defined.
|
13
16
|
|
14
17
|
This isn't meant to be a replacement for migrations, it is simply a way to get
|
15
18
|
started on a project quickly while you iron out your data definitions.
|
@@ -19,13 +22,20 @@ warning! Only use this with volatile data! Never attach it to an existing model
|
|
19
22
|
you care about as it will start adding and dropping columns without your
|
20
23
|
consent!
|
21
24
|
|
22
|
-
|
23
|
-
|
25
|
+
Install
|
26
|
+
-------
|
27
|
+
|
28
|
+
$ gem install schemer
|
24
29
|
|
30
|
+
ActiveRecord
|
31
|
+
------------
|
32
|
+
|
33
|
+
require "schemer/active_record"
|
34
|
+
|
25
35
|
class User < ActiveRecord::Base
|
26
36
|
schema :username, :password
|
27
37
|
end
|
28
|
-
|
38
|
+
|
29
39
|
Creates a `users` table if it doesn't exist, complete with `username` and
|
30
40
|
`password` columns the first time the User class is loaded.
|
31
41
|
|
@@ -34,7 +44,7 @@ Need another column to play with?
|
|
34
44
|
class User < ActiveRecord::Base
|
35
45
|
schema :username, :password, :email
|
36
46
|
end
|
37
|
-
|
47
|
+
|
38
48
|
Adds an `email` column the next time `User` class is loaded.
|
39
49
|
|
40
50
|
Want a relationship? (but fear commitment...)
|
@@ -59,13 +69,13 @@ Have a need for a particular type of column?
|
|
59
69
|
schema :name, { :size => :integer }, :description
|
60
70
|
end
|
61
71
|
|
62
|
-
Will create `size` as an `:integer` column so you can take advantage of
|
63
|
-
|
72
|
+
Will create `size` as an `:integer` column so you can take advantage of type
|
73
|
+
loading.
|
64
74
|
|
65
|
-
Feeling more confident and ready to make that big leap to migrations?
|
75
|
+
Feeling more confident and ready to make that big leap to migrations? Run:
|
66
76
|
|
67
77
|
rake schemer:migration
|
68
|
-
|
78
|
+
|
69
79
|
To get:
|
70
80
|
|
71
81
|
Migration from schema declarations in User, Widget
|
@@ -88,15 +98,34 @@ and you're on your way to the big leagues!
|
|
88
98
|
|
89
99
|
**NOTE:** All columns are created as string columns unless type is given.
|
90
100
|
|
91
|
-
|
92
|
-
|
101
|
+
Sequel
|
102
|
+
------
|
103
|
+
|
104
|
+
require "schemer/sequel"
|
105
|
+
|
106
|
+
class Widget < Sequel::Model
|
107
|
+
plugin Schemer::Sequel
|
108
|
+
|
109
|
+
schema :name, { :size => :integer }, :description
|
110
|
+
end
|
111
|
+
|
112
|
+
Usage is as above w/ ActiveRecord
|
113
|
+
|
114
|
+
Test
|
115
|
+
----
|
116
|
+
|
117
|
+
$ rake
|
118
|
+
|
119
|
+
Thanks!
|
120
|
+
-------
|
93
121
|
|
94
|
-
|
122
|
+
Michel Martens ([soveran](http://github.com/soveran)) + Cyril David
|
123
|
+
([cyx](http://github.com/cyx)) for helping with Sequel support.
|
95
124
|
|
96
125
|
License
|
97
126
|
-------
|
98
127
|
|
99
|
-
Copyright (c) 2009 Ben Alavi for Citrusbyte
|
128
|
+
Copyright (c) 2009-2011 Ben Alavi for Citrusbyte
|
100
129
|
|
101
130
|
Permission is hereby granted, free of charge, to any person
|
102
131
|
obtaining a copy of this software and associated documentation
|
data/Rakefile
CHANGED
@@ -1,35 +1,10 @@
|
|
1
1
|
require 'rake'
|
2
|
-
require 'rake/gempackagetask'
|
3
2
|
require 'rake/testtask'
|
4
3
|
require 'rake/clean'
|
5
4
|
|
6
|
-
gem_spec_file = 'schemer.gemspec'
|
7
|
-
|
8
|
-
gem_spec = eval(File.read(gem_spec_file)) rescue nil
|
9
|
-
|
10
5
|
task :default => :test
|
11
6
|
|
12
7
|
Rake::TestTask.new(:test) do |t|
|
13
|
-
t.pattern =
|
8
|
+
t.pattern = "test/**/*_test.rb"
|
14
9
|
t.verbose = false
|
15
10
|
end
|
16
|
-
|
17
|
-
Rake::GemPackageTask.new(gem_spec) do |pkg|
|
18
|
-
pkg.need_zip = false
|
19
|
-
pkg.need_tar = false
|
20
|
-
rm_f FileList['pkg/**/*.*']
|
21
|
-
end if gem_spec
|
22
|
-
|
23
|
-
desc "Generate the gemspec file."
|
24
|
-
task :gemspec do
|
25
|
-
require 'erb'
|
26
|
-
|
27
|
-
File.open(gem_spec_file, 'w') do |f|
|
28
|
-
f.write ERB.new(File.read("#{gem_spec_file}.erb")).result(binding)
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
desc "Builds and installs the gem."
|
33
|
-
task :install => :repackage do
|
34
|
-
`sudo gem install pkg/#{gem_spec.name}-#{gem_spec.version}.gem`
|
35
|
-
end
|
data/lib/schemer.rb
CHANGED
@@ -1,58 +1,3 @@
|
|
1
|
-
require 'activerecord'
|
2
|
-
|
3
1
|
module Schemer
|
4
|
-
|
5
|
-
extend ClassMethods
|
6
|
-
|
7
|
-
class_inheritable_accessor :schema_columns
|
8
|
-
self.schema_columns = {}
|
9
|
-
args.collect{ |a| a.is_a?(Hash) ? a.stringify_keys : { a.to_s => :string } }.each do |column|
|
10
|
-
self.schema_columns.merge!(column)
|
11
|
-
end
|
12
|
-
|
13
|
-
update_schema
|
14
|
-
update_methods
|
15
|
-
end
|
16
|
-
|
17
|
-
module ClassMethods
|
18
|
-
# Columns which we don't touch regardless of not being defined in schema
|
19
|
-
# (and are ignored if they are defined in schema)
|
20
|
-
def protected_columns
|
21
|
-
%w( id )
|
22
|
-
end
|
23
|
-
|
24
|
-
# Create the underlying table for this class
|
25
|
-
def create_table
|
26
|
-
ActiveRecord::Migration.create_table(table_name) do |t|;end;
|
27
|
-
end
|
28
|
-
|
29
|
-
# Update ActiveRecord's automatically generated methods so we don't have to
|
30
|
-
# reload for schema changes to take effect
|
31
|
-
def update_methods
|
32
|
-
generated_methods.each { |method| remove_method(method) }
|
33
|
-
@columns = @column_names = @columns_hash = @generated_methods = nil
|
34
|
-
end
|
35
|
-
|
36
|
-
# Update the underlying schema as defined by schema call
|
37
|
-
def update_schema
|
38
|
-
create_table unless table_exists?
|
39
|
-
|
40
|
-
columns.reject{ |column| protected_columns.include?(column.name) }.each do |column|
|
41
|
-
if !schema_columns.has_key?(column.name)
|
42
|
-
# remove any extraneous columns
|
43
|
-
ActiveRecord::Migration.remove_column(table_name, column.name)
|
44
|
-
elsif column.type != schema_columns[column.name]
|
45
|
-
# change any columns w/ wrong type
|
46
|
-
ActiveRecord::Migration.change_column(table_name, column.name, schema_columns[column.name])
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
# add any missing columns
|
51
|
-
(schema_columns.keys - column_names).each do |column|
|
52
|
-
ActiveRecord::Migration.add_column(table_name, column, schema_columns[column])
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
2
|
+
VERSION="0.1.0"
|
56
3
|
end
|
57
|
-
|
58
|
-
ActiveRecord::Base.extend(Schemer)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require "active_record"
|
2
|
+
|
3
|
+
module Schemer
|
4
|
+
module ActiveRecord
|
5
|
+
def schema(*args)
|
6
|
+
extend ClassMethods
|
7
|
+
|
8
|
+
class_inheritable_accessor :schema_columns
|
9
|
+
self.schema_columns = {}
|
10
|
+
args.collect{ |a| a.is_a?(Hash) ? a.stringify_keys : { a.to_s => :string } }.each do |column|
|
11
|
+
self.schema_columns.merge!(column)
|
12
|
+
end
|
13
|
+
|
14
|
+
update_schema
|
15
|
+
update_methods
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
# Columns which we don't touch regardless of not being defined in schema
|
20
|
+
# (and are ignored if they are defined in schema)
|
21
|
+
def protected_columns
|
22
|
+
%w( id )
|
23
|
+
end
|
24
|
+
|
25
|
+
# Create the underlying table for this class
|
26
|
+
def create_table
|
27
|
+
::ActiveRecord::Migration.suppress_messages do
|
28
|
+
::ActiveRecord::Migration.create_table(table_name) do |t|;end;
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Update ActiveRecord's automatically generated methods so we don't have to
|
33
|
+
# reload for schema changes to take effect
|
34
|
+
def update_methods
|
35
|
+
undefine_attribute_methods
|
36
|
+
@columns = @column_names = @columns_hash = @generated_methods = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Update the underlying schema as defined by schema call
|
40
|
+
def update_schema
|
41
|
+
create_table unless table_exists?
|
42
|
+
|
43
|
+
columns.reject{ |column| protected_columns.include?(column.name) }.each do |column|
|
44
|
+
if !schema_columns.has_key?(column.name)
|
45
|
+
# remove any extraneous columns
|
46
|
+
migrate_quietly{ ::ActiveRecord::Migration.remove_column(table_name, column.name) }
|
47
|
+
elsif column.type != schema_columns[column.name]
|
48
|
+
# change any columns w/ wrong type
|
49
|
+
migrate_quietly{ ::ActiveRecord::Migration.change_column(table_name, column.name, schema_columns[column.name]) }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# add any missing columns
|
54
|
+
(schema_columns.keys - column_names).each do |column|
|
55
|
+
migrate_quietly{ ::ActiveRecord::Migration.add_column(table_name, column, schema_columns[column]) }
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def migrate_quietly(&block)
|
60
|
+
::ActiveRecord::Migration.suppress_messages do
|
61
|
+
yield
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class Migrator
|
67
|
+
# Outputs the Rails migration for the schema defined in the given class.
|
68
|
+
#
|
69
|
+
# Outputs an empty string if no schema is defined on the class.
|
70
|
+
def self.migration(klass)
|
71
|
+
return nil unless klass.respond_to?(:schema_columns)
|
72
|
+
|
73
|
+
"create_table :#{klass.table_name} do |t|\n" +
|
74
|
+
(klass.schema_columns.keys - klass.protected_columns).collect do |column|
|
75
|
+
" t.#{klass.schema_columns[column]} :#{column}"
|
76
|
+
end.join("\n") +
|
77
|
+
"\nend"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
ActiveRecord::Base.extend(Schemer::ActiveRecord)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require "sequel"
|
2
|
+
|
3
|
+
module Schemer
|
4
|
+
module Sequel
|
5
|
+
module ClassMethods
|
6
|
+
# TODO: document
|
7
|
+
def schema(*args)
|
8
|
+
@schema_columns = {}
|
9
|
+
|
10
|
+
args.collect{ |a| a.is_a?(Hash) ? a : { a => String } }.each do |column|
|
11
|
+
self.schema_columns.merge!(column)
|
12
|
+
end
|
13
|
+
|
14
|
+
update_schema
|
15
|
+
end
|
16
|
+
|
17
|
+
def protected_columns
|
18
|
+
@protected_columns = [ :id ].freeze
|
19
|
+
end
|
20
|
+
|
21
|
+
def schema_columns
|
22
|
+
@schema_columns
|
23
|
+
end
|
24
|
+
|
25
|
+
# Update ActiveRecord's automatically generated methods so we don't have to
|
26
|
+
# reload for schema changes to take effect
|
27
|
+
def update_methods
|
28
|
+
# undefine_attribute_methods
|
29
|
+
# @columns = @column_names = @columns_hash = @generated_methods = nil
|
30
|
+
end
|
31
|
+
|
32
|
+
# Update the underlying schema as defined by schema call
|
33
|
+
def update_schema
|
34
|
+
db.create_table?(self.table_name) do
|
35
|
+
primary_key :id
|
36
|
+
end
|
37
|
+
|
38
|
+
get_db_schema.reject{ |column, definition| protected_columns.include?(column) }.each do |column, definition|
|
39
|
+
if !schema_columns.has_key?(column)
|
40
|
+
# remove any extraneous columns
|
41
|
+
db.drop_column(table_name, column)
|
42
|
+
|
43
|
+
# remove the accessors (sequel doesn't appear to have a facility
|
44
|
+
# for this)
|
45
|
+
[ "#{column}", "#{column}=" ].each do |method|
|
46
|
+
overridable_methods_module.send(:undef_method, method) if public_instance_methods.include?(method)
|
47
|
+
end
|
48
|
+
elsif (definition[:type] || definition[:db_type]) != schema_columns[column]
|
49
|
+
# change any columns w/ wrong type
|
50
|
+
db.set_column_type(table_name, column, schema_columns[column])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# add any missing columns
|
55
|
+
(schema_columns.keys - columns).each do |column|
|
56
|
+
db.add_column(table_name, column, schema_columns[column])
|
57
|
+
def_column_accessor column
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Migrator
|
63
|
+
# Outputs the Rails migration for the schema defined in the given class.
|
64
|
+
#
|
65
|
+
# Outputs an empty string if no schema is defined on the class.
|
66
|
+
def self.migration(klass)
|
67
|
+
return nil unless klass.respond_to?(:schema_columns)
|
68
|
+
|
69
|
+
"create_table :#{klass.table_name} do |t|\n" +
|
70
|
+
(klass.schema_columns.keys - klass::protected_columns).collect do |column|
|
71
|
+
" add_column :#{column}, " + (klass.schema_columns[column].is_a?(Symbol) ? ":#{klass.schema_columns[column]}" : klass.schema_columns[column].to_s)
|
72
|
+
end.join("\n") +
|
73
|
+
"\nend"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -1,9 +1,8 @@
|
|
1
1
|
namespace :schemer do
|
2
|
-
|
3
|
-
task :migration => :environment do
|
2
|
+
def migrations_for(glob, migrator)
|
4
3
|
klasses = []
|
5
|
-
|
6
|
-
Dir.glob(
|
4
|
+
|
5
|
+
Dir.glob(glob).each do |file|
|
7
6
|
lineno = 0
|
8
7
|
result = File.readlines(file).each do |line|
|
9
8
|
lineno += 1
|
@@ -13,10 +12,35 @@ namespace :schemer do
|
|
13
12
|
end
|
14
13
|
|
15
14
|
migration = klasses.collect do |klass|
|
16
|
-
|
15
|
+
migrator.migration(klass)
|
17
16
|
end.join("\n\n")
|
18
17
|
|
19
18
|
puts "\nMigration from schema declarations in #{klasses.join(', ')}"
|
20
19
|
puts "\n#{migration}\n\n"
|
21
20
|
end
|
21
|
+
|
22
|
+
namespace :rails do
|
23
|
+
desc "Outputs a Rails migration from your schema declarations"
|
24
|
+
task :migration => :environment do
|
25
|
+
migrations_for File.join(Rails.root, "app", "models", "**.rb"), Schemer::ActiveRecord::Migrator
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
namespace :activerecord do
|
30
|
+
desc "Outputs an ActiveRecord migration from your schema declarations"
|
31
|
+
task :migration do
|
32
|
+
raise ArgumentError.new("Must provide path to your models on ENV[\"MODELS\"], i.e. rake schemer:activerecord:migration MODELS=./app/models/") unless ENV["MODELS"]
|
33
|
+
|
34
|
+
migrations_for File.join(ENV["MODELS"], "**.rb"), Schemer::ActiveRecord::Migrator
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
namespace :sequel do
|
39
|
+
desc "Output a Sequel migration from your schema declarations"
|
40
|
+
task :migration do
|
41
|
+
raise ArgumentError.new("Must provide path to your models on ENV[\"MODELS\"], i.e. rake schemer:sequel:migration MODELS=./app/models/") unless ENV["MODELS"]
|
42
|
+
|
43
|
+
migrations_for File.join(ENV["MODELS"], "**.rb"), Schemer::Sequel::Migrator
|
44
|
+
end
|
45
|
+
end
|
22
46
|
end
|
data/schemer.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require "./lib/schemer"
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = "schemer"
|
5
|
+
s.version = Schemer::VERSION
|
6
|
+
s.summary = %{On-the-fly schema changes for extremely rapid prototyping.}
|
7
|
+
s.date = %q{2011-08-30}
|
8
|
+
s.authors = ["Ben Alavi"]
|
9
|
+
s.email = "benalavi@gmail.com"
|
10
|
+
s.homepage = "http://github.com/citrusbyte/schemer"
|
11
|
+
|
12
|
+
s.files = Dir[
|
13
|
+
"README.markdown",
|
14
|
+
"Rakefile",
|
15
|
+
"*.gemspec",
|
16
|
+
"lib/**/*.rb",
|
17
|
+
"lib/**/*.rake",
|
18
|
+
"test/**/*.rb"
|
19
|
+
]
|
20
|
+
|
21
|
+
s.add_development_dependency "contest"
|
22
|
+
s.add_development_dependency "sqlite3"
|
23
|
+
s.add_development_dependency "sequel"
|
24
|
+
s.add_development_dependency "active_record"
|
25
|
+
end
|
@@ -1,19 +1,17 @@
|
|
1
|
-
require
|
2
|
-
require 'contest'
|
3
|
-
require 'override'
|
4
|
-
require 'ruby-debug'
|
5
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'schemer')
|
6
|
-
require File.join(File.dirname(__FILE__), '..', 'lib', 'schemer', 'migrator')
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
7
2
|
|
8
|
-
|
9
|
-
ActiveRecord::Base.logger = Logger.new(File.join(File.dirname(__FILE__), "debug.log"))
|
3
|
+
require "schemer/active_record"
|
10
4
|
|
11
|
-
|
12
|
-
ActiveRecord::
|
13
|
-
|
14
|
-
ActiveRecord::Migration.drop_table(Bar.table_name) if Bar.table_exists?
|
5
|
+
logger = Logger.new(File.join(OUTPUT, "debug.log"))
|
6
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => File.join(OUTPUT, "schemer_active_record_test.db")
|
7
|
+
ActiveRecord::Base.logger = logger
|
15
8
|
|
16
|
-
class
|
9
|
+
class ActiveRecordTest < Test::Unit::TestCase
|
10
|
+
class Foo < ActiveRecord::Base;end;
|
11
|
+
ActiveRecord::Migration.drop_table(Foo.table_name) if Foo.table_exists?
|
12
|
+
class Bar < ActiveRecord::Base;end;
|
13
|
+
ActiveRecord::Migration.drop_table(Bar.table_name) if Bar.table_exists?
|
14
|
+
|
17
15
|
context "defining the schema" do
|
18
16
|
setup do
|
19
17
|
Foo.schema :foo, :bar
|
@@ -53,7 +51,7 @@ class FooTest < Test::Unit::TestCase
|
|
53
51
|
context "with types" do
|
54
52
|
setup do
|
55
53
|
Foo.schema :foo, { :bar => :integer }, :baz
|
56
|
-
@foo = Foo.find(Foo.create!(:foo =>
|
54
|
+
@foo = Foo.find(Foo.create!(:foo => "5", :bar => 5).id)
|
57
55
|
end
|
58
56
|
|
59
57
|
should "create foo, bar and baz columns" do
|
@@ -67,12 +65,12 @@ class FooTest < Test::Unit::TestCase
|
|
67
65
|
end
|
68
66
|
|
69
67
|
should "create foo column using string datatype" do
|
70
|
-
assert_equal
|
68
|
+
assert_equal "5", @foo.foo
|
71
69
|
end
|
72
70
|
|
73
71
|
should "recreate foo column as integer" do
|
74
72
|
Foo.schema({ :foo => :integer }, { :bar => :integer }, :baz)
|
75
|
-
foo = Foo.find(Foo.create!(:foo =>
|
73
|
+
foo = Foo.find(Foo.create!(:foo => "5", :bar => "5").id)
|
76
74
|
assert_equal 5, foo.foo
|
77
75
|
end
|
78
76
|
end
|
@@ -87,7 +85,7 @@ class FooTest < Test::Unit::TestCase
|
|
87
85
|
%Q{create_table :foos do |t|
|
88
86
|
t.string :foo
|
89
87
|
t.string :bar
|
90
|
-
end}, Schemer::Migrator.migration(Foo)
|
88
|
+
end}, Schemer::ActiveRecord::Migrator.migration(Foo)
|
91
89
|
)
|
92
90
|
end
|
93
91
|
end
|
data/test/sequel_test.rb
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "test_helper")
|
2
|
+
|
3
|
+
require "schemer/sequel"
|
4
|
+
|
5
|
+
$db = Sequel.sqlite(File.join(OUTPUT, "schemer_sequel_test.db"))
|
6
|
+
$db.drop_table(:foos) if $db.table_exists?(:foos)
|
7
|
+
$db.drop_table(:bars) if $db.table_exists?(:bars)
|
8
|
+
|
9
|
+
class SequelTest < Test::Unit::TestCase
|
10
|
+
class Foo < Sequel::Model
|
11
|
+
plugin Schemer::Sequel
|
12
|
+
end
|
13
|
+
|
14
|
+
class Bar < Sequel::Model
|
15
|
+
plugin Schemer::Sequel
|
16
|
+
end
|
17
|
+
|
18
|
+
setup do
|
19
|
+
Foo.schema
|
20
|
+
Bar.schema
|
21
|
+
end
|
22
|
+
|
23
|
+
context "defining the schema" do
|
24
|
+
setup do
|
25
|
+
Foo.schema :foo, :bar
|
26
|
+
end
|
27
|
+
|
28
|
+
should "create the foos table" do
|
29
|
+
assert Foo.db.table_exists?(Foo.table_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "define the columns on the table" do
|
33
|
+
assert_equal :foo, $db.schema(:foos)[1][0]
|
34
|
+
assert_equal :bar, $db.schema(:foos)[2][0]
|
35
|
+
end
|
36
|
+
|
37
|
+
should "refresh the schema on the model" do
|
38
|
+
@foo = Foo.create :foo => "foo", :bar => "bar"
|
39
|
+
|
40
|
+
assert_equal "foo", @foo.foo
|
41
|
+
assert_equal "bar", @foo.bar
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "updating the schema" do
|
46
|
+
setup do
|
47
|
+
Foo.schema :foo, :bar
|
48
|
+
Foo.schema :foo
|
49
|
+
@foo = Foo.new
|
50
|
+
end
|
51
|
+
|
52
|
+
should "remove the bar column" do
|
53
|
+
assert !@foo.respond_to?(:bar)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context "with types" do
|
58
|
+
setup do
|
59
|
+
Foo.schema :foo, { :bar => :integer }, :baz
|
60
|
+
@foo = Foo[Foo.create(:foo => "5", :bar => 5).id]
|
61
|
+
end
|
62
|
+
|
63
|
+
should "create foo, bar and baz columns" do
|
64
|
+
assert @foo.respond_to?(:foo)
|
65
|
+
assert @foo.respond_to?(:bar)
|
66
|
+
assert @foo.respond_to?(:baz)
|
67
|
+
end
|
68
|
+
|
69
|
+
should "create bar column using integer datatype" do
|
70
|
+
assert_equal 5, @foo.bar
|
71
|
+
end
|
72
|
+
|
73
|
+
should "create foo column using string datatype" do
|
74
|
+
assert_equal "5", @foo.foo
|
75
|
+
end
|
76
|
+
|
77
|
+
should "recreate foo column as integer" do
|
78
|
+
Foo.schema({ :foo => :integer }, { :bar => :integer }, :baz)
|
79
|
+
foo = Foo[Foo.create(:foo => "5", :bar => "5").id]
|
80
|
+
assert_equal 5, foo.foo
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "building a migration" do
|
85
|
+
setup do
|
86
|
+
Foo.schema :foo, { :bar => :integer }
|
87
|
+
end
|
88
|
+
|
89
|
+
should "output the migration for Foo" do
|
90
|
+
assert_equal(
|
91
|
+
%Q{create_table :foos do |t|
|
92
|
+
add_column :foo, String
|
93
|
+
add_column :bar, :integer
|
94
|
+
end}, Schemer::Sequel::Migrator.migration(Foo)
|
95
|
+
)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
$: << File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
require "fileutils"
|
5
|
+
require "contest"
|
6
|
+
require "logger"
|
7
|
+
|
8
|
+
begin
|
9
|
+
require "ruby-debug"
|
10
|
+
rescue LoadError
|
11
|
+
end
|
12
|
+
|
13
|
+
OUTPUT = File.join(File.dirname(__FILE__), "out")
|
14
|
+
FileUtils.mkdir_p(OUTPUT)
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schemer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 27
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Ben Alavi
|
@@ -9,12 +15,66 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
13
|
-
|
14
|
-
|
15
|
-
|
18
|
+
date: 2011-08-30 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: contest
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: sqlite3
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: sequel
|
50
|
+
prerelease: false
|
51
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
none: false
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
hash: 3
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
type: :development
|
61
|
+
version_requirements: *id003
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: active_record
|
64
|
+
prerelease: false
|
65
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
type: :development
|
75
|
+
version_requirements: *id004
|
16
76
|
description:
|
17
|
-
email:
|
77
|
+
email: benalavi@gmail.com
|
18
78
|
executables: []
|
19
79
|
|
20
80
|
extensions: []
|
@@ -23,14 +83,15 @@ extra_rdoc_files: []
|
|
23
83
|
|
24
84
|
files:
|
25
85
|
- README.markdown
|
26
|
-
- LICENSE
|
27
86
|
- Rakefile
|
28
|
-
-
|
87
|
+
- schemer.gemspec
|
88
|
+
- lib/schemer/active_record.rb
|
89
|
+
- lib/schemer/sequel.rb
|
29
90
|
- lib/schemer.rb
|
30
91
|
- lib/schemer/tasks/schemer.rake
|
31
|
-
-
|
32
|
-
- test/
|
33
|
-
|
92
|
+
- test/active_record_test.rb
|
93
|
+
- test/sequel_test.rb
|
94
|
+
- test/test_helper.rb
|
34
95
|
homepage: http://github.com/citrusbyte/schemer
|
35
96
|
licenses: []
|
36
97
|
|
@@ -40,23 +101,29 @@ rdoc_options: []
|
|
40
101
|
require_paths:
|
41
102
|
- lib
|
42
103
|
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
43
105
|
requirements:
|
44
106
|
- - ">="
|
45
107
|
- !ruby/object:Gem::Version
|
108
|
+
hash: 3
|
109
|
+
segments:
|
110
|
+
- 0
|
46
111
|
version: "0"
|
47
|
-
version:
|
48
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
49
114
|
requirements:
|
50
115
|
- - ">="
|
51
116
|
- !ruby/object:Gem::Version
|
117
|
+
hash: 3
|
118
|
+
segments:
|
119
|
+
- 0
|
52
120
|
version: "0"
|
53
|
-
version:
|
54
121
|
requirements: []
|
55
122
|
|
56
123
|
rubyforge_project:
|
57
|
-
rubygems_version: 1.
|
124
|
+
rubygems_version: 1.8.9
|
58
125
|
signing_key:
|
59
126
|
specification_version: 3
|
60
|
-
summary: On-the-fly
|
127
|
+
summary: On-the-fly schema changes for extremely rapid prototyping.
|
61
128
|
test_files: []
|
62
129
|
|
data/LICENSE
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
Copyright (c) 2009 Ben Alavi for Citrusbyte
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
of this software and associated documentation files (the "Software"), to deal
|
5
|
-
in the Software without restriction, including without limitation the rights
|
6
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
copies of the Software, and to permit persons to whom the Software is
|
8
|
-
furnished to do so, subject to the following conditions:
|
9
|
-
|
10
|
-
The above copyright notice and this permission notice shall be included in
|
11
|
-
all copies or substantial portions of the Software.
|
12
|
-
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
THE SOFTWARE.
|
data/lib/schemer/migrator.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module Schemer
|
2
|
-
class Migrator
|
3
|
-
class << self
|
4
|
-
# Outputs the Rails migration for the schema defined in the given class.
|
5
|
-
#
|
6
|
-
# Outputs an empty string if no schema is defined on the class.
|
7
|
-
def migration(klass)
|
8
|
-
return nil unless klass.respond_to?(:schema_columns)
|
9
|
-
|
10
|
-
"create_table :#{klass.table_name} do |t|\n" +
|
11
|
-
(klass.schema_columns.keys - klass.protected_columns).collect do |column|
|
12
|
-
" t.#{klass.schema_columns[column]} :#{column}"
|
13
|
-
end.join("\n") +
|
14
|
-
"\nend"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/rails/init.rb
DELETED