activespec 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +75 -0
- data/lib/active_spec.rb +21 -0
- data/lib/active_spec/base.rb +141 -0
- data/lib/active_spec/context.rb +30 -0
- data/lib/active_spec/satisfies.rb +78 -0
- data/lib/active_spec/specifications.rb +13 -0
- data/lib/active_spec/specifications/attributes_specification.rb +39 -0
- data/lib/active_spec/specifications/collection_specification.rb +42 -0
- data/lib/active_spec/specifications/composite_specification.rb +24 -0
- data/lib/active_spec/specifications/confirmation_specification.rb +50 -0
- data/lib/active_spec/specifications/not_specification.rb +19 -0
- data/lib/active_spec/specifications/presence_specification.rb +35 -0
- data/lib/active_spec/specifications/proc_specification.rb +22 -0
- data/lib/active_spec/specifications/size_specification.rb +38 -0
- data/spec/collection_specification_spec.rb +56 -0
- data/spec/composite_specification_spec.rb +66 -0
- data/spec/confirmation_specification_spec.rb +39 -0
- data/spec/not_specification_spec.rb +25 -0
- data/spec/presence_specification_spec.rb +63 -0
- data/spec/proc_specification_spec.rb +28 -0
- data/spec/size_specification_spec.rb +74 -0
- data/spec/spec_helper.rb +4 -0
- metadata +66 -0
data/README
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
= ActiveSpec - Ruby Specifications Library
|
2
|
+
|
3
|
+
ActiveSpec is a Ruby implementation of the Specification pattern. It was born out of the desire to implement more complicated validations than the built-in Ruby On Rails validations macros allow and can be used with both Rails and non-Rails applications.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
ActiveSpec can currently be downloaded from Subversion. The repository URL is:
|
8
|
+
|
9
|
+
http://opensource.agileevolved.com/svn/root/activespec/trunk
|
10
|
+
|
11
|
+
It will be released as a gem shortly.
|
12
|
+
|
13
|
+
== Overview
|
14
|
+
|
15
|
+
ActiveSpec is comprised of four main components:
|
16
|
+
|
17
|
+
=== 1. A set of low-level Specification classes
|
18
|
+
Many of these are designed to work with one or more attributes of a given object and are mostly modelled on the existing set of Ruby On Rails validation macros. There is also a CompositeSpecification class for working with more than one specification at one time. It is also very easy (and actively encouraged) to create your own low-level Specification classes. See ActiveSpec::Specifications for more information.
|
19
|
+
|
20
|
+
=== 2. ActiveSpec::Base class
|
21
|
+
This can be sub-classed to create specifications in a more declarative manner. Here is a small example:
|
22
|
+
|
23
|
+
class UserSpecification < ActiveSpec::Base
|
24
|
+
requires_presence_of :username, :password
|
25
|
+
requires_confirmation_of :password
|
26
|
+
end
|
27
|
+
|
28
|
+
The main interface for any specification is a <tt>satisfied_by?</tt> method. The low-level specification classes (including CompositeSpecification) define <tt>satisfied_by?</tt> as an instance method and the ActiveSpec::Base specifications define it as a class method (it is not necessary to instantiate ActiveSpec::Base specifications).
|
29
|
+
|
30
|
+
=== 3. High-level specification DSL
|
31
|
+
ActiveSpec provides a high level DSL for creating specifications, that builds on top of ActiveSpec::Base. An alternative way of creating the above UserSpecification using the specification DSL would be:
|
32
|
+
|
33
|
+
specification :user do
|
34
|
+
requires_presence_of :username, :password
|
35
|
+
requires_confirmation_of :password
|
36
|
+
end
|
37
|
+
|
38
|
+
This will automatically create a UserSpecification class with the given specifications. See ActiveSpec::Context for more information.
|
39
|
+
|
40
|
+
=== 4. ActiveSpec::Satisfies module
|
41
|
+
The Satisfies module can be included into your own classes to provide functionality for working with specifications. This will allow you to directly associate specifications with your classes in a style similar to using Rails' validates_* macros.
|
42
|
+
|
43
|
+
class User
|
44
|
+
include ActiveSpec::Satisifies
|
45
|
+
|
46
|
+
must_satisfy :user_specification
|
47
|
+
end
|
48
|
+
|
49
|
+
user = User.new
|
50
|
+
user.satisfies_specs?
|
51
|
+
|
52
|
+
For more information, see ActiveSpec::Satisfies.
|
53
|
+
|
54
|
+
Also included with the library is a helper function for pre-loading specification classes in a given directory. See ActiveSpec#preload_specifications.
|
55
|
+
|
56
|
+
== Rails integration
|
57
|
+
|
58
|
+
You can use ActiveSpec in your Rails app with your ActiveRecord model classes by adding the following lines to your environment.rb file:
|
59
|
+
|
60
|
+
require 'active_spec'
|
61
|
+
ActiveRecord::Base.send(:include, ActiveSpec::Satisfies)
|
62
|
+
|
63
|
+
You will currently have to deal with the loading of your specification files yourself and you might find the preload_specifications method handy for this. There are plans to make integration with a Rails app even easier with an ActiveSpec Rails plugin in the near future.
|
64
|
+
|
65
|
+
== Future plans
|
66
|
+
|
67
|
+
One of the main features that ActiveSpec is missing that Rails' validations module provides is error message functionality. This will eventually be added to ActiveSpec, possibly with integration into the ActiveRecord::Errors class.
|
68
|
+
|
69
|
+
== Comments and feedback
|
70
|
+
|
71
|
+
Please send any comments to contact [AT] lukeredpath [DOT] co [DOT] uk. Please report any bugs on the Agile Evolved Open Source Trac at http://opensource.agileevolved.com.
|
72
|
+
|
73
|
+
== Credits
|
74
|
+
|
75
|
+
Copyright (c) Luke Redpath 2006. Released under the MIT license.
|
data/lib/active_spec.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
|
4
|
+
module ActiveSpec
|
5
|
+
|
6
|
+
# Globs the given path for files with the name
|
7
|
+
# *_specification.rb and requires any files that it finds.
|
8
|
+
def self.preload_specifications(path_to_specs)
|
9
|
+
Dir.glob("#{path_to_specs}/*_specification.rb").each do |f|
|
10
|
+
require "#{path_to_specs}/#{File.basename(f, ".rb")}"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
require File.dirname(__FILE__) + '/active_spec/specifications'
|
17
|
+
require File.dirname(__FILE__) + '/active_spec/base'
|
18
|
+
require File.dirname(__FILE__) + '/active_spec/satisfies'
|
19
|
+
require File.dirname(__FILE__) + '/active_spec/context'
|
20
|
+
|
21
|
+
include ActiveSpec::Context
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# The ActiveSpec::Base class provides a more declarative way of
|
2
|
+
# creating specifications than using the low-level Specification
|
3
|
+
# classes. It essentially acts as a composite specification (it
|
4
|
+
# actually delegates to ActiveSpec::Specifications::CompositeSpecification
|
5
|
+
# when calling <tt>satisfied_by?</tt>) and allows you to create new specifications
|
6
|
+
# by sub-classing ActiveSpec::Base and calling the built-in macros to add
|
7
|
+
# individual specifications.
|
8
|
+
#
|
9
|
+
# This declarative way of creating specifications will be more familiar
|
10
|
+
# to those who are used to using Rails' built-in validates_* macros.
|
11
|
+
#
|
12
|
+
# Example specification:
|
13
|
+
#
|
14
|
+
# class UserSpecification < ActiveSpec::Base
|
15
|
+
# require_presence_of :username, :email
|
16
|
+
# require_confirmation_of :password
|
17
|
+
# require_inclusion_in 18..30, :age
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# You can execute an ActiveSpec against an object by calling
|
21
|
+
# the class method <tt>satisfied_by?</tt>. There is no need to
|
22
|
+
# instantiate an ActiveSpec class.
|
23
|
+
#
|
24
|
+
# user = User.new
|
25
|
+
# UserSpecification.satisfied_by?(user)
|
26
|
+
class ActiveSpec::Base
|
27
|
+
|
28
|
+
class << self
|
29
|
+
|
30
|
+
# Adds a ActiveSpec::Specifications::PresenceSpecification for the given attributes.
|
31
|
+
def requires_presence_of(*attributes)
|
32
|
+
add_specification ActiveSpec::Specifications::PresenceSpecification.new(*attributes)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Adds a ActiveSpec::Specifications::CollectionSpecification for the given collection and attributes.
|
36
|
+
def requires_inclusion_in(collection, *attributes)
|
37
|
+
add_specification ActiveSpec::Specifications::CollectionSpecification.new(collection, *attributes)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Adds a ActiveSpec::Specifications::CollectionSpecification wrapped in a
|
41
|
+
# ActiveSpec::Specifications::NotSpecification decorator
|
42
|
+
# for the given collection and attributes.
|
43
|
+
def requires_exclusion_from(collection, *attributes)
|
44
|
+
add_specification ActiveSpec::Specifications::NotSpecification.new(
|
45
|
+
ActiveSpec::Specifications::CollectionSpecification.new(collection, *attributes)
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Adds a ActiveSpec::Specifications::ConfirmationSpecification for the given attributes.
|
50
|
+
def requires_confirmation_of(*attributes)
|
51
|
+
add_specification ActiveSpec::Specifications::ConfirmationSpecification.new(*attributes)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Adds a ActiveSpec::Specifications::SizeSpecification for the given attributes.
|
55
|
+
def requires_size(size, *attributes)
|
56
|
+
add_specification ActiveSpec::Specifications::SizeSpecification.new(size, *attributes)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Adds a ActiveSpec::Specifications::MatchSpecification for the given regexp and attributes.
|
60
|
+
def requires_match(regexp, *attributes)
|
61
|
+
# TODO add_specification MatchSpecification.new(regexp, *attributes)
|
62
|
+
end
|
63
|
+
|
64
|
+
# A generic method that lets you add arbitrary specifications in several
|
65
|
+
# formats. <tt>specification</tt> can be a specification class (that
|
66
|
+
# responds to <tt>satisfied_by?</tt>), a Symbol (which is used to find a specification
|
67
|
+
# class) or a Proc object. As an alternative to passing a Proc, you can
|
68
|
+
# simply call <tt>satisfy</tt> with a block. The Proc/block will
|
69
|
+
# be passed the object that is sent to <tt>satisfied_by?</tt> when <tt>satisfied_by?</tt>
|
70
|
+
# is called.
|
71
|
+
#
|
72
|
+
# # Using a class
|
73
|
+
# must_satisfy UserSpecification
|
74
|
+
#
|
75
|
+
# # Using a symbol
|
76
|
+
# must_satisfy :user_specification
|
77
|
+
#
|
78
|
+
# # Using a Proc
|
79
|
+
# must_satisfy proc{ |object| # do something with object }
|
80
|
+
#
|
81
|
+
# # Passing in a block
|
82
|
+
# must_satisfy { |object| # do something with object }
|
83
|
+
#
|
84
|
+
# This method gives you the power to create very complicated specifications.
|
85
|
+
# Because you can pass in anything that responds to <tt>satisfied_by?</tt>, you can
|
86
|
+
# pass in your own low-level specification classes, ActiveSpec::Specifications::CompositeSpecification
|
87
|
+
# classes, or even other ActiveSpec classes, e.g.
|
88
|
+
#
|
89
|
+
# class UserSpecification < ActiveSpec::Base
|
90
|
+
# require_presence_of :email
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# class AdvancedUserSpecification < ActiveSpec::Base
|
94
|
+
# must_satisfy :user_specification
|
95
|
+
# require_presence_of :something_else
|
96
|
+
# end
|
97
|
+
def must_satisfy(specification=nil, &block)
|
98
|
+
case specification
|
99
|
+
when Symbol
|
100
|
+
add_specification Object.const_get(Inflector::classify(specification))
|
101
|
+
when Proc
|
102
|
+
add_specification ActiveSpec::Specifications::ProcSpecification.new(specification)
|
103
|
+
when Class
|
104
|
+
add_specification specification
|
105
|
+
else
|
106
|
+
if block_given?
|
107
|
+
add_specification ActiveSpec::Specifications::ProcSpecification.new(block)
|
108
|
+
else
|
109
|
+
raise "satisfy must be passed a symbol, proc, class or block"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
# Calls <tt>satisfied_by?</tt> on each specification with
|
115
|
+
# the given object. Returns <tt>true</tt> if all of the specifications
|
116
|
+
# pass, otherwise it returns <tt>false</tt>.
|
117
|
+
def satisfied_by?(object)
|
118
|
+
composite_spec.satisfied_by?(object)
|
119
|
+
end
|
120
|
+
|
121
|
+
protected
|
122
|
+
def write_inheritable_set(key, spec)
|
123
|
+
existing_specs = read_inheritable_attribute(key) || []
|
124
|
+
specs_to_write = existing_specs << spec
|
125
|
+
write_inheritable_attribute(key, specs_to_write)
|
126
|
+
end
|
127
|
+
|
128
|
+
def add_specification(spec)
|
129
|
+
write_inheritable_set(:specifications, spec)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns a ActiveSpec::Specifications::CompositeSpecification with all of the
|
133
|
+
# declared specifications.
|
134
|
+
def composite_spec
|
135
|
+
composite_spec = ActiveSpec::Specifications::CompositeSpecification.new
|
136
|
+
read_inheritable_attribute(:specifications).each { |spec| composite_spec.add_specification(spec) }
|
137
|
+
composite_spec
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# Provides a high-level DSL-like interface to the ActiveSpec
|
2
|
+
# library.
|
3
|
+
module ActiveSpec::Context
|
4
|
+
|
5
|
+
# This method allows you to build ActiveSpec specifications
|
6
|
+
# using a DSL-like syntax. Pass in a name for your specification
|
7
|
+
# (without the _specification suffix which will be added
|
8
|
+
# automatically) and a block which contains your individual
|
9
|
+
# specifications.
|
10
|
+
#
|
11
|
+
# The ActiveSpec::Context module gets included automatically
|
12
|
+
# when the ActiveSpec library is required, so the <tt>specification</tt>
|
13
|
+
# method is available in the global namespace.
|
14
|
+
#
|
15
|
+
# Example usage:
|
16
|
+
#
|
17
|
+
# specification :user do
|
18
|
+
# should_require_presence_of :username, :password
|
19
|
+
# should_require_confirmation_of :password
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# The above code will create a UserSpecification class (a sub-class
|
23
|
+
# of ActiveSpec::Base) with the given specifications.
|
24
|
+
def specification(name, &block)
|
25
|
+
klass = Inflector::classify("#{name.to_s}_specification")
|
26
|
+
Object.const_set(klass, Class.new(ActiveSpec::Base))
|
27
|
+
Object.const_get(klass).class_eval(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Provides functionality for working with specifications
|
2
|
+
# inside your own classes. Simply include the module
|
3
|
+
# inside any class that you want to use with specifications.
|
4
|
+
#
|
5
|
+
# Example usage:
|
6
|
+
#
|
7
|
+
# specification :user do
|
8
|
+
# should_require_presence_of :username
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# specification :authenticated_user do
|
12
|
+
# # some other specs
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# class User
|
16
|
+
# must_satisfy :user_specification
|
17
|
+
# must_satisfy :authenticated_user_specification, :if => { |u| u.has_password? }
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# user = User.new
|
21
|
+
# user.satisfies_specs? # returns false
|
22
|
+
# user.username = 'joebloggs'
|
23
|
+
# user.satisfies_specs? # returns true
|
24
|
+
#
|
25
|
+
# For information on adding specifications, see the ActiveSpec::Satisfies::ClassMethods module.
|
26
|
+
module ActiveSpec::Satisfies
|
27
|
+
|
28
|
+
def self.included(base)
|
29
|
+
base.extend(ClassMethods)
|
30
|
+
end
|
31
|
+
|
32
|
+
module ClassMethods
|
33
|
+
|
34
|
+
# Specifies a specification class (can be anything that responds to <tt>satisfied_by?</tt>)
|
35
|
+
# that any instances of the class should satisfy. Takes one option:
|
36
|
+
#
|
37
|
+
# * <tt>:if</tt> - used to pass in a block that must return true
|
38
|
+
# for the specification to apply. Can be used to conditionally declare
|
39
|
+
# specifications.
|
40
|
+
def must_satisfy(spec_name, opts={})
|
41
|
+
satisfies = read_inheritable_attribute(:satisfies) || []
|
42
|
+
satisfies << {:spec => spec_name, :options => opts}
|
43
|
+
write_inheritable_attribute(:satisfies, satisfies)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
# Checks that all relevant, assigned specifications pass.
|
49
|
+
# Specifications assigned with the <tt>:if</tt> option will only
|
50
|
+
# be evaluated if the <tt>:if</tt> block returns true.
|
51
|
+
def satisfies_specs?
|
52
|
+
satisfies = self.class.read_inheritable_attribute(:satisfies) || []
|
53
|
+
satisfies.collect do |s|
|
54
|
+
if s[:options][:if]
|
55
|
+
return true unless passes_predicate?(s[:options][:if])
|
56
|
+
end
|
57
|
+
satisfies?(s[:spec])
|
58
|
+
end.grep(false).empty?
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
def satisfies?(spec)
|
63
|
+
if spec.instance_of?(Symbol)
|
64
|
+
spec = Kernel.const_get(Inflector::classify(spec))
|
65
|
+
end
|
66
|
+
spec.satisfied_by? self
|
67
|
+
end
|
68
|
+
|
69
|
+
def passes_predicate?(predicate)
|
70
|
+
case predicate
|
71
|
+
when Symbol
|
72
|
+
return self.send(predicate)
|
73
|
+
when Proc
|
74
|
+
return predicate.call(self)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module ActiveSpec
|
2
|
+
module Specifications
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require File.dirname(__FILE__) + '/specifications/composite_specification'
|
7
|
+
require File.dirname(__FILE__) + '/specifications/attributes_specification'
|
8
|
+
require File.dirname(__FILE__) + '/specifications/presence_specification'
|
9
|
+
require File.dirname(__FILE__) + '/specifications/confirmation_specification'
|
10
|
+
require File.dirname(__FILE__) + '/specifications/size_specification'
|
11
|
+
require File.dirname(__FILE__) + '/specifications/collection_specification'
|
12
|
+
require File.dirname(__FILE__) + '/specifications/proc_specification'
|
13
|
+
require File.dirname(__FILE__) + '/specifications/not_specification'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This is the base class for all specification classes that
|
2
|
+
# can act on any number of public object attributes. If you want
|
3
|
+
# to write a specification class that can act on many public
|
4
|
+
# object attributes, sub-class this class and define your own
|
5
|
+
# <tt>satisfied_by?</tt> method.
|
6
|
+
class ActiveSpec::Specifications::AttributesSpecification
|
7
|
+
|
8
|
+
# The default initialize method stores all attributes in
|
9
|
+
# an instance variable called <tt>@attributes</tt>. When
|
10
|
+
# sub-classing, it is important to call <tt>super</tt>
|
11
|
+
# with the given attributes, for example:
|
12
|
+
#
|
13
|
+
# class MyOwnSpecification < ActiveSpec::Specifications::AttributesSpecification
|
14
|
+
# def initialize(custom_var, *attributes)
|
15
|
+
# # do something with custom_var
|
16
|
+
# super(*attributes)
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
def initialize(*attributes)
|
20
|
+
@attributes = attributes
|
21
|
+
end
|
22
|
+
|
23
|
+
# This default implementation always returns <tt>true</tt>.
|
24
|
+
# Override this method in your own specification classes.
|
25
|
+
def satisfied_by?(object)
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
# Yields each attribute in the <tt>@attributes</tt>
|
32
|
+
# collection to the given block and if all block
|
33
|
+
# calls return <tt>true</tt>, then it returns <tt>true</tt>.
|
34
|
+
# Otherwise it returns <tt>false</tt>.
|
35
|
+
def attributes_satisfy?(&block) #:yields: attribute
|
36
|
+
@attributes.collect { |a| yield a }.grep(false).empty?
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Checks the values of one or more attributes for
|
2
|
+
# inclusion within a given collection. This is similar to
|
3
|
+
# the Rails validation macro <tt>validates_inclusion_of</tt>.
|
4
|
+
#
|
5
|
+
# Example usage:
|
6
|
+
#
|
7
|
+
# include ActiveSpec::Specifications
|
8
|
+
#
|
9
|
+
# class ColorPicker
|
10
|
+
# def color
|
11
|
+
# 'red'
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# spec_one = CollectionSpecification.new(['red', 'yellow'], :color)
|
16
|
+
# spec_two = CollectionSpecification.new(['green', 'yellow'], :color)
|
17
|
+
# spec_one.satisfied_by?(ColorPicker.new) # returns true
|
18
|
+
# spec_two.satisfied_by?(ColorPicker.new) # returns false
|
19
|
+
#
|
20
|
+
# The equivalent of the Rails <tt>validates_exclusion_of</tt>
|
21
|
+
# validation macro can be implemented by wrapping a CollectionSpecification
|
22
|
+
# inside a NotSpecification decorator.
|
23
|
+
class ActiveSpec::Specifications::CollectionSpecification < ActiveSpec::Specifications::AttributesSpecification
|
24
|
+
|
25
|
+
# <tt>collection</tt> can be any object that responds to
|
26
|
+
# <tt>include?</tt>, such as Array and Range objects.
|
27
|
+
def initialize(collection, *attributes)
|
28
|
+
@collection = collection
|
29
|
+
super(*attributes)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns false if the object fails to respond to
|
33
|
+
# to any of the given attributes, or if any of the attribute
|
34
|
+
# values for the object are not in the specified collection.
|
35
|
+
def satisfied_by?(object)
|
36
|
+
attributes_satisfy? do |a|
|
37
|
+
return false unless object.respond_to?(a)
|
38
|
+
return false unless @collection.include?(object.send(a))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Uses the Composite pattern to allow an object to be
|
2
|
+
# run against any number of specifications in one operation.
|
3
|
+
# A specification can be any object that responds to <tt>satisfied_by?</tt>.
|
4
|
+
# Because the composite specification also responds to <tt>satisfied_by?</tt>, you can
|
5
|
+
# add composite specifications to other composite specifications.
|
6
|
+
class ActiveSpec::Specifications::CompositeSpecification
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@specs = []
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adds a new specification to the composite
|
13
|
+
def add_specification(spec)
|
14
|
+
@specs << spec
|
15
|
+
end
|
16
|
+
|
17
|
+
# Calls <tt>satisfied_by?</tt> on each specification with
|
18
|
+
# the given object. Returns <tt>true</tt> if all of the specifications
|
19
|
+
# pass, otherwise it returns <tt>false</tt>.
|
20
|
+
def satisfied_by?(object)
|
21
|
+
@specs.collect { |s| s.satisfied_by?(object) }.grep(false).empty?
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# Looks for a confirmation attribute for each given attribute.
|
2
|
+
# It looks for a confirmation attribtue named attributename_confirmation
|
3
|
+
# and checks that the value of the attribute and its confirmation attribute match.
|
4
|
+
# This could be used to validate password confirmations.
|
5
|
+
#
|
6
|
+
# Example usage:
|
7
|
+
#
|
8
|
+
# include ActiveSpec::Specifications
|
9
|
+
#
|
10
|
+
# class User
|
11
|
+
# attr_accessor :password, :password_confirmation
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# spec = ConfirmationSpecification.new(:password)
|
15
|
+
#
|
16
|
+
# # passing spec
|
17
|
+
# user_one = User.new
|
18
|
+
# user_one.password = 'foo'
|
19
|
+
# user_one.password_confirmation = 'foo'
|
20
|
+
# spec.satisfied_by?(user_one) # returns true
|
21
|
+
#
|
22
|
+
# # failing spec
|
23
|
+
# user_two = User.new
|
24
|
+
# user_two.password = 'foo'
|
25
|
+
# user_two.password_confirmation = 'bar'
|
26
|
+
# spec.satisfied_by?(user_two) # returns false
|
27
|
+
#
|
28
|
+
# This works in the same way as the Rails validation macro
|
29
|
+
# <tt>validates_confirmation_of</tt>.
|
30
|
+
class ActiveSpec::Specifications::ConfirmationSpecification < ActiveSpec::Specifications::AttributesSpecification
|
31
|
+
|
32
|
+
# Returns false if the given object fails to respond to
|
33
|
+
# any of the attributes, or the attributes' confirmation
|
34
|
+
# methods. If both attribute and attribute confirmation methods
|
35
|
+
# respond, then it checks that the values of both match.
|
36
|
+
def satisfied_by?(object)
|
37
|
+
attributes_satisfy? do |a|
|
38
|
+
return false unless object.respond_to?(a)
|
39
|
+
return false unless object.respond_to?(confirmation_attribute(a))
|
40
|
+
return false unless object.send(a) == object.send(confirmation_attribute(a))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def confirmation_attribute(attribute)
|
47
|
+
"#{attribute.to_s}_confirmation"
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# A simple decorator class that negates the
|
2
|
+
# specification that it wraps, e.g.:
|
3
|
+
#
|
4
|
+
# include ActiveSpec::Specifications
|
5
|
+
#
|
6
|
+
# spec = AlwaysPassSpec.new(:foo)
|
7
|
+
# spec.satisfied_by? # returns true
|
8
|
+
# NotSpecification.new(spec).satisfied_by? # returns false
|
9
|
+
class ActiveSpec::Specifications::NotSpecification
|
10
|
+
|
11
|
+
def initialize(decorated_spec)
|
12
|
+
@decorated_spec = decorated_spec
|
13
|
+
end
|
14
|
+
|
15
|
+
def satisfied_by?(object)
|
16
|
+
not @decorated_spec.satisfied_by?(object)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This specification will check that the values for
|
2
|
+
# each attribute are neither nil, or empty.
|
3
|
+
#
|
4
|
+
# Example usage:
|
5
|
+
#
|
6
|
+
# include ActiveSpec::Specifications
|
7
|
+
#
|
8
|
+
# class Foo
|
9
|
+
# attr_accessor :bar
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# spec = PresenceSpecification.new(:bar)
|
13
|
+
# foo = Foo.new
|
14
|
+
# spec.satisfied_by?(foo) # returns false
|
15
|
+
# foo.bar = ''
|
16
|
+
# spec.satisfied_by?(foo) # returns false
|
17
|
+
# foo.bar = 'baz'
|
18
|
+
# spec.satisfied_by?(foo) # returns true
|
19
|
+
#
|
20
|
+
# This works in the same way as the Rails validation
|
21
|
+
# macro <tt>validates_presence_of</tt>.
|
22
|
+
class ActiveSpec::Specifications::PresenceSpecification < ActiveSpec::Specifications::AttributesSpecification
|
23
|
+
|
24
|
+
# Checks that the value for each attribute on the given object
|
25
|
+
# is neither nil or empty. It will also return false if
|
26
|
+
# the object fails to respond to any attribute.
|
27
|
+
def satisfied_by?(object)
|
28
|
+
attributes_satisfy? do |a|
|
29
|
+
return false unless object.respond_to?(a)
|
30
|
+
return false if object.send(a).nil?
|
31
|
+
return false if object.send(a).empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# A ProcSpecification is a simple wrapper around a Proc
|
2
|
+
# object, that makes it conform to the Specification
|
3
|
+
# interface (with a <tt>satisfied_by?</tt> method). If the given
|
4
|
+
# Proc returns true, the specification passes, otherwise
|
5
|
+
# it does not pass.
|
6
|
+
class ActiveSpec::Specifications::ProcSpecification
|
7
|
+
|
8
|
+
def initialize(proc)
|
9
|
+
@proc = proc
|
10
|
+
end
|
11
|
+
|
12
|
+
# Calls the wrapped Proc object, passing the given object
|
13
|
+
# to the proc. Returns the result of the Proc (either <tt>true</tt>
|
14
|
+
# or <tt>false</tt>). If the Proc raises an exception of any
|
15
|
+
# kind, then <tt>satisfied_by?</tt> will return <tt>false</tt>.
|
16
|
+
def satisfied_by?(object)
|
17
|
+
@proc.call(object)
|
18
|
+
rescue
|
19
|
+
false
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# Checks that the values for the given attributes are
|
2
|
+
# of a particular size. The size can be a precise number (Fixnum)
|
3
|
+
# or a Range. If a Range is given, the specification will pass
|
4
|
+
# if the value's size falls within the Range.
|
5
|
+
#
|
6
|
+
# Creating a SizeSpecification with a Fixnum is the same as
|
7
|
+
# the Rails <tt>validates_size_of</tt> macro with the <tt>:exactly</tt> option.
|
8
|
+
# Using a Range is the equivalent of using <tt>validates_size_of</tt>
|
9
|
+
# with the <tt>:in</tt> option.
|
10
|
+
class ActiveSpec::Specifications::SizeSpecification < ActiveSpec::Specifications::AttributesSpecification
|
11
|
+
|
12
|
+
# <tt>size</tt> can be a Fixnum or a Range.
|
13
|
+
def initialize(size, *attributes)
|
14
|
+
@size = size
|
15
|
+
super(*attributes)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Will return false if the object does not respond
|
19
|
+
# to any of the specified attributes, or if any of the
|
20
|
+
# the values for each attribute does not respond to
|
21
|
+
# <tt>size</tt>. Otherwise it will check that the size of the value
|
22
|
+
# for each attribute equals the given size (if size is
|
23
|
+
# a Fixnum) or within the given Range.
|
24
|
+
def satisfied_by?(object)
|
25
|
+
attributes_satisfy? do |a|
|
26
|
+
return false unless object.respond_to?(a)
|
27
|
+
return false unless object.send(a).respond_to?(:size)
|
28
|
+
case @size
|
29
|
+
when Fixnum
|
30
|
+
return false unless object.send(a).size == @size
|
31
|
+
when Range
|
32
|
+
return false unless @size.include?(object.send(a).size)
|
33
|
+
end
|
34
|
+
true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Collection specification" do
|
5
|
+
setup do
|
6
|
+
@spec = CollectionSpecification.new(['foo', 'bar'], :widget)
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass if the given object returns a value in the specified collection for the specified attribute" do
|
10
|
+
klass = Class.new
|
11
|
+
klass.send(:attr_accessor, :widget)
|
12
|
+
object = klass.new
|
13
|
+
object.widget = 'foo'
|
14
|
+
@spec.should_be_satisfied_by object
|
15
|
+
object.widget = 'bar'
|
16
|
+
@spec.should_be_satisfied_by object
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "should not pass if the given object doesn't respond to the specified attribute" do
|
20
|
+
@spec.should_not_be_satisfied_by Object.new
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "should not pass if the given object doesn't return a value in the specified collection for the specified attribute" do
|
24
|
+
klass = Class.new
|
25
|
+
klass.send(:attr_accessor, :widget)
|
26
|
+
object = klass.new
|
27
|
+
object.widget = 'baz'
|
28
|
+
@spec.should_not_be_satisfied_by object
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "Collection specification with range" do
|
33
|
+
setup do
|
34
|
+
@spec = CollectionSpecification.new(Range.new(10, 30), :age)
|
35
|
+
end
|
36
|
+
|
37
|
+
specify "should pass if the given object returns a fixnum for the attribute in the given range" do
|
38
|
+
klass = Class.new
|
39
|
+
klass.send(:attr_accessor, :age)
|
40
|
+
object = klass.new
|
41
|
+
object.age = 20
|
42
|
+
@spec.should_be_satisfied_by object
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should not pass if the given object does not respond to the specified attribute" do
|
46
|
+
@spec.should_not_be_satisfied_by Object.new
|
47
|
+
end
|
48
|
+
|
49
|
+
specify "should not pass if the given object returns a fixnum for the attribute that isn't in the given range" do
|
50
|
+
klass = Class.new
|
51
|
+
klass.send(:attr_accessor, :age)
|
52
|
+
object = klass.new
|
53
|
+
object.age = 35
|
54
|
+
@spec.should_not_be_satisfied_by object
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Empty composite specifcation" do
|
5
|
+
setup do
|
6
|
+
@spec = CompositeSpecification.new
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass" do
|
10
|
+
@spec.should_be_satisfied_by Object.new
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "Composite specifcation with just passing specifications" do
|
15
|
+
setup do
|
16
|
+
@spec = CompositeSpecification.new
|
17
|
+
@spec.add_specification(PresenceSpecification.new(:foo))
|
18
|
+
@spec.add_specification(PresenceSpecification.new(:bar))
|
19
|
+
klass = Class.new
|
20
|
+
klass.send(:attr_accessor, :foo)
|
21
|
+
klass.send(:attr_accessor, :bar)
|
22
|
+
@object = klass.new
|
23
|
+
@object.foo = 'something'
|
24
|
+
@object.bar = 'something else'
|
25
|
+
end
|
26
|
+
|
27
|
+
specify "should pass" do
|
28
|
+
@spec.should_be_satisfied_by @object
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "Composite specifcation with just failing specifications" do
|
33
|
+
setup do
|
34
|
+
@spec = CompositeSpecification.new
|
35
|
+
@spec.add_specification(PresenceSpecification.new(:foo))
|
36
|
+
@spec.add_specification(PresenceSpecification.new(:bar))
|
37
|
+
klass = Class.new
|
38
|
+
klass.send(:attr_accessor, :foo)
|
39
|
+
klass.send(:attr_accessor, :bar)
|
40
|
+
@object = klass.new
|
41
|
+
@object.foo = ''
|
42
|
+
@object.bar = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
specify "should not pass" do
|
46
|
+
@spec.should_not_be_satisfied_by @object
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "Composite specifcation with passing and failing specifications" do
|
51
|
+
setup do
|
52
|
+
@spec = CompositeSpecification.new
|
53
|
+
@spec.add_specification(PresenceSpecification.new(:foo))
|
54
|
+
@spec.add_specification(PresenceSpecification.new(:bar))
|
55
|
+
klass = Class.new
|
56
|
+
klass.send(:attr_accessor, :foo)
|
57
|
+
klass.send(:attr_accessor, :bar)
|
58
|
+
@object = klass.new
|
59
|
+
@object.foo = 'something'
|
60
|
+
@object.bar = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
specify "should not pass" do
|
64
|
+
@spec.should_not_be_satisfied_by @object
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Confirmation specification" do
|
5
|
+
setup do
|
6
|
+
@spec = ConfirmationSpecification.new(:password)
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass if the given object returns the same value for attribute as it does for attribute_confirmation" do
|
10
|
+
klass = Class.new
|
11
|
+
klass.send(:attr_accessor, :password)
|
12
|
+
klass.send(:attr_accessor, :password_confirmation)
|
13
|
+
object = klass.new
|
14
|
+
object.password = 'foobar'
|
15
|
+
object.password_confirmation = 'foobar'
|
16
|
+
@spec.should_be_satisfied_by object
|
17
|
+
end
|
18
|
+
|
19
|
+
specify "should fail if the given object doesn't respond to the specified attribute" do
|
20
|
+
@spec.should_not_be_satisfied_by Object.new
|
21
|
+
end
|
22
|
+
|
23
|
+
specify "should fail if the given object doesn't respond to specified_attribute_confirmation" do
|
24
|
+
klass = Class.new
|
25
|
+
klass.send(:attr_accessor, :password)
|
26
|
+
object = klass.new
|
27
|
+
@spec.should_not_be_satisfied_by object
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should fail if the given object returns a different value for attribute as it does for attribute_confirmation" do
|
31
|
+
klass = Class.new
|
32
|
+
klass.send(:attr_accessor, :password)
|
33
|
+
klass.send(:attr_accessor, :password_confirmation)
|
34
|
+
object = klass.new
|
35
|
+
object.password = 'foobar'
|
36
|
+
object.password_confirmation = 'foobarbaz'
|
37
|
+
@spec.should_not_be_satisfied_by object
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Not specification" do
|
5
|
+
setup do
|
6
|
+
@original_spec = PresenceSpecification.new(:foo, :bar)
|
7
|
+
@klass = Class.new
|
8
|
+
end
|
9
|
+
|
10
|
+
specify "should not pass if the decorated spec passes" do
|
11
|
+
@klass.send(:attr_accessor, :foo)
|
12
|
+
@klass.send(:attr_accessor, :bar)
|
13
|
+
object = @klass.new
|
14
|
+
object.foo = 'make me pass'
|
15
|
+
object.bar = 'make me pass'
|
16
|
+
@original_spec.should_be_satisfied_by object
|
17
|
+
NotSpecification.new(@original_spec).should_not_be_satisfied_by(object)
|
18
|
+
end
|
19
|
+
|
20
|
+
specify "should pass if the decorated spec does not pass" do
|
21
|
+
object = @klass.new
|
22
|
+
@original_spec.should_not_be_satisfied_by object
|
23
|
+
NotSpecification.new(@original_spec).should_be_satisfied_by(object)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Presence specification with one attribute" do
|
5
|
+
setup do
|
6
|
+
@spec = PresenceSpecification.new(:foo)
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass if the given object has a value for the required attribute" do
|
10
|
+
klass = Class.new
|
11
|
+
klass.send(:attr_accessor, :foo)
|
12
|
+
object = klass.new
|
13
|
+
object.foo = 'anything'
|
14
|
+
@spec.should_be_satisfied_by object
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should not pass if the given object doesn't respond to required attribute" do
|
18
|
+
klass = Class.new
|
19
|
+
@spec.should_not_be_satisfied_by klass.new
|
20
|
+
end
|
21
|
+
|
22
|
+
specify "should not pass if the given object returns nil for required attribute" do
|
23
|
+
klass = Class.new
|
24
|
+
klass.send(:attr_accessor, :foo)
|
25
|
+
object = klass.new
|
26
|
+
object.foo = nil
|
27
|
+
@spec.should_not_be_satisfied_by object
|
28
|
+
end
|
29
|
+
|
30
|
+
specify "should not pass if the given object returns an empty string for required attribute" do
|
31
|
+
klass = Class.new
|
32
|
+
klass.send(:attr_accessor, :foo)
|
33
|
+
object = klass.new
|
34
|
+
object.foo = ''
|
35
|
+
@spec.should_not_be_satisfied_by object
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "Presence specification with multiple attributes" do
|
40
|
+
setup do
|
41
|
+
@spec = PresenceSpecification.new(:foo, :bar)
|
42
|
+
end
|
43
|
+
|
44
|
+
specify "should pass if object satisfies spec for all attributes" do
|
45
|
+
klass = Class.new
|
46
|
+
klass.send(:attr_accessor, :foo)
|
47
|
+
klass.send(:attr_accessor, :bar)
|
48
|
+
object = klass.new
|
49
|
+
object.foo = 'something'
|
50
|
+
object.bar = 'anything'
|
51
|
+
@spec.should_be_satisfied_by object
|
52
|
+
end
|
53
|
+
|
54
|
+
specify "should not pass if object fails to satisfy spec for at least one attribute" do
|
55
|
+
klass = Class.new
|
56
|
+
klass.send(:attr_accessor, :foo)
|
57
|
+
klass.send(:attr_accessor, :bar)
|
58
|
+
object = klass.new
|
59
|
+
object.foo = 'something'
|
60
|
+
object.bar = ''
|
61
|
+
@spec.should_not_be_satisfied_by object
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Proc specification" do
|
5
|
+
setup do
|
6
|
+
@spec = ProcSpecification.new(Proc.new { |o| o.respond_to?(:foo) })
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass when the proc returns true when called with the given object" do
|
10
|
+
klass = Class.new
|
11
|
+
klass.send(:attr_reader, :foo)
|
12
|
+
@spec.should_be_satisfied_by klass.new
|
13
|
+
end
|
14
|
+
|
15
|
+
specify "should not pass when the proc returns false when called with the given object" do
|
16
|
+
@spec.should_not_be_satisfied_by Object.new
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context "Proc specification with proc that raises" do
|
21
|
+
setup do
|
22
|
+
@spec = ProcSpecification.new(Proc.new { |o| o.non_existant_method })
|
23
|
+
end
|
24
|
+
|
25
|
+
specify "should never pass" do
|
26
|
+
@spec.should_not_be_satisfied_by Object.new
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include ActiveSpec::Specifications
|
3
|
+
|
4
|
+
context "Size specification with a number" do
|
5
|
+
setup do
|
6
|
+
@spec = SizeSpecification.new(5, :foo)
|
7
|
+
end
|
8
|
+
|
9
|
+
specify "should pass if the given object returns a string of the specified size for the specified attribute" do
|
10
|
+
klass = Class.new
|
11
|
+
klass.send(:attr_accessor, :foo)
|
12
|
+
object = klass.new
|
13
|
+
object.foo = 'xxxxx'
|
14
|
+
@spec.should_be_satisfied_by object
|
15
|
+
end
|
16
|
+
|
17
|
+
specify "should not pass if the given object does not respond to the specified attribute" do
|
18
|
+
@spec.should_not_be_satisfied_by Object.new
|
19
|
+
end
|
20
|
+
|
21
|
+
specify "should not pass if the value of the given object does not respond to size" do
|
22
|
+
klass = Class.new
|
23
|
+
klass.send(:attr_accessor, :foo)
|
24
|
+
object = klass.new
|
25
|
+
object.foo = nil
|
26
|
+
@spec.should_not_be_satisfied_by object
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "should not pass if the given object does not return a string of the specified size for the specified attribute" do
|
30
|
+
klass = Class.new
|
31
|
+
klass.send(:attr_accessor, :foo)
|
32
|
+
object = klass.new
|
33
|
+
object.foo = 'xxxxxxxxx'
|
34
|
+
@spec.should_not_be_satisfied_by object
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "Size specification with a range" do
|
39
|
+
setup do
|
40
|
+
@spec = SizeSpecification.new(5..10, :foo)
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "should pass if the given object returns a string of a size within range for the specified attribute" do
|
44
|
+
klass = Class.new
|
45
|
+
klass.send(:attr_accessor, :foo)
|
46
|
+
object = klass.new
|
47
|
+
object.foo = 'xxxxx'
|
48
|
+
@spec.should_be_satisfied_by object
|
49
|
+
object.foo = 'xxxxxxxx'
|
50
|
+
@spec.should_be_satisfied_by object
|
51
|
+
end
|
52
|
+
|
53
|
+
specify "should not pass if the given object does not respond to the specified attribute" do
|
54
|
+
@spec.should_not_be_satisfied_by Object.new
|
55
|
+
end
|
56
|
+
|
57
|
+
specify "should not pass if the given object does not return a string for the specified attribute" do
|
58
|
+
klass = Class.new
|
59
|
+
klass.send(:attr_accessor, :foo)
|
60
|
+
object = klass.new
|
61
|
+
object.foo = DateTime.new
|
62
|
+
@spec.should_not_be_satisfied_by object
|
63
|
+
end
|
64
|
+
|
65
|
+
specify "should not pass if the given object does not return a string of a size within range for the specified attribute" do
|
66
|
+
klass = Class.new
|
67
|
+
klass.send(:attr_accessor, :foo)
|
68
|
+
object = klass.new
|
69
|
+
object.foo = 'xxxx'
|
70
|
+
@spec.should_not_be_satisfied_by object
|
71
|
+
object.foo = 'xxxxxxxxxxxxxx'
|
72
|
+
@spec.should_not_be_satisfied_by object
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.9.0
|
3
|
+
specification_version: 1
|
4
|
+
name: activespec
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.1"
|
7
|
+
date: 2006-09-22 00:00:00 +01:00
|
8
|
+
summary: Ruby Specification Library
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: contact @nospam@ lukeredpath.co.uk
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: rubyslim
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: false
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Luke Redpath
|
31
|
+
files:
|
32
|
+
- lib/active_spec.rb
|
33
|
+
- lib/active_spec/base.rb
|
34
|
+
- lib/active_spec/context.rb
|
35
|
+
- lib/active_spec/satisfies.rb
|
36
|
+
- lib/active_spec/specifications.rb
|
37
|
+
- lib/active_spec/specifications/attributes_specification.rb
|
38
|
+
- lib/active_spec/specifications/collection_specification.rb
|
39
|
+
- lib/active_spec/specifications/composite_specification.rb
|
40
|
+
- lib/active_spec/specifications/confirmation_specification.rb
|
41
|
+
- lib/active_spec/specifications/not_specification.rb
|
42
|
+
- lib/active_spec/specifications/presence_specification.rb
|
43
|
+
- lib/active_spec/specifications/proc_specification.rb
|
44
|
+
- lib/active_spec/specifications/size_specification.rb
|
45
|
+
- README
|
46
|
+
test_files:
|
47
|
+
- spec/collection_specification_spec.rb
|
48
|
+
- spec/composite_specification_spec.rb
|
49
|
+
- spec/confirmation_specification_spec.rb
|
50
|
+
- spec/not_specification_spec.rb
|
51
|
+
- spec/presence_specification_spec.rb
|
52
|
+
- spec/proc_specification_spec.rb
|
53
|
+
- spec/size_specification_spec.rb
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
extra_rdoc_files:
|
58
|
+
- README
|
59
|
+
executables: []
|
60
|
+
|
61
|
+
extensions: []
|
62
|
+
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
dependencies: []
|
66
|
+
|