moosex 0.0.10 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|