schema_plus 0.1.0.pre3 → 0.1.0.pre4

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -6,9 +6,7 @@ SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for
6
6
 
7
7
  For added rails DRYness see also the gems
8
8
  {+schema_associations+}[http://rubygems.org/gems/schema_associations] and
9
- {+schema_validations+}[http://rubygems.org/gems/schema_associations]
10
- <b>IMPORTANT PRERELEASE NOTE: <i>schema_validations is not yet separate
11
- gems, it's currently bundled in here. It's not documented yet though.</i></b>
9
+ {+schema_validations+}[http://rubygems.org/gems/schema_validations]
12
10
 
13
11
  == Compatibility
14
12
 
@@ -127,26 +125,39 @@ ActiveRecord works with views the same as with ordinary tables. That is, for th
127
125
  * Greg Barnett (https://github.com/greg-barnett)
128
126
  * Ronen Barzel (https://github.com/ronen)
129
127
 
130
- * SchemaPlus was created in 2011 by Michal Lomnicki and Ronen Barzel
128
+ * SchemaPlus was created in 2011 by Michał Łomnicki and Ronen Barzel
131
129
 
132
130
 
133
131
 
134
132
  == Testing
135
133
 
136
- SchemaPlus is tested using rspec. To run the tests, after you've forked & cloned: Make sure you have Postgresql and MySQL running. Create database user "schema_plus" with permissions for database "schema_plus_unittest". Then:
134
+ SchemaPlus is tested using rspec and rvm, with some hackery to test against
135
+ multiple versions of rails and ruby and db adapters. To run the tests,
136
+ after you've forked & cloned: Make sure you have Postgresql and MySQL
137
+ running. Create database user "schema_plus" with permissions for database
138
+ "schema_plus_unittest". Then:
137
139
 
138
140
  $ cd schema_plus
139
141
  $ bundle install
140
142
  $ rake postgresql:build_databases
141
143
  $ rake mysql:build_databases
144
+ $ ./runspecs --install # do this once to install gem dependencies for all versions (slow)
145
+ $ ./runspecs # as many times as you like
146
+
147
+ You can also pick a specific version of rails and ruby to use, such as:
148
+ $ rvm use 1.9.2
149
+ $ export SCHEMA_ASSOCIATIONS_RAILS_VERSION=3.1
150
+ $ bundle update --local rails mysql2 # different versions of rails require different mysql2's
151
+ $ rake spec
152
+
153
+ And you can run the specs for a specific adapter:
142
154
  $ rake postgresql:spec # to run postgresql tests only
143
155
  $ rake mysql:spec # to run mysql tests only
144
156
  $ rake mysql2:spec # to run mysql2 tests only
145
157
  $ rake sqlite3:spec # to run sqlite3 tests only
146
- $ rake spec # run all tests
147
158
 
148
159
  If you're running ruby 1.9.2, code coverage results will be in coverage/index.html -- it should be at 100% coverage.
149
160
 
150
161
  == License
151
162
 
152
- This plugin is released under the MIT license.
163
+ This gem is released under the MIT license.
@@ -7,32 +7,18 @@ module SchemaPlus
7
7
  module Base
8
8
  def self.included(base) #:nodoc:
9
9
  base.extend(ClassMethods)
10
- base.extend(SchemaPlus::ActiveRecord::Validations)
11
10
  end
12
11
 
13
12
  module ClassMethods #:nodoc:
14
13
  def self.extended(base) #:nodoc:
15
14
  class << base
16
15
  alias_method_chain :columns, :schema_plus
17
- alias_method_chain :abstract_class?, :schema_plus
18
16
  alias_method_chain :reset_column_information, :schema_plus
19
17
  end
20
18
  end
21
19
 
22
20
  public
23
21
 
24
- # Per-model override of Config options. Use via, e.g.
25
- # class MyModel < ActiveRecord::Base
26
- # schema_plus :associations => { :auto_create => false }
27
- # end
28
- def schema_plus(opts)
29
- @schema_plus_config = SchemaPlus.config.merge(opts)
30
- end
31
-
32
- def abstract_class_with_schema_plus? #:nodoc:
33
- abstract_class_without_schema_plus? || !(name =~ /^Abstract/).nil?
34
- end
35
-
36
22
  def columns_with_schema_plus #:nodoc:
37
23
  unless @schema_plus_extended_columns
38
24
  @schema_plus_extended_columns = true
@@ -69,11 +55,6 @@ module SchemaPlus
69
55
  connection.reverse_foreign_keys(table_name, "#{name} Reverse Foreign Keys")
70
56
  end
71
57
 
72
- private
73
-
74
- def schema_plus_config # :nodoc:
75
- @schema_plus_config ||= SchemaPlus.config.dup
76
- end
77
58
  end
78
59
  end
79
60
  end
@@ -35,6 +35,11 @@ module SchemaPlus
35
35
  adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
36
36
  self.class.send(:include, adapter_module) unless self.class.include?(adapter_module)
37
37
  self.post_initialize if self.respond_to? :post_initialize
38
+ # rails 3.1 defines a separate Mysql2IndexDefinition which is
39
+ # compatible with the monkey patches; but the definition only
40
+ # appears once the adapter is loaded. so wait til now to check
41
+ # if that constant exists, then include the patches
42
+ ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
38
43
  end
39
44
  end
40
45
 
@@ -118,6 +118,7 @@ module SchemaPlus::ActiveRecord::ConnectionAdapters
118
118
  protected
119
119
  def column_index(name, options) #:nodoc:
120
120
  options = {} if options == true
121
+ options = {:unique => true} if options == :unique
121
122
  name = [name] + Array.wrap(options.delete(:with)).compact
122
123
  self.index(name, options)
123
124
  end
@@ -1,11 +1,10 @@
1
1
  module SchemaPlus
2
2
  class Railtie < Rails::Railtie #:nodoc:
3
- config.before_initialize do
4
- SchemaPlus.insert_connection_adapters
5
- end
6
3
 
7
- initializer 'schema_plus.insert', :after => :load_config_initializers do
8
- SchemaPlus.insert
4
+ initializer 'schema_plus.insert', :after => "active_record.initialize_database" do
5
+ ActiveSupport.on_load(:active_record) do
6
+ SchemaPlus.insert
7
+ end
9
8
  end
10
9
 
11
10
  end
@@ -1,3 +1,3 @@
1
1
  module SchemaPlus
2
- VERSION = "0.1.0.pre3"
2
+ VERSION = "0.1.0.pre4"
3
3
  end
data/lib/schema_plus.rb CHANGED
@@ -16,8 +16,6 @@ require 'schema_plus/railtie' if defined?(Rails)
16
16
  module SchemaPlus
17
17
  module ActiveRecord
18
18
 
19
- autoload :Validations, 'schema_plus/active_record/validations'
20
-
21
19
  module ConnectionAdapters
22
20
  autoload :MysqlAdapter, 'schema_plus/active_record/connection_adapters/mysql_adapter'
23
21
  autoload :PostgresqlAdapter, 'schema_plus/active_record/connection_adapters/postgresql_adapter'
@@ -33,7 +31,7 @@ module SchemaPlus
33
31
  # end
34
32
  #
35
33
  # The options are grouped into subsets based on area of functionality.
36
- # See Config::ForeignKeys, Config::Validations
34
+ # See Config::ForeignKeys
37
35
  #
38
36
  class Config < Valuable
39
37
 
@@ -80,56 +78,6 @@ module SchemaPlus
80
78
  end
81
79
  has_value :foreign_keys, :klass => ForeignKeys, :default => ForeignKeys.new
82
80
 
83
- # This set of configuration options control SchemaPlus's automatic
84
- # validations behavior. Set them in
85
- # +config/initializers/schema_plus.rb+ using:
86
- #
87
- # SchemaPlus.setup do |config|
88
- # config.validations.auto_create = ...
89
- # end
90
- #
91
- class Validations < Valuable
92
- ##
93
- # :attr_accessor: auto_create
94
- #
95
- # Whether to automatically create validations based on database constraints.
96
- # Boolean, default is +true+.
97
- has_value :auto_create, :klass => :boolean, :default => true
98
-
99
- ##
100
- # :attr_accessor: only
101
- #
102
- # List of field names to include in automatic validation.
103
- # Value is a single name, and array of names, or +nil+. Default is +nil+.
104
- has_value :only, :default => nil
105
-
106
- ##
107
- # :attr_accessor: except
108
- #
109
- # List of field names to exclude from automatic validation.
110
- # Value is a single name, an array of names, or +nil+. Default is <tt>[:created_at, :updated_at, :created_on, :updated_on]</tt>.
111
- has_value :except, :default => [:created_at, :updated_at, :created_on, :updated_on]
112
-
113
- ##
114
- # :attr_accessor: only_type
115
- #
116
- # List of validation types to exclude from automatic validation.
117
- # Value is a single type, and array of types, or +nil+. Default is +nil+.
118
- # A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
119
- has_value :except_type, :default => nil
120
-
121
- ##
122
- # :attr_accessor: only_type
123
- #
124
- # List of validation types to include in automatic validation.
125
- # Value is a single type, and array of types, or +nil+. Default is +nil+.
126
- # A type is specified as, e.g., +:validates_presence_of+ or simply +:presence+.
127
- has_value :only_type, :default => nil
128
-
129
- end
130
- has_value :validations, :klass => Validations, :default => Validations.new
131
-
132
-
133
81
  def dup #:nodoc:
134
82
  self.class.new(Hash[attributes.collect{ |key, val| [key, Valuable === val ? val.class.new(val.attributes) : val] }])
135
83
  end
@@ -171,8 +119,6 @@ module SchemaPlus
171
119
  ::ActiveRecord::ConnectionAdapters::AbstractAdapter.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::AbstractAdapter)
172
120
  ::ActiveRecord::ConnectionAdapters::Column.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::Column)
173
121
  ::ActiveRecord::ConnectionAdapters::IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition)
174
- # (mysql2 v0.2.7 uses its own IndexDefinition, which is compatible with the monkey patches; so if that constant exists, include the patches
175
- ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::IndexDefinition) if defined? ::ActiveRecord::ConnectionAdapters::Mysql2IndexDefinition
176
122
  ::ActiveRecord::ConnectionAdapters::SchemaStatements.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::SchemaStatements)
177
123
  ::ActiveRecord::ConnectionAdapters::TableDefinition.send(:include, SchemaPlus::ActiveRecord::ConnectionAdapters::TableDefinition)
178
124
  end
data/runspecs ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'optparse'
4
+
5
+ RUBY_VERSIONS = %W[1.8.7 1.9.2]
6
+ RAILS_VERSIONS = %W[3.0 3.1]
7
+
8
+ options = {}
9
+ OptionParser.new do |opts|
10
+ opts.banner = "Usage: #{$0} [options]"
11
+
12
+ opts.on("--install", "Install gem dependencies") do |v|
13
+ options[:install] = v
14
+ end
15
+ end.parse!
16
+
17
+ cmds = if options [:install]
18
+ ['bundle update']
19
+ else
20
+ ['bundle update --local rails mysql2 | egrep "rails|mysql2"', 'rake spec']
21
+ end
22
+
23
+ n = 1
24
+ total = RUBY_VERSIONS.size * RAILS_VERSIONS.size
25
+ RUBY_VERSIONS.each do |ruby|
26
+ RAILS_VERSIONS.each do |rails|
27
+ puts "\n\n*** ruby version #{ruby} - rails version #{rails} [#{n} of #{total}]\n\n"
28
+ n += 1
29
+ allcmds = []
30
+ allcmds << "rvm use #{ruby}"
31
+ allcmds << "export SCHEMA_PLUS_RAILS_VERSION=#{rails}"
32
+ allcmds += cmds
33
+ allcmds << 'exit'
34
+ system %Q{echo '#{allcmds.join(' \n ')}' | bash -i} or abort "aborting #{$0}"
35
+ end
36
+ end
data/schema_plus.gemspec CHANGED
@@ -23,12 +23,21 @@ Gem::Specification.new do |s|
23
23
  s.add_dependency("rails")
24
24
  s.add_dependency("valuable")
25
25
 
26
+ case ENV['SCHEMA_PLUS_RAILS_VERSION']
27
+ when '3.0'
28
+ s.add_development_dependency("rails", "~> 3.0")
29
+ s.add_development_dependency("mysql2", "~> 0.2.6")
30
+ when '3.1'
31
+ s.add_development_dependency("rails", ">= 3.1.0.rc1")
32
+ s.add_development_dependency("mysql2")
33
+ else
34
+ s.add_development_dependency("mysql2")
35
+ end
36
+
26
37
  s.add_development_dependency("rake", "~> 0.8.7")
27
- s.add_development_dependency("rails", ">= 3.1.0.rc1")
28
38
  s.add_development_dependency("rspec")
29
39
  s.add_development_dependency("pg")
30
40
  s.add_development_dependency("mysql")
31
- s.add_development_dependency("mysql2")
32
41
  s.add_development_dependency("sqlite3")
33
42
  s.add_development_dependency("simplecov")
34
43
  s.add_development_dependency("simplecov-gem-adapter")
@@ -0,0 +1,99 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ require 'models/user'
4
+
5
+ describe "Column" do
6
+ let(:migration) { ::ActiveRecord::Migration }
7
+
8
+ context "regarding indexes" do
9
+
10
+ context "if not unique" do
11
+
12
+ before (:each) do
13
+ create_table(User, :login => { :index => true})
14
+ @login = User.columns.find{|column| column.name == "login"}
15
+ end
16
+
17
+ it "should report not unique" do
18
+ @login.should_not be_unique
19
+ end
20
+
21
+ it "should report nil unique scope" do
22
+ create_table(User, :login => { :index => true})
23
+ @login.unique_scope.should be_nil
24
+ end
25
+ end
26
+
27
+ context "if unique single column" do
28
+ before (:each) do
29
+ create_table(User, :login => { :index => :unique})
30
+ @login = User.columns.find{|column| column.name == "login"}
31
+ end
32
+
33
+ it "should report unique" do
34
+ @login.should be_unique
35
+ end
36
+
37
+ it "should report an empty unique scope" do
38
+ @login.unique_scope.should == []
39
+ end
40
+ end
41
+
42
+ context "if unique multicolumn" do
43
+
44
+ before (:each) do
45
+ create_table(User, :first => {}, :middle => {}, :last => { :index => {:with => [:first, :middle], :unique => true}})
46
+ @first = User.columns.find{|column| column.name == "first"}
47
+ @middle = User.columns.find{|column| column.name == "middle"}
48
+ @last = User.columns.find{|column| column.name == "last"}
49
+ end
50
+
51
+ it "should report unique for each" do
52
+ @first.should be_unique
53
+ @middle.should be_unique
54
+ @last.should be_unique
55
+ end
56
+
57
+ it "should report unique scope for each" do
58
+ @first.unique_scope.should =~ %W[middle last]
59
+ @middle.unique_scope.should =~ %W[first last]
60
+ @last.unique_scope.should =~ %W[first middle]
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ context "regarding when it requires a value" do
67
+
68
+ it "not required if the column can be null" do
69
+ create_table(User, :login => { :null => true})
70
+ User.columns.find{|column| column.name == "login"}.required_on.should be_nil
71
+ end
72
+
73
+ it "must have a value on :save if there's no default" do
74
+ create_table(User, :login => { :null => false })
75
+ User.columns.find{|column| column.name == "login"}.required_on.should == :save
76
+ end
77
+
78
+ it "must have a value on :updae if there's default" do
79
+ create_table(User, :login => { :null => false, :default => "foo" })
80
+ User.columns.find{|column| column.name == "login"}.required_on.should == :update
81
+ end
82
+
83
+ end
84
+
85
+
86
+ protected
87
+
88
+ def create_table(model, columns_with_options)
89
+ migration.suppress_messages do
90
+ migration.create_table model.table_name, :force => true do |t|
91
+ columns_with_options.each_pair do |column, options|
92
+ t.send :string, column, options
93
+ end
94
+ end
95
+ model.reset_column_information
96
+ end
97
+ end
98
+
99
+ end
@@ -9,7 +9,7 @@ ActiveRecord::Base.configurations = {
9
9
  :database => 'schema_plus_unittest',
10
10
  :username => 'schema_plus',
11
11
  :encoding => 'utf8',
12
- :socket => '/tmp/mysql.sock',
12
+ #:socket => '/tmp/mysql.sock',
13
13
  :min_messages => 'warning'
14
14
  }
15
15
 
@@ -9,7 +9,7 @@ ActiveRecord::Base.configurations = {
9
9
  :database => 'schema_plus_unittest',
10
10
  :username => 'schema_plus',
11
11
  :encoding => 'utf8',
12
- :socket => '/tmp/mysql.sock',
12
+ #:socket => '/tmp/mysql.sock',
13
13
  :min_messages => 'warning'
14
14
  }
15
15
 
@@ -46,6 +46,15 @@ describe ActiveRecord::Migration do
46
46
  @model.should have_index.on(:state)
47
47
  end
48
48
 
49
+ it "should create a unique index if specified on column" do
50
+ create_table(@model, :state => { :index => {:unique => true} })
51
+ @model.should have_unique_index.on(:state)
52
+ end
53
+ it "should create a unique index if specified on column using shorthand" do
54
+ create_table(@model, :state => { :index => :unique })
55
+ @model.should have_unique_index.on(:state)
56
+ end
57
+
49
58
  it "should create an index if specified explicitly" do
50
59
  create_table_opts(@model, {}, {:state => {}}, {:state => {}})
51
60
  @model.should have_index.on(:state)
@@ -250,6 +259,12 @@ describe ActiveRecord::Migration do
250
259
  end
251
260
  end
252
261
 
262
+ it "should create a unique index if specified by shorthand" do
263
+ add_column(:post_id, :integer, :index => :unique) do
264
+ @model.should have_unique_index.on(:post_id)
265
+ end
266
+ end
267
+
253
268
  it "should allow custom name for index" do
254
269
  index_name = 'comments_post_id_unique_index'
255
270
  add_column(:post_id, :integer, :index => { :unique => true, :name => index_name }) do
metadata CHANGED
@@ -1,8 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schema_plus
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: 6
5
- version: 0.1.0.pre3
4
+ prerelease: true
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ - pre4
10
+ version: 0.1.0.pre4
6
11
  platform: ruby
7
12
  authors:
8
13
  - Ronen Barzel
@@ -11,17 +16,18 @@ autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2011-07-17 00:00:00 -07:00
19
+ date: 2011-07-25 00:00:00 +02:00
15
20
  default_executable:
16
21
  dependencies:
17
22
  - !ruby/object:Gem::Dependency
18
23
  name: rails
19
24
  prerelease: false
20
25
  requirement: &id001 !ruby/object:Gem::Requirement
21
- none: false
22
26
  requirements:
23
27
  - - ">="
24
28
  - !ruby/object:Gem::Version
29
+ segments:
30
+ - 0
25
31
  version: "0"
26
32
  type: :runtime
27
33
  version_requirements: *id001
@@ -29,43 +35,49 @@ dependencies:
29
35
  name: valuable
30
36
  prerelease: false
31
37
  requirement: &id002 !ruby/object:Gem::Requirement
32
- none: false
33
38
  requirements:
34
39
  - - ">="
35
40
  - !ruby/object:Gem::Version
41
+ segments:
42
+ - 0
36
43
  version: "0"
37
44
  type: :runtime
38
45
  version_requirements: *id002
39
46
  - !ruby/object:Gem::Dependency
40
- name: rake
47
+ name: mysql2
41
48
  prerelease: false
42
49
  requirement: &id003 !ruby/object:Gem::Requirement
43
- none: false
44
50
  requirements:
45
- - - ~>
51
+ - - ">="
46
52
  - !ruby/object:Gem::Version
47
- version: 0.8.7
53
+ segments:
54
+ - 0
55
+ version: "0"
48
56
  type: :development
49
57
  version_requirements: *id003
50
58
  - !ruby/object:Gem::Dependency
51
- name: rails
59
+ name: rake
52
60
  prerelease: false
53
61
  requirement: &id004 !ruby/object:Gem::Requirement
54
- none: false
55
62
  requirements:
56
- - - ">="
63
+ - - ~>
57
64
  - !ruby/object:Gem::Version
58
- version: 3.1.0.rc1
65
+ segments:
66
+ - 0
67
+ - 8
68
+ - 7
69
+ version: 0.8.7
59
70
  type: :development
60
71
  version_requirements: *id004
61
72
  - !ruby/object:Gem::Dependency
62
73
  name: rspec
63
74
  prerelease: false
64
75
  requirement: &id005 !ruby/object:Gem::Requirement
65
- none: false
66
76
  requirements:
67
77
  - - ">="
68
78
  - !ruby/object:Gem::Version
79
+ segments:
80
+ - 0
69
81
  version: "0"
70
82
  type: :development
71
83
  version_requirements: *id005
@@ -73,10 +85,11 @@ dependencies:
73
85
  name: pg
74
86
  prerelease: false
75
87
  requirement: &id006 !ruby/object:Gem::Requirement
76
- none: false
77
88
  requirements:
78
89
  - - ">="
79
90
  - !ruby/object:Gem::Version
91
+ segments:
92
+ - 0
80
93
  version: "0"
81
94
  type: :development
82
95
  version_requirements: *id006
@@ -84,68 +97,50 @@ dependencies:
84
97
  name: mysql
85
98
  prerelease: false
86
99
  requirement: &id007 !ruby/object:Gem::Requirement
87
- none: false
88
100
  requirements:
89
101
  - - ">="
90
102
  - !ruby/object:Gem::Version
103
+ segments:
104
+ - 0
91
105
  version: "0"
92
106
  type: :development
93
107
  version_requirements: *id007
94
108
  - !ruby/object:Gem::Dependency
95
- name: mysql2
109
+ name: sqlite3
96
110
  prerelease: false
97
111
  requirement: &id008 !ruby/object:Gem::Requirement
98
- none: false
99
112
  requirements:
100
113
  - - ">="
101
114
  - !ruby/object:Gem::Version
115
+ segments:
116
+ - 0
102
117
  version: "0"
103
118
  type: :development
104
119
  version_requirements: *id008
105
120
  - !ruby/object:Gem::Dependency
106
- name: sqlite3
121
+ name: simplecov
107
122
  prerelease: false
108
123
  requirement: &id009 !ruby/object:Gem::Requirement
109
- none: false
110
124
  requirements:
111
125
  - - ">="
112
126
  - !ruby/object:Gem::Version
127
+ segments:
128
+ - 0
113
129
  version: "0"
114
130
  type: :development
115
131
  version_requirements: *id009
116
132
  - !ruby/object:Gem::Dependency
117
- name: simplecov
133
+ name: simplecov-gem-adapter
118
134
  prerelease: false
119
135
  requirement: &id010 !ruby/object:Gem::Requirement
120
- none: false
121
136
  requirements:
122
137
  - - ">="
123
138
  - !ruby/object:Gem::Version
139
+ segments:
140
+ - 0
124
141
  version: "0"
125
142
  type: :development
126
143
  version_requirements: *id010
127
- - !ruby/object:Gem::Dependency
128
- name: simplecov-gem-adapter
129
- prerelease: false
130
- requirement: &id011 !ruby/object:Gem::Requirement
131
- none: false
132
- requirements:
133
- - - ">="
134
- - !ruby/object:Gem::Version
135
- version: "0"
136
- type: :development
137
- version_requirements: *id011
138
- - !ruby/object:Gem::Dependency
139
- name: ruby-debug19
140
- prerelease: false
141
- requirement: &id012 !ruby/object:Gem::Requirement
142
- none: false
143
- requirements:
144
- - - ">="
145
- - !ruby/object:Gem::Version
146
- version: "0"
147
- type: :development
148
- version_requirements: *id012
149
144
  description: "SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views."
150
145
  email:
151
146
  - ronen@barzel.org
@@ -177,12 +172,11 @@ files:
177
172
  - lib/schema_plus/active_record/migration.rb
178
173
  - lib/schema_plus/active_record/schema.rb
179
174
  - lib/schema_plus/active_record/schema_dumper.rb
180
- - lib/schema_plus/active_record/validations.rb
181
175
  - lib/schema_plus/railtie.rb
182
176
  - lib/schema_plus/version.rb
177
+ - runspecs
183
178
  - schema_plus.gemspec
184
- - schema_plus.gemspec.rails3.0
185
- - schema_plus.gemspec.rails3.1
179
+ - spec/column_spec.rb
186
180
  - spec/connections/mysql/connection.rb
187
181
  - spec/connections/mysql2/connection.rb
188
182
  - spec/connections/postgresql/connection.rb
@@ -207,7 +201,6 @@ files:
207
201
  - spec/support/matchers/have_index.rb
208
202
  - spec/support/matchers/reference.rb
209
203
  - spec/support/reference.rb
210
- - spec/validations_spec.rb
211
204
  - spec/views_spec.rb
212
205
  has_rdoc: true
213
206
  homepage: https://github.com/ronen/schema_plus
@@ -219,48 +212,27 @@ rdoc_options: []
219
212
  require_paths:
220
213
  - lib
221
214
  required_ruby_version: !ruby/object:Gem::Requirement
222
- none: false
223
215
  requirements:
224
216
  - - ">="
225
217
  - !ruby/object:Gem::Version
218
+ segments:
219
+ - 0
226
220
  version: "0"
227
221
  required_rubygems_version: !ruby/object:Gem::Requirement
228
- none: false
229
222
  requirements:
230
223
  - - ">"
231
224
  - !ruby/object:Gem::Version
225
+ segments:
226
+ - 1
227
+ - 3
228
+ - 1
232
229
  version: 1.3.1
233
230
  requirements: []
234
231
 
235
232
  rubyforge_project: schema_plus
236
- rubygems_version: 1.6.2
233
+ rubygems_version: 1.3.6
237
234
  signing_key:
238
235
  specification_version: 3
239
236
  summary: Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views.
240
- test_files:
241
- - spec/connections/mysql/connection.rb
242
- - spec/connections/mysql2/connection.rb
243
- - spec/connections/postgresql/connection.rb
244
- - spec/connections/sqlite3/connection.rb
245
- - spec/foreign_key_definition_spec.rb
246
- - spec/foreign_key_spec.rb
247
- - spec/index_definition_spec.rb
248
- - spec/index_spec.rb
249
- - spec/migration_spec.rb
250
- - spec/models/comment.rb
251
- - spec/models/post.rb
252
- - spec/models/user.rb
253
- - spec/references_spec.rb
254
- - spec/schema/auto_schema.rb
255
- - spec/schema/core_schema.rb
256
- - spec/schema_dumper_spec.rb
257
- - spec/schema_spec.rb
258
- - spec/spec_helper.rb
259
- - spec/support/extensions/active_model.rb
260
- - spec/support/helpers.rb
261
- - spec/support/matchers/automatic_foreign_key_matchers.rb
262
- - spec/support/matchers/have_index.rb
263
- - spec/support/matchers/reference.rb
264
- - spec/support/reference.rb
265
- - spec/validations_spec.rb
266
- - spec/views_spec.rb
237
+ test_files: []
238
+
@@ -1,139 +0,0 @@
1
- module SchemaPlus
2
- module ActiveRecord
3
- module Validations
4
-
5
- def inherited(klass) #:nodoc:
6
- if self == ::ActiveRecord::Base
7
- klass.instance_eval do
8
-
9
- # create a callback to load the validations before validation
10
- # happens. the callback deletes itself after use (just to
11
- # eliminate the callback overhead).
12
- before_validation :load_schema_validations
13
- private
14
- define_method :load_schema_validations do
15
- self.class.send :load_schema_validations
16
- self.class.skip_callback :validation, :before, :load_schema_validations
17
- end
18
- end
19
- end
20
- super
21
- end
22
-
23
- # Adds schema-based validations to model.
24
- # Attributes as well as associations are validated.
25
- # For instance if there is column
26
- #
27
- # <code>email NOT NULL</code>
28
- #
29
- # defined at database-level it will be translated to
30
- #
31
- # <code>validates_presence_of :email</code>
32
- #
33
- # If there is an association named <tt>user</tt>
34
- # based on <tt>user_id NOT NULL</tt> it will be translated to
35
- #
36
- # <code>validates_presence_of :user</code>
37
- #
38
- # Note it uses the name of association (user) not the column name (user_id).
39
- # Only <tt>belongs_to</tt> associations are validated.
40
- #
41
- # This accepts following options:
42
- # * :only - auto-validate only given attributes
43
- # * :except - auto-validate all but given attributes
44
- #
45
- def schema_plus(*) #:nodoc:
46
- super
47
- load_schema_validations
48
- end
49
-
50
- private
51
-
52
- def load_schema_validations #:nodoc:
53
- # Don't bother if: it's already been loaded; the class is abstract; not a base class; or the table doesn't exist
54
- return unless create_schema_validations?
55
-
56
- load_column_validations
57
- load_association_validations
58
- @schema_validations_loaded = true
59
- end
60
-
61
- def load_column_validations #:nodoc:
62
- content_columns.each do |column|
63
- name = column.name.to_sym
64
-
65
- # Data-type validation
66
- if column.type == :integer
67
- validate_logged :validates_numericality_of, name, :allow_nil => true, :only_integer => true
68
- elsif column.number?
69
- validate_logged :validates_numericality_of, name, :allow_nil => true
70
- elsif column.text? && column.limit
71
- validate_logged :validates_length_of, name, :allow_nil => true, :maximum => column.limit
72
- end
73
-
74
- # NOT NULL constraints
75
- if column.required_on
76
- if column.type == :boolean
77
- validate_logged :validates_inclusion_of, name, :in => [true, false], :message => :blank
78
- else
79
- validate_logged :validates_presence_of, name
80
- end
81
- end
82
-
83
- # UNIQUE constraints
84
- add_uniqueness_validation(column) if column.unique?
85
- end
86
- end
87
-
88
- def load_association_validations #:nodoc:
89
- reflect_on_all_associations(:belongs_to).each do |association|
90
- # :primary_key_name was deprecated (noisily) in rails 3.1
91
- foreign_key_method = (association.respond_to? :foreign_key) ? :foreign_key : :primary_key_name
92
- column = columns_hash[association.send(foreign_key_method).to_s]
93
- next unless column
94
-
95
- # NOT NULL constraints
96
- validate_logged :validates_presence_of, association.name if column.required_on
97
-
98
- # UNIQUE constraints
99
- add_uniqueness_validation(column) if column.unique?
100
- end
101
- end
102
-
103
- def add_uniqueness_validation(column) #:nodoc:
104
- scope = column.unique_scope.map(&:to_sym)
105
- condition = :"#{column.name}_changed?"
106
- name = column.name.to_sym
107
- validate_logged :validates_uniqueness_of, name, :scope => scope, :allow_nil => true, :if => condition
108
- end
109
-
110
- def create_schema_validations? #:nodoc:
111
- schema_plus_config.validations.auto_create? && !(@schema_validations_loaded || abstract_class? || name.blank? || !table_exists?)
112
- end
113
-
114
- def validate_logged(method, arg, opts={}) #:nodoc:
115
- if _filter_validation(method, arg)
116
- msg = "SchemaPlus validations: #{self.name}.#{method} #{arg.inspect}"
117
- msg += ", #{opts.inspect[1...-1]}" if opts.any?
118
- logger.info msg
119
- send method, arg, opts
120
- end
121
- end
122
-
123
- def _filter_validation(macro, name) #:nodoc:
124
- config = schema_plus_config.validations
125
- types = [macro]
126
- if match = macro.to_s.match(/^validates_(.*)_of$/)
127
- types << match[1].to_sym
128
- end
129
- return false if config.only and not Array.wrap(config.only).include?(name)
130
- return false if config.except and Array.wrap(config.except).include?(name)
131
- return false if config.only_type and not (Array.wrap(config.only_type) & types).any?
132
- return false if config.except_type and (Array.wrap(config.except_type) & types).any?
133
- return true
134
- end
135
-
136
- end
137
-
138
- end
139
- end
@@ -1,36 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "schema_plus/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "schema_plus"
7
- s.version = SchemaPlus::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Ronen Barzel", "Michał Łomnicki"]
10
- s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
- s.homepage = "https://github.com/ronen/schema_plus"
12
- s.summary = "Enhances ActiveRecord schema mechanism, including more DRY index creation and support for foreign key constraints and views."
13
- s.description = "SchemaPlus is an ActiveRecord extension that provides enhanced capabilities for schema definition and querying, including: enhanced and more DRY index capabilities, support and automation for foreign key constraints, and support for views."
14
-
15
- s.rubyforge_project = "schema_plus"
16
-
17
- s.files = `git ls-files`.split("\n")
18
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
- s.require_paths = ["lib"]
21
-
22
- s.add_dependency("rails")
23
- s.add_dependency("valuable")
24
-
25
- s.add_development_dependency("rake", "~> 0.8.7")
26
- s.add_development_dependency("rails", "~> 3.0")
27
- s.add_development_dependency("rspec")
28
- s.add_development_dependency("pg")
29
- s.add_development_dependency("mysql")
30
- s.add_development_dependency("mysql2", "0.2.6")
31
- s.add_development_dependency("sqlite3")
32
- s.add_development_dependency("simplecov")
33
- s.add_development_dependency("simplecov-gem-adapter")
34
- s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
35
- end
36
-
@@ -1,36 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "schema_plus/version"
4
-
5
- Gem::Specification.new do |s|
6
- s.name = "schema_plus"
7
- s.version = SchemaPlus::VERSION
8
- s.platform = Gem::Platform::RUBY
9
- s.authors = ["Ronen Barzel", "Michał Łomnicki"]
10
- s.email = ["ronen@barzel.org", "michal.lomnicki@gmail.com"]
11
- s.homepage = "https://github.com/ronen/schema_plus"
12
- s.summary = "Provides ActiveRecord support for foreign keys, database defined validations and associations."
13
- s.description = "SchemaPlus is an ActiveRecord extension that provides support for defining foreign keys and indexes in database migrations and schemas, as well as for defining model validations and associations based on the database."
14
-
15
- s.rubyforge_project = "schema_plus"
16
-
17
- s.files = `git ls-files`.split("\n")
18
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
- s.require_paths = ["lib"]
21
-
22
- s.add_dependency("rails")
23
- s.add_dependency("valuable")
24
-
25
- s.add_development_dependency("rake", "~> 0.8.7")
26
- s.add_development_dependency("rails", ">= 3.1.0.rc1")
27
- s.add_development_dependency("rspec")
28
- s.add_development_dependency("pg")
29
- s.add_development_dependency("mysql")
30
- s.add_development_dependency("mysql2")
31
- s.add_development_dependency("sqlite3")
32
- s.add_development_dependency("simplecov")
33
- s.add_development_dependency("simplecov-gem-adapter")
34
- s.add_development_dependency("ruby-debug19") if RUBY_VERSION >= "1.9.2"
35
- end
36
-
@@ -1,292 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
-
3
- describe "Validations" do
4
-
5
- before(:all) do
6
- define_schema
7
- end
8
-
9
- after(:each) do
10
- remove_all_models
11
- end
12
-
13
- context "auto-created" do
14
- before(:each) do
15
- with_auto_validations do
16
- class Article < ActiveRecord::Base ; end
17
-
18
- class Review < ActiveRecord::Base
19
- belongs_to :article
20
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
21
- schema_plus :validations => { :except => :content }
22
- end
23
- end
24
- end
25
-
26
- it "should be valid with valid attributes" do
27
- Article.new(valid_attributes).should be_valid
28
- end
29
-
30
- it "should validate content presence" do
31
- post = Article.new.should have(1).error_on(:content)
32
- end
33
-
34
- it "should check title length" do
35
- Article.new(:title => 'a' * 100).should have(1).error_on(:title)
36
- end
37
-
38
- it "should validate state numericality" do
39
- Article.new(:state => 'unknown').should have(1).error_on(:state)
40
- end
41
-
42
- it "should validate if state is integer" do
43
- Article.new(:state => 1.23).should have(1).error_on(:state)
44
- end
45
-
46
- it "should validate average_mark numericality" do
47
- Article.new(:average_mark => "high").should have(1).error_on(:average_mark)
48
- end
49
-
50
- it "should validate boolean fields" do
51
- Article.new(:active => nil).should have(1).error_on(:active)
52
- end
53
-
54
- it "should validate title uniqueness" do
55
- article1 = Article.create(valid_attributes)
56
- article2 = Article.new(:title => valid_attributes[:title])
57
- article2.should have(1).error_on(:title)
58
- article1.destroy
59
- end
60
-
61
- it "should validate state uniqueness in scope of 'active' value" do
62
- article1 = Article.create(valid_attributes)
63
- article2 = Article.new(valid_attributes.merge(:title => 'SchemaPlus 2.0 released'))
64
- article2.should_not be_valid
65
- article2.toggle(:active)
66
- article2.should be_valid
67
- article1.destroy
68
- end
69
-
70
- it "should validate presence of belongs_to association" do
71
- review = Review.new
72
- review.should have(1).error_on(:article)
73
- end
74
-
75
- it "should validate uniqueness of belongs_to association" do
76
- article = Article.create(valid_attributes)
77
- article.should be_valid
78
- review1 = Review.create(:article => article, :author => 'michal')
79
- review1.should be_valid
80
- review2 = Review.new(:article => article, :author => 'michal')
81
- review2.should have_at_least(1).error_on(:article_id)
82
- end
83
-
84
- it "should validate associations with unmatched column and name" do
85
- Review.new.should have(1).error_on(:news_article)
86
- end
87
-
88
- def valid_attributes
89
- {
90
- :title => 'SchemaPlus released!',
91
- :content => "Database matters. Get full use of it but don't write unecessary code. Get SchemaPlus!",
92
- :state => 3,
93
- :average_mark => 9.78,
94
- :active => true
95
- }
96
- end
97
-
98
- end
99
-
100
- context "auto-created but changed" do
101
- before(:each) do
102
- with_auto_validations do
103
- class Article < ActiveRecord::Base ; end
104
- class Review < ActiveRecord::Base
105
- belongs_to :article
106
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
107
- end
108
- end
109
- too_big_content = 'a' * 1000
110
- @review = Review.new(:content => too_big_content)
111
- end
112
-
113
- it "would normally have an error" do
114
- @review.should have(1).error_on(:content)
115
- @review.should have(1).error_on(:author)
116
- end
117
-
118
- it "shouldn't validate fields passed to :except option" do
119
- Review.schema_plus :validations => { :except => :content }
120
- @review.should have(:no).errors_on(:content)
121
- @review.should have(1).error_on(:author)
122
- end
123
-
124
- it "shouldn't validate types passed to :except_type option using full validation" do
125
- Review.schema_plus :validations => { :except_type => :validates_length_of }
126
- @review.should have(:no).errors_on(:content)
127
- @review.should have(1).error_on(:author)
128
- end
129
-
130
- it "shouldn't validate types passed to :except_type option using shorthand" do
131
- Review.schema_plus :validations => { :except_type => :length }
132
- @review.should have(:no).errors_on(:content)
133
- @review.should have(1).error_on(:author)
134
- end
135
-
136
- it "should only validate type passed to :only_type option" do
137
- Review.schema_plus :validations => { :only_type => :length }
138
- @review.should have(1).error_on(:content)
139
- @review.should have(:no).errors_on(:author)
140
- end
141
-
142
-
143
- it "shouldn't create validations if locally disabled" do
144
- Review.schema_plus :validations => { :auto_create => false }
145
- @review.should have(:no).errors_on(:content)
146
- @review.should have(:no).error_on(:author)
147
- end
148
- end
149
-
150
- context "auto-created disabled" do
151
- around(:each) do |example|
152
- with_auto_validations(false, &example)
153
- end
154
-
155
- before(:each) do
156
- class Article < ActiveRecord::Base ; end
157
-
158
- class Review < ActiveRecord::Base
159
- belongs_to :article
160
- belongs_to :news_article, :class_name => 'Article', :foreign_key => :article_id
161
- end
162
- too_big_content = 'a' * 1000
163
- @review = Review.new(:content => too_big_content)
164
- end
165
-
166
- it "should not create validation" do
167
- @review.should have(:no).errors_on(:content)
168
- end
169
-
170
- it "should create validation if locally enabled" do
171
- Review.schema_plus :validations => { :auto_create => true }
172
- @review.should have(1).error_on(:content)
173
- end
174
-
175
- end
176
-
177
- context "manually invoked" do
178
- before(:each) do
179
- class Article < ActiveRecord::Base ; end
180
- Article.schema_plus :validations => { :only => [:title, :state] }
181
-
182
- class Review < ActiveRecord::Base
183
- belongs_to :dummy_association
184
- schema_plus :validations => { :except => :content }
185
- end
186
- end
187
-
188
- it "should validate fields passed to :only option" do
189
- too_big_title = 'a' * 100
190
- wrong_state = 'unknown'
191
- article = Article.new(:title => too_big_title, :state => wrong_state)
192
- article.should have(1).error_on(:title)
193
- article.should have(1).error_on(:state)
194
- end
195
-
196
- it "shouldn't validate skipped fields" do
197
- article = Article.new
198
- article.should have(:no).errors_on(:content)
199
- article.should have(:no).errors_on(:average_mark)
200
- end
201
-
202
- it "shouldn't validate association on unexisting column" do
203
- Review.new.should have(:no).errors_on(:dummy_association)
204
- end
205
-
206
- it "shouldn't validate fields passed to :except option" do
207
- Review.new.should have(:no).errors_on(:content)
208
- end
209
-
210
- it "should validate all fields but passed to :except option" do
211
- Review.new.should have(1).error_on(:author)
212
- end
213
-
214
- end
215
-
216
- context "manually invoked" do
217
- before(:each) do
218
- class Review < ActiveRecord::Base
219
- belongs_to :article
220
- end
221
- @columns = Review.content_columns.dup
222
- Review.schema_plus :validations => { :only => [:title] }
223
- end
224
-
225
- it "shouldn't validate associations not included in :only option" do
226
- Review.new.should have(:no).errors_on(:article)
227
- end
228
-
229
- it "shouldn't change content columns of the model" do
230
- @columns.should == Review.content_columns
231
- end
232
-
233
- end
234
-
235
- context "when used with STI" do
236
- around(:each) { |example| with_auto_validations(&example) }
237
-
238
- it "should set validations on base class" do
239
- class Review < ActiveRecord::Base ; end
240
- class PremiumReview < Review ; end
241
- PremiumReview.new
242
- Review.new.should have(1).error_on(:author)
243
- end
244
-
245
- it "shouldn't create doubled validations" do
246
- class Review < ActiveRecord::Base ; end
247
- Review.new
248
- class PremiumReview < Review ; end
249
- PremiumReview.new.should have(1).error_on(:author)
250
- end
251
-
252
- end
253
-
254
- protected
255
- def with_auto_validations(value = true)
256
- old_value = SchemaPlus.config.validations.auto_create
257
- begin
258
- SchemaPlus.config.validations.auto_create = value
259
- yield
260
- ensure
261
- SchemaPlus.config.validations.auto_create = old_value
262
- end
263
- end
264
-
265
- def define_schema
266
- ActiveRecord::Migration.suppress_messages do
267
- ActiveRecord::Schema.define do
268
- connection.tables.each do |table| drop_table table end
269
-
270
- create_table :articles, :force => true do |t|
271
- t.string :title, :limit => 50
272
- t.text :content, :null => false
273
- t.integer :state
274
- t.float :average_mark, :null => false
275
- t.boolean :active, :null => false
276
- end
277
- add_index :articles, :title, :unique => true
278
- add_index :articles, [:state, :active], :unique => true
279
-
280
- create_table :reviews, :force => true do |t|
281
- t.integer :article_id, :null => false
282
- t.string :author, :null => false
283
- t.string :content, :limit => 200
284
- t.string :type
285
- end
286
- add_index :reviews, :article_id, :unique => true
287
-
288
- end
289
- end
290
- end
291
-
292
- end