context_validations 0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c724b87e632a393002424843cee3cba7ebc3d9a4
4
+ data.tar.gz: dfae41788870a4f868a5788d862ffc9594cc8136
5
+ SHA512:
6
+ metadata.gz: 542d270b429d4a8411881c32d472bbc189fa0edae33d3adc2df2f02691621a9c89f05f94691ca74fa1bebd993f56111820a7f4ec64dc4cecfc800096160513a0
7
+ data.tar.gz: 6a168a33e2603811f8c594d3792df684cc4ba0396faf464ca952b86eeee389c9c8e1dee1206b6c022f076d162d5f104a8fd61d3e29fb281537ec37c9c97adc07
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ bin/*
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ rvm:
2
+ - 1.9.3
3
+ - 2.0.0
4
+
5
+ notifications:
6
+ email:
7
+ - brian@dockyard.com
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in context_validations.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # ContextValidations #
2
+
3
+ [![Build Status](https://secure.travis-ci.org/dockyard/context_validations.png?branch=master)](http://travis-ci.org/dockyard/context_validations)
4
+ [![Dependency Status](https://gemnasium.com/dockyard/context_validations.png?travis)](https://gemnasium.com/dockyard/context_validations)
5
+ [![Code Climate](https://codeclimate.com/github/dockyard/context_validations.png)](https://codeclimate.com/github/dockyard/context_validations)
6
+
7
+ Rails exceptions automatically opened as issues on GitHub
8
+
9
+ ## Looking for help? ##
10
+
11
+ If it is a bug [please open an issue on GitHub](https://github.com/dockyard/context_validations/issues).
12
+
13
+ ## About ##
14
+
15
+ Context based validations for model instances.
16
+
17
+ ## Example ##
18
+
19
+ ```ruby
20
+ class UserController < ApplicationController
21
+ include ContextValidations::Controller
22
+
23
+ def create
24
+ @user = User.new(user_params)
25
+ @user.validations = validations(:create)
26
+
27
+ if @user.save
28
+ # happy path
29
+ else
30
+ # sad path
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def create_validations
37
+ validates :password, :presence => true
38
+ end
39
+
40
+ def base_validations
41
+ validates :first_name, :last_name, :presence => true
42
+ validates :password, :confirmation => true
43
+ validates :email, :uniqueness => true, :format => EmailFormat
44
+ end
45
+ end
46
+
47
+ class User < ActiveRecord::Base
48
+ include ContextValidations::Model
49
+ end
50
+ ```
51
+
52
+ ### Controllers ###
53
+ In the above example we just call `validations` and pass the context. We
54
+ set the result to `#validations=` on the model.
55
+
56
+ While this does introduce some complexity into our controllers it frees
57
+ us from the mental gymnastics of conditional validators and state flags.
58
+
59
+ The corresponding `#{context}_validations` method, in this case
60
+ `create_validations` defines the validations that will be used. Call the
61
+ `#validates` method just like you would in model validations, the API is
62
+ identical.
63
+
64
+ A `#base_validations` method is always called prior to
65
+ `#{context}_validations` that will allow you to group together common
66
+ validations. The result of these methods appends onto a `@validations`
67
+ array.
68
+
69
+ If you are using `Ruby 2.0+` you can use implicit contexts:
70
+
71
+ ```ruby
72
+ def create
73
+ @user = User.new(user_params)
74
+ # Notice we are only calling the #validations method and not passing
75
+ # context. In this example the context is derived from the calling
76
+ # method `create`
77
+ @user.validations = validations
78
+ end
79
+
80
+ private
81
+
82
+ def create_validations
83
+ ...
84
+ end
85
+ ```
86
+
87
+ ### Models ###
88
+ When the `ContextValidations::Model` module is mixed into the module all
89
+ of the validation callbacks are removed from that model.
90
+
91
+ Because we are setting the validations on the instance you should not
92
+ use `ActiveRecord::Base.create` as we do not want to allow the
93
+ validations to be set via mass-assignment. This does introduce an extra
94
+ step in some places but it shouldn't be that big of a deal.
95
+
96
+ ## Authors ##
97
+
98
+ * [Brian Cardarella](http://twitter.com/bcardarella)
99
+
100
+ [We are very thankful for the many contributors](https://github.com/dockyard/context_validations/graphs/contributors)
101
+
102
+ ## Versioning ##
103
+
104
+ This gem follows [Semantic Versioning](http://semver.org)
105
+
106
+ ## Want to help? ##
107
+
108
+ Please do! We are always looking to improve this gem. Please see our
109
+ [Contribution Guidelines](https://github.com/dockyard/context_validations/blob/master/CONTRIBUTING.md)
110
+ on how to properly submit issues and pull requests.
111
+
112
+ ## Legal ##
113
+
114
+ [DockYard](http://dockyard.com), LLC &copy; 2013
115
+
116
+ [@dockyard](http://twitter.com/dockyard)
117
+
118
+ [Licensed under the MIT license](http://www.opensource.org/licenses/mit-license.php)
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new(:test) do |t|
6
+ t.libs << 'lib'
7
+ t.libs << 'test'
8
+ t.pattern = 'test/**/*_test.rb'
9
+ t.verbose = false
10
+ end
11
+
12
+ task :default => :test
@@ -0,0 +1,79 @@
1
+ module ContextValidations::Controller
2
+ # Will build the validations used to assign to a model instance
3
+ #
4
+ # Passing a context will call the `#{context}_validations` method if available
5
+ # `#base_validations` will always be called prior to `#{context}_validations`
6
+ #
7
+ # If you are using Ruby 2.0+ not passing a context will force an implicit context call
8
+ # based upon the calling method name.
9
+ #
10
+ # examples:
11
+ # # Implicit method call will call `#base_validations` then `#create_validations`
12
+ # def create
13
+ # @user.validations = validations
14
+ # end
15
+ #
16
+ # # Will call `#base_validations` then `#create_validations`
17
+ # def other_create
18
+ # @user.validations = validations(:create)
19
+ # end
20
+ #
21
+ # # Will onliy call `#base_validations` because `#update_validations` does not exist
22
+ # def update
23
+ # @user.validations = validations
24
+ # end
25
+ #
26
+ # def create_validations
27
+ # ...
28
+ # end
29
+ #
30
+ # @param [String, Symbol]
31
+ def validations(context = nil)
32
+ if RUBY_VERSION > '2'
33
+ context ||= caller_locations(1, 1).first.label
34
+ end
35
+ @validations = []
36
+ base_validations
37
+ if respond_to?("#{context}_validations")
38
+ send("#{context}_validations")
39
+ end
40
+ @validations
41
+ end
42
+
43
+ # Instance level implementation of `ActiveModel::Validations.validates`
44
+ # Will accept all of the same options as the class-level model versions of the method
45
+ def validates(*attributes)
46
+ defaults = attributes.extract_options!
47
+ validations = defaults.slice!(*_validates_default_keys)
48
+
49
+ attributes.inject(@validations) do |validators, attribute|
50
+ defaults[:attributes] = [attribute]
51
+ validations.each do |key, options|
52
+ key = "#{key.to_s.camelize}Validator"
53
+ klass = key.include?('::') ? key.constantize : "ActiveModel::Validations::#{key}".constantize
54
+ validator = klass.new(defaults.merge(_parse_validates_options(options)))
55
+ validators << validator
56
+ end
57
+ validators
58
+ end.flatten.uniq
59
+ end
60
+
61
+ private
62
+
63
+ def _validates_default_keys
64
+ [:if, :unless, :on, :allow_blank, :allow_nil , :strict]
65
+ end
66
+
67
+ def _parse_validates_options(options)
68
+ case options
69
+ when TrueClass
70
+ {}
71
+ when Hash
72
+ options
73
+ when Range, Array
74
+ { :in => options }
75
+ else
76
+ { :with => options }
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,36 @@
1
+ module ContextValidations::Model
2
+ def self.included(base)
3
+ base.class_eval do
4
+ reset_callbacks(:validate)
5
+ end
6
+
7
+ base._validators.keys.each do |key|
8
+ base._validators.delete(key)
9
+ end
10
+ end
11
+
12
+ # The collection of validations assigned to this model instance
13
+ #
14
+ # @return [Array]
15
+ def validations
16
+ @validations ||= []
17
+ end
18
+
19
+ # Use to set the validations collection assigned to this model instance
20
+ #
21
+ # Pass an array of validator instances
22
+ #
23
+ # @param [[ActiveMode::Validations::Validator]]
24
+ def validations=(validations)
25
+ @validations = validations.flatten
26
+ end
27
+
28
+ protected
29
+
30
+ def run_validations!
31
+ Array.wrap(validations).each do |validator|
32
+ validator.validate(self)
33
+ end
34
+ errors.empty?
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module ContextValidations
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,9 @@
1
+ require 'context_validations/version'
2
+ require 'active_support'
3
+
4
+ module ContextValidations
5
+ extend ActiveSupport::Autoload
6
+
7
+ autoload :Controller
8
+ autoload :Model
9
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'context_validations/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'context_validations'
8
+ spec.version = ContextValidations::VERSION
9
+ spec.authors = ['Brian Cardarella']
10
+ spec.email = ['bcardarella@gmail.com']
11
+ spec.description = %q{Context based validations for ActiveRecord models}
12
+ spec.summary = %q{Context based validations for ActiveRecord models}
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files`.split($/)
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ['lib']
18
+
19
+ spec.add_dependency 'activesupport'
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'minitest'
24
+ spec.add_development_dependency 'm'
25
+ spec.add_development_dependency 'activemodel'
26
+ end
@@ -0,0 +1,45 @@
1
+ require 'test_helper'
2
+
3
+ class UsersController
4
+ include ContextValidations::Controller
5
+
6
+ def create
7
+ validations
8
+ end
9
+
10
+ def other_create
11
+ validations(:create)
12
+ end
13
+
14
+ def update
15
+ validations
16
+ end
17
+
18
+ def base_validations
19
+ validates :first_name, :presence => true
20
+ end
21
+
22
+ def create_validations
23
+ validates :password, :presence => true
24
+ end
25
+ end
26
+
27
+ describe 'Controller' do
28
+ before do
29
+ @controller = UsersController.new
30
+ end
31
+
32
+ if RUBY_VERSION >= '2'
33
+ it 'combines base and create validations for create action, context is implied' do
34
+ @controller.create.length.must_equal 2
35
+ end
36
+ end
37
+
38
+ it 'combines base and create validations for other create action, context is forced' do
39
+ @controller.other_create.length.must_equal 2
40
+ end
41
+
42
+ it 'uses base validations when context validations are not set for update action' do
43
+ @controller.update.length.must_equal 1
44
+ end
45
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+ require 'active_model'
3
+
4
+ EmailFormat = /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/
5
+
6
+ class User
7
+ include ActiveModel::Validations
8
+ include ContextValidations::Model
9
+ attr_accessor :first_name, :email
10
+
11
+ validates :first_name, :presence => true
12
+ validates :email, :format => EmailFormat
13
+ end
14
+
15
+ describe 'Model' do
16
+ before do
17
+ @user = User.new
18
+ end
19
+
20
+ it 'ignores existing validations' do
21
+ @user.valid?.must_equal true
22
+ end
23
+
24
+ it 'accepts validations set onto the instance' do
25
+ validations = [ActiveModel::Validations::PresenceValidator.new(:attributes => [:first_name]), ActiveModel::Validations::FormatValidator.new(:attributes => [:email], :with => EmailFormat)]
26
+ @user.validations = validations
27
+ @user.valid?.must_equal false
28
+ @user.errors.count.must_equal 2
29
+ end
30
+ end
@@ -0,0 +1,15 @@
1
+ require 'bundler/setup'
2
+
3
+ if defined?(M)
4
+ require 'minitest/spec'
5
+ else
6
+ require 'minitest/autorun'
7
+ end
8
+
9
+ require 'context_validations'
10
+
11
+ class MiniTest::Spec
12
+ class << self
13
+ alias :context :describe
14
+ end
15
+ end
metadata ADDED
@@ -0,0 +1,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: context_validations
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Brian Cardarella
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-05-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.3'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.3'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: minitest
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: m
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activemodel
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: Context based validations for ActiveRecord models
98
+ email:
99
+ - bcardarella@gmail.com
100
+ executables: []
101
+ extensions: []
102
+ extra_rdoc_files: []
103
+ files:
104
+ - .gitignore
105
+ - .travis.yml
106
+ - Gemfile
107
+ - README.md
108
+ - Rakefile
109
+ - lib/context_validations.rb
110
+ - lib/context_validations/controller.rb
111
+ - lib/context_validations/model.rb
112
+ - lib/context_validations/version.rb
113
+ - strong_validations.gemspec
114
+ - test/controller_test.rb
115
+ - test/model_test.rb
116
+ - test/test_helper.rb
117
+ homepage:
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - '>='
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - '>='
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.0.3
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Context based validations for ActiveRecord models
141
+ test_files:
142
+ - test/controller_test.rb
143
+ - test/model_test.rb
144
+ - test/test_helper.rb