validation_scopes 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.3.1 2011-02-24
2
+
3
+ * Added Rails3 compatibility
4
+
1
5
  == 0.3.0 2009-01-04
2
6
 
3
7
  * Fixed problem with DelegateClass not picking up method definitions that come after the validation_scope block.
@@ -8,4 +12,4 @@
8
12
 
9
13
  == 0.1.0 2009-01-03
10
14
 
11
- * Initial release. Only tested within an app. Probably has lots of bugs. Test suite forthcoming.
15
+ * Initial release. Only tested within an app. Probably has lots of bugs. Test suite forthcoming.
data/README.md CHANGED
@@ -1,43 +1,108 @@
1
1
  # Validation Scopes
2
2
 
3
- This gem adds a simple class method `validation_scope` to `ActiveRecord::Base`. Inside the block you can define validations that don't apply to the life-cycle of the object (ie. they aren't implicitly checked when the object is saved).
3
+ This gem adds a simple class method `validation_scope` to ActiveRecord. This generates a new collection of
4
+ `ActiveRecord::Errors` that can be manipulated independently of the standard `errors`, `valid?` and `save` methods. The
5
+ full power of ActiveRecord validations are preserved in these distinct error collections, including all the macros.
6
+
7
+ For example, in addition to standard errors that prevent an object from being saved to the database, you may want
8
+ a second collection of warnings that you display to the user or otherwise shape the control flow:
4
9
 
5
10
  class Film < ActiveRecord::Base
11
+ validates_presence_of :title # Standard errors
12
+
6
13
  validation_scope :warnings do |s|
7
- s.validates_presence_of :title
14
+ s.validate :ensure_title_is_capitalized
15
+ s.validate { |r| r.warnings.add_to_base("Inline warning") }
16
+ s.validates_presence_of…
17
+ s.validates_inclusion_of…
18
+ s.validates_each…
19
+ s.validates_on_create…
20
+ end
21
+
22
+ def ensure_title_is_capitalized
23
+ warnings.add(:title, "should be capitalized") unless title =~ %r{\A[A-Z]}
8
24
  end
9
25
  end
10
26
 
11
- The generated scope produces 3 helper methods based on the symbol passed to the validation_scope method. Continuing the previous example:
27
+ The generated scope produces 3 helper methods based on the symbol passed to the validation_scope method. Continuing the
28
+ previous example:
12
29
 
13
- film.warnings # analagous to film.errors
30
+ film = Film.new(:title => 'lowercase title')
31
+ film.valid?
32
+ => true
33
+
34
+ film.no_warnings? # analagous to valid?
35
+ => false
36
+
37
+ film.has_warnings? # analagous to invalid?
38
+ => true
39
+
40
+ film.warnings # analagous to film.errors
14
41
  => #<ActiveRecord::Errors>
15
42
 
16
- film.no_warnings? # analagous to film.valid?
43
+ film.warnings.full_messages
44
+ => ["Title should be capitalized", "Inline warning"]
45
+
46
+ film.errors.full_messages
47
+ => []
48
+
49
+ film.save
17
50
  => true
18
51
 
19
- film.has_warnings? # analagous to film.invalid?
20
- => false
52
+ One rough edge at the moment is when you want to use the builtin `error_messages_for` helper in your views. That helper
53
+ does not accept an `ActiveRecord::Errors` object directly. Instead you need to pass it the proxy object that
54
+ `ValidationScopes` creates to encapsulate the generated error set:
21
55
 
22
- All standard `ActiveRecord::Validations` should work.
56
+ error_messages_for :object => film.validation_scope_proxy_for_warnings
57
+
58
+ ## Compatibility
59
+
60
+ Should work for Ruby 1.8 and 1.9, as well as Rails 2.x and 3.x; Battle-tested in the formers.
61
+
62
+ ## Installation
63
+
64
+ The usual:
65
+
66
+ gem install validation_scopes
67
+
68
+ In your Gemfile:
69
+
70
+ gem 'validation_scopes'
71
+
72
+ Or old-school Rails-style, in your environment.rb:
73
+
74
+ config.gem 'validation_scopes'
75
+
76
+ Outside of Rails:
77
+
78
+ require 'validation_scopes'
23
79
 
24
80
 
25
81
  ## Caveats
26
82
 
27
- Due to the use of a proxy DelegateClass to store each additional set of validations, and some heavy meta-programming to tie it all together with a clean API, there are likely to be some unexpected and confusing edge cases. Please let me know if you discover anything wonky. I believe the opacity of the solution is worth the convenience it provides in exposing the entirety of the Validations API.
83
+ Due to the use of a proxy DelegateClass to store each additional set of validations, and some heavy meta-programming to
84
+ tie it all together with a clean API, there are likely to be some weird edge cases. Please let me know if you discover
85
+ anything wonky. I believe the opacity of the solution is worth the convenience it provides in exposing the entirety of
86
+ the Validations API.
28
87
 
29
88
  ### Don't use private methods
30
89
 
31
- Because the any validation method supplied as a symbol (eg. `validate :verify_something`) is actually running in the context of a delegate class, private methods won't work as they would in standard validations.
90
+ Because the any validation method supplied as a symbol (eg. `validate :verify_something`) is actually running in the
91
+ context of a delegate class, private methods won't work as they would in standard validations.
32
92
 
33
93
 
34
94
  ## Implementation
35
95
 
36
- The implementation of this gem is meta-programming heavy and very dependent on the internal structure of ActiveRecord as of Rails 2.3.5. The goal was to be able to utilize the entire functionality of ActiveRecord validations with a minimum of code. The resulting code is a bit more magic than I would have liked, but it seems to be working for me so far. I plan on forward porting to Rails 3 and maybe it will be nicer.
96
+ I had a lot of fun writing this gem even though the result isn't exactly a shining example elegant code. An [article
97
+ about the design process](http://www.darwinweb.net/articles/80) is on my blog.
98
+
99
+
100
+ ## TODO
37
101
 
38
- The core of the implemention is a dynamically created proxy_class that has ActiveRecord::Validations included in order to isolate its own copy of @errors. The proxy class is a DelegateClass which gets initialized to the base ActiveRecord object so that validations can use any of the methods of the base object. Although the use of DelegateClass raises a few issues, it seemed like the cleanest way to do the integration so that all of the ActiveRecord::Validations concerns just work without too much regard to the specifics of the method implementations.
102
+ * In Rails 3 validations are no longer coupled to ActiveRecord. As part of of ActiveModel, validations can be included
103
+ in any object. It shouldn't be too much work to make validation_scopes work with arbitrary models as well.
39
104
 
40
105
 
41
106
  ## Copyright
42
107
 
43
- Copyright (c) 2010 Gabe da Silveira. See LICENSE for details.
108
+ Copyright (c) 2010,2011 Gabe da Silveira. See LICENSE for details.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.3.1
@@ -11,7 +11,10 @@ module ValidationScopes
11
11
  base_class = self
12
12
  deferred_proxy_class_declaration = Proc.new do
13
13
  proxy_class = Class.new(DelegateClass(base_class)) do
14
- include ActiveRecord::Validations
14
+ validations_module = defined?(ActiveModel) ? ActiveModel::Validations : ActiveRecord::Validations
15
+ errors_class = defined?(ActiveModel) ? ActiveModel::Errors : ActiveRecord::Errors
16
+
17
+ include validations_module
15
18
 
16
19
  def initialize(record)
17
20
  @base_record = record
@@ -19,8 +22,8 @@ module ValidationScopes
19
22
  end
20
23
 
21
24
  # Hack since DelegateClass doesn't seem to be making AR::Base class methods available.
22
- def errors
23
- @errors ||= ActiveRecord::Errors.new(@base_record)
25
+ define_method("errors") do
26
+ @errors ||= errors_class.new(@base_record)
24
27
  end
25
28
  end
26
29
 
@@ -56,4 +59,4 @@ module ValidationScopes
56
59
  end
57
60
  end
58
61
 
59
- ActiveRecord::Base.send(:include, ValidationScopes)
62
+ ActiveRecord::Base.send(:include, ValidationScopes)
@@ -1,54 +1,52 @@
1
1
  # Generated by jeweler
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{validation_scopes}
8
- s.version = "0.3.0"
8
+ s.version = "0.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Gabe da Silveira"]
12
- s.date = %q{2010-01-04}
12
+ s.date = %q{2011-02-24}
13
13
  s.description = %q{Define additional sets of validations beyond the standard "errors" that is tied to the ActiveRecord life-cycle. These additional sets can be defined with all the standard ActiveRecord::Validation macros, and the resulting collection is a standard ActiveRecord::Errors object.}
14
14
  s.email = %q{gabe@websaviour.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
17
- "README.md"
17
+ "README.md"
18
18
  ]
19
19
  s.files = [
20
20
  ".document",
21
- ".gitignore",
22
- "CHANGELOG",
23
- "LICENSE",
24
- "README.md",
25
- "Rakefile",
26
- "VERSION",
27
- "lib/validation_scopes.rb",
28
- "test/db/schema.rb",
29
- "test/fixtures/users.yml",
30
- "test/helper.rb",
31
- "test/models/user.rb",
32
- "test/test_validation_scopes.rb",
33
- "validation_scopes.gemspec"
21
+ "CHANGELOG",
22
+ "LICENSE",
23
+ "README.md",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "lib/validation_scopes.rb",
27
+ "test/db/schema.rb",
28
+ "test/fixtures/users.yml",
29
+ "test/helper.rb",
30
+ "test/models/user.rb",
31
+ "test/test_validation_scopes.rb",
32
+ "validation_scopes.gemspec"
34
33
  ]
35
34
  s.homepage = %q{http://github.com/dasil003/validation_scopes}
36
- s.rdoc_options = ["--charset=UTF-8"]
37
35
  s.require_paths = ["lib"]
38
- s.rubygems_version = %q{1.3.5}
36
+ s.rubygems_version = %q{1.3.7}
39
37
  s.summary = %q{Create sets of validations independent of the life-cycle of an ActiveRecord object}
40
38
  s.test_files = [
41
39
  "test/db/schema.rb",
42
- "test/helper.rb",
43
- "test/models/user.rb",
44
- "test/test_validation_scopes.rb"
40
+ "test/helper.rb",
41
+ "test/models/user.rb",
42
+ "test/test_validation_scopes.rb"
45
43
  ]
46
44
 
47
45
  if s.respond_to? :specification_version then
48
46
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
49
47
  s.specification_version = 3
50
48
 
51
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
52
50
  s.add_development_dependency(%q<shoulda>, [">= 0"])
53
51
  else
54
52
  s.add_dependency(%q<shoulda>, [">= 0"])
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: validation_scopes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 3
8
+ - 1
9
+ version: 0.3.1
5
10
  platform: ruby
6
11
  authors:
7
12
  - Gabe da Silveira
@@ -9,19 +14,22 @@ autorequire:
9
14
  bindir: bin
10
15
  cert_chain: []
11
16
 
12
- date: 2010-01-04 00:00:00 -08:00
17
+ date: 2011-02-24 00:00:00 -08:00
13
18
  default_executable:
14
19
  dependencies:
15
20
  - !ruby/object:Gem::Dependency
16
21
  name: shoulda
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
20
25
  requirements:
21
26
  - - ">="
22
27
  - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
23
30
  version: "0"
24
- version:
31
+ type: :development
32
+ version_requirements: *id001
25
33
  description: Define additional sets of validations beyond the standard "errors" that is tied to the ActiveRecord life-cycle. These additional sets can be defined with all the standard ActiveRecord::Validation macros, and the resulting collection is a standard ActiveRecord::Errors object.
26
34
  email: gabe@websaviour.com
27
35
  executables: []
@@ -33,7 +41,6 @@ extra_rdoc_files:
33
41
  - README.md
34
42
  files:
35
43
  - .document
36
- - .gitignore
37
44
  - CHANGELOG
38
45
  - LICENSE
39
46
  - README.md
@@ -51,26 +58,30 @@ homepage: http://github.com/dasil003/validation_scopes
51
58
  licenses: []
52
59
 
53
60
  post_install_message:
54
- rdoc_options:
55
- - --charset=UTF-8
61
+ rdoc_options: []
62
+
56
63
  require_paths:
57
64
  - lib
58
65
  required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
59
67
  requirements:
60
68
  - - ">="
61
69
  - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
62
72
  version: "0"
63
- version:
64
73
  required_rubygems_version: !ruby/object:Gem::Requirement
74
+ none: false
65
75
  requirements:
66
76
  - - ">="
67
77
  - !ruby/object:Gem::Version
78
+ segments:
79
+ - 0
68
80
  version: "0"
69
- version:
70
81
  requirements: []
71
82
 
72
83
  rubyforge_project:
73
- rubygems_version: 1.3.5
84
+ rubygems_version: 1.3.7
74
85
  signing_key:
75
86
  specification_version: 3
76
87
  summary: Create sets of validations independent of the life-cycle of an ActiveRecord object
data/.gitignore DELETED
@@ -1,21 +0,0 @@
1
- ## MAC OS
2
- .DS_Store
3
-
4
- ## TEXTMATE
5
- *.tmproj
6
- tmtags
7
-
8
- ## EMACS
9
- *~
10
- \#*
11
- .\#*
12
-
13
- ## VIM
14
- *.swp
15
-
16
- ## PROJECT::GENERAL
17
- coverage
18
- rdoc
19
- pkg
20
-
21
- ## PROJECT::SPECIFIC