activerecord_mysql_strict 0.0.1 → 0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour
data/README.md CHANGED
@@ -1,3 +1,75 @@
1
1
  # ActiveRecord::MySQL::Strict
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/activerecord_mysql_strict.png)](https://rubygems.org/gems/activerecord_mysql_strict)
4
+
3
5
  `ActiveRecord::MySQL::Strict` adds validations to ActiveRecord models to make sure they do not trigger errors in MySQL strict mode.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'activerecord_mysql_strict'
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ruby
18
+ create_table "events" do |t|
19
+ t.string "name"
20
+ t.text "description"
21
+ t.integer "people_count"
22
+ end
23
+
24
+ class Event < ActiveRecord::Base
25
+ validates_strict_columns
26
+ end
27
+
28
+ # String columns
29
+
30
+ event = Event.new(name: '.' * 400)
31
+ event.valid? # => false
32
+
33
+ event = Event.new(name: '.' * 255)
34
+ event.valid? # => true
35
+
36
+ # Text columns
37
+
38
+ event = Event.new(description: '.' * 70000)
39
+ event.valid? # => false
40
+
41
+ event = Event.new(description: '.' * 65535)
42
+ event.valid? # => true
43
+
44
+ # Integer columns
45
+
46
+ event = Event.new(people_count: 9999999999)
47
+ event.valid? # => false
48
+
49
+ event = Event.new(people_count: 2147483647)
50
+ event.valid? # => true
51
+ ```
52
+
53
+ ### Options
54
+
55
+ You can use a few options when calling `validates_strict_columns`:
56
+
57
+ ```ruby
58
+ class Event < ActiveRecord::Base
59
+ validates_strict_columns, only: [:name]
60
+ end
61
+
62
+ class Event < ActiveRecord::Base
63
+ validates_strict_columns, except: [:people_count]
64
+ end
65
+ ```
66
+
67
+ ## License
68
+
69
+ `ActiveRecord::MySQL::Strict` is © 2013 [Mirego](http://www.mirego.com) and may be freely distributed under the [New BSD license](http://opensource.org/licenses/BSD-3-Clause). See the [`LICENSE.md`](https://github.com/mirego/activerecord_mysql_strict/blob/master/LICENSE.md) file.
70
+
71
+ ## About Mirego
72
+
73
+ Mirego is a team of passionate people who believe that work is a place where you can innovate and have fun. We proudly build mobile applications for [iPhone](http://mirego.com/en/iphone-app-development/ "iPhone application development"), [iPad](http://mirego.com/en/ipad-app-development/ "iPad application development"), [Android](http://mirego.com/en/android-app-development/ "Android application development"), [Blackberry](http://mirego.com/en/blackberry-app-development/ "Blackberry application development"), [Windows Phone](http://mirego.com/en/windows-phone-app-development/ "Windows Phone application development") and [Windows 8](http://mirego.com/en/windows-8-app-development/ "Windows 8 application development") in beautiful Quebec City.
74
+
75
+ We also love [open-source software](http://open.mirego.com/) and we try to extract as much code as possible from our projects to give back to the community.
data/Rakefile CHANGED
@@ -1 +1,11 @@
1
- require "bundler/gem_tasks"
1
+ require 'bundler'
2
+ require 'rake'
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ task default: :spec
7
+
8
+ desc 'Run all specs'
9
+ RSpec::Core::RakeTask.new(:spec) do |task|
10
+ task.pattern = 'spec/**/*_spec.rb'
11
+ end
@@ -22,5 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_dependency 'activesupport', '>= 3.0.0'
23
23
 
24
24
  spec.add_development_dependency 'bundler', '~> 1.3'
25
+ spec.add_development_dependency 'rspec', '~> 2.14'
25
26
  spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'sqlite3'
26
28
  end
@@ -1,5 +1,36 @@
1
1
  module ActiveRecord
2
- module Mixin
3
- # The magic will happen here
2
+ module MySQL
3
+ module Strict
4
+ module Mixin
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ define_mysql_strict_validations
9
+ end
10
+
11
+ module ClassMethods
12
+ def define_mysql_strict_validations
13
+ except = @mysql_strict_options[:except] || []
14
+ model_columns = self.columns.dup.reject { |c| except.include?(c.name.to_sym) }
15
+
16
+ if only = @mysql_strict_options[:only]
17
+ model_columns = model_columns.select { |c| only.include?(c.name.to_sym) }
18
+ end
19
+
20
+ model_columns.select { |c| c.type == :string }.each do |field|
21
+ validates field.name, length: { in: 0..(field.limit || 255) }, allow_blank: true
22
+ end
23
+
24
+ model_columns.select { |c| c.type == :text }.each do |field|
25
+ validates field.name, length: { in: 0..(field.limit || 65535) }, allow_blank: true
26
+ end
27
+
28
+ model_columns.select { |c| c.type == :integer }.each do |field|
29
+ validates field.name, numericality: { greather_than_or_equal_to: -2147483647, less_than_or_equal_to: 2147483647 }, allow_blank: true
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
4
35
  end
5
36
  end
@@ -1,7 +1,7 @@
1
1
  module ActiveRecord
2
2
  module MySQL
3
3
  module Strict
4
- VERSION = '0.0.1'
4
+ VERSION = '0.1'
5
5
  end
6
6
  end
7
7
  end
@@ -0,0 +1,13 @@
1
+ require 'active_record/mysql/strict/version'
2
+
3
+ require 'active_record'
4
+ require 'active_support'
5
+
6
+ require 'active_record/mysql/strict/mixin'
7
+
8
+ class ActiveRecord::Base
9
+ def self.validates_strict_columns(options = {})
10
+ @mysql_strict_options = options
11
+ include ActiveRecord::MySQL::Strict::Mixin
12
+ end
13
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveRecord::MySQL::Strict::Mixin do
4
+ describe :validates_strict_columns do
5
+ context 'for model without other validations' do
6
+ let(:model) { strict_model 'User' }
7
+
8
+ context 'for `string` columns' do
9
+ context 'with field with default limit' do
10
+ before do
11
+ run_migration do
12
+ create_table(:users, force: true) { |t| t.string :name }
13
+ end
14
+ end
15
+
16
+ context 'with field value exceeding limit' do
17
+ subject { model.new(name: '*' * 400) }
18
+ it { should_not be_valid }
19
+ end
20
+
21
+ context 'with field value not exceeding limit' do
22
+ subject { model.new(name: '*' * 100) }
23
+ it { should be_valid }
24
+ end
25
+ end
26
+
27
+ context 'with field with custom limit' do
28
+ before do
29
+ run_migration do
30
+ create_table(:users, force: true) { |t| t.string :name, limit: 128 }
31
+ end
32
+ end
33
+
34
+ context 'with field value exceeding default limit' do
35
+ subject { model.new(name: '*' * 400) }
36
+ it { should_not be_valid }
37
+ end
38
+
39
+ context 'with field value exceeding custom limit' do
40
+ subject { model.new(name: '*' * 140) }
41
+ it { should_not be_valid }
42
+ end
43
+
44
+ context 'with field value not exceeding custom limit' do
45
+ subject { model.new(name: '*' * 120) }
46
+ it { should be_valid }
47
+ end
48
+ end
49
+ end
50
+
51
+ context 'for `text` columns' do
52
+ context 'with field with default limit' do
53
+ before do
54
+ run_migration do
55
+ create_table(:users, force: true) { |t| t.text :bio }
56
+ end
57
+ end
58
+
59
+ context 'with field value exceeding limit' do
60
+ subject { model.new(bio: '*' * 70000) }
61
+ it { should_not be_valid }
62
+ end
63
+
64
+ context 'with field value not exceeding limit' do
65
+ subject { model.new(bio: '*' * 4000) }
66
+ it { should be_valid }
67
+ end
68
+ end
69
+
70
+ context 'with field with custom limit' do
71
+ before do
72
+ run_migration do
73
+ create_table(:users, force: true) { |t| t.text :bio, limit: 10000 }
74
+ end
75
+ end
76
+
77
+ context 'with field value exceeding default limit' do
78
+ subject { model.new(bio: '*' * 70000) }
79
+ it { should_not be_valid }
80
+ end
81
+
82
+ context 'with field value exceeding custom limit' do
83
+ subject { model.new(bio: '*' * 12000) }
84
+ it { should_not be_valid }
85
+ end
86
+
87
+ context 'with field value not exceeding custom limit' do
88
+ subject { model.new(bio: '*' * 4000) }
89
+ it { should be_valid }
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'for `integer` columns' do
95
+ context 'with field with default limit' do
96
+ before do
97
+ run_migration do
98
+ create_table(:users, force: true) { |t| t.integer :number }
99
+ end
100
+ end
101
+
102
+ context 'with field value exceeding limit' do
103
+ subject { model.new(number: 9999999999) }
104
+ it { should_not be_valid }
105
+ end
106
+
107
+ context 'with field value not exceeding limit' do
108
+ subject { model.new(number: 2147483647) }
109
+ it { should be_valid }
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ context 'for model with related validations' do
116
+ context 'for presence validation' do
117
+ let(:model) do
118
+ strict_model 'User' do
119
+ validates :name, presence: true
120
+ end
121
+ end
122
+
123
+ before do
124
+ run_migration do
125
+ create_table(:users, force: true) { |t| t.string :name }
126
+ end
127
+ end
128
+
129
+ subject { model.new.tap(&:valid?) }
130
+ it { expect(subject.errors.full_messages).to eql ["Name can't be blank"] }
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,25 @@
1
+ $:.unshift File.expand_path('../lib', __FILE__)
2
+
3
+ require 'rspec'
4
+ require 'sqlite3'
5
+
6
+ require 'activerecord_mysql_strict'
7
+
8
+ # Require our macros and extensions
9
+ Dir[File.expand_path('../../spec/support/macros/*.rb', __FILE__)].map(&method(:require))
10
+
11
+ RSpec.configure do |config|
12
+ # Include our macros
13
+ config.include DatabaseMacros
14
+ config.include ModelMacros
15
+
16
+ config.before(:each) do
17
+ # Create the SQLite database
18
+ setup_database
19
+ end
20
+
21
+ config.after(:each) do
22
+ # Make sure we remove our test database file
23
+ cleanup_database
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ module DatabaseMacros
2
+ # Run migrations in the test database
3
+ def run_migration(&block)
4
+ # Create a new migration class
5
+ klass = Class.new(ActiveRecord::Migration)
6
+
7
+ # Create a new `up` that executes the argument
8
+ klass.send(:define_method, :up) { self.instance_exec(&block) }
9
+
10
+ # Create a new instance of it and execute its `up` method
11
+ klass.new.up
12
+ end
13
+
14
+ def self.database_file
15
+ @database_file || File.expand_path('../test.db', __FILE__)
16
+ end
17
+
18
+ def setup_database
19
+ # Make sure the test database file is gone
20
+ cleanup_database
21
+
22
+ # Establish the connection
23
+ SQLite3::Database.new FileUtils.touch(DatabaseMacros.database_file).first
24
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: DatabaseMacros.database_file)
25
+
26
+ # Silence everything
27
+ ActiveRecord::Base.logger = ActiveRecord::Migration.verbose = false
28
+ end
29
+
30
+ def cleanup_database
31
+ FileUtils.rm(DatabaseMacros.database_file) if File.exists?(DatabaseMacros.database_file)
32
+ end
33
+ end
@@ -0,0 +1,19 @@
1
+ module ModelMacros
2
+ # Create a new microscope model
3
+ def strict_model(klass_name, options = {}, &block)
4
+ spawn_model klass_name, ActiveRecord::Base do
5
+ validates_strict_columns options
6
+ instance_exec(&block) if block
7
+ end
8
+ end
9
+
10
+ protected
11
+
12
+ # Create a new model class
13
+ def spawn_model(klass_name, parent_klass, &block)
14
+ Object.instance_eval { remove_const klass_name } if Object.const_defined?(klass_name)
15
+ Object.const_set(klass_name, Class.new(parent_klass))
16
+ Object.const_get(klass_name).class_eval(&block) if block_given?
17
+ Object.const_get(klass_name)
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activerecord_mysql_strict
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: '0.1'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -59,6 +59,22 @@ dependencies:
59
59
  - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: '1.3'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: '2.14'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: '2.14'
62
78
  - !ruby/object:Gem::Dependency
63
79
  name: rake
64
80
  requirement: !ruby/object:Gem::Requirement
@@ -75,6 +91,22 @@ dependencies:
75
91
  - - ! '>='
76
92
  - !ruby/object:Gem::Version
77
93
  version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: sqlite3
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
78
110
  description: ActiveRecord::MySQL::Strict adds validations to ActiveRecord models to
79
111
  make sure they do not trigger errors in MySQL strict mode.
80
112
  email:
@@ -84,13 +116,18 @@ extensions: []
84
116
  extra_rdoc_files: []
85
117
  files:
86
118
  - .gitignore
119
+ - .rspec
87
120
  - Gemfile
88
121
  - README.md
89
122
  - Rakefile
90
123
  - activerecord_mysql_strict.gemspec
91
124
  - lib/active_record/mysql/strict/mixin.rb
92
125
  - lib/active_record/mysql/strict/version.rb
93
- - lib/active_record_mysql_strict.rb
126
+ - lib/activerecord_mysql_strict.rb
127
+ - spec/activerecord_mysql_strict/mixin_spec.rb
128
+ - spec/spec_helper.rb
129
+ - spec/support/macros/database_macros.rb
130
+ - spec/support/macros/model_macros.rb
94
131
  homepage: https://github.com/mirego/activerecord_mysql_strict
95
132
  licenses:
96
133
  - BSD 3-Clause
@@ -106,7 +143,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
106
143
  version: '0'
107
144
  segments:
108
145
  - 0
109
- hash: -2992963016304571034
146
+ hash: -412845040514754438
110
147
  required_rubygems_version: !ruby/object:Gem::Requirement
111
148
  none: false
112
149
  requirements:
@@ -115,7 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
115
152
  version: '0'
116
153
  segments:
117
154
  - 0
118
- hash: -2992963016304571034
155
+ hash: -412845040514754438
119
156
  requirements: []
120
157
  rubyforge_project:
121
158
  rubygems_version: 1.8.23
@@ -123,4 +160,8 @@ signing_key:
123
160
  specification_version: 3
124
161
  summary: ActiveRecord::MySQL::Strict adds validations to ActiveRecord models to make
125
162
  sure they do not trigger errors in MySQL strict mode.
126
- test_files: []
163
+ test_files:
164
+ - spec/activerecord_mysql_strict/mixin_spec.rb
165
+ - spec/spec_helper.rb
166
+ - spec/support/macros/database_macros.rb
167
+ - spec/support/macros/model_macros.rb
@@ -1,6 +0,0 @@
1
- require 'active_record/mysql/strict/version'
2
-
3
- require 'active_record'
4
- require 'active_support'
5
-
6
- require 'active_record/mysql/strict/mixin'