yeastymobs-remarkable_mongomapper 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +10 -0
- data/VERSION +1 -1
- data/lib/remarkable_mongomapper/base.rb +0 -2
- data/lib/remarkable_mongomapper/describe.rb +199 -0
- data/lib/remarkable_mongomapper/human_names.rb +37 -0
- data/lib/remarkable_mongomapper/matchers/allow_values_for_matcher.rb +86 -0
- data/lib/remarkable_mongomapper/matchers/validate_presence_of_matcher.rb +4 -1
- data/lib/remarkable_mongomapper.rb +3 -1
- data/locales/en.yml +21 -1
- data/remarkable_mongomapper.gemspec +10 -3
- data/spec/matchers/allow_values_for_matcher_spec.rb +71 -0
- data/spec/matchers/have_key_matcher_spec.rb +1 -1
- data/spec/model_builder.rb +64 -0
- data/spec/models.rb +1 -1
- data/spec/spec_helper.rb +3 -2
- metadata +9 -2
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require 'spec/rake/spectask'
|
3
4
|
|
4
5
|
begin
|
5
6
|
require 'jeweler'
|
@@ -15,4 +16,13 @@ begin
|
|
15
16
|
end
|
16
17
|
rescue LoadError
|
17
18
|
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'Default: run specs.'
|
22
|
+
task :default => :spec
|
23
|
+
|
24
|
+
desc 'Run all the specs for the machinist plugin.'
|
25
|
+
Spec::Rake::SpecTask.new do |t|
|
26
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
t.rcov = false
|
18
28
|
end
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
@@ -104,7 +104,6 @@ module Remarkable
|
|
104
104
|
|
105
105
|
return true if model.valid?
|
106
106
|
|
107
|
-
# FIXME
|
108
107
|
error_message_to_avoid = error_message_from_model(model, attribute, error_message_to_avoid)
|
109
108
|
assert_does_not_contain(model.errors.on(attribute), error_message_to_avoid)
|
110
109
|
end
|
@@ -131,7 +130,6 @@ module Remarkable
|
|
131
130
|
|
132
131
|
return false if model.valid? || model.errors.on(attribute).blank?
|
133
132
|
|
134
|
-
# FIXME
|
135
133
|
error_message_to_expect = error_message_from_model(model, attribute, error_message_to_expect)
|
136
134
|
assert_contains(model.errors.on(attribute), error_message_to_expect)
|
137
135
|
end
|
@@ -0,0 +1,199 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module ActiveRecord
|
3
|
+
|
4
|
+
def self.after_include(target) #:nodoc:
|
5
|
+
target.class_inheritable_reader :describe_subject_attributes, :default_subject_attributes
|
6
|
+
target.send :include, Describe
|
7
|
+
end
|
8
|
+
|
9
|
+
# Overwrites describe to provide quick way to configure your subject:
|
10
|
+
#
|
11
|
+
# describe Post
|
12
|
+
# should_validate_presente_of :title
|
13
|
+
#
|
14
|
+
# describe :published => true do
|
15
|
+
# should_validate_presence_of :published_at
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# This is the same as:
|
20
|
+
#
|
21
|
+
# describe Post
|
22
|
+
# should_validate_presente_of :title
|
23
|
+
#
|
24
|
+
# describe "when published is true" do
|
25
|
+
# subject { Post.new(:published => true) }
|
26
|
+
# should_validate_presence_of :published_at
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# The string can be localized using I18n. An example yml file is:
|
31
|
+
#
|
32
|
+
# locale:
|
33
|
+
# remarkable:
|
34
|
+
# mongo_mapper:
|
35
|
+
# describe:
|
36
|
+
# each: "{{key}} is {{value}}"
|
37
|
+
# prepend: "when "
|
38
|
+
# connector: " and "
|
39
|
+
#
|
40
|
+
# You can also call subject attributes to set the default attributes for a
|
41
|
+
# subject. You can even mix with a fixture replacement tool:
|
42
|
+
#
|
43
|
+
# describe Post
|
44
|
+
# # Fixjour example
|
45
|
+
# subject_attributes { valid_post_attributes }
|
46
|
+
#
|
47
|
+
# describe :published => true do
|
48
|
+
# should_validate_presence_of :published_at
|
49
|
+
# end
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# You can retrieve the merged result of all attributes given using the
|
53
|
+
# subject_attributes instance method:
|
54
|
+
#
|
55
|
+
# describe Post
|
56
|
+
# # Fixjour example
|
57
|
+
# subject_attributes { valid_post_attributes }
|
58
|
+
#
|
59
|
+
# describe :published => true do
|
60
|
+
# it "should have default subject attributes" do
|
61
|
+
# subject_attributes.should == { :title => 'My title', :published => true }
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
module Describe
|
67
|
+
|
68
|
+
def self.included(base) #:nodoc:
|
69
|
+
base.extend ClassMethods
|
70
|
+
end
|
71
|
+
|
72
|
+
module ClassMethods
|
73
|
+
|
74
|
+
# Overwrites describe to provide quick way to configure your subject:
|
75
|
+
#
|
76
|
+
# describe Post
|
77
|
+
# should_validate_presente_of :title
|
78
|
+
#
|
79
|
+
# describe :published => true do
|
80
|
+
# should_validate_presence_of :published_at
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# This is the same as:
|
85
|
+
#
|
86
|
+
# describe Post
|
87
|
+
# should_validate_presente_of :title
|
88
|
+
#
|
89
|
+
# describe "when published is true" do
|
90
|
+
# subject { Post.new(:published => true) }
|
91
|
+
# should_validate_presence_of :published_at
|
92
|
+
# end
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# The string can be localized using I18n. An example yml file is:
|
96
|
+
#
|
97
|
+
# locale:
|
98
|
+
# remarkable:
|
99
|
+
# mongo_mapper:
|
100
|
+
# describe:
|
101
|
+
# each: "{{key}} is {{value}}"
|
102
|
+
# prepend: "when "
|
103
|
+
# connector: " and "
|
104
|
+
#
|
105
|
+
# See also subject_attributes instance and class methods for more
|
106
|
+
# information.
|
107
|
+
#
|
108
|
+
def describe(*args, &block)
|
109
|
+
if described_class && args.first.is_a?(Hash)
|
110
|
+
attributes = args.shift
|
111
|
+
|
112
|
+
connector = Remarkable.t "remarkable.mongo_mapper.describe.connector", :default => " and "
|
113
|
+
|
114
|
+
description = if self.describe_subject_attributes.blank?
|
115
|
+
Remarkable.t("remarkable.mongo_mapper.describe.prepend", :default => "when ")
|
116
|
+
else
|
117
|
+
connector.lstrip
|
118
|
+
end
|
119
|
+
|
120
|
+
pieces = []
|
121
|
+
attributes.each do |key, value|
|
122
|
+
translated_key = if described_class.respond_to?(:human_attribute_name)
|
123
|
+
described_class.human_attribute_name(key.to_s, :locale => Remarkable.locale)
|
124
|
+
else
|
125
|
+
key.to_s.humanize
|
126
|
+
end
|
127
|
+
|
128
|
+
pieces << Remarkable.t("remarkable.mongo_mapper.describe.each",
|
129
|
+
:default => "{{key}} is {{value}}",
|
130
|
+
:key => translated_key.downcase, :value => value.inspect)
|
131
|
+
end
|
132
|
+
|
133
|
+
description << pieces.join(connector)
|
134
|
+
args.unshift(description)
|
135
|
+
|
136
|
+
# Creates an example group, set the subject and eval the given block.
|
137
|
+
#
|
138
|
+
example_group = super(*args) do
|
139
|
+
write_inheritable_hash(:describe_subject_attributes, attributes)
|
140
|
+
set_described_subject!
|
141
|
+
instance_eval(&block)
|
142
|
+
end
|
143
|
+
else
|
144
|
+
super(*args, &block)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# Sets default attributes for the subject. You can use this to set up
|
149
|
+
# your subject with valid attributes. You can even mix with a fixture
|
150
|
+
# replacement tool and still use quick subjects:
|
151
|
+
#
|
152
|
+
# describe Post
|
153
|
+
# # Fixjour example
|
154
|
+
# subject_attributes { valid_post_attributes }
|
155
|
+
#
|
156
|
+
# describe :published => true do
|
157
|
+
# should_validate_presence_of :published_at
|
158
|
+
# end
|
159
|
+
# end
|
160
|
+
#
|
161
|
+
def subject_attributes(options=nil, &block)
|
162
|
+
write_inheritable_attribute(:default_subject_attributes, options || block)
|
163
|
+
set_described_subject!
|
164
|
+
end
|
165
|
+
|
166
|
+
def set_described_subject!
|
167
|
+
subject {
|
168
|
+
record = self.class.described_class.new
|
169
|
+
record.send(:attributes=, subject_attributes, false)
|
170
|
+
record
|
171
|
+
}
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns a hash with the subject attributes declared using the
|
176
|
+
# subject_attributes class method and the attributes given using the
|
177
|
+
# describe method.
|
178
|
+
#
|
179
|
+
# describe Post
|
180
|
+
# subject_attributes { valid_post_attributes }
|
181
|
+
#
|
182
|
+
# describe :published => true do
|
183
|
+
# it "should have default subject attributes" do
|
184
|
+
# subject_attributes.should == { :title => 'My title', :published => true }
|
185
|
+
# end
|
186
|
+
# end
|
187
|
+
# end
|
188
|
+
#
|
189
|
+
def subject_attributes
|
190
|
+
default = self.class.default_subject_attributes
|
191
|
+
default = self.instance_eval(&default) if default.is_a?(Proc)
|
192
|
+
default ||= {}
|
193
|
+
|
194
|
+
default.merge(self.class.describe_subject_attributes || {})
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
if defined?(Spec)
|
2
|
+
module Spec #:nodoc:
|
3
|
+
module Example #:nodoc:
|
4
|
+
module ExampleGroupMethods #:nodoc:
|
5
|
+
|
6
|
+
# This allows "describe User" to use the I18n human name of User.
|
7
|
+
#
|
8
|
+
def self.build_description_with_i18n(*args)
|
9
|
+
args.inject("") do |description, arg|
|
10
|
+
arg = if arg.respond_to?(:human_name)
|
11
|
+
arg.human_name(:locale => Remarkable.locale)
|
12
|
+
else
|
13
|
+
arg.to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
description << " " unless (description == "" || arg =~ /^(\s|\.|#)/)
|
17
|
+
description << arg
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# This is for rspec <= 1.1.12.
|
22
|
+
#
|
23
|
+
def self.description_text(*args)
|
24
|
+
self.build_description_with_i18n(*args)
|
25
|
+
end
|
26
|
+
|
27
|
+
# This is for rspec >= 1.2.0.
|
28
|
+
#
|
29
|
+
def self.build_description_from(*args)
|
30
|
+
text = ExampleGroupMethods.build_description_with_i18n(*args)
|
31
|
+
text == "" ? nil : text
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Remarkable
|
2
|
+
module MongoMapper
|
3
|
+
module Matchers
|
4
|
+
class AllowValuesForMatcher < Remarkable::MongoMapper::Base #:nodoc:
|
5
|
+
include Remarkable::Negative
|
6
|
+
arguments :collection => :attributes, :as => :attribute
|
7
|
+
|
8
|
+
optional :message
|
9
|
+
optional :in, :splat => true
|
10
|
+
optional :allow_nil, :allow_blank, :default => true
|
11
|
+
|
12
|
+
collection_assertions :is_valid?, :is_invalid?, :allow_nil?, :allow_blank?
|
13
|
+
|
14
|
+
default_options :message => "is invalid"
|
15
|
+
|
16
|
+
before_assert do
|
17
|
+
first_value = @options[:in].is_a?(Array) ? @options[:in].first : @options[:in]
|
18
|
+
@in_range = first_value.is_a?(Range)
|
19
|
+
|
20
|
+
@options[:in] = if @in_range
|
21
|
+
first_value.to_a[0,2] + first_value.to_a[-2,2]
|
22
|
+
else
|
23
|
+
[*@options[:in]].compact
|
24
|
+
end
|
25
|
+
|
26
|
+
@options[:in].uniq!
|
27
|
+
end
|
28
|
+
|
29
|
+
protected
|
30
|
+
|
31
|
+
def is_valid?
|
32
|
+
assert_collection :value, valid_values do |value|
|
33
|
+
good?(value)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def is_invalid?
|
38
|
+
assert_collection :value, invalid_values do |value|
|
39
|
+
bad?(value)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def valid_values
|
44
|
+
@options[:in]
|
45
|
+
end
|
46
|
+
|
47
|
+
def invalid_values
|
48
|
+
[]
|
49
|
+
end
|
50
|
+
|
51
|
+
def interpolation_options
|
52
|
+
options = if @in_range
|
53
|
+
{ :in => (@options[:in].first..@options[:in].last).inspect }
|
54
|
+
elsif @options[:in].is_a?(Array)
|
55
|
+
{ :in => array_to_sentence(@options[:in], true, '[]') }
|
56
|
+
else
|
57
|
+
{ :in => @options[:in].inspect }
|
58
|
+
end
|
59
|
+
|
60
|
+
options.merge!(:behavior => @behavior.to_s)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
# Ensures that the attribute can be set to the given values.
|
66
|
+
#
|
67
|
+
# == Options
|
68
|
+
#
|
69
|
+
# * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
|
70
|
+
# * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
|
71
|
+
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
72
|
+
# Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.invalid')</tt>
|
73
|
+
#
|
74
|
+
# == Examples
|
75
|
+
#
|
76
|
+
# should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
|
77
|
+
# it { should allow_values_for(:isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0") }
|
78
|
+
#
|
79
|
+
def allow_values_for(attribute, *args, &block)
|
80
|
+
options = args.extract_options!
|
81
|
+
AllowValuesForMatcher.new(attribute, options.merge!(:in => args), &block).spec(self)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -2,7 +2,6 @@ module Remarkable
|
|
2
2
|
module MongoMapper
|
3
3
|
module Matchers
|
4
4
|
class ValidatePresenceOfMatcher < Remarkable::MongoMapper::Base
|
5
|
-
|
6
5
|
arguments :collection => :attributes, :as => :attribute
|
7
6
|
optional :message
|
8
7
|
|
@@ -19,6 +18,10 @@ module Remarkable
|
|
19
18
|
|
20
19
|
# Ensures that the model cannot be saved if one of the attributes listed is not present.
|
21
20
|
#
|
21
|
+
# == Options
|
22
|
+
#
|
23
|
+
# * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
|
24
|
+
# Regexp, string or symbol. Default = "can't be empty"
|
22
25
|
#
|
23
26
|
# == Examples
|
24
27
|
#
|
@@ -14,7 +14,9 @@ dir = File.dirname(__FILE__)
|
|
14
14
|
Remarkable.add_locale File.join(dir, '..', 'locales', 'en.yml')
|
15
15
|
|
16
16
|
require File.join(dir, 'remarkable_mongomapper', 'base')
|
17
|
-
|
17
|
+
require File.join(dir, 'remarkable_mongomapper', 'describe')
|
18
|
+
# require File.join(dir, 'remarkable_mongomapper', 'human_names')
|
19
|
+
|
18
20
|
# Add matchers
|
19
21
|
Dir[File.join(dir, 'remarkable_mongomapper', 'matchers', '*.rb')].each do |file|
|
20
22
|
require file
|
data/locales/en.yml
CHANGED
@@ -1,6 +1,26 @@
|
|
1
1
|
en:
|
2
2
|
remarkable:
|
3
3
|
mongo_mapper:
|
4
|
+
describe:
|
5
|
+
each: "{{key}} is {{value}}"
|
6
|
+
prepend: "when "
|
7
|
+
connector: " and "
|
8
|
+
expectations:
|
9
|
+
allow_nil: "{{subject_name}} to {{not}}allow nil values for {{attribute}}"
|
10
|
+
allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
|
11
|
+
optionals:
|
12
|
+
allow_nil:
|
13
|
+
positive: "allowing nil values"
|
14
|
+
negative: "not allowing nil values"
|
15
|
+
allow_blank:
|
16
|
+
positive: "allowing blank values"
|
17
|
+
negative: "not allowing blank values"
|
18
|
+
|
19
|
+
allow_values_for:
|
20
|
+
description: "allow {{in}} as values for {{attributes}}"
|
21
|
+
expectations:
|
22
|
+
is_valid: "{{subject_name}} to be valid when {{attribute}} is set to {{value}}"
|
23
|
+
|
4
24
|
association:
|
5
25
|
many: have many
|
6
26
|
belongs_to: belong to
|
@@ -12,7 +32,7 @@ en:
|
|
12
32
|
options_match: "{{subject_name}} records {{type}} {{association}} with options {{options}}, got {{actual}}"
|
13
33
|
|
14
34
|
have_key:
|
15
|
-
description: "have key(s) {{attributes}}"
|
35
|
+
description: "have key(s) {{attributes}} with type {{type}}"
|
16
36
|
expectations:
|
17
37
|
has_key: "{{subject_name}} to have key named {{attribute}} with type {{type}}"
|
18
38
|
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = %q{remarkable_mongomapper}
|
5
|
-
s.version = "0.1.
|
5
|
+
s.version = "0.1.1"
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Nicolas M\303\251rouze", "Vincent Hellot", "Mathieu Fosse"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-31}
|
10
10
|
s.email = %q{dev@yeastymobs.com}
|
11
11
|
s.extra_rdoc_files = [
|
12
12
|
"LICENSE",
|
@@ -20,14 +20,19 @@ Gem::Specification.new do |s|
|
|
20
20
|
"VERSION",
|
21
21
|
"lib/remarkable_mongomapper.rb",
|
22
22
|
"lib/remarkable_mongomapper/base.rb",
|
23
|
+
"lib/remarkable_mongomapper/describe.rb",
|
24
|
+
"lib/remarkable_mongomapper/human_names.rb",
|
25
|
+
"lib/remarkable_mongomapper/matchers/allow_values_for_matcher.rb",
|
23
26
|
"lib/remarkable_mongomapper/matchers/association_matcher.rb",
|
24
27
|
"lib/remarkable_mongomapper/matchers/have_key_matcher.rb",
|
25
28
|
"lib/remarkable_mongomapper/matchers/validate_presence_of_matcher.rb",
|
26
29
|
"locales/en.yml",
|
27
30
|
"remarkable_mongomapper.gemspec",
|
31
|
+
"spec/matchers/allow_values_for_matcher_spec.rb",
|
28
32
|
"spec/matchers/association_matcher_spec.rb",
|
29
33
|
"spec/matchers/have_key_matcher_spec.rb",
|
30
34
|
"spec/matchers/validate_presence_of_matcher_spec.rb",
|
35
|
+
"spec/model_builder.rb",
|
31
36
|
"spec/models.rb",
|
32
37
|
"spec/spec.opts",
|
33
38
|
"spec/spec_helper.rb"
|
@@ -38,9 +43,11 @@ Gem::Specification.new do |s|
|
|
38
43
|
s.rubygems_version = %q{1.3.5}
|
39
44
|
s.summary = %q{MongoMapper Remarkable Matchers}
|
40
45
|
s.test_files = [
|
41
|
-
"spec/matchers/
|
46
|
+
"spec/matchers/allow_values_for_matcher_spec.rb",
|
47
|
+
"spec/matchers/association_matcher_spec.rb",
|
42
48
|
"spec/matchers/have_key_matcher_spec.rb",
|
43
49
|
"spec/matchers/validate_presence_of_matcher_spec.rb",
|
50
|
+
"spec/model_builder.rb",
|
44
51
|
"spec/models.rb",
|
45
52
|
"spec/spec_helper.rb"
|
46
53
|
]
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe 'allow_values_for' do
|
4
|
+
include ModelBuilder
|
5
|
+
|
6
|
+
# Defines a model, create a validation and returns a raw matcher
|
7
|
+
def define_and_validate(options={})
|
8
|
+
@model = define_model :product do
|
9
|
+
include MongoMapper::Document
|
10
|
+
|
11
|
+
key :title, String
|
12
|
+
key :category, String
|
13
|
+
|
14
|
+
validates_format_of :title, options
|
15
|
+
end
|
16
|
+
|
17
|
+
allow_values_for(:title)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'messages' do
|
21
|
+
before(:each){ @matcher = define_and_validate(:with => /X|Y|Z/) }
|
22
|
+
|
23
|
+
it 'should contain a description' do
|
24
|
+
@matcher = allow_values_for(:title, "X", "Y", "Z")
|
25
|
+
@matcher.description.should == 'allow "X", "Y", and "Z" as values for title'
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'should set is_valid? message' do
|
29
|
+
@matcher.in("A").matches?(subject)
|
30
|
+
@matcher.failure_message.should == 'Expected Product to be valid when title is set to "A"'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should set allow_nil? message' do
|
34
|
+
@matcher.allow_nil.matches?(subject)
|
35
|
+
@matcher.failure_message.should == 'Expected Product to allow nil values for title'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should set allow_blank? message' do
|
39
|
+
@matcher.allow_blank.matches?(subject)
|
40
|
+
@matcher.failure_message.should == 'Expected Product to allow blank values for title'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe 'matchers' do
|
45
|
+
it { should define_and_validate(:with => /X|Y|Z/).in('X', 'Y', 'Z') }
|
46
|
+
it { should_not define_and_validate(:with => /X|Y|Z/).in('A') }
|
47
|
+
|
48
|
+
it { should define_and_validate(:with => /X|Y|Z/, :message => 'valid').in('X', 'Y', 'Z').message('valid') }
|
49
|
+
|
50
|
+
create_optional_boolean_specs(:allow_nil, self, :with => /X|Y|Z/)
|
51
|
+
create_optional_boolean_specs(:allow_blank, self, :with => /X|Y|Z/)
|
52
|
+
end
|
53
|
+
|
54
|
+
describe 'macros' do
|
55
|
+
before(:each){ define_and_validate(:with => /X|Y|Z/) }
|
56
|
+
|
57
|
+
should_allow_values_for :title, 'X'
|
58
|
+
should_not_allow_values_for :title, 'A'
|
59
|
+
end
|
60
|
+
|
61
|
+
describe 'failures' do
|
62
|
+
it "should fail if any of the values are valid on invalid cases" do
|
63
|
+
define_and_validate(:with => /X|Y|Z/)
|
64
|
+
|
65
|
+
lambda {
|
66
|
+
should_not allow_values_for(:title, 'A', 'X', 'B')
|
67
|
+
}.should raise_error(Spec::Expectations::ExpectationNotMetError, /Did not expect Product to be valid/)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -9,7 +9,7 @@ describe 'have_key' do
|
|
9
9
|
|
10
10
|
it 'should contain a description' do
|
11
11
|
matcher = have_key(:title, String)
|
12
|
-
matcher.description.should == 'have key(s) title'
|
12
|
+
matcher.description.should == 'have key(s) title with type String'
|
13
13
|
end
|
14
14
|
|
15
15
|
it 'should set has_key? message' do
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# This is based on Shoulda model builder for Test::Unit.
|
2
|
+
#
|
3
|
+
module ModelBuilder
|
4
|
+
def self.included(base)
|
5
|
+
return unless base.name =~ /^Spec/
|
6
|
+
|
7
|
+
base.class_eval do
|
8
|
+
after(:each) do
|
9
|
+
if @defined_constants
|
10
|
+
@defined_constants.each do |class_name|
|
11
|
+
Object.send(:remove_const, class_name)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
base.extend ClassMethods
|
18
|
+
end
|
19
|
+
|
20
|
+
def define_constant(class_name, &block)
|
21
|
+
class_name = class_name.to_s.camelize
|
22
|
+
|
23
|
+
klass = Class.new
|
24
|
+
Object.const_set(class_name, klass)
|
25
|
+
|
26
|
+
klass.class_eval(&block) if block_given?
|
27
|
+
|
28
|
+
@defined_constants ||= []
|
29
|
+
@defined_constants << class_name
|
30
|
+
|
31
|
+
klass
|
32
|
+
end
|
33
|
+
|
34
|
+
def define_model(name, columns = {}, &block)
|
35
|
+
instance = define_constant(name.to_s.classify, &block).new
|
36
|
+
|
37
|
+
self.class.subject { instance } if self.class.respond_to?(:subject)
|
38
|
+
instance
|
39
|
+
end
|
40
|
+
|
41
|
+
module ClassMethods
|
42
|
+
# This is a macro to run validations of boolean optionals such as :allow_nil
|
43
|
+
# and :allow_blank. This macro tests all scenarios. The specs must have a
|
44
|
+
# define_and_validate method defined.
|
45
|
+
#
|
46
|
+
def create_optional_boolean_specs(optional, base, options={})
|
47
|
+
base.describe "with #{optional} option" do
|
48
|
+
it { should define_and_validate(options.merge(optional => true)).send(optional) }
|
49
|
+
it { should define_and_validate(options.merge(optional => false)).send(optional, false) }
|
50
|
+
it { should_not define_and_validate(options.merge(optional => true)).send(optional, false) }
|
51
|
+
it { should_not define_and_validate(options.merge(optional => false)).send(optional) }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def create_message_specs(base)
|
56
|
+
base.describe "with message option" do
|
57
|
+
it { should define_and_validate(:message => 'valid_message').message('valid_message') }
|
58
|
+
it { should_not define_and_validate(:message => 'not_valid').message('valid_message') }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
data/spec/models.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
|
3
|
-
gem "mongomapper", "~> 0.
|
3
|
+
gem "mongomapper", "~> 0.3.1"
|
4
4
|
require "mongomapper"
|
5
5
|
|
6
6
|
MongoMapper.database = "remarkable_mongomapper"
|
@@ -15,4 +15,5 @@ Spec::Runner.configure do |config|
|
|
15
15
|
end
|
16
16
|
|
17
17
|
require File.join(File.dirname(__FILE__), "..", "lib", "remarkable_mongomapper")
|
18
|
-
require File.join(File.dirname(__FILE__), "models")
|
18
|
+
require File.join(File.dirname(__FILE__), "models")
|
19
|
+
require File.join(File.dirname(__FILE__), "model_builder")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: yeastymobs-remarkable_mongomapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- "Nicolas M\xC3\xA9rouze"
|
@@ -11,7 +11,7 @@ autorequire:
|
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
13
|
|
14
|
-
date: 2009-07-
|
14
|
+
date: 2009-07-31 00:00:00 -07:00
|
15
15
|
default_executable:
|
16
16
|
dependencies:
|
17
17
|
- !ruby/object:Gem::Dependency
|
@@ -51,14 +51,19 @@ files:
|
|
51
51
|
- VERSION
|
52
52
|
- lib/remarkable_mongomapper.rb
|
53
53
|
- lib/remarkable_mongomapper/base.rb
|
54
|
+
- lib/remarkable_mongomapper/describe.rb
|
55
|
+
- lib/remarkable_mongomapper/human_names.rb
|
56
|
+
- lib/remarkable_mongomapper/matchers/allow_values_for_matcher.rb
|
54
57
|
- lib/remarkable_mongomapper/matchers/association_matcher.rb
|
55
58
|
- lib/remarkable_mongomapper/matchers/have_key_matcher.rb
|
56
59
|
- lib/remarkable_mongomapper/matchers/validate_presence_of_matcher.rb
|
57
60
|
- locales/en.yml
|
58
61
|
- remarkable_mongomapper.gemspec
|
62
|
+
- spec/matchers/allow_values_for_matcher_spec.rb
|
59
63
|
- spec/matchers/association_matcher_spec.rb
|
60
64
|
- spec/matchers/have_key_matcher_spec.rb
|
61
65
|
- spec/matchers/validate_presence_of_matcher_spec.rb
|
66
|
+
- spec/model_builder.rb
|
62
67
|
- spec/models.rb
|
63
68
|
- spec/spec.opts
|
64
69
|
- spec/spec_helper.rb
|
@@ -90,8 +95,10 @@ signing_key:
|
|
90
95
|
specification_version: 3
|
91
96
|
summary: MongoMapper Remarkable Matchers
|
92
97
|
test_files:
|
98
|
+
- spec/matchers/allow_values_for_matcher_spec.rb
|
93
99
|
- spec/matchers/association_matcher_spec.rb
|
94
100
|
- spec/matchers/have_key_matcher_spec.rb
|
95
101
|
- spec/matchers/validate_presence_of_matcher_spec.rb
|
102
|
+
- spec/model_builder.rb
|
96
103
|
- spec/models.rb
|
97
104
|
- spec/spec_helper.rb
|