type_struct 0.4.0 → 0.5.0
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/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
|