boof-not-naughty 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,57 @@
1
+ === 0.6.2 (2008-10-31)
2
+ * NotNaughty::Builder is now NotNaughty::ClassMethods
3
+ * NotNaughty::Builder::ValidationDelegator is now NotNaughty::ClassMethods::Builder
4
+ * NotNaughty::ClassMethods::Builder does not inherit from Delegation anymore, so { format :with => /rx/ } works
5
+ * NotNaughty::Validation loads validations from directories listed in load_paths
6
+
7
+ === 0.6.1 (2008-10-10)
8
+ * builder/validation cleanups
9
+ * added gemspecs for github
10
+ * added support for predefined format expressions [resolves:#19814]
11
+
12
+ === 0.6 (2008-10-08)
13
+ * fixed Rakefile
14
+ * removed whitespaces
15
+ * removed Ruby-Sequel adapter (becomes an extra gem)
16
+ * removed assistance gem dependency
17
+
18
+ === 0.5.1 (2008-03-17)
19
+ * fixed missing dependency
20
+
21
+ === 0.5 (2008-03-17)
22
+ * added an error handler, can now handle SQL validation errors
23
+ * renamed Errors to Violation and merged it with ValidationException
24
+ * changed specs for 0.4.1
25
+
26
+ === 0.4.2 (2008-03-12)
27
+ * fixed bug that causes infinite recursion in some apps that reload classes
28
+
29
+ === 0.4.1 (2008-03-12)
30
+ * some minor changes in validator method
31
+
32
+ === 0.4 (2008-02-18)
33
+ * completed documentation
34
+ * added spec for :each in Builder::ValidationDelegator
35
+
36
+ === 0.3.1 (2008-02-14)
37
+ * fixed missing require
38
+
39
+ === 0.3 (2008-02-09)
40
+ * renamed to NotNaughty - The Validation Framework
41
+ * made predefined Validation optional, you can load them with:
42
+
43
+ ::NotNaughty::Validation.load '*'
44
+
45
+ or ordered (should be preferred):
46
+
47
+ ::NotNaughty::Validation.load :acceptance, :confirmation, :format, :length,
48
+ :numericality, :presence
49
+
50
+ * specs pass, 100% code coverage, 2 not complete, so pending specs
51
+ * docs added
52
+
53
+ === 0.2 (2008-02-09)
54
+ * complete rewrite
55
+
56
+ === 0.1 (2008-02-06)
57
+ * initial release
data/COPYING ADDED
@@ -0,0 +1,18 @@
1
+ Copyright (c) 2007-2008 Florian Aßmann
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to
5
+ deal in the Software without restriction, including without limitation the
6
+ rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7
+ sell copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
16
+ THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,59 @@
1
+ = NotNaughty - The Validation Framework
2
+
3
+ NotNaughty extends your ruby Project with a highly custumizable validation API.
4
+
5
+ == Features
6
+
7
+ <b>Easy to adapt:</b>
8
+
9
+ require 'rubygems'
10
+ require 'not_naughty'
11
+
12
+ Person = Struct.new(:name) do
13
+ extend NotNaughty
14
+ validates(:name) { presence and length :minimum => 4 }
15
+ end
16
+
17
+ Person.new('Horst').valid? # => true
18
+ Person.new('Foo').valid? # => false
19
+
20
+ <b>Easy to extent:</b>
21
+
22
+ class ExampleValidation < NotNaughty::Validation
23
+ def initialize(options, attributes)
24
+ msg = options[:message] || '#{"%s".humanize} is not an example.'
25
+
26
+ super options, attributes do |record, attribute, value|
27
+ record.errors.add(attribute, msg) unless value.is_a? Example
28
+ end
29
+ end
30
+ end
31
+
32
+ Person.instance_eval do
33
+ validates_example_of :example_attribute
34
+ end
35
+
36
+ <b>Handle SQL error gracefully:</b>
37
+
38
+ Person.instance_eval do
39
+ validator.error_handler.handle(SQLError) { |err| '...' }
40
+ end
41
+
42
+ <b>Syntactical Sugar with Builder methods:</b>
43
+
44
+ validates(:username, :password, :if => :new?) {length :minimum => 6}
45
+ validates(:password, :allow_blank => 1) {confirmation and complexity :high}
46
+
47
+ <b>Beautiful error messages:</b>
48
+
49
+ validates_presence_of :red_shoes,
50
+ :message => '#{"%s".humanize} are not here.' # => Red shoes are not here.
51
+
52
+ <b>Conditional Validations:</b>
53
+
54
+ validates(:if => :necessary?) {...}
55
+ validates(:unless => proc {|obj| obj.vip?}) { '...' }
56
+
57
+ == Copying
58
+
59
+ :include: COPYING
data/Rakefile ADDED
@@ -0,0 +1,126 @@
1
+ require "rake"
2
+ require "rake/clean"
3
+ require "rake/gempackagetask"
4
+ require "rake/rdoctask"
5
+ require "fileutils"
6
+ include FileUtils
7
+
8
+ ##############################################################################
9
+ # Configuration
10
+ ##############################################################################
11
+ NAME = "not-naughty"
12
+ VERS = "0.6.2"
13
+ CLEAN.include %w[ pkg doc coverage ]
14
+ RDOC_OPTS = [
15
+ "--quiet",
16
+ "--title", "NotNaughty: The Validation Framework",
17
+ "--opname", "index.html",
18
+ "--inline-source",
19
+ "--line-numbers",
20
+ "--main", "README.rdoc",
21
+ "--inline-source",
22
+ "--charset", "utf-8"
23
+ ]
24
+
25
+ ##############################################################################
26
+ # RDoc
27
+ ##############################################################################
28
+ task :doc => [:rdoc]
29
+
30
+ Rake::RDocTask.new do |rdoc|
31
+ rdoc.rdoc_dir = "doc"
32
+ rdoc.options += RDOC_OPTS
33
+ rdoc.main = "README.rdoc"
34
+ rdoc.title = "NotNaughty: The Validation Framework"
35
+ rdoc.rdoc_files.add %w[README.rdoc COPYING CHANGELOG.rdoc lib/**/*.rb]
36
+ end
37
+
38
+ task :doc_rforge => [:doc]
39
+
40
+ desc "Update docs and upload to rubyforge.org"
41
+ task :doc_rforge do
42
+ sh %{scp -r doc/* boof@rubyforge.org:/var/www/gforge-projects/not-naughty}
43
+ end
44
+
45
+ ##############################################################################
46
+ # specs
47
+ ##############################################################################
48
+ require "spec/rake/spectask"
49
+
50
+ desc "Run specs with coverage"
51
+ Spec::Rake::SpecTask.new("spec") do |t|
52
+ t.spec_files = FileList["spec/**/*_spec.rb"]
53
+ t.spec_opts = File.read("spec/spec.opts").split("\n")
54
+ t.rcov_opts = File.read("spec/rcov.opts").split("\n")
55
+ t.rcov = true
56
+ end
57
+
58
+ desc "Run specs without coverage"
59
+ Spec::Rake::SpecTask.new("spec_no_cov") do |t|
60
+ t.spec_files = FileList["spec/**/*_spec.rb"]
61
+ t.spec_opts = File.read("spec/spec.opts").split("\n")
62
+ end
63
+
64
+ desc "check documentation coverage"
65
+ task :dcov do
66
+ sh "find lib -name '*.rb' | xargs dcov"
67
+ end
68
+
69
+ ##############################################################################
70
+ # Gem packaging
71
+ ##############################################################################
72
+ desc "Packages up NotNaughty."
73
+ task :default => [:package]
74
+ task :package => [:clean]
75
+
76
+ spec = Gem::Specification.new do |s|
77
+ s.name = NAME
78
+ s.rubyforge_project = NAME
79
+ s.version = VERS
80
+ s.platform = Gem::Platform::RUBY
81
+ s.has_rdoc = true
82
+ s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "COPYING"]
83
+ s.summary = "Heavily armed validation framework."
84
+ s.description = s.summary
85
+ s.author = "Florian Aßmann"
86
+ s.email = "boof@monkey-patch.me"
87
+ s.homepage = "http://monkey-patch.me/p/notnaughty"
88
+ s.required_ruby_version = ">= 1.8.6"
89
+ s.add_dependency("rubytree", ">= 0.5.2")
90
+
91
+ s.files = %w(COPYING README.rdoc Rakefile) + Dir.glob("{spec,lib}/**/*")
92
+
93
+ s.require_path = "lib"
94
+ end
95
+
96
+ Rake::GemPackageTask.new(spec) do |p|
97
+ p.need_tar = true
98
+ p.gem_spec = spec
99
+ end
100
+
101
+ ##############################################################################
102
+ # installation & removal
103
+ ##############################################################################
104
+ task :install do
105
+ sh %{rake package}
106
+ sh %{sudo gem install pkg/#{NAME}-#{VERS}}
107
+ end
108
+
109
+ task :install_no_docs do
110
+ sh %{rake package}
111
+ sh %{sudo gem install pkg/#{NAME}-#{VERS} --no-rdoc --no-ri}
112
+ end
113
+
114
+ task :uninstall => [:clean] do
115
+ sh %{sudo gem uninstall #{NAME}}
116
+ end
117
+
118
+ ##############################################################################
119
+ # gem and rdoc release
120
+ ##############################################################################
121
+ task :release => [:package] do
122
+ sh %{rubyforge login}
123
+ sh %{rubyforge add_release #{NAME} #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.tgz}
124
+ sh %{rubyforge add_file #{NAME} #{NAME} #{VERS} pkg/#{NAME}-#{VERS}.gem}
125
+ end
126
+
@@ -0,0 +1,20 @@
1
+ class Array #:nodoc:
2
+ instance_methods.include? 'extract_options!' or
3
+ define_method(:extract_options!) { Hash === last ? pop : {} }
4
+ end
5
+ class Object #:nodoc:
6
+ instance_methods.include? 'blank?' or
7
+ define_method(:blank?) { respond_to?(:empty?) ? empty? : !self }
8
+ end
9
+ class String #:nodoc:
10
+ instance_methods.include? 'blank?' or
11
+ define_method(:blank?) { self !~ /\S/ }
12
+ end
13
+ class Numeric #:nodoc:
14
+ instance_methods.include? 'blank?' or
15
+ define_method(:blank?) { false }
16
+ end
17
+
18
+ def nil.blank?() true end unless nil.respond_to? :blank?
19
+ def true.blank?() false end unless true.respond_to? :blank?
20
+ def false.blank?() true end unless false.respond_to? :blank?
@@ -0,0 +1,86 @@
1
+ require 'forwardable'
2
+ require 'observer'
3
+
4
+ require 'rubygems'
5
+ gem 'rubytree', '>= 0.5.2'
6
+ require 'tree'
7
+
8
+ $:.unshift File.dirname(__FILE__)
9
+ require 'core_extensions'
10
+
11
+ module NotNaughty
12
+ require 'not_naughty/validator'
13
+
14
+ require 'not_naughty/class_methods'
15
+ require 'not_naughty/validation'
16
+ Validation.add_observer ClassMethods
17
+
18
+ require 'not_naughty/violation'
19
+ require 'not_naughty/error_handler'
20
+ require 'not_naughty/instance_methods'
21
+
22
+ # Extended classes get NotNaughty::ClassMethods and
23
+ # NotNaughty::InstanceMethods.
24
+ def self.extended(base)
25
+ base.instance_eval do
26
+ include InstanceMethods
27
+ extend ClassMethods
28
+ end
29
+ end
30
+
31
+ # call-seq:
32
+ # validator(validator_klass = NotNaughty::Validator, *states = [:default])
33
+ #
34
+ # Returns instance of Validator. This is either the validator's clone of
35
+ # superclass, an instance of the the given descendant of or the
36
+ # <tt>NotNaughty:Validator</tt> himself.
37
+ #
38
+ # <b>Examples:</b>
39
+ # validator # => Instance of NotNaughty::Validator with :default state
40
+ # validator :create, :update # ~ - but with :create and :update states
41
+ # validator AnotherValidator # Instance of AnotherValidator
42
+ #
43
+ # validator AnotherValidator, :state_a, :state_b
44
+ #
45
+ # The above examples work as long validator is not already called. To reset
46
+ # an already assigned validator set <tt>@validator</tt> to nil.
47
+ def validator(*states)
48
+ @validator ||= if !states.empty?
49
+ validator_klass =
50
+ if states.first.is_a? Class and states.first <= NotNaughty::Validator
51
+ states.shift
52
+ else
53
+ NotNaughty::Validator
54
+ end
55
+
56
+ validator_klass.new(*states)
57
+
58
+ elsif superclass.respond_to? :validator
59
+ superclass.validator.clone
60
+
61
+ else
62
+ NotNaughty::Validator.new
63
+
64
+ end
65
+ end
66
+
67
+ # Prepends a call for validation before then given method. If, on call, the
68
+ # validation passes the method is called. Otherwise it raises an
69
+ # NotNaughty::ValidationException or returns false.
70
+ #
71
+ # <b>Example:</b>
72
+ # validated_before :save # raise ValidationException unless valid?
73
+ def validated_before(method)
74
+ __method = :"#{method}_without_validations"
75
+ alias_method __method, method
76
+
77
+ define_method method do |*params|
78
+ begin
79
+ if valid? then send __method else raise errors end
80
+ rescue Exception => error
81
+ self.class.validator.error_handler.raise error
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,78 @@
1
+ module NotNaughty
2
+ module ClassMethods
3
+
4
+ def self.update(validation) # :nodoc:
5
+ if basename = validation.name[/([^:]+)Validation$/, 1]
6
+ define_method 'validates_%s_of' % basename.downcase do |*params|
7
+ validator.add_validation(validation, *params)
8
+ end
9
+ end
10
+ end
11
+
12
+ # == Syntactic sugar.
13
+ #
14
+ # <b>Example:</b>
15
+ # validates { presence_of :example, :if => :reading? }
16
+ # # => validate_presence_of :example, :if => :reading?
17
+ # validates(:name) { presence and length :minimum => 6 }
18
+ # # => validates_presence_of :name
19
+ # validates_length_of :name, :minimum => 6
20
+ # validates(:temp, :if => water?) { value :lt => 100 }
21
+ # # => validates_value_of :temp, :lt => 100, :if => water?
22
+ def validates(*params, &block)
23
+ Builder.new(self, *params).instance_eval(&block)
24
+ end
25
+
26
+ # Allows adding validations the legacy way.
27
+ def validates_each(*attributes, &block)
28
+ validator.add_validation(*attributes, &block)
29
+ end
30
+
31
+ # With this you get syntactical sugar for all descendants of Validation
32
+ # see validates for examples.
33
+ class Builder
34
+
35
+ def initialize(klass, *params) # :nodoc:
36
+ @_vd_obj = klass
37
+ @_vd_obj_opts = params.extract_options!
38
+ @_vd_obj_attrs = params
39
+
40
+ methods = ClassMethods.instance_methods(false).grep(/^validates_.+_of$/)
41
+
42
+ if @_vd_obj_attrs.empty?
43
+ for method in methods
44
+ eval <<-EOS
45
+ def self.#{ method[/^validates_(.+)$/, 1] }(*params)
46
+ params << @_vd_obj_opts.merge(params.extract_options!)
47
+
48
+ begin
49
+ @_vd_obj.__send__(:#{ method }, *params)
50
+ rescue Exception
51
+ $@.delete_if { |s| /^\\(eval\\):/ =~ s }
52
+ raise
53
+ end
54
+ end
55
+ EOS
56
+ end
57
+ else
58
+ for method in methods
59
+ eval <<-EOS
60
+ def self.#{ method[/^validates_(.+)_of$/, 1] }(*args)
61
+ params = @_vd_obj_attrs.dup
62
+ params << @_vd_obj_opts.merge(args.extract_options!)
63
+
64
+ begin
65
+ @_vd_obj.__send__(:#{ method }, *params)
66
+ rescue Exception
67
+ $@.delete_if { |s| /^\\(eval\\):/ =~ s }
68
+ raise
69
+ end
70
+ end
71
+ EOS
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ end
78
+ end