not_naughty 0.3

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.
@@ -0,0 +1,95 @@
1
+ module NotNaughty
2
+
3
+ # == Validates length of obj's attribute via the <tt>:length</tt> method.
4
+ #
5
+ # Unless the validation succeeds an error hash (:attribute => :message)
6
+ # is added to the obj's instance of Errors.
7
+ #
8
+ # <b>Options:</b>
9
+ # <tt>:message</tt>:: see NotNaughty::Errors for details
10
+ # <tt>:if</tt>:: see NotNaughty::Validation::Condition for details
11
+ # <tt>:unless</tt>:: see NotNaughty::Validation::Condition for details
12
+ #
13
+ # <b>Boundaries (by precendence):</b>
14
+ # <tt>:is</tt>:: valid length
15
+ # <tt>:within</tt>:: valid range of length
16
+ # <tt>:minimum</tt>:: maximum length
17
+ # <tt>:maximum</tt>:: minimum length
18
+ #
19
+ # If both, <tt>:minimum</tt> and <tt>:maximum</tt> are provided they're
20
+ # converted to :within. Each boundary type has its own default message:
21
+ # precise:: "Length of %s is not equal to #{__length}."
22
+ # range:: "Length of %s is not within #{__range.first} and #{__range.last}."
23
+ # lower:: "Length of %s is smaller than #{__boundary}."
24
+ # upper:: "Length of %s is greater than #{__boundary}."
25
+ #
26
+ # <b>Example:</b>
27
+ #
28
+ # obj = %w[a sentence with five words] #
29
+ # def obj.errors() @errors ||= NotNauthy::Errors.new end
30
+ #
31
+ # LengthValidation.new({:minimum => 4}, :to_a).
32
+ # call obj, :to_a, %w[a sentence with five words]
33
+ # obj.errors.on(:to_s).any? # => false
34
+ #
35
+ # LengthValidation.new({:within => 1..4}, :to_a).
36
+ # call obj, :to_a, %w[a sentence with five words]
37
+ # obj.errors.on(:to_s).any? # => true
38
+ class LengthValidation < Validation
39
+
40
+ def initialize(opts, attributes) #:nodoc:
41
+
42
+ block = build_block opts
43
+
44
+ if opts[:allow_blank]
45
+ super opts, attributes do |o, a, v|
46
+ block[o, a, v] unless v.blank?
47
+ end
48
+ else
49
+ super opts, attributes do |o, a, v|
50
+ block[o, a, v] unless v.nil?
51
+ end
52
+ end
53
+ end
54
+
55
+ protected
56
+ def build_block(opts) #:nodoc:
57
+ if __length = opts[:is]
58
+ __message = opts[:message] ||
59
+ "Length of %s is not equal to #{__length}."
60
+ proc do |o, a, v|
61
+ o.errors.add a, __message unless __length.eql? v.length
62
+ end
63
+ elsif opts[:within] or opts[:minimum] && opts[:maximum]
64
+ __range = opts[:within]
65
+ __range ||= Range.new opts[:minimum], opts[:maximum]
66
+
67
+ __message = opts[:message] ||
68
+ "Length of %s is not within #{__range.first} and #{__range.last}."
69
+
70
+ proc do |o, a, v|
71
+ o.errors.add a, __message unless __range.include? v.length
72
+ end
73
+ elsif opts[:minimum]
74
+ __boundary = opts[:minimum]
75
+ __message = opts[:message] ||
76
+ "Length of %s is smaller than #{__boundary}."
77
+
78
+ proc do |o, a, v|
79
+ o.errors.add a, __message unless __boundary <= v.length
80
+ end
81
+ elsif opts[:maximum]
82
+ __boundary = opts[:maximum]
83
+ __message = opts[:message] ||
84
+ "Length of %s is greater than #{__boundary}."
85
+
86
+ proc do |o, a, v|
87
+ o.errors.add a, __message unless __boundary >= v.length
88
+ end
89
+ else
90
+ raise ArgumentError, 'no boundary given'
91
+ end
92
+ end
93
+
94
+ end
95
+ end
@@ -0,0 +1,43 @@
1
+ NotNaughty::Validation.load :format
2
+
3
+ module NotNaughty
4
+
5
+ # == Validates numericality of obj's attribute via an regular expression.
6
+ #
7
+ # Unless the validation succeeds an error hash (:attribute => :message)
8
+ # is added to the obj's instance of Errors.
9
+ #
10
+ # <b>Options:</b>
11
+ # <tt>:only_integer</tt>:: validates with <tt>/^[+-]?\d+$/</tt> (false)
12
+ # <tt>:message</tt>:: see NotNaughty::Errors for details
13
+ # <tt>:if</tt>:: see NotNaughty::Validation::Condition for details
14
+ # <tt>:unless</tt>:: see NotNaughty::Validation::Condition for details
15
+ #
16
+ # <b>Example:</b>
17
+ #
18
+ # obj = '-12.2' #
19
+ # def obj.errors() @errors ||= NotNauthy::Errors.new end
20
+ #
21
+ # NumericalityValidation.new({}, :to_s).call obj, :to_s, '-12.2'
22
+ # obj.errors.on(:to_s).any? # => false
23
+ #
24
+ # NumericalityValidation.new({:only_integer => true}, :to_s).
25
+ # call obj, :to_s, '-12.2'
26
+ #
27
+ # obj.errors.on(:to_s).any? # => true
28
+ class NumericalityValidation < FormatValidation
29
+
30
+ def initialize(opts, attributes) #:nodoc:
31
+ opts[:with] = if opts[:only_integer]
32
+ opts[:message] ||= '#{"%s".humanize} is not an integer.'
33
+ /^[+-]?\d+$/
34
+ else
35
+ opts[:message] ||= '#{"%s".humanize} is not a number.'
36
+ /^[+-]?\d*\.?\d+$/
37
+ end
38
+
39
+ super opts, attributes
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,31 @@
1
+ module NotNaughty
2
+
3
+ # == Validates presence of obj's attribute via the <tt>:blank?</tt> method.
4
+ #
5
+ # Unless the validation succeeds an error hash (:attribute => :message)
6
+ # is added to the obj's instance of Errors.
7
+ #
8
+ # <b>Options:</b>
9
+ # <tt>:message</tt>:: see NotNaughty::Errors for details
10
+ # <tt>:if</tt>:: see NotNaughty::Validation::Condition for details
11
+ # <tt>:unless</tt>:: see NotNaughty::Validation::Condition for details
12
+ #
13
+ # <b>Example:</b>
14
+ #
15
+ # obj = '' # blank? => true
16
+ # def obj.errors() @errors ||= NotNauthy::Errors.new end
17
+ #
18
+ # PresenceValidation.new({}, :to_s).call obj, :to_s, ''
19
+ # obj.errors.on(:to_s) # => ["To s is not present."]
20
+ class PresenceValidation < Validation
21
+
22
+ def initialize(opts, attributes) #:nodoc:
23
+ __message = opts[:message] || '#{"%s".humanize} is not present.'
24
+
25
+ super opts, attributes do |o, a, v|
26
+ o.errors.add a, __message if v.blank?
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,119 @@
1
+ module NotNaughty
2
+
3
+ # == Superclass for all Adapters.
4
+ #
5
+ # See new and get_state for more information.
6
+ class Validator
7
+
8
+ attr_reader :states
9
+
10
+ # By default it comes with the :default State unless other states are
11
+ # provided.
12
+ #
13
+ # <b>Example:</b>
14
+ # NotNaughty::Validator.new
15
+ # # has the :default state
16
+ # NotNaughty::Validator.new :create, :update
17
+ # # has the :create and :update states
18
+ #
19
+ # <em>Adapters should overwrite this method.</em>
20
+ def initialize(*states)
21
+ states << :default if states.empty?
22
+
23
+ @states = states.inject({}) {|m, s| m.update s => State.new(s)}
24
+ @initial_state = @states[states.first]
25
+ end
26
+
27
+ def clone #:nodoc:
28
+ states = [@initial_state.name] | @states.keys
29
+
30
+ clone = self.class.new(*states)
31
+ @states.each do |n, s|
32
+ s.validations.each { |a, v| clone.states[n].validations[a] = v.clone }
33
+ end
34
+ clone.instance_eval { @initial_state = @states[states.first] }
35
+
36
+ clone
37
+ end
38
+
39
+ # Returns the state for the given object. By default it does return the
40
+ # initial state.
41
+ #
42
+ # <em>Adapters that provide multiple states should eventually overwrite
43
+ # this method</em>.
44
+ def get_state(obj = nil) @initial_state end
45
+
46
+ # Adds a validation to all/specified states.
47
+ #
48
+ # <b>Example:</b>
49
+ # add_validation(:firstname, :lastname, :on => :default) {|o, a, v|}
50
+ # # adds validation to :default state
51
+ # add_validation(:firstname, :lastname) {|o, a, v|}
52
+ # # adds validation to all states
53
+ # add_validation(:first, :last, :on => [:create, :update]) {|o, a, v|}
54
+ # # adds validation to :create and :update states
55
+ def add_validation(*p, &b)
56
+ options = (p.last.is_a? Hash) ? p.last : {}
57
+
58
+ if states = options.delete(:on)
59
+ @states.values_at(*states).each do |state|
60
+ state.add_validation(*p, &b) unless state.nil?
61
+ end
62
+ else
63
+ @states.each { |name, state| state.add_validation(*p, &b) }
64
+ end
65
+ end
66
+
67
+ # Returns true if given object has validations in its current state. If
68
+ # no object was given it returns true if any state has validations. It
69
+ # otherwise returns false.
70
+ def has_validations?(obj = nil)
71
+ if obj.nil? then @states.any? { |name, state| state.has_validations? }
72
+ else get_state(obj).has_validations? end
73
+ end
74
+
75
+ # Runs all validations on object for the object's state.
76
+ def invoke(obj)
77
+ get_state(obj).validations.each do |attr, validations|
78
+ val = obj.send! attr
79
+ validations.each { |validation| validation.call obj, attr, val }
80
+ end
81
+ end
82
+
83
+ # == Container for attribute specific validations
84
+ #
85
+ # See Validator for details.
86
+ class State
87
+
88
+ attr_reader :validations, :name
89
+
90
+ # Initializes the state with given name.
91
+ def initialize(name = :default)
92
+ @name, @validations = name, Hash.new {|h, k| h[k] = []}
93
+ end
94
+
95
+ # Adds the validation that results from <tt>params</tt> and
96
+ # <tt>block</tt> to validated attributes (see Validation#new for
97
+ # details).
98
+ def add_validation(*params, &block)
99
+ validation = Validation.new(*params, &block)
100
+
101
+ validation.attributes.each do |attribute|
102
+ @validations[attribute] << validation if attribute.is_a? Symbol
103
+ end
104
+ end
105
+
106
+ # Returns validations for given attribute.
107
+ def [](attribute)
108
+ @validations[attribute]
109
+ end
110
+
111
+ # Returns true if a attributes has validations assigned, false
112
+ # otherwise.
113
+ def has_validations?
114
+ @validations.any? { |attribute, validations| validations.any? }
115
+ end
116
+
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,85 @@
1
+ require 'delegate'
2
+ require 'observer'
3
+
4
+ require 'rubygems'
5
+ require 'assistance'
6
+
7
+ module Kernel#:nodoc:all
8
+ methods.include? 'send!' or
9
+ alias_method :send!, :send
10
+ end
11
+
12
+ $:.unshift File.dirname(__FILE__)
13
+
14
+ module NotNaughty
15
+ require 'not_naughty/validator'
16
+
17
+ require 'not_naughty/builder'
18
+ require 'not_naughty/validation'
19
+ Validation.add_observer Builder
20
+
21
+ require 'not_naughty/errors'
22
+ require 'not_naughty/instance_methods'
23
+
24
+ # Extended classes get NotNaughty::Builder and NotNaughty::InstanceMethods.
25
+ def self.extended(base)
26
+ base.instance_eval do
27
+ include InstanceMethods
28
+ extend Builder
29
+ end
30
+ end
31
+
32
+ # call-seq:
33
+ # validator(validator_klass = NotNaughty::Validator, *states = [:default])
34
+ #
35
+ # Returns instance of Validator. This is either the validator's clone of
36
+ # superclass, an instance of the the given descendant of or the
37
+ # <tt>NotNaughty:Validator</tt> himself.
38
+ #
39
+ # <b>Examples:</b>
40
+ # validator # => Instance of NotNaughty::Validator with :default state
41
+ # validator :create, :update # ~ - but with :create and :update states
42
+ # validator AnotherValidator # Instance of AnotherValidator
43
+ #
44
+ # The above examples work as long validator is not already called. To reset
45
+ # an already assigned validator set <tt>@validator</tt> to nil.
46
+ def validator(*states)
47
+ @validator ||= if superclass.respond_to? :validator
48
+ superclass.validator.clone
49
+
50
+ else
51
+ validator_klass =
52
+ if states[0].is_a? Class and states[0] <= NotNaughty::Validator
53
+ states.shift
54
+ else
55
+ NotNaughty::Validator
56
+ end
57
+
58
+ validator_klass.new(*states)
59
+ end
60
+ end
61
+
62
+ # Prepends a call for validation before then given method. If, on call, the
63
+ # validation passes the method is called. Otherwise it raises an
64
+ # NotNaughty::ValidationException or returns false.
65
+ #
66
+ # <b>Example:</b>
67
+ # validated_before :save # raise ValidationException unless valid?
68
+ # validated_before :save, :without => :exception # => false unless valid?
69
+ def validated_before(method, *args)
70
+ __method = :"#{method}_without_validations"
71
+ alias_method __method, method
72
+
73
+ without = args.extract_options![:without]
74
+ if [*without].include? :exception
75
+ define_method method do |*params|
76
+ if valid? then send! __method else false end
77
+ end
78
+ else
79
+ define_method method do |*params|
80
+ if valid? then send! __method else raise errors.to_exception end
81
+ end
82
+ end
83
+ end
84
+
85
+ end
@@ -0,0 +1,106 @@
1
+ require File.dirname(__FILE__) + '/not_naughty'
2
+ require 'sequel'
3
+
4
+ module Sequel #:nodoc:
5
+ module Plugins #:nodoc:
6
+ # == Adapter for Sequel ...
7
+ #
8
+ # ... is a Sequel::Plugin.
9
+ #
10
+ # ---
11
+ #
12
+ # <b>To make it overall available:</b>
13
+ #
14
+ # class Sequel::Model
15
+ # is :not_naughty
16
+ # end
17
+ #
18
+ # <b>To turn off before_validate and after_validate hooks:</b>
19
+ #
20
+ # class User < Sequel::Model
21
+ # is :not_naughty, :without => :hooks
22
+ # end
23
+ #
24
+ # <b>To turn off raised Exceptions if validation before save fails:</b>
25
+ #
26
+ # class User < Sequel::Model
27
+ # # save on invalid users will return false
28
+ # is :not_naughty, :without => :exceptions
29
+ # end
30
+ #
31
+ # <b>To combine those:</b>
32
+ #
33
+ # class User < Sequel::Model
34
+ # is :not_naughty, :without => [:exceptions, :hooks]
35
+ # end
36
+ #
37
+ class NotNaughty < NotNaughty::Validator
38
+
39
+ # Applies plugin to a Sequel::Model.
40
+ def self.apply(receiver, *args)
41
+ receiver.extend ::NotNaughty
42
+ receiver.validator self, :create, :update
43
+
44
+ ::NotNaughty::Validation.load(
45
+ :acceptance, :confirmation, :format,
46
+ :length, :numericality, :presence
47
+ )
48
+
49
+ receiver.extend ClassMethods
50
+ receiver.instance_eval { alias_method :save, :save! }
51
+ receiver.validated_before :save, *args
52
+
53
+ without = args.extract_options![:without]
54
+ receiver.send! :include, Hooks unless [*without].include? :hooks
55
+ end
56
+
57
+ # Returns state for given instance.
58
+ def get_state(instance)
59
+ if instance.new? then @states[:create] else @states[:update] end
60
+ end
61
+
62
+ # Adds validation hooks to Sequel::Model.
63
+ module Hooks
64
+ def self.included(base)
65
+ base.instance_eval do
66
+ def_hook_method :before_validate
67
+ def_hook_method :after_validate
68
+ alias_method :validate_without_hooks, :validate
69
+ alias_method :validate, :validate_with_hooks
70
+ end
71
+ end
72
+
73
+ def before_validate() end
74
+ def after_validate() end
75
+
76
+ def validate_with_hooks
77
+ before_validate
78
+ validate_without_hooks
79
+ after_validate
80
+ end
81
+ end
82
+
83
+ # Ensures Sequel::Model API compatibility.
84
+ module ClassMethods
85
+
86
+ # Returns the validations hash for the class.
87
+ def validations
88
+ validator.states.
89
+ inject({}) do |validations, state_with_name|
90
+ validations.merge(state_with_name[1].validations) {|k,o,n| o|n}
91
+ end
92
+ end
93
+ # Returns true if validations are defined.
94
+ def has_validations?()
95
+ validator.has_validations?
96
+ end
97
+ # Validates the given instance.
98
+ def validate(instance)
99
+ validator.invoke instance
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,69 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ describe subject::Builder do
4
+
5
+ before(:each) do
6
+ @validatable = Class.new(Object) do
7
+ def self.validator=(validator) @validator = validator end
8
+ def self.validator() @validator end
9
+ def initialize(state) @state = state end
10
+ def validation_state() state end
11
+ end
12
+ @validatable.validator = mock 'Validator'
13
+ @validatable.extend(subject::Builder)
14
+ end
15
+
16
+ it "should have a delegator class" do
17
+ subject::Builder.constants.
18
+ should include('ValidationDelegator')
19
+ subject::Builder.const_get('ValidationDelegator').
20
+ should < SimpleDelegator
21
+ end
22
+ it "should provide the :validates builder method" do
23
+ @validatable.should respond_to(:validates)
24
+ end
25
+ it "should add validation for :name via :validates" do
26
+ @validatable.validator.should_receive(:add_validation).
27
+ with(NotNaughty::PresenceValidation, :name, {}).twice
28
+ @validatable.validates { presence_of :name }
29
+ @validatable.validates(:name) { presence }
30
+ end
31
+ it "should add validation for :name on update via :validates" do
32
+ @validatable.validator.should_receive(:add_validation).
33
+ with(NotNaughty::PresenceValidation, :name, {:on => :update}).twice
34
+ @validatable.validates { presence_of :name, :on => :update }
35
+ @validatable.validates(:on => :update) { presence_of :name }
36
+ end
37
+ it "should add validation for :firstname and :lastname via :validates" do
38
+ @validatable.validator.should_receive(:add_validation).
39
+ with(NotNaughty::PresenceValidation, :firstname, :lastname, {}).twice
40
+ @validatable.validates { presence_of :firstname, :lastname }
41
+ @validatable.validates(:firstname, :lastname) { presence :name }
42
+ end
43
+ it "should register validation" do
44
+ validation = Class.new(subject::Validation) do
45
+ def self.name() 'TestValidation' end
46
+ def initialize(opts, &block) end
47
+ def call(obj, attr, value) end
48
+ end
49
+
50
+ @validatable.should respond_to(:validates_test_of)
51
+ end
52
+ it "should provide the :validates_each builder method" do
53
+ @validatable.should respond_to(:validates_each)
54
+ end
55
+ it "should build the Validations with :validates_each" do
56
+ @validatable.validator = mock 'Validator'
57
+ @validatable.validator.
58
+ should_receive(:add_validation).
59
+ with(:a, :b)
60
+ @validatable.validates_each(:a, :b) {|o, a, v|}
61
+
62
+ pending 'expect a block'
63
+ end
64
+ it "should raise a NoMethodError is builder method does not exist" do
65
+ lambda { @validatable.validates() { bunch_of :holy_crap } }.
66
+ should raise_error(NoMethodError)
67
+ end
68
+
69
+ end
@@ -0,0 +1,61 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ describe subject::Errors do
4
+
5
+ before(:each) { @errors = subject::Errors.new }
6
+
7
+ it "should add errors in a hash" do
8
+ @errors.add :attribute, 'Message'
9
+
10
+ @errors.instance_variable_get(:@errors)[:attribute].
11
+ should include('Message')
12
+ end
13
+ it "should return full messages" do
14
+ @errors.add :attribute, 'Message #{"%s".capitalize}'
15
+
16
+ @errors.full_messages.
17
+ should == ['Message Attribute']
18
+ end
19
+ it "should return an #{subject::ValidationException} with errors" do
20
+ exception = @errors.to_exception
21
+ exception.should be_an_instance_of(subject::ValidationException)
22
+ exception.errors.should == @errors
23
+ end
24
+ it "should have methods delegated" do
25
+ probe = mock 'Probe'
26
+ methods = [:empty?, :clear, :[], :each, :to_yaml]
27
+
28
+ methods.each { |m| probe.should_receive m }
29
+ @errors.instance_variable_set :@errors, probe
30
+
31
+ methods.each { |m| @errors.send! m }
32
+ end
33
+ it "should return evaluated errors messages" do
34
+ @errors.add :attribute, 'Message #{"%s".capitalize}'
35
+ @errors.on(:attribute).should == ['Message Attribute']
36
+ end
37
+
38
+ end
39
+
40
+ describe subject::ValidationException do
41
+
42
+ it "should return an exception with errors" do
43
+ probe = mock 'probe'
44
+ probe.should_receive(:any?).and_return(true)
45
+ exception = subject::ValidationException.new probe
46
+
47
+ lambda { raise exception }.should_not raise_error(TypeError)
48
+ exception.errors.should == probe
49
+ end
50
+ it "should have methods delegated" do
51
+ methods = [:on, :full_messages, :each]
52
+
53
+ probe = mock 'Probe'
54
+ probe.should_receive(:any?).and_return(true)
55
+ exception = subject::ValidationException.new probe
56
+
57
+ methods.each { |m| probe.should_receive m }
58
+ methods.each { |m| exception.send! m }
59
+ end
60
+
61
+ end
@@ -0,0 +1,80 @@
1
+ require "#{ File.dirname(__FILE__) }/spec_helper.rb"
2
+
3
+ module subject::Builder
4
+ def self.extended(base) end
5
+ end
6
+ module subject::InstanceMethods
7
+ def self.included(base) end
8
+ end
9
+
10
+ describe subject do
11
+
12
+ it "should load necessary files" do
13
+ subject::should be_const_defined(:Validation)
14
+ subject::should be_const_defined(:Validator)
15
+ subject::should be_const_defined(:Builder)
16
+ subject::should be_const_defined(:InstanceMethods)
17
+ subject::should be_const_defined(:Errors)
18
+ end
19
+ it "should define a validator" do
20
+ validated = Class.new(Object).extend subject
21
+ validated.should respond_to(:validator)
22
+ validated.validator.should be_an_instance_of(subject::Validator)
23
+
24
+ validator = Class.new(subject::Validator)
25
+ validated = Class.new(Object).extend subject
26
+ validated.validator validator, :create, :update
27
+ validated.validator.should be_an_instance_of(validator)
28
+ validated.validator.states.keys.should include(:create, :update)
29
+ end
30
+ it "should extend the receiver if validator is defined" do
31
+ validated = Class.new(Object)
32
+
33
+ subject::Builder.should_receive(:extended).with(validated)
34
+ subject::InstanceMethods.should_receive(:included).with(validated)
35
+
36
+ validated.extend subject
37
+ end
38
+ it "should deep-clone the validator if inherited" do
39
+ super_validated = Class.new(Object).extend subject
40
+ super_validated.validator.add_validation(:name) {|o, a, v|}
41
+ validated = Class.new(super_validated)
42
+
43
+ validated.validator.should_not == super_validated.validator
44
+ validated.validator.should have_validations
45
+ validated.validator.add_validation(:name) {|o, a, v|}
46
+
47
+ super_validated.validator.get_state.validations[:name].length.
48
+ should < validated.validator.get_state.validations[:name].length
49
+ end
50
+ it "should prepend a validation before any method" do
51
+ validated = Class.new(Object).extend subject
52
+
53
+ validated.validated_before :clone
54
+ instance = validated.new
55
+ instance.should_receive(:valid?).once.and_return(true)
56
+ instance.should_receive(:clone_without_validations)
57
+ instance.clone
58
+ end
59
+ it "should raise an exception if invalid and method called" do
60
+ validated = Class.new(Object).extend subject
61
+
62
+ validated.validated_before :clone
63
+ instance = validated.new
64
+ instance.should_receive(:valid?).once.and_return(false)
65
+ lambda { instance.clone }.should raise_error(subject::ValidationException)
66
+ end
67
+ it "should return false if invalid and method called" do
68
+ validated = Class.new(Object).extend subject
69
+
70
+ validated.validated_before :clone, :without => :exception
71
+ instance = validated.new
72
+ instance.should_receive(:valid?).once.and_return(false)
73
+ instance.clone.should == false
74
+ end
75
+ it "should add Builder to Validation observers" do
76
+ subject::Validation.instance_variable_get(:@observer_peers).
77
+ should include(subject::Builder)
78
+ end
79
+
80
+ end
data/spec/rcov.opts ADDED
@@ -0,0 +1,4 @@
1
+ --exclude
2
+ gems
3
+ --exclude
4
+ spec