type_struct 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +79 -8
- data/Rakefile +1 -1
- data/lib/type_struct.rb +35 -20
- data/lib/type_struct/ext.rb +4 -0
- data/lib/type_struct/hash_of.rb +1 -0
- data/lib/type_struct/version.rb +1 -1
- data/lib/type_struct_benchmark_test.rb +42 -0
- data/lib/type_struct_test.rb +194 -43
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cf544085d5325212144ddfb4119b2360807e1869
|
4
|
+
data.tar.gz: 2c7efe99a85c7442ddc2fc5b304bb55ca9e78ac1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6b6872ff8ea9c9bcb43c2743726a8458a7d0018a98f81191c511d03a700df971794de75f6d75ffbef9f8ff94e12230fb1483ede2c8cd66581ac7b94c97b4cfe5
|
7
|
+
data.tar.gz: 93d5f28458f94944711361846df2ecdb9223ee87d8636444fb8cedba51a0068088679c53873c37a08f7c0b2d00118feda067eb2f38c565964c4cd9ff122a3362
|
data/README.md
CHANGED
@@ -6,6 +6,75 @@ Imitating static typed struct.
|
|
6
6
|
|
7
7
|
All type is checked by `===` method.
|
8
8
|
|
9
|
+
## Motivation
|
10
|
+
|
11
|
+
### I don't like Hash
|
12
|
+
|
13
|
+
```ruby
|
14
|
+
p h #=> {color: 'red', width: 120, height: 200}
|
15
|
+
```
|
16
|
+
|
17
|
+
**No name**
|
18
|
+
|
19
|
+
What is this a data?
|
20
|
+
We cannot know this name.
|
21
|
+
|
22
|
+
Where is this an instance from?
|
23
|
+
How do we grep doing?
|
24
|
+
|
25
|
+
**Bad syntax**
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
h[:widht] #=> Cannot detect typo
|
29
|
+
#=> nil
|
30
|
+
h.dig(:widht) #=> ditto
|
31
|
+
#=> nil
|
32
|
+
h.fetch(:widht) #=> Can detect typo, But too long and cannot know suggestion from did_you_mean gem
|
33
|
+
# KeyError: key not found: :widht
|
34
|
+
```
|
35
|
+
|
36
|
+
**Too freedom**
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
# Where is from `who` key? Is this expected?
|
40
|
+
p h #=> {color: 'red', width: 120, height: 200, who: 'are you?'}
|
41
|
+
```
|
42
|
+
|
43
|
+
### I like Struct
|
44
|
+
|
45
|
+
**Grepable Name**
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
Circle = Struct.new(:color, :width, :height)
|
49
|
+
circle = Circle.new('red', 120, 200)
|
50
|
+
```
|
51
|
+
|
52
|
+
**Good syntax**
|
53
|
+
|
54
|
+
```ruby
|
55
|
+
circle.color
|
56
|
+
#=> 'red'
|
57
|
+
circle.widht
|
58
|
+
# NoMethodError:
|
59
|
+
Did you mean? width
|
60
|
+
width=
|
61
|
+
```
|
62
|
+
|
63
|
+
**Strictly members**
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
circle.who = "are you?"
|
67
|
+
# NoMethodError: undefined method `who='
|
68
|
+
```
|
69
|
+
|
70
|
+
## Evolution
|
71
|
+
|
72
|
+
- Can use keyword arguments
|
73
|
+
- Add **Type** system
|
74
|
+
- Recursive Mapping
|
75
|
+
|
76
|
+
This is the **TypeStruct**.
|
77
|
+
|
9
78
|
## Usage
|
10
79
|
|
11
80
|
### Check type
|
@@ -38,16 +107,18 @@ sample.string #=> NoMethodError
|
|
38
107
|
sample.str = 1 #=> TypeError
|
39
108
|
```
|
40
109
|
|
41
|
-
### Mapping
|
110
|
+
### Recursive Mapping
|
42
111
|
|
43
|
-
Generate object from hash recursive
|
112
|
+
Generate object from hash by recursive
|
44
113
|
|
45
114
|
```ruby
|
46
115
|
Point = TypeStruct.new(
|
47
116
|
x: Integer,
|
48
117
|
y: Integer,
|
49
118
|
)
|
50
|
-
Color =
|
119
|
+
Color = TypeStruct.new(
|
120
|
+
code: /\A#[0-9a-f]{6}\z/i,
|
121
|
+
)
|
51
122
|
Line = TypeStruct.new(
|
52
123
|
start: Point,
|
53
124
|
end: Point,
|
@@ -58,18 +129,18 @@ hash = JSON.parse(%({"start":{"x":3,"y":10},"end":{"x":5,"y":9},"color":{"code":
|
|
58
129
|
line = Line.from_hash(hash)
|
59
130
|
|
60
131
|
p line
|
61
|
-
#=> #<Line start=#<Point x=3, y=10>, end=#<Point x=5, y=9>, color=#<
|
132
|
+
#=> #<Line start=#<Point x=3, y=10>, end=#<Point x=5, y=9>, color=#<Color code="#CAFE00">>
|
62
133
|
p line.start.y
|
63
134
|
#=> 10
|
64
135
|
line.stort
|
65
136
|
#=> NoMethodError
|
66
137
|
```
|
67
138
|
|
68
|
-
## Four special
|
139
|
+
## Four special classes
|
69
140
|
|
70
141
|
### Union
|
71
142
|
|
72
|
-
Union is
|
143
|
+
Union is an object express class that some classes as one class like crystal `Union`.
|
73
144
|
|
74
145
|
`Union#===` check all object with `===` method.
|
75
146
|
|
@@ -92,7 +163,7 @@ Foo = TypeStruct.new(
|
|
92
163
|
|
93
164
|
### ArrayOf
|
94
165
|
|
95
|
-
ArrayOf is
|
166
|
+
ArrayOf is an object express array type.
|
96
167
|
|
97
168
|
`ArrayOf#===` check all item with `===` method.
|
98
169
|
|
@@ -119,7 +190,7 @@ p Baz.new(qux: { "a" => [1, 2, nil] }) #=> TypeError
|
|
119
190
|
|
120
191
|
### Interface
|
121
192
|
|
122
|
-
Interface is
|
193
|
+
Interface is an object for duck typing like golang `interface`.
|
123
194
|
|
124
195
|
`Interface#===` check all method using `respond_to?`
|
125
196
|
|
data/Rakefile
CHANGED
data/lib/type_struct.rb
CHANGED
@@ -57,11 +57,17 @@ class TypeStruct
|
|
57
57
|
alias_method :new, :original_new
|
58
58
|
|
59
59
|
def from_hash(h)
|
60
|
+
unless Hash === h
|
61
|
+
h = h.to_hash if h.respond_to?(:to_hash)
|
62
|
+
unless Hash === h
|
63
|
+
raise TypeError, "#{self}.from_hash only accept Hash got `#{h.class}'"
|
64
|
+
end
|
65
|
+
end
|
60
66
|
args = {}
|
61
67
|
h.each do |key, value|
|
62
68
|
key = key.to_sym
|
63
69
|
t = type(key)
|
64
|
-
args[key] = try_convert(t, value)
|
70
|
+
args[key] = try_convert(t, key, value)
|
65
71
|
end
|
66
72
|
new(args)
|
67
73
|
end
|
@@ -84,43 +90,52 @@ class TypeStruct
|
|
84
90
|
|
85
91
|
private
|
86
92
|
|
87
|
-
def try_convert(klass, value)
|
93
|
+
def try_convert(klass, key, value)
|
88
94
|
return nil unless !klass.nil? && !value.nil?
|
89
95
|
|
90
|
-
|
96
|
+
case klass
|
97
|
+
when Union
|
91
98
|
errors = []
|
92
99
|
klass.each do |k|
|
93
100
|
t = begin
|
94
|
-
try_convert(k, value)
|
101
|
+
try_convert(k, key, value)
|
95
102
|
rescue TypeError => e
|
96
103
|
errors << e
|
97
104
|
nil
|
98
105
|
end
|
99
106
|
return t if !t.nil?
|
100
107
|
end
|
101
|
-
raise UnionNotFoundError, "#{klass} is not found with
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
108
|
+
raise UnionNotFoundError, "#{klass} is not found with value `#{value}'\nerrors:\n#{errors.join("\n")}"
|
109
|
+
when ArrayOf
|
110
|
+
unless Array === value
|
111
|
+
raise TypeError, "#{self}##{key} expect #{klass.inspect} got #{value.inspect}"
|
112
|
+
end
|
113
|
+
value.map { |v| try_convert(klass.type, key, v) }
|
114
|
+
when HashOf
|
115
|
+
unless Hash === value
|
116
|
+
raise TypeError, "#{self}##{key} expect #{klass.inspect} got #{value.inspect}"
|
117
|
+
end
|
106
118
|
new_hash = {}
|
107
119
|
value.each do |hk, hv|
|
108
|
-
new_hash[hk] = try_convert(klass.value_type, hv)
|
120
|
+
new_hash[hk] = try_convert(klass.value_type, key, hv)
|
109
121
|
end
|
110
122
|
new_hash
|
111
|
-
|
112
|
-
if klass.
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
123
|
+
else
|
124
|
+
if klass.respond_to?(:ancestors)
|
125
|
+
if klass.ancestors.include?(TypeStruct)
|
126
|
+
klass.from_hash(value)
|
127
|
+
elsif klass.ancestors.include?(Struct)
|
128
|
+
struct = klass.new
|
129
|
+
value.each { |k, v| struct[k] = v }
|
130
|
+
struct
|
131
|
+
elsif klass === value
|
132
|
+
value
|
133
|
+
else
|
134
|
+
raise TypeError, "#{self}##{key} expect #{klass.inspect} got #{value.inspect}"
|
135
|
+
end
|
119
136
|
else
|
120
137
|
value
|
121
138
|
end
|
122
|
-
else
|
123
|
-
value
|
124
139
|
end
|
125
140
|
end
|
126
141
|
end
|
data/lib/type_struct/ext.rb
CHANGED
@@ -12,24 +12,28 @@ class TypeStruct
|
|
12
12
|
def to_s
|
13
13
|
"#{self.class.name.split('::').last}(#{@type})"
|
14
14
|
end
|
15
|
+
alias inspect to_s
|
15
16
|
end
|
16
17
|
|
17
18
|
class HashOf
|
18
19
|
def to_s
|
19
20
|
"#{self.class.name.split('::').last}(#{@key_type}, #{@value_type})"
|
20
21
|
end
|
22
|
+
alias inspect to_s
|
21
23
|
end
|
22
24
|
|
23
25
|
class Interface
|
24
26
|
def to_s
|
25
27
|
"#<#{self.class.name.split('::').last}(#{@methods.map(&:inspect).join(',')})>"
|
26
28
|
end
|
29
|
+
alias inspect to_s
|
27
30
|
end
|
28
31
|
|
29
32
|
class Union
|
30
33
|
def to_s
|
31
34
|
"#<#{self.class.name.split('::').last} #{@classes.join('|')}>"
|
32
35
|
end
|
36
|
+
alias inspect to_s
|
33
37
|
end
|
34
38
|
end
|
35
39
|
|
data/lib/type_struct/hash_of.rb
CHANGED
data/lib/type_struct/version.rb
CHANGED
@@ -0,0 +1,42 @@
|
|
1
|
+
require "type_struct"
|
2
|
+
require "type_struct/ext"
|
3
|
+
|
4
|
+
module TypeStructBenchmarkTest
|
5
|
+
using TypeStruct::Union::Ext
|
6
|
+
|
7
|
+
def benchmark_new(b)
|
8
|
+
i = 0
|
9
|
+
while i < b.n
|
10
|
+
TypeStruct.new(
|
11
|
+
a: String,
|
12
|
+
b: Integer,
|
13
|
+
c: Regexp,
|
14
|
+
)
|
15
|
+
i += 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
A = TypeStruct.new(
|
20
|
+
a: Integer,
|
21
|
+
)
|
22
|
+
B = TypeStruct.new(
|
23
|
+
b: A,
|
24
|
+
)
|
25
|
+
C = TypeStruct.new(
|
26
|
+
c: B,
|
27
|
+
)
|
28
|
+
D = TypeStruct.new(
|
29
|
+
d: C,
|
30
|
+
)
|
31
|
+
E = TypeStruct.new(
|
32
|
+
e: D,
|
33
|
+
)
|
34
|
+
|
35
|
+
def benchmark_from_hash(b)
|
36
|
+
i = 0
|
37
|
+
while i < b.n
|
38
|
+
E.from_hash(e: { d: { c: { b: { a: 1 } } } })
|
39
|
+
i += 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/type_struct_test.rb
CHANGED
@@ -12,23 +12,6 @@ module TypeStructTest
|
|
12
12
|
any: Object,
|
13
13
|
); end
|
14
14
|
|
15
|
-
class Quux < Struct.new(:q)
|
16
|
-
end
|
17
|
-
|
18
|
-
class Qux < TypeStruct.new(
|
19
|
-
quux1: Quux,
|
20
|
-
quux2: Quux,
|
21
|
-
); end
|
22
|
-
|
23
|
-
class Bar < TypeStruct.new(
|
24
|
-
baz: ArrayOf(Integer | NilClass),
|
25
|
-
); end
|
26
|
-
|
27
|
-
class Foo < TypeStruct.new(
|
28
|
-
nil: NilClass,
|
29
|
-
bar: Bar,
|
30
|
-
); end
|
31
|
-
|
32
15
|
BoolClass = TrueClass | FalseClass
|
33
16
|
C = TypeStruct.new(
|
34
17
|
a: ArrayOf(BoolClass),
|
@@ -124,6 +107,45 @@ module TypeStructTest
|
|
124
107
|
else
|
125
108
|
t.error("TypeError dose not raise error")
|
126
109
|
end
|
110
|
+
|
111
|
+
hsbn = TypeStruct.new(
|
112
|
+
a: HashOf(Symbol, b) | NilClass,
|
113
|
+
)
|
114
|
+
begin
|
115
|
+
hsbn.from_hash(a: [])
|
116
|
+
rescue TypeStruct::UnionNotFoundError
|
117
|
+
rescue => e
|
118
|
+
t.error("Unexpected error #{e.class}: #{e.message}")
|
119
|
+
else
|
120
|
+
t.error("Unexpected behavior")
|
121
|
+
end
|
122
|
+
|
123
|
+
begin
|
124
|
+
hsbn.from_hash(a: {a: {b: 1.1}})
|
125
|
+
rescue TypeStruct::UnionNotFoundError
|
126
|
+
rescue => e
|
127
|
+
t.error("Unexpected error #{e.class}: #{e.message}")
|
128
|
+
else
|
129
|
+
t.error("Unexpected behavior")
|
130
|
+
end
|
131
|
+
|
132
|
+
begin
|
133
|
+
hsbn.from_hash(a: {"a" => {b: 1}})
|
134
|
+
rescue TypeError
|
135
|
+
rescue => e
|
136
|
+
t.error("Unexpected error #{e.class}: #{e.message}")
|
137
|
+
else
|
138
|
+
t.error("Unexpected behavior")
|
139
|
+
end
|
140
|
+
|
141
|
+
begin
|
142
|
+
hsbn.from_hash(a: {"a" => {b: 1.1}})
|
143
|
+
rescue TypeStruct::UnionNotFoundError
|
144
|
+
rescue => e
|
145
|
+
t.error("Unexpected error #{e.class}: #{e.message}")
|
146
|
+
else
|
147
|
+
t.error("Unexpected behavior")
|
148
|
+
end
|
127
149
|
end
|
128
150
|
|
129
151
|
def test_array_of(t)
|
@@ -139,46 +161,147 @@ module TypeStructTest
|
|
139
161
|
end
|
140
162
|
end
|
141
163
|
|
164
|
+
def test_array_of_error(t)
|
165
|
+
a = TypeStruct.new(a: ArrayOf(Integer))
|
166
|
+
begin
|
167
|
+
a.from_hash(a: [1.1])
|
168
|
+
rescue TypeError
|
169
|
+
rescue => e
|
170
|
+
t.error("Unexpected error #{e.class}")
|
171
|
+
else
|
172
|
+
t.error("Nothing raised TypeError")
|
173
|
+
end
|
174
|
+
|
175
|
+
b = TypeStruct.new(a: ArrayOf(Integer) | NilClass)
|
176
|
+
begin
|
177
|
+
b.from_hash(a: [1.1])
|
178
|
+
rescue TypeStruct::UnionNotFoundError
|
179
|
+
rescue => e
|
180
|
+
t.error("Unexpected error #{e.class}")
|
181
|
+
else
|
182
|
+
t.error("Nothing raised TypeStruct::UnionNotFoundError")
|
183
|
+
end
|
184
|
+
|
185
|
+
c = TypeStruct.new(c: Integer)
|
186
|
+
d = TypeStruct.new(d: ArrayOf(c) | NilClass)
|
187
|
+
begin
|
188
|
+
d.from_hash(d: [{c: 1.1}])
|
189
|
+
rescue TypeStruct::UnionNotFoundError
|
190
|
+
rescue => e
|
191
|
+
t.error("Unexpected error #{e.class}")
|
192
|
+
else
|
193
|
+
t.error("Nothing raised TypeStruct::UnionNotFoundError")
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
142
197
|
def test_s_from_hash(t)
|
143
|
-
|
144
|
-
|
198
|
+
bar = TypeStruct.new(
|
199
|
+
baz: ArrayOf(Integer | NilClass),
|
200
|
+
)
|
201
|
+
foo = TypeStruct.new(
|
202
|
+
nil: NilClass,
|
203
|
+
bar: bar,
|
204
|
+
)
|
205
|
+
|
206
|
+
f = foo.from_hash(bar: { baz: [1, 2, 3] })
|
207
|
+
unless foo === f
|
145
208
|
t.error("return value was break")
|
146
209
|
end
|
147
210
|
|
148
211
|
begin
|
149
|
-
|
150
|
-
rescue
|
212
|
+
foo.from_hash(bar: { baz: [1, 2, "3"] })
|
213
|
+
rescue TypeStruct::UnionNotFoundError
|
151
214
|
else
|
152
215
|
t.error("'3' is not valid value for Baz.baz:#{Bar.definition.fetch(:baz)}")
|
153
216
|
end
|
154
217
|
|
155
|
-
|
156
|
-
unless
|
218
|
+
f = foo.from_hash("bar" => { "baz" => [1, 2, 3] })
|
219
|
+
unless foo === f
|
157
220
|
t.error("return value was break")
|
158
221
|
end
|
159
222
|
|
160
|
-
|
161
|
-
unless TypeStruct ===
|
223
|
+
f = foo.from_hash(bar: { baz: [1, 2, 3] }, nil: nil)
|
224
|
+
unless TypeStruct === f
|
162
225
|
t.error("return value type was break")
|
163
226
|
end
|
164
|
-
unless
|
227
|
+
unless foo === f
|
165
228
|
t.error("return value type was break")
|
166
229
|
end
|
167
230
|
|
168
231
|
begin
|
169
|
-
|
232
|
+
foo.from_hash(bar: { baz: [1, nil, 3] })
|
170
233
|
rescue => e
|
171
234
|
t.error("Bar.baz is able to nil but raise error #{e.class}: #{e.message}")
|
172
235
|
end
|
173
236
|
|
174
237
|
begin
|
175
|
-
|
238
|
+
foo.from_hash(bar: { baz: nil })
|
176
239
|
rescue TypeError
|
177
240
|
else
|
178
241
|
t.error("Bar.baz is not able to nil")
|
179
242
|
end
|
180
243
|
end
|
181
244
|
|
245
|
+
def test_s_from_hash_with_other_object(t)
|
246
|
+
a = TypeStruct.new(a: Integer)
|
247
|
+
o = Object.new
|
248
|
+
begin
|
249
|
+
a.from_hash(o)
|
250
|
+
rescue TypeError => e
|
251
|
+
rescue => e
|
252
|
+
t.error("Unexpected error #{e.class}")
|
253
|
+
else
|
254
|
+
t.error("should raise TypeError")
|
255
|
+
end
|
256
|
+
|
257
|
+
def o.to_hash
|
258
|
+
{a: 1}
|
259
|
+
end
|
260
|
+
unless a === a.from_hash(o)
|
261
|
+
t.error("Unexpected behavior")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def test_s_from_hash_with_array_of(t)
|
266
|
+
a = TypeStruct.new(a: ArrayOf(Integer))
|
267
|
+
begin
|
268
|
+
a.from_hash(a: 1)
|
269
|
+
rescue TypeError => e
|
270
|
+
unless /#a expect ArrayOf\(Integer\) got 1/ =~ e.message
|
271
|
+
t.error("message was changed: #{e.message}")
|
272
|
+
end
|
273
|
+
rescue => e
|
274
|
+
t.error("Unexpected error #{e}")
|
275
|
+
else
|
276
|
+
t.error("Unexpected behavior")
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def test_s_from_hash_with_hash_of(t)
|
281
|
+
a = TypeStruct.new(a: HashOf(String, Integer))
|
282
|
+
begin
|
283
|
+
a.from_hash(a: 1)
|
284
|
+
rescue TypeError => e
|
285
|
+
unless /#a expect HashOf\(String, Integer\) got 1/ =~ e.message
|
286
|
+
t.error("message was changed: #{e.message}")
|
287
|
+
end
|
288
|
+
rescue => e
|
289
|
+
t.error("Unexpected error #{e}")
|
290
|
+
else
|
291
|
+
t.error("Unexpected behavior")
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
def test_s_from_hash_with_not_class(t)
|
296
|
+
a = TypeStruct.new(a: "a")
|
297
|
+
begin
|
298
|
+
a.from_hash(a: "b")
|
299
|
+
rescue TypeError
|
300
|
+
else
|
301
|
+
t.error("Unexpected behavior")
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
182
305
|
def test_s_from_hash_union(t)
|
183
306
|
a = TypeStruct.new(a: Integer)
|
184
307
|
b = TypeStruct.new(b: Integer)
|
@@ -186,13 +309,17 @@ module TypeStructTest
|
|
186
309
|
u = TypeStruct::Union.new(a, b, c)
|
187
310
|
d = TypeStruct.new(d: u)
|
188
311
|
|
189
|
-
|
312
|
+
begin
|
313
|
+
d.from_hash(d: { b: 1 })
|
314
|
+
rescue => e
|
315
|
+
t.error("Unexpected error was raised #{e.class}: #{e.message}")
|
316
|
+
end
|
190
317
|
|
191
318
|
begin
|
192
319
|
d.from_hash(d: [b: 1])
|
193
320
|
rescue TypeStruct::UnionNotFoundError => err
|
194
|
-
unless /is not found with
|
195
|
-
t.error("error message was changed")
|
321
|
+
unless /is not found with value/ =~ err.message
|
322
|
+
t.error("error message was changed: '#{err.message}'")
|
196
323
|
end
|
197
324
|
else
|
198
325
|
t.error("error dose not raised")
|
@@ -201,7 +328,16 @@ module TypeStructTest
|
|
201
328
|
begin
|
202
329
|
d.from_hash(d: { b: "a" })
|
203
330
|
rescue TypeStruct::UnionNotFoundError => err
|
204
|
-
unless /is not found with
|
331
|
+
unless /is not found with value/ =~ err.message
|
332
|
+
t.error("error message was changed")
|
333
|
+
end
|
334
|
+
unless /#a expect Integer got nil/ =~ err.message
|
335
|
+
t.error("error message was changed")
|
336
|
+
end
|
337
|
+
unless /#b expect Integer got "a"/ =~ err.message
|
338
|
+
t.error("error message was changed")
|
339
|
+
end
|
340
|
+
unless /#c expect Integer got nil/ =~ err.message
|
205
341
|
t.error("error message was changed")
|
206
342
|
end
|
207
343
|
else
|
@@ -210,36 +346,51 @@ module TypeStructTest
|
|
210
346
|
end
|
211
347
|
|
212
348
|
def test_s_from_hash_equal(t)
|
213
|
-
|
214
|
-
|
349
|
+
bar = TypeStruct.new(
|
350
|
+
baz: ArrayOf(Integer | NilClass),
|
351
|
+
)
|
352
|
+
foo = TypeStruct.new(
|
353
|
+
nil: NilClass,
|
354
|
+
bar: bar,
|
355
|
+
)
|
356
|
+
|
357
|
+
expect = foo.new(bar: bar.new(baz: [1, 2, 3]))
|
358
|
+
actual = foo.from_hash(bar: { baz: [1, 2, 3] })
|
215
359
|
if expect != actual
|
216
360
|
t.error("expect #{expect} got #{actual}")
|
217
361
|
end
|
218
362
|
|
219
|
-
noteq =
|
363
|
+
noteq = foo.from_hash(bar: { baz: [1, 2, 4] })
|
220
364
|
if expect == noteq
|
221
365
|
t.error("expect #{expect} not equal #{noteq}")
|
222
366
|
end
|
223
367
|
|
224
|
-
noteq =
|
368
|
+
noteq = foo.from_hash(bar: { baz: [1, 2, nil] })
|
225
369
|
if expect == noteq
|
226
370
|
t.error("expect #{expect} not equal #{noteq}")
|
227
371
|
end
|
228
372
|
end
|
229
373
|
|
230
374
|
def test_s_from_hash_with_struct(t)
|
231
|
-
|
232
|
-
|
375
|
+
quux = Struct.new(:q)
|
376
|
+
|
377
|
+
qux = TypeStruct.new(
|
378
|
+
quux1: quux,
|
379
|
+
quux2: quux,
|
380
|
+
)
|
381
|
+
|
382
|
+
q = qux.from_hash(quux1: { q: 1 }, quux2: { q: nil })
|
383
|
+
unless qux === q
|
233
384
|
t.error("return value was break")
|
234
385
|
end
|
235
|
-
unless
|
386
|
+
unless quux === q.quux1
|
236
387
|
t.error("struct type was not applied")
|
237
388
|
end
|
238
|
-
unless 1 ==
|
239
|
-
t.error("mapping failed #{
|
389
|
+
unless 1 == q.quux1.q
|
390
|
+
t.error("mapping failed #{q.quux.q} != 1")
|
240
391
|
end
|
241
|
-
unless nil ==
|
242
|
-
t.error("mapping failed #{
|
392
|
+
unless nil == q.quux2.q
|
393
|
+
t.error("mapping failed #{q.quux.q} != nil")
|
243
394
|
end
|
244
395
|
end
|
245
396
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: type_struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ksss
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -76,6 +76,7 @@ files:
|
|
76
76
|
- lib/type_struct/union.rb
|
77
77
|
- lib/type_struct/union_test.rb
|
78
78
|
- lib/type_struct/version.rb
|
79
|
+
- lib/type_struct_benchmark_test.rb
|
79
80
|
- lib/type_struct_test.rb
|
80
81
|
- type_struct.gemspec
|
81
82
|
homepage: https://github.com/ksss/type_struct
|