must_be 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/README.md +348 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/doc/readme/examples.rb +262 -0
- data/doc/readme/run_examples.rb +47 -0
- data/lib/must_be/attr_typed.rb +78 -0
- data/lib/must_be/basic.rb +120 -0
- data/lib/must_be/containers.rb +291 -0
- data/lib/must_be/containers_registered_classes.rb +83 -0
- data/lib/must_be/core.rb +247 -0
- data/lib/must_be/nonstandard_control_flow.rb +159 -0
- data/lib/must_be/proxy.rb +62 -0
- data/lib/must_be.rb +9 -0
- data/must_be.gemspec +71 -0
- data/spec/must_be/attr_typed_spec.rb +225 -0
- data/spec/must_be/basic_spec.rb +578 -0
- data/spec/must_be/containers_spec.rb +952 -0
- data/spec/must_be/core_spec.rb +675 -0
- data/spec/must_be/nonstandard_control_flow_spec.rb +845 -0
- data/spec/must_be/proxy_spec.rb +194 -0
- data/spec/notify_matcher_spec.rb +59 -0
- data/spec/spec_helper.rb +180 -0
- data/spec/typical_usage_spec.rb +176 -0
- metadata +98 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MustBe do
|
4
|
+
include MustBeExampleHelper
|
5
|
+
|
6
|
+
describe 'Module#attr_typed' do
|
7
|
+
context "when updating" do
|
8
|
+
module ModuleWhoUsesAttrTyped
|
9
|
+
attr_typed :int, Bignum, Fixnum
|
10
|
+
attr_typed :positive_int, Bignum, Fixnum do |n|
|
11
|
+
n > 0
|
12
|
+
end
|
13
|
+
attr_typed :non_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
class UsesAttrTyped
|
17
|
+
include ModuleWhoUsesAttrTyped
|
18
|
+
|
19
|
+
attr_typed :float, Float
|
20
|
+
attr_typed :empty, &:empty?
|
21
|
+
attr_typed :collection, Array, Hash, Range
|
22
|
+
end
|
23
|
+
|
24
|
+
subject { UsesAttrTyped.new }
|
25
|
+
|
26
|
+
context "against one type constraint" do
|
27
|
+
it "should not notify if new value has the type" do
|
28
|
+
subject.float = 23.3
|
29
|
+
subject.float.should == 23.3
|
30
|
+
should_not notify
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should notify if new value does not have the type" do
|
34
|
+
subject.float = 23
|
35
|
+
should notify("attribute `float' must be a Float,"\
|
36
|
+
" but value 23 is a Fixnum")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "against two type constraints" do
|
41
|
+
it "should not notify if new value matches one of the constraints" do
|
42
|
+
subject.int = 56
|
43
|
+
should_not notify
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should notify if new value does not match either constraint " do
|
47
|
+
subject.int = 56.6
|
48
|
+
should notify("attribute `int' must be a Bignum or Fixnum,"\
|
49
|
+
" but value 56.6 is a Float")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context "against multiple type constraints" do
|
54
|
+
it "should not notify if new value matches last constraint" do
|
55
|
+
subject.collection = 1..3
|
56
|
+
should_not notify
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should notify if new value matches none of the constraints" do
|
60
|
+
subject.collection = :scalar
|
61
|
+
should notify("attribute `collection' must be a one of"\
|
62
|
+
" [Array, Hash, Range], but value :scalar is a Symbol")
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context "against a block constraint" do
|
67
|
+
it "should not notify if block[value] is true" do
|
68
|
+
subject.empty = []
|
69
|
+
should_not notify
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should notify if block[value] is not true" do
|
73
|
+
subject.empty = [:not, :empty]
|
74
|
+
should notify("attribute `empty' cannot be [:not, :empty]")
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "against two types and a block constraint" do
|
79
|
+
it "should not notify if new value matches one of the types"\
|
80
|
+
" and block[value] is true" do
|
81
|
+
subject.positive_int = 45
|
82
|
+
should_not notify
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should notify if new value does not match one of the types" do
|
86
|
+
subject.positive_int = 87.6
|
87
|
+
should notify("attribute `positive_int' must be a Bignum"\
|
88
|
+
" or Fixnum, but value 87.6 is a Float")
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should notify if block[value] is not true" do
|
92
|
+
subject.positive_int = -11
|
93
|
+
should notify("attribute `positive_int' cannot be -11")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context "against no listed contraint" do
|
98
|
+
it "should not notify if new value is non-nil" do
|
99
|
+
subject.non_nil = false
|
100
|
+
should_not notify
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should notify if new value is nil" do
|
104
|
+
subject.non_nil = nil
|
105
|
+
should notify("attribute `non_nil' cannot be nil")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context "when called twice with the same symbol" do
|
111
|
+
class AttrTypedCalledTwiceForSameSymbol
|
112
|
+
attr_typed :twice, Symbol
|
113
|
+
attr_typed :twice, String
|
114
|
+
end
|
115
|
+
|
116
|
+
subject { AttrTypedCalledTwiceForSameSymbol.new }
|
117
|
+
|
118
|
+
it "second call should override first" do
|
119
|
+
subject.twice = :symbol
|
120
|
+
should notify("attribute `twice' must be a String,"\
|
121
|
+
" but value :symbol is a Symbol")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context "when called with bad arguments" do
|
126
|
+
subject { Class.new }
|
127
|
+
|
128
|
+
context "when symbol is bad" do
|
129
|
+
it "should raise if symbol cannot be converted #to_sym" do
|
130
|
+
expect do
|
131
|
+
subject.attr_typed [], Object
|
132
|
+
end.should raise_error(TypeError, "[] is not a symbol")
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should raise if symbol is a Fixnum" do
|
136
|
+
expect do
|
137
|
+
subject.attr_typed 111, Object
|
138
|
+
end.should raise_error(TypeError, "111 is not a symbol")
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should be fine if symbol is a String" do
|
142
|
+
expect do
|
143
|
+
subject.attr_typed "string", Object
|
144
|
+
end.should_not raise_error
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context "when types is bad" do
|
149
|
+
it "should raise if any type is an array" do
|
150
|
+
expect do
|
151
|
+
subject.attr_typed :prop, [Array, Object]
|
152
|
+
end.should raise_error(TypeError, "class or module required")
|
153
|
+
end
|
154
|
+
|
155
|
+
it "should raise if any type is a String" do
|
156
|
+
expect do
|
157
|
+
subject.attr_typed :prop, "string"
|
158
|
+
end.should raise_error(TypeError, "class or module required")
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context "after disabling" do
|
164
|
+
before do
|
165
|
+
@enabled_class = Class.new
|
166
|
+
@enabled_class.attr_typed :prop, Symbol
|
167
|
+
@enabled_instance = @enabled_class.new
|
168
|
+
end
|
169
|
+
|
170
|
+
before_disable_after_enable
|
171
|
+
|
172
|
+
context "when .attr_typed was called while still enabled" do
|
173
|
+
it "should not notify" do
|
174
|
+
@enabled_instance.prop = 91
|
175
|
+
@enabled_instance.prop.should == 91
|
176
|
+
should_not notify
|
177
|
+
end
|
178
|
+
|
179
|
+
context "after being re-enabled" do
|
180
|
+
before do
|
181
|
+
MustBe.enable
|
182
|
+
end
|
183
|
+
|
184
|
+
it "should notify again" do
|
185
|
+
@enabled_instance.prop = 91
|
186
|
+
should notify("attribute `prop' must be a Symbol,"\
|
187
|
+
" but value 91 is a Fixnum")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "when .attr_typed is called" do
|
193
|
+
before do
|
194
|
+
@disabled_class = Class.new
|
195
|
+
@disabled_class.attr_typed :prop, Symbol
|
196
|
+
@disabled_instance = @disabled_class.new
|
197
|
+
end
|
198
|
+
|
199
|
+
it "should not notify" do
|
200
|
+
@disabled_instance.prop = 91
|
201
|
+
@disabled_instance.prop.should == 91
|
202
|
+
should_not notify
|
203
|
+
end
|
204
|
+
|
205
|
+
context "after being re-enabled" do
|
206
|
+
before do
|
207
|
+
MustBe.enable
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should still not notify" do
|
211
|
+
@disabled_instance.prop = 91
|
212
|
+
should_not notify
|
213
|
+
end
|
214
|
+
|
215
|
+
it ".attr_typed should be re-enabled" do
|
216
|
+
@disabled_class.attr_typed :prop, Symbol
|
217
|
+
@disabled_instance.prop = 91
|
218
|
+
should notify("attribute `prop' must be a Symbol,"\
|
219
|
+
" but value 91 is a Fixnum")
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|