moosex 0.0.10 → 0.0.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,3 +1,3 @@
1
- module Moosex
2
- VERSION = "0.0.10"
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 = Moosex::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
@@ -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('isa check for "x" failed: is not instance of Integer!')
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('isa check for "x" failed: is not instance of Integer!')
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('isa check for "z" failed: is not instance of Integer!')
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('isa check for "z" failed: is not instance of Integer!')
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
@@ -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