moosex 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +232 -5
- data/lib/moosex.rb +113 -27
- data/lib/moosex/types.rb +225 -0
- data/lib/moosex/version.rb +2 -2
- data/moosex.gemspec +1 -1
- data/spec/complex_spec.rb +33 -0
- data/spec/hooks_spec.rb +96 -0
- data/spec/point_spec.rb +9 -4
- data/spec/types_spec.rb +477 -0
- metadata +9 -2
data/lib/moosex/types.rb
ADDED
@@ -0,0 +1,225 @@
|
|
1
|
+
module MooseX
|
2
|
+
module Types
|
3
|
+
|
4
|
+
def Types.included(c)
|
5
|
+
c.extend(MooseX::Types::Core)
|
6
|
+
end
|
7
|
+
|
8
|
+
class TypeCheckError < TypeError
|
9
|
+
end
|
10
|
+
|
11
|
+
module Core
|
12
|
+
|
13
|
+
# TODO
|
14
|
+
# String
|
15
|
+
# format
|
16
|
+
# length (min, max, between, is)
|
17
|
+
# add custom message
|
18
|
+
# integer / number odd, even, >=, <=, etc
|
19
|
+
# allow new/blank
|
20
|
+
# required :method?
|
21
|
+
|
22
|
+
# Types::Numeric
|
23
|
+
# PositiveNum
|
24
|
+
# PositiveOrZeroNum
|
25
|
+
# PositiveInt
|
26
|
+
# PositiveOrZeroInt
|
27
|
+
# NegativeNum
|
28
|
+
# NegativeOrZeroNum
|
29
|
+
# NegativeInt
|
30
|
+
# NegativeOrZeroInt
|
31
|
+
# SingleDigit
|
32
|
+
|
33
|
+
def createValidator(message, &block)
|
34
|
+
l = block
|
35
|
+
l.define_singleton_method(:to_s) { message }
|
36
|
+
l
|
37
|
+
end
|
38
|
+
|
39
|
+
def isAny
|
40
|
+
createValidator("[Any]") {|value| }
|
41
|
+
end
|
42
|
+
|
43
|
+
def isConstant(constant_value)
|
44
|
+
createValidator("[Constant: '#{constant_value}' (#{constant_value.class})]") do |value|
|
45
|
+
unless value === constant_value
|
46
|
+
raise TypeCheckError,"Constant violation: value '#{value}' (#{value.class}) is not '#{constant_value}' (#{constant_value.class})"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def isType(type)
|
52
|
+
return type if type.is_a?(Proc)
|
53
|
+
|
54
|
+
createValidator("[Type #{type}]") do |value|
|
55
|
+
raise TypeCheckError, "Type violation: value '#{value}' (#{value.class}) is not an instance of [Type #{type}]" unless value.is_a?(type)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
alias_method :isInstanceOf, :isType
|
60
|
+
alias_method :isConsumerOf, :isType
|
61
|
+
|
62
|
+
def hasMethods(*methods)
|
63
|
+
createValidator("[hasMethods #{methods}]") do |object|
|
64
|
+
methods.each do |method|
|
65
|
+
unless object.respond_to? method.to_sym
|
66
|
+
raise TypeCheckError, "hasMethods violation: object #{object} (#{object.class}) should implement method #{method}"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def isAllOf(*conditions)
|
73
|
+
createValidator("[AllOf [#{conditions.map{|t| t.to_s }.join(', ')}]]") do |value|
|
74
|
+
begin
|
75
|
+
conditions.each { |c| isType(c).call(value) }
|
76
|
+
rescue TypeCheckError => e
|
77
|
+
raise TypeCheckError, "AllOf Check violation: caused by [#{e}]"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def isAnyOf(*conditions)
|
83
|
+
conditions = conditions.flatten
|
84
|
+
createValidator("[AnyOf [#{conditions.map{|t| t.to_s }.join(', ')}]]") do |value|
|
85
|
+
|
86
|
+
find = false
|
87
|
+
exceptions = []
|
88
|
+
|
89
|
+
for c in conditions
|
90
|
+
begin
|
91
|
+
isType(c).call(value)
|
92
|
+
find = true
|
93
|
+
break
|
94
|
+
rescue TypeCheckError => ex
|
95
|
+
exceptions << ex
|
96
|
+
rescue => e
|
97
|
+
raise TypeCheckError, "unexpected exception #{e}"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
raise TypeCheckError, "AnyOf Check violation: caused by [#{exceptions.map{|e| e.to_s}.join', '}]" unless find
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def isEnum(*possible_values)
|
106
|
+
possible_constants = possible_values.flatten.map do |value|
|
107
|
+
isConstant(value)
|
108
|
+
end
|
109
|
+
|
110
|
+
createValidator("[Enum #{possible_values}]") do |value|
|
111
|
+
begin
|
112
|
+
isAnyOf(possible_constants).call(value)
|
113
|
+
rescue TypeCheckError => e
|
114
|
+
raise TypeCheckError, "Enum Check violation: value '#{value}' (#{value.class}) is not #{possible_values}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def isNot(condition)
|
120
|
+
createValidator("[NOT #{condition.to_s}]") do |value|
|
121
|
+
success = false
|
122
|
+
begin
|
123
|
+
condition.call(value)
|
124
|
+
success = true
|
125
|
+
rescue TypeCheckError => e
|
126
|
+
nil
|
127
|
+
end
|
128
|
+
|
129
|
+
if success
|
130
|
+
raise TypeCheckError, "Not violation: value '#{value}' (#{value.class}) is not #{condition.to_s}"
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def isMaybe(type)
|
136
|
+
createValidator("[Maybe #{type.to_s}]") do |value|
|
137
|
+
begin
|
138
|
+
isAnyOf(isType(type), isConstant(nil)).call(value)
|
139
|
+
rescue TypeCheckError => e
|
140
|
+
raise TypeCheckError, "Maybe violation: caused by #{e}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def isArray(type=nil)
|
146
|
+
type = isAny if type.nil?
|
147
|
+
|
148
|
+
createValidator "[Array #{type.to_s}]" do |array|
|
149
|
+
isType(Array).call(array)
|
150
|
+
|
151
|
+
array.each do |item|
|
152
|
+
begin
|
153
|
+
isType(type).call(item)
|
154
|
+
rescue TypeCheckError => e
|
155
|
+
raise TypeCheckError, "Array violation: caused by #{e}"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def isHash(map={})
|
162
|
+
if map.empty?
|
163
|
+
map = {isAny => isAny }
|
164
|
+
end
|
165
|
+
|
166
|
+
keyType, valueType = map.shift
|
167
|
+
|
168
|
+
createValidator "[Hash #{keyType.to_s} => #{valueType.to_s}]" do |hash|
|
169
|
+
isType(Hash).call(hash)
|
170
|
+
|
171
|
+
hash.each_pair do| key, value|
|
172
|
+
begin
|
173
|
+
isType(keyType).call(key)
|
174
|
+
isType(valueType).call(value)
|
175
|
+
rescue TypeCheckError => e
|
176
|
+
raise TypeCheckError, "Hash violation: caused by #{e}"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def isTuple(*types)
|
183
|
+
|
184
|
+
createValidator "[Tuple [#{types.map{|t| t.to_s}.join ', '}]]" do |tuple|
|
185
|
+
isType(Array).call(tuple)
|
186
|
+
|
187
|
+
unless tuple.size == types.size
|
188
|
+
raise TypeCheckError, "Tuple violation: size should be #{types.size} instead #{tuple.size}"
|
189
|
+
end
|
190
|
+
|
191
|
+
types.each_index do |index|
|
192
|
+
begin
|
193
|
+
isType(types[index]).call(tuple[index])
|
194
|
+
rescue TypeCheckError => e
|
195
|
+
raise TypeCheckError, "Tuple violation: on position #{index} caused by #{e}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
202
|
+
def isSet(type=nil)
|
203
|
+
type = isAny if type.nil?
|
204
|
+
|
205
|
+
createValidator "[Set #{type.to_s}]" do |set|
|
206
|
+
isType(Array).call(set)
|
207
|
+
|
208
|
+
if set.uniq.size != set.size
|
209
|
+
duplicated = set.inject(Hash.new(0)) {|h,i| h[i] += 1; h }.select{|k,v| v > 1 }
|
210
|
+
raise TypeCheckError, "Set violation: has one or more non unique elements: #{duplicated} (value => count)"
|
211
|
+
end
|
212
|
+
|
213
|
+
set.each do |item|
|
214
|
+
begin
|
215
|
+
isType(type).call(item)
|
216
|
+
rescue TypeCheckError => e
|
217
|
+
raise TypeCheckError, "Set violation: caused by #{e}"
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
data/lib/moosex/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
module
|
2
|
-
VERSION = "0.0.
|
1
|
+
module MooseX
|
2
|
+
VERSION = "0.0.11"
|
3
3
|
end
|
data/moosex.gemspec
CHANGED
@@ -5,7 +5,7 @@ require 'moosex/version'
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "moosex"
|
8
|
-
spec.version =
|
8
|
+
spec.version = MooseX::VERSION
|
9
9
|
spec.authors = ["Tiago Peczenyj"]
|
10
10
|
spec.email = ["tiago.peczenyj@gmail.com"]
|
11
11
|
spec.summary = %q{A postmodern object DSL for Ruby}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'moosex'
|
2
|
+
|
3
|
+
class SuperTypes
|
4
|
+
include MooseX
|
5
|
+
include MooseX::Types
|
6
|
+
|
7
|
+
has x: {
|
8
|
+
is: :rw,
|
9
|
+
isa: isAnyOf(
|
10
|
+
isConstant(1),
|
11
|
+
isMaybe(Integer),
|
12
|
+
isArray( hasMethods(:baz) ),
|
13
|
+
isEnum(:foo, :bar)
|
14
|
+
)
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
describe "SuperTypes" do
|
19
|
+
it "should verify tyoe if x" do
|
20
|
+
SuperTypes.new(x: 1)
|
21
|
+
SuperTypes.new(x: nil)
|
22
|
+
SuperTypes.new(x: 1024)
|
23
|
+
SuperTypes.new(x: [])
|
24
|
+
SuperTypes.new(x: :foo)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should raise error" do
|
28
|
+
expect {
|
29
|
+
SuperTypes.new(x: [1])
|
30
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
31
|
+
"isa check for field x: AnyOf Check violation: caused by [Constant violation: value '[1]' (Array) is not '1' (Fixnum), Maybe violation: caused by AnyOf Check violation: caused by [Type violation: value '[1]' (Array) is not an instance of [Type Integer], Constant violation: value '[1]' (Array) is not '' (NilClass)], Array violation: caused by hasMethods violation: object 1 (Fixnum) should implement method baz, Enum Check violation: value '[1]' (Array) is not [:foo, :bar]]")
|
32
|
+
end
|
33
|
+
end
|
data/spec/hooks_spec.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'moosex'
|
2
|
+
|
3
|
+
class Hooks
|
4
|
+
include MooseX
|
5
|
+
|
6
|
+
has logger: {
|
7
|
+
is: :rw,
|
8
|
+
required: true,
|
9
|
+
}
|
10
|
+
|
11
|
+
def sum(a,b,c)
|
12
|
+
self.logger.inside_method(a,b,c)
|
13
|
+
a + b + c
|
14
|
+
end
|
15
|
+
|
16
|
+
before(:sum) do |object,a,b,c|
|
17
|
+
object.logger.inside_before(a,b,c)
|
18
|
+
end
|
19
|
+
|
20
|
+
after(:sum) do |object,a,b,c|
|
21
|
+
object.logger.inside_after(a,b,c)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "Hooks" do
|
26
|
+
it "should call after and before" do
|
27
|
+
logger = double
|
28
|
+
logger.should_receive(:inside_method).with(1,2,3)
|
29
|
+
logger.should_receive(:inside_before).with(1,2,3)
|
30
|
+
logger.should_receive(:inside_after).with(1,2,3)
|
31
|
+
|
32
|
+
h = Hooks.new(logger: logger)
|
33
|
+
h.sum(1,2,3).should == 6
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Hooks2 < Hooks
|
38
|
+
around(:sum) do |original_method, object, a,b,c|
|
39
|
+
object.logger.inside_around_begin(a,b,c)
|
40
|
+
result = original_method.bind(object).call(a,b,c)
|
41
|
+
object.logger.inside_around_end(a,b,c)
|
42
|
+
result + 1
|
43
|
+
end
|
44
|
+
|
45
|
+
after(:sum) do |object,a,b,c|
|
46
|
+
object.logger.inside_after2(a,b,c)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "Hooks2" do
|
51
|
+
it "should call after and before" do
|
52
|
+
logger = double
|
53
|
+
logger.should_receive(:inside_method).with(1,2,3)
|
54
|
+
logger.should_receive(:inside_before).with(1,2,3)
|
55
|
+
logger.should_receive(:inside_after).with(1,2,3)
|
56
|
+
logger.should_receive(:inside_after2).with(1,2,3)
|
57
|
+
logger.should_receive(:inside_around_begin).with(1,2,3)
|
58
|
+
logger.should_receive(:inside_around_end).with(1,2,3)
|
59
|
+
h = Hooks2.new(logger: logger)
|
60
|
+
h.sum(1,2,3).should == 7
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class OtherPoint
|
65
|
+
include MooseX
|
66
|
+
|
67
|
+
has [:x, :y ], { is: :rw, required: true }
|
68
|
+
|
69
|
+
def clear!
|
70
|
+
self.x = 0
|
71
|
+
self.y = 0
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class OtherPoint3D < OtherPoint
|
76
|
+
|
77
|
+
has z: { is: :rw, required: true }
|
78
|
+
|
79
|
+
after :clear! do |object|
|
80
|
+
object.z = 0
|
81
|
+
end
|
82
|
+
end
|
83
|
+
describe "OtherPoint3D" do
|
84
|
+
it "should clear a 3d point" do
|
85
|
+
p = OtherPoint3D.new(x: 1, y: 2, z: 3)
|
86
|
+
p.x.should == 1
|
87
|
+
p.y.should == 2
|
88
|
+
p.z.should == 3
|
89
|
+
|
90
|
+
p.clear!
|
91
|
+
|
92
|
+
p.x.should == 0
|
93
|
+
p.y.should == 0
|
94
|
+
p.z.should == 0
|
95
|
+
end
|
96
|
+
end
|
data/spec/point_spec.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'moosex'
|
2
|
+
require 'moosex/types'
|
2
3
|
|
3
4
|
class Point
|
4
5
|
include MooseX
|
@@ -88,13 +89,15 @@ describe "Point" do
|
|
88
89
|
p = Point.new
|
89
90
|
expect {
|
90
91
|
p.x = "lol"
|
91
|
-
}.to raise_error(
|
92
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
93
|
+
"isa check for x=: Type violation: value 'lol' (String) is not an instance of [Type Integer]")
|
92
94
|
end
|
93
95
|
|
94
96
|
it "for x, with type check" do
|
95
97
|
expect {
|
96
98
|
Point.new(x: "lol")
|
97
|
-
}.to raise_error(
|
99
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
100
|
+
"isa check for field x: Type violation: value 'lol' (String) is not an instance of [Type Integer]")
|
98
101
|
end
|
99
102
|
|
100
103
|
it "clear should clean attributes" do
|
@@ -172,13 +175,15 @@ describe "Point3D" do
|
|
172
175
|
p = Point3D.new
|
173
176
|
expect {
|
174
177
|
p.z = "lol"
|
175
|
-
}.to raise_error(
|
178
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
179
|
+
"isa check for z=: Type violation: value 'lol' (String) is not an instance of [Type Integer]")
|
176
180
|
end
|
177
181
|
|
178
182
|
it "for z, with type check" do
|
179
183
|
expect {
|
180
184
|
Point3D.new(z: "lol")
|
181
|
-
}.to raise_error(
|
185
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
186
|
+
"isa check for field z: Type violation: value 'lol' (String) is not an instance of [Type Integer]")
|
182
187
|
end
|
183
188
|
|
184
189
|
it "clear should clean attributes" do
|
data/spec/types_spec.rb
ADDED
@@ -0,0 +1,477 @@
|
|
1
|
+
require 'moosex/types'
|
2
|
+
|
3
|
+
module Test
|
4
|
+
include MooseX::Types
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "MooseX::Types" do
|
8
|
+
describe "Any" do
|
9
|
+
it "should accept any value" do
|
10
|
+
Test.isAny.call(nil)
|
11
|
+
Test.isAny.call(1)
|
12
|
+
Test.isAny.call(0)
|
13
|
+
Test.isAny.call(true)
|
14
|
+
Test.isAny.call(false)
|
15
|
+
Test.isAny.call(:foo)
|
16
|
+
Test.isAny.call("lol")
|
17
|
+
Test.isAny.call([])
|
18
|
+
Test.isAny.call({})
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should return [Any]" do
|
22
|
+
Test.isAny.to_s.should == "[Any]"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "Constant" do
|
27
|
+
it "should accept any value" do
|
28
|
+
Test.isConstant(nil).call(nil)
|
29
|
+
Test.isConstant(1).call(1)
|
30
|
+
Test.isConstant(0).call(0)
|
31
|
+
Test.isConstant(true).call(true)
|
32
|
+
Test.isConstant(false).call(false)
|
33
|
+
Test.isConstant(:foo).call(:foo)
|
34
|
+
Test.isConstant("lol").call("lol")
|
35
|
+
Test.isConstant([]).call([])
|
36
|
+
Test.isConstant({}).call({})
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should return [Constant: value (class)]" do
|
40
|
+
Test.isConstant(nil).to_s.should == "[Constant: '' (NilClass)]"
|
41
|
+
Test.isConstant(1).to_s.should == "[Constant: '1' (Fixnum)]"
|
42
|
+
Test.isConstant(0).to_s.should == "[Constant: '0' (Fixnum)]"
|
43
|
+
Test.isConstant(true).to_s.should == "[Constant: 'true' (TrueClass)]"
|
44
|
+
Test.isConstant(false).to_s.should == "[Constant: 'false' (FalseClass)]"
|
45
|
+
Test.isConstant(:foo).to_s.should == "[Constant: 'foo' (Symbol)]"
|
46
|
+
Test.isConstant("lol").to_s.should == "[Constant: 'lol' (String)]"
|
47
|
+
Test.isConstant([]).to_s.should == "[Constant: '[]' (Array)]"
|
48
|
+
Test.isConstant({}).to_s.should == "[Constant: '{}' (Hash)]"
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should raise error" do
|
52
|
+
expect {
|
53
|
+
Test.isConstant(1).call(0)
|
54
|
+
}.to raise_error(MooseX::Types::TypeCheckError, "Constant violation: value '0' (Fixnum) is not '1' (Fixnum)")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "Type" do
|
59
|
+
|
60
|
+
it "should accept values" do
|
61
|
+
Test.isType(NilClass).call(nil)
|
62
|
+
Test.isType(Fixnum).call(1)
|
63
|
+
Test.isType(Integer).call(1)
|
64
|
+
Test.isType(Fixnum).call(0)
|
65
|
+
Test.isType(Integer).call(0)
|
66
|
+
Test.isType(TrueClass).call(true)
|
67
|
+
Test.isType(FalseClass).call(false)
|
68
|
+
Test.isType(Symbol).call(:foo)
|
69
|
+
Test.isType(String).call("lol")
|
70
|
+
Test.isType(Array).call([])
|
71
|
+
Test.isType(Hash).call({})
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should return [Type Class]" do
|
75
|
+
Test.isType(NilClass).to_s.should == "[Type NilClass]"
|
76
|
+
Test.isType(Fixnum).to_s.should == "[Type Fixnum]"
|
77
|
+
Test.isType(Integer).to_s.should == "[Type Integer]"
|
78
|
+
Test.isType(TrueClass).to_s.should == "[Type TrueClass]"
|
79
|
+
Test.isType(FalseClass).to_s.should == "[Type FalseClass]"
|
80
|
+
Test.isType(Symbol).to_s.should == "[Type Symbol]"
|
81
|
+
Test.isType(String).to_s.should == "[Type String]"
|
82
|
+
Test.isType(Array).to_s.should == "[Type Array]"
|
83
|
+
Test.isType(Hash).to_s.should == "[Type Hash]"
|
84
|
+
end
|
85
|
+
|
86
|
+
it "test aliases" do
|
87
|
+
Test.isInstanceOf(TrueClass).call(true)
|
88
|
+
Test.isConsumerOf(TrueClass).call(true)
|
89
|
+
|
90
|
+
Test.isInstanceOf(TrueClass).to_s.should == "[Type TrueClass]"
|
91
|
+
Test.isConsumerOf(TrueClass).to_s.should == "[Type TrueClass]"
|
92
|
+
end
|
93
|
+
|
94
|
+
it "Constant should raise error" do
|
95
|
+
expect {
|
96
|
+
Test.isType(Array).call({})
|
97
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
98
|
+
"Type violation: value '{}' (Hash) is not an instance of [Type Array]")
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "AllOf" do
|
104
|
+
|
105
|
+
it "should accept values" do
|
106
|
+
Test.isAllOf(Object).call(nil)
|
107
|
+
Test.isAllOf(Object, NilClass).call(nil)
|
108
|
+
Test.isAllOf(Fixnum).call(1)
|
109
|
+
Test.isAllOf(Fixnum,Integer).call(1)
|
110
|
+
Test.isAllOf(Fixnum,Integer,Numeric).call(1)
|
111
|
+
Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1)).call(1)
|
112
|
+
|
113
|
+
Test.isAllOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).call(1)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "shouldreturn [AllOf *]" do
|
117
|
+
Test.isAllOf(Object).to_s.should == "[AllOf [Object]]"
|
118
|
+
Test.isAllOf(Object, NilClass).to_s.should == "[AllOf [Object, NilClass]]"
|
119
|
+
Test.isAllOf(Fixnum).to_s.should == "[AllOf [Fixnum]]"
|
120
|
+
Test.isAllOf(Fixnum,Integer).to_s.should == "[AllOf [Fixnum, Integer]]"
|
121
|
+
Test.isAllOf(Fixnum,Integer,Numeric).to_s.should == "[AllOf [Fixnum, Integer, Numeric]]"
|
122
|
+
Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1)).to_s
|
123
|
+
.should == "[AllOf [Fixnum, Integer, Numeric, [Constant: '1' (Fixnum)]]]"
|
124
|
+
|
125
|
+
Test.isAllOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).to_s
|
126
|
+
.should == "[AllOf [[AllOf [Fixnum, Integer]], Numeric, [Constant: '1' (Fixnum)]]]"
|
127
|
+
end
|
128
|
+
|
129
|
+
it "Constant should raise error" do
|
130
|
+
expect {
|
131
|
+
Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1)).call(2)
|
132
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
133
|
+
"AllOf Check violation: caused by [Constant violation: value '2' (Fixnum) is not '1' (Fixnum)]")
|
134
|
+
|
135
|
+
expect {
|
136
|
+
Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1)).call(nil)
|
137
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
138
|
+
"AllOf Check violation: caused by [Type violation: value '' (NilClass) is not an instance of [Type Fixnum]]")
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "AnyOf" do
|
144
|
+
|
145
|
+
it "should accept values" do
|
146
|
+
Test.isAnyOf(Object).call(nil)
|
147
|
+
Test.isAnyOf(Object, NilClass).call(nil)
|
148
|
+
|
149
|
+
Test.isAnyOf(TrueClass, FalseClass).call(true)
|
150
|
+
Test.isAnyOf(TrueClass, FalseClass).call(false)
|
151
|
+
|
152
|
+
Test.isAnyOf(Fixnum).call(1)
|
153
|
+
Test.isAnyOf(Fixnum,Integer).call(1)
|
154
|
+
Test.isAnyOf(Fixnum,Integer,Numeric).call(1)
|
155
|
+
Test.isAnyOf(Fixnum,Integer,Numeric, Test.isConstant(1)).call(1)
|
156
|
+
|
157
|
+
Test.isAnyOf(Fixnum, String, Symbol).call(1)
|
158
|
+
Test.isAnyOf(Fixnum, String, Symbol).call("string")
|
159
|
+
Test.isAnyOf(Fixnum, String, Symbol).call(:symbol)
|
160
|
+
|
161
|
+
Test.isAnyOf(Test.isConstant(0), Test.isConstant(1)).call(1)
|
162
|
+
Test.isAnyOf(Test.isConstant(0), Test.isConstant(1)).call(0)
|
163
|
+
|
164
|
+
Test.isAnyOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).call(1)
|
165
|
+
Test.isAnyOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).call(2)
|
166
|
+
Test.isAnyOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).call(3.0)
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should return [AnyOf *]" do
|
170
|
+
Test.isAnyOf(Object).to_s.should == "[AnyOf [Object]]"
|
171
|
+
Test.isAnyOf(Object, NilClass).to_s.should == "[AnyOf [Object, NilClass]]"
|
172
|
+
Test.isAnyOf(Fixnum).to_s.should == "[AnyOf [Fixnum]]"
|
173
|
+
Test.isAnyOf(Fixnum,Integer).to_s.should == "[AnyOf [Fixnum, Integer]]"
|
174
|
+
Test.isAnyOf(Fixnum,Integer,Numeric).to_s.should == "[AnyOf [Fixnum, Integer, Numeric]]"
|
175
|
+
Test.isAnyOf(Fixnum,Integer,Numeric, Test.isConstant(1)).to_s
|
176
|
+
.should == "[AnyOf [Fixnum, Integer, Numeric, [Constant: '1' (Fixnum)]]]"
|
177
|
+
|
178
|
+
Test.isAnyOf(Test.isAllOf(Fixnum,Integer),Numeric, Test.isConstant(1)).to_s
|
179
|
+
.should == "[AnyOf [[AllOf [Fixnum, Integer]], Numeric, [Constant: '1' (Fixnum)]]]"
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should raise error" do
|
183
|
+
expect {
|
184
|
+
Test.isAnyOf(TrueClass, FalseClass).call(nil)
|
185
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
186
|
+
"AnyOf Check violation: caused by [Type violation: value '' (NilClass) is not an instance of [Type TrueClass], Type violation: value '' (NilClass) is not an instance of [Type FalseClass]]")
|
187
|
+
|
188
|
+
expect {
|
189
|
+
Test.isAnyOf(Fixnum, String, Symbol).call([])
|
190
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
191
|
+
"AnyOf Check violation: caused by [Type violation: value '[]' (Array) is not an instance of [Type Fixnum], Type violation: value '[]' (Array) is not an instance of [Type String], Type violation: value '[]' (Array) is not an instance of [Type Symbol]]")
|
192
|
+
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
describe "Enum" do
|
197
|
+
it "should accept a constant value" do
|
198
|
+
Test.isEnum(1,2,3).call(1)
|
199
|
+
Test.isEnum(1,2,3).call(2)
|
200
|
+
Test.isEnum(1,2,3).call(3)
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should return [Enum ...]" do
|
204
|
+
Test.isEnum(1,2,3).to_s.should == "[Enum [1, 2, 3]]"
|
205
|
+
end
|
206
|
+
|
207
|
+
it "should raise error" do
|
208
|
+
expect {
|
209
|
+
Test.isEnum(1,2,3).call(4)
|
210
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
211
|
+
"Enum Check violation: value '4' (Fixnum) is not [1, 2, 3]")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
describe "Not" do
|
216
|
+
it "should accept values" do
|
217
|
+
Test.isNot(Test.isConstant(1)).call(0)
|
218
|
+
Test.isNot(Test.isType(String)).call(0)
|
219
|
+
Test.isNot(Test.isAnyOf(TrueClass, FalseClass)).call(nil)
|
220
|
+
|
221
|
+
Test.isNot(Test.isType(Array)).call({})
|
222
|
+
Test.isNot(Test.isEnum(1,2,3)).call(4)
|
223
|
+
|
224
|
+
Test.isNot(Test.isAnyOf(Fixnum, String, Symbol)).call([])
|
225
|
+
Test.isNot(Test.isAnyOf(TrueClass, FalseClass)).call(3)
|
226
|
+
|
227
|
+
Test.isNot(Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1))).call(2)
|
228
|
+
Test.isNot(Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1))).call(nil)
|
229
|
+
end
|
230
|
+
|
231
|
+
it "shuld return [NOT ...]" do
|
232
|
+
Test.isNot(Test.isConstant(1)).to_s.should == "[NOT [Constant: '1' (Fixnum)]]"
|
233
|
+
Test.isNot(Test.isType(String)).to_s.should == "[NOT [Type String]]"
|
234
|
+
Test.isNot(Test.isAnyOf(TrueClass, FalseClass)).to_s
|
235
|
+
.should == "[NOT [AnyOf [TrueClass, FalseClass]]]"
|
236
|
+
|
237
|
+
Test.isNot(Test.isType(Array)).to_s.should == "[NOT [Type Array]]"
|
238
|
+
Test.isNot(Test.isEnum(1,2,3)).to_s.should == "[NOT [Enum [1, 2, 3]]]"
|
239
|
+
|
240
|
+
Test.isNot(Test.isAnyOf(Fixnum, String, Symbol)).to_s
|
241
|
+
.should == "[NOT [AnyOf [Fixnum, String, Symbol]]]"
|
242
|
+
|
243
|
+
|
244
|
+
Test.isNot(Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1))).to_s
|
245
|
+
.should == "[NOT [AllOf [Fixnum, Integer, Numeric, [Constant: '1' (Fixnum)]]]]"
|
246
|
+
end
|
247
|
+
|
248
|
+
it "should raise error" do
|
249
|
+
expect {
|
250
|
+
Test.isNot(Test.isEnum(1,2,3)).call(2)
|
251
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
252
|
+
"Not violation: value '2' (Fixnum) is not [Enum [1, 2, 3]]")
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "Maybe" do
|
257
|
+
it "should accept value or nil" do
|
258
|
+
Test.isMaybe(Test.isConstant(9)).call(9)
|
259
|
+
Test.isMaybe(Test.isType(TrueClass)).call(true)
|
260
|
+
Test.isMaybe(Test.isEnum(1,2,3)).call(1)
|
261
|
+
|
262
|
+
Test.isMaybe(Test.isConstant(9)).call(nil)
|
263
|
+
Test.isMaybe(Test.isType(TrueClass)).call(nil)
|
264
|
+
Test.isMaybe(Test.isEnum(1,2,3)).call(nil)
|
265
|
+
|
266
|
+
Test.isMaybe(TrueClass).call(nil)
|
267
|
+
Test.isMaybe(TrueClass).call(true)
|
268
|
+
|
269
|
+
Test.isMaybe(Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1))).call(nil)
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should return [Maybe [...]]" do
|
273
|
+
Test.isMaybe(Test.isConstant(9)).to_s.should == "[Maybe [Constant: '9' (Fixnum)]]"
|
274
|
+
Test.isMaybe(Test.isType(TrueClass)).to_s.should == "[Maybe [Type TrueClass]]"
|
275
|
+
Test.isMaybe(TrueClass).to_s.should == "[Maybe TrueClass]"
|
276
|
+
Test.isMaybe(Test.isEnum(1,2,3)).to_s.should == "[Maybe [Enum [1, 2, 3]]]"
|
277
|
+
Test.isMaybe(Test.isAllOf(Fixnum,Integer,Numeric, Test.isConstant(1))).to_s
|
278
|
+
.should == "[Maybe [AllOf [Fixnum, Integer, Numeric, [Constant: '1' (Fixnum)]]]]"
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should raise error" do
|
282
|
+
expect {
|
283
|
+
Test.isMaybe(Test.isConstant(9)).call(8)
|
284
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
285
|
+
"Maybe violation: caused by AnyOf Check violation: caused by [Constant violation: value '8' (Fixnum) is not '9' (Fixnum), Constant violation: value '8' (Fixnum) is not '' (NilClass)]")
|
286
|
+
|
287
|
+
expect {
|
288
|
+
Test.isMaybe(TrueClass).call(false)
|
289
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
290
|
+
"Maybe violation: caused by AnyOf Check violation: caused by [Type violation: value 'false' (FalseClass) is not an instance of [Type TrueClass], Constant violation: value 'false' (FalseClass) is not '' (NilClass)]")
|
291
|
+
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe "Array" do
|
296
|
+
it "should accept values" do
|
297
|
+
Test.isArray().call([])
|
298
|
+
Test.isArray().call([1])
|
299
|
+
Test.isArray().call([1,2])
|
300
|
+
|
301
|
+
Test.isArray(Integer).call([])
|
302
|
+
Test.isArray(Integer).call([1])
|
303
|
+
Test.isArray(Integer).call([1,2])
|
304
|
+
|
305
|
+
Test.isArray(Test.isMaybe(Integer)).call([1,2,nil])
|
306
|
+
Test.isArray(Test.isArray(Integer)).call([[1,2],[3,4]])
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should return [Array ]" do
|
310
|
+
Test.isArray().to_s.should == "[Array [Any]]"
|
311
|
+
Test.isArray(Integer).to_s.should == "[Array Integer]"
|
312
|
+
Test.isArray(Test.isMaybe(Integer)).to_s.should == "[Array [Maybe Integer]]"
|
313
|
+
Test.isArray(Test.isArray(Integer)).to_s.should == "[Array [Array Integer]]"
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should raise error" do
|
317
|
+
expect {
|
318
|
+
Test.isArray(Test.isArray(Test.isMaybe(Integer))).call(nil)
|
319
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
320
|
+
"Type violation: value '' (NilClass) is not an instance of [Type Array]")
|
321
|
+
|
322
|
+
expect {
|
323
|
+
Test.isArray(Test.isArray(Test.isMaybe(Integer))).call([false])
|
324
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
325
|
+
"Array violation: caused by Type violation: value 'false' (FalseClass) is not an instance of [Type Array]")
|
326
|
+
|
327
|
+
expect {
|
328
|
+
Test.isArray(Test.isArray(Test.isMaybe(Integer))).call([[false]])
|
329
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
330
|
+
"Array violation: caused by Array violation: caused by Maybe violation: caused by AnyOf Check violation: caused by [Type violation: value 'false' (FalseClass) is not an instance of [Type Integer], Constant violation: value 'false' (FalseClass) is not '' (NilClass)]")
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
describe "Hash" do
|
335
|
+
it "should accept values" do
|
336
|
+
Test.isHash().call({})
|
337
|
+
Test.isHash().call({ a: 1 })
|
338
|
+
Test.isHash().call({ 1 => 2})
|
339
|
+
|
340
|
+
Test.isHash(Integer => Integer).call({})
|
341
|
+
Test.isHash(Integer => Integer).call({1 => 2})
|
342
|
+
Test.isHash(Integer => Integer).call({2 => 1, 4 => 5})
|
343
|
+
|
344
|
+
Test.isHash(Symbol => Test.isArray(Test.isMaybe(Test.isEnum(1,2,3))))
|
345
|
+
.call( foo: [nil, 1,2,3], bar: [nil, 2], baz: [])
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should return [Hash ]" do
|
349
|
+
Test.isHash()
|
350
|
+
.to_s.should == "[Hash [Any] => [Any]]"
|
351
|
+
|
352
|
+
Test.isHash(Integer => Integer)
|
353
|
+
.to_s.should == "[Hash Integer => Integer]"
|
354
|
+
|
355
|
+
Test.isHash(Symbol => Test.isArray(Test.isMaybe(Test.isEnum(1,2,3))))
|
356
|
+
.to_s.should == "[Hash Symbol => [Array [Maybe [Enum [1, 2, 3]]]]]"
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should raise error" do
|
360
|
+
expect{
|
361
|
+
Test.isHash().call(nil)
|
362
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
363
|
+
"Type violation: value '' (NilClass) is not an instance of [Type Hash]")
|
364
|
+
expect{
|
365
|
+
Test.isHash(Symbol => Integer).call({ 1 => 2})
|
366
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
367
|
+
"Hash violation: caused by Type violation: value '1' (Fixnum) is not an instance of [Type Symbol]")
|
368
|
+
end
|
369
|
+
end
|
370
|
+
|
371
|
+
describe "Tuple" do
|
372
|
+
it "should accept values" do
|
373
|
+
Test.isTuple().call([])
|
374
|
+
|
375
|
+
Test.isTuple(Test.isAny).call([1])
|
376
|
+
Test.isTuple(Test.isAny, Test.isAny).call([1,2])
|
377
|
+
|
378
|
+
Test.isTuple(Integer).call([1])
|
379
|
+
Test.isTuple(Integer, Integer).call([1,2])
|
380
|
+
|
381
|
+
Test.isTuple(Integer, Symbol, Test.isAny, TrueClass).call([1,:symbol, nil, true])
|
382
|
+
end
|
383
|
+
|
384
|
+
it "should return [Tuple ]" do
|
385
|
+
Test.isTuple().to_s.should == "[Tuple []]"
|
386
|
+
Test.isTuple(Integer).to_s.should == "[Tuple [Integer]]"
|
387
|
+
Test.isTuple(Integer, Integer).to_s.should == "[Tuple [Integer, Integer]]"
|
388
|
+
Test.isTuple(Integer, Symbol, Test.isAny, TrueClass).to_s
|
389
|
+
.should == "[Tuple [Integer, Symbol, [Any], TrueClass]]"
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should raise error" do
|
393
|
+
expect {
|
394
|
+
Test.isTuple().call([1])
|
395
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
396
|
+
"Tuple violation: size should be 0 instead 1")
|
397
|
+
expect {
|
398
|
+
Test.isTuple(Integer).call([])
|
399
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
400
|
+
"Tuple violation: size should be 1 instead 0")
|
401
|
+
expect {
|
402
|
+
Test.isTuple().call(nil)
|
403
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
404
|
+
"Type violation: value '' (NilClass) is not an instance of [Type Array]")
|
405
|
+
expect {
|
406
|
+
Test.isTuple(Integer, Symbol, Test.isAny, TrueClass).call([1,:symbol, nil, false])
|
407
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
408
|
+
"Tuple violation: on position 3 caused by Type violation: value 'false' (FalseClass) is not an instance of [Type TrueClass]")
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
describe "Set" do
|
413
|
+
it "should accept values" do
|
414
|
+
Test.isSet().call([])
|
415
|
+
Test.isSet().call([1])
|
416
|
+
Test.isSet().call([1,2])
|
417
|
+
|
418
|
+
Test.isSet(Integer).call([])
|
419
|
+
Test.isSet(Integer).call([1])
|
420
|
+
Test.isSet(Integer).call([1,2])
|
421
|
+
end
|
422
|
+
|
423
|
+
it "should return [Set ]" do
|
424
|
+
Test.isSet().to_s.should == "[Set [Any]]"
|
425
|
+
Test.isSet(Integer).to_s.should == "[Set Integer]"
|
426
|
+
Test.isSet(Test.isMaybe(Integer)).to_s.should == "[Set [Maybe Integer]]"
|
427
|
+
Test.isSet(Test.isArray(Integer)).to_s.should == "[Set [Array Integer]]"
|
428
|
+
end
|
429
|
+
|
430
|
+
it "should raise error" do
|
431
|
+
expect {
|
432
|
+
Test.isSet(Test.isArray(Test.isMaybe(Integer))).call(nil)
|
433
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
434
|
+
"Type violation: value '' (NilClass) is not an instance of [Type Array]")
|
435
|
+
|
436
|
+
expect {
|
437
|
+
Test.isSet(Test.isArray(Test.isMaybe(Integer))).call([false])
|
438
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
439
|
+
"Set violation: caused by Type violation: value 'false' (FalseClass) is not an instance of [Type Array]")
|
440
|
+
|
441
|
+
expect {
|
442
|
+
Test.isSet(Test.isArray(Test.isMaybe(Integer))).call([[false]])
|
443
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
444
|
+
"Set violation: caused by Array violation: caused by Maybe violation: caused by AnyOf Check violation: caused by [Type violation: value 'false' (FalseClass) is not an instance of [Type Integer], Constant violation: value 'false' (FalseClass) is not '' (NilClass)]")
|
445
|
+
|
446
|
+
expect {
|
447
|
+
Test.isSet(Integer).call([1,2,2])
|
448
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
449
|
+
"Set violation: has one or more non unique elements: {2=>2} (value => count)")
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
describe "hasMethods" do
|
454
|
+
class MyFoo
|
455
|
+
def bar ; end
|
456
|
+
def baz ; end
|
457
|
+
end
|
458
|
+
|
459
|
+
it "should verify if has methods" do
|
460
|
+
Test.hasMethods(:bar).call(MyFoo.new)
|
461
|
+
Test.hasMethods(:baz).call(MyFoo.new)
|
462
|
+
Test.hasMethods(:bar, :baz).call(MyFoo.new)
|
463
|
+
end
|
464
|
+
|
465
|
+
it "should return [hasMethods ...]" do
|
466
|
+
Test.hasMethods(:bar).to_s.should == "[hasMethods [:bar]]"
|
467
|
+
Test.hasMethods(:bar, :baz).to_s.should == "[hasMethods [:bar, :baz]]"
|
468
|
+
end
|
469
|
+
|
470
|
+
it "should raise error" do
|
471
|
+
expect {
|
472
|
+
Test.hasMethods(:bar, :baz, :bam).call(1)
|
473
|
+
}.to raise_error(MooseX::Types::TypeCheckError,
|
474
|
+
"hasMethods violation: object 1 (Fixnum) should implement method bar")
|
475
|
+
end
|
476
|
+
end
|
477
|
+
end
|