activerecord_mysql_strict 0.0.1 → 0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.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'