algebrick 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/README_FULL.md +13 -21
  4. data/VERSION +1 -1
  5. data/doc/actor.rb +21 -0
  6. data/doc/data.in.rb +99 -0
  7. data/doc/data.out.rb +103 -0
  8. data/doc/extending_behavior.in.rb +61 -0
  9. data/doc/extending_behavior.out.rb +62 -0
  10. data/doc/format.rb +75 -0
  11. data/doc/init.rb +1 -0
  12. data/doc/json.in.rb +39 -0
  13. data/doc/json.out.rb +43 -0
  14. data/doc/null.in.rb +36 -0
  15. data/doc/null.out.rb +40 -0
  16. data/doc/parametrized.in.rb +37 -0
  17. data/doc/parametrized.out.rb +41 -0
  18. data/doc/pattern_matching.in.rb +116 -0
  19. data/doc/pattern_matching.out.rb +122 -0
  20. data/doc/quick_example.in.rb +27 -0
  21. data/doc/quick_example.out.rb +27 -0
  22. data/doc/tree1.in.rb +10 -0
  23. data/doc/tree1.out.rb +10 -0
  24. data/doc/type_def.in.rb +21 -0
  25. data/doc/type_def.out.rb +21 -0
  26. data/doc/values.in.rb +52 -0
  27. data/doc/values.out.rb +58 -0
  28. data/lib/algebrick/atom.rb +49 -0
  29. data/lib/algebrick/dsl.rb +104 -0
  30. data/lib/algebrick/field_method_readers.rb +43 -0
  31. data/lib/algebrick/matcher_delegations.rb +45 -0
  32. data/lib/algebrick/matchers/abstract.rb +127 -0
  33. data/lib/algebrick/matchers/abstract_logic.rb +38 -0
  34. data/lib/algebrick/matchers/and.rb +29 -0
  35. data/lib/algebrick/matchers/any.rb +37 -0
  36. data/lib/algebrick/matchers/array.rb +57 -0
  37. data/lib/algebrick/matchers/atom.rb +28 -0
  38. data/lib/algebrick/matchers/not.rb +44 -0
  39. data/lib/algebrick/matchers/or.rb +51 -0
  40. data/lib/algebrick/matchers/product.rb +73 -0
  41. data/lib/algebrick/matchers/variant.rb +29 -0
  42. data/lib/algebrick/matchers/wrapper.rb +57 -0
  43. data/lib/algebrick/matchers.rb +31 -0
  44. data/lib/algebrick/matching.rb +62 -0
  45. data/lib/algebrick/parametrized_type.rb +122 -0
  46. data/lib/algebrick/product_constructors/abstract.rb +70 -0
  47. data/lib/algebrick/product_constructors/basic.rb +47 -0
  48. data/lib/algebrick/product_constructors/named.rb +58 -0
  49. data/lib/algebrick/product_constructors.rb +25 -0
  50. data/lib/algebrick/product_variant.rb +195 -0
  51. data/lib/algebrick/reclude.rb +39 -0
  52. data/lib/algebrick/serializer.rb +129 -0
  53. data/lib/algebrick/serializers.rb +25 -0
  54. data/lib/algebrick/type.rb +61 -0
  55. data/lib/algebrick/type_check.rb +58 -0
  56. data/lib/algebrick/types.rb +59 -0
  57. data/lib/algebrick/value.rb +41 -0
  58. data/lib/algebrick.rb +14 -1170
  59. data/spec/algebrick_test.rb +708 -0
  60. metadata +105 -27
@@ -0,0 +1,708 @@
1
+ # Copyright 2013 Petr Chalupa <git@pitr.ch>
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require 'bundler/setup'
16
+ require 'minitest/autorun'
17
+ require 'minitest/reporters'
18
+ MiniTest::Reporters.use!
19
+
20
+ require 'pp'
21
+ require 'algebrick'
22
+ require 'pry'
23
+
24
+ class Module
25
+ # Return any modules we +extend+
26
+ def extended_modules
27
+ class << self
28
+ self
29
+ end.included_modules
30
+ end
31
+ end
32
+
33
+ describe 'AlgebrickTest' do
34
+ i_suck_and_my_tests_are_order_dependent!
35
+
36
+ Algebrick.types do
37
+ Tree = type do |tree|
38
+ Empty = type
39
+ Leaf = type { fields Integer }
40
+ Node = type { fields tree, tree }
41
+
42
+ variants Empty, Leaf
43
+ end
44
+
45
+ Tree.set_variants Node
46
+
47
+ BTree = type do |btree|
48
+ fields! value: Comparable, left: btree, right: btree
49
+ variants Empty, btree
50
+ end
51
+ end
52
+
53
+ module Tree
54
+ def a
55
+ :a
56
+ end
57
+
58
+ def depth
59
+ case self
60
+ when Empty
61
+ 0
62
+ when Leaf
63
+ 1
64
+ when Node
65
+ left, right = *self
66
+ 1 + [left.depth, right.depth].max
67
+ end
68
+ end
69
+
70
+ def each(&block)
71
+ return to_enum :each unless block
72
+ case self
73
+ when Empty
74
+ when Leaf
75
+ block.call self.value
76
+ when Node
77
+ left, right = *self
78
+ left.each &block
79
+ right.each &block
80
+ end
81
+ end
82
+
83
+ def sum
84
+ each.inject(0) { |sum, v| sum + v }
85
+ end
86
+ end
87
+
88
+ List = Algebrick.type do |list|
89
+ variants Empty, list
90
+ fields Integer, list
91
+ end
92
+
93
+ describe 'type definition' do
94
+ module Asd
95
+ C = Algebrick.type
96
+ D = Algebrick.type
97
+ B = Algebrick.type { variants C, D }
98
+ end
99
+
100
+ it 'asd' do
101
+ assert Asd::B
102
+ end
103
+ end
104
+
105
+ describe 'type.to_s' do
106
+ it { Empty.to_s.must_equal 'Empty' }
107
+ it { Node.to_s.must_equal 'Node(Tree, Tree)' }
108
+ it { Leaf.to_s.must_equal 'Leaf(Integer)' }
109
+ it { Tree.to_s.must_equal 'Tree(Empty | Leaf | Node)' }
110
+ it { List.to_s.must_equal 'List(Empty | List(Integer, List))' }
111
+ end
112
+
113
+ describe 'atom' do
114
+ it { Empty.must_be_kind_of Algebrick::Type }
115
+ it { Empty.must_be_kind_of Algebrick::Value }
116
+ it { assert Empty.kind_of? Empty }
117
+
118
+ it { assert Empty == Empty }
119
+ it { assert Empty === Empty }
120
+ it { eval(Empty.to_s).must_equal Empty }
121
+ it { eval(Empty.inspect).must_equal Empty }
122
+ end
123
+
124
+ describe 'product' do
125
+ it { Leaf[1].must_be_kind_of Algebrick::Value }
126
+ it { Leaf.must_be_kind_of Algebrick::Type }
127
+ it { Leaf[1].wont_be_kind_of Algebrick::Type }
128
+ it { Leaf.wont_be_kind_of Algebrick::Value }
129
+
130
+ it { assert Leaf[1] == Leaf[1] }
131
+ it { assert Leaf[1] != Leaf[0] }
132
+ it { assert Leaf === Leaf[1] }
133
+ it { assert Leaf[1].kind_of? Leaf }
134
+ it { eval(Leaf[1].to_s).must_equal Leaf[1] }
135
+ it { eval(Leaf[1].inspect).must_equal Leaf[1] }
136
+ it { eval(Node[Leaf[1], Empty].to_s).must_equal Node[Leaf[1], Empty] }
137
+ it { eval(Node[Leaf[1], Empty].inspect).must_equal Node[Leaf[1], Empty] }
138
+
139
+ it 'field assign' do
140
+ value = Leaf[1].value
141
+ value.must_equal 1
142
+
143
+ left, right = *Node[Empty, Leaf[1]]
144
+ left.must_equal Empty
145
+ right.must_equal Leaf[1]
146
+
147
+ lambda { Node[Empty, Empty].value }.must_raise NoMethodError
148
+ end
149
+
150
+ it 'can be marshaled' do
151
+ dump = Marshal.dump(leaf = Leaf[1])
152
+ assert_equal Marshal.load(dump), leaf
153
+ end
154
+
155
+ it { lambda { Leaf['a'] }.must_raise TypeError }
156
+ it { lambda { Leaf[nil] }.must_raise TypeError }
157
+ it { lambda { Node['a'] }.must_raise TypeError }
158
+ ComparableItem = Class.new { include Comparable }
159
+ it { BTree[1.0, Empty, Empty] }
160
+ it { BTree['s', Empty, Empty] }
161
+ it { BTree[ComparableItem.new, Empty, Empty] }
162
+ it { lambda { BTree[Object.new, Empty, Empty] }.must_raise TypeError }
163
+ it { lambda { Node[Empty, nil] }.must_raise TypeError }
164
+
165
+ describe 'named field' do
166
+ Named = Algebrick.type do
167
+ fields! a: Integer, b: Object
168
+ end
169
+
170
+ it { -> { Named[:a, 1] }.must_raise TypeError }
171
+ it { Named[1, :a][:a].must_equal 1 }
172
+ it { Named[1, :a][:b].must_equal :a }
173
+ it { Named[a: 1, b: :a][:a].must_equal 1 }
174
+ it { Named[b: :a, a: 1][:a].must_equal 1 }
175
+ it { Named[a: 1, b: :a][:b].must_equal :a }
176
+ it { Named[a: 1, b: 2].to_s.must_equal 'Named[a: 1, b: 2]' }
177
+ it { Named[a: 1, b: 2].a.must_equal 1 }
178
+ it { Named[a: 1, b: 2].b.must_equal 2 }
179
+ end
180
+
181
+ it { Named[1, :a].to_hash.must_equal a: 1, b: :a }
182
+ it { Named[1, Node[Empty, Empty]].to_hash.must_equal a: 1, b: Node[Empty, Empty] }
183
+ end
184
+
185
+ describe 'variant' do
186
+ it { Tree.must_be_kind_of Algebrick::Type }
187
+ it { Empty.must_be_kind_of Tree }
188
+ it { Empty.a.must_equal :a }
189
+ it { Leaf[1].must_be_kind_of Tree }
190
+ it { Leaf[1].a.must_equal :a }
191
+ it { Node[Empty, Empty].must_be_kind_of Tree }
192
+ it { assert Empty.kind_of? List }
193
+
194
+ it { assert Empty > List }
195
+ it { assert Leaf > Tree }
196
+ it { assert Node > Tree }
197
+
198
+ it { assert Tree === Empty }
199
+ it { assert Tree === Leaf[1] }
200
+
201
+ describe 'inherit behavior deep' do
202
+ module Deep
203
+ B1 = Algebrick.type
204
+ B2 = Algebrick.type
205
+ A1 = Algebrick.type { variants B1, B2 }
206
+ A2 = Algebrick.type
207
+ A = Algebrick.type { variants A1, A2 }
208
+
209
+ module A
210
+ def a
211
+ :a
212
+ end
213
+ end
214
+ end
215
+
216
+ it { Deep::B1.a.must_equal :a }
217
+ it { Deep::B1 > Deep::A }
218
+ end
219
+
220
+ describe 'a klass as a variant' do
221
+ MaybeString = Algebrick.type { variants Empty, String }
222
+ it { 'a'.must_be_kind_of MaybeString }
223
+ end
224
+ end
225
+
226
+ describe 'product_variant' do
227
+ it { List[1, Empty].must_be_kind_of Algebrick::Value }
228
+ it { List.must_be_kind_of Algebrick::Type }
229
+
230
+ it { List[1, Empty].must_be_kind_of List }
231
+ it { List[1, List[1, Empty]].must_be_kind_of List }
232
+ it { Empty.must_be_kind_of List }
233
+
234
+ it { assert List[1, Empty] == List[1, Empty] }
235
+ it { assert List[1, Empty] != List[2, Empty] }
236
+ it { assert List === List[1, Empty] }
237
+ it { assert List === Empty }
238
+ it { assert List[1, Empty].kind_of? List }
239
+ end
240
+
241
+ describe 'inspecting' do
242
+ let :tree do
243
+ tree = Node[Leaf[1], Node[Leaf[2], Empty]]
244
+ tree = Node[tree, tree]
245
+ Node[tree, tree]
246
+ end
247
+
248
+ it { tree.to_s.must_equal 'Node[Node[Node[Leaf[1], Node[Leaf[2], Empty]], Node[Leaf[1], Node[Leaf[2], Empty]]], Node[Node[Leaf[1], Node[Leaf[2], Empty]], Node[Leaf[1], Node[Leaf[2], Empty]]]]' }
249
+ it { tree.inspect.must_equal tree.to_s }
250
+ it do
251
+ tree.pretty_inspect.must_equal <<-TXT
252
+ Node[
253
+ Node[
254
+ Node[Leaf[1], Node[Leaf[2], Empty]],
255
+ Node[Leaf[1], Node[Leaf[2], Empty]]],
256
+ Node[
257
+ Node[Leaf[1], Node[Leaf[2], Empty]],
258
+ Node[Leaf[1], Node[Leaf[2], Empty]]]]
259
+ TXT
260
+ end
261
+
262
+ let :named do
263
+ n = Named[-1, 'as'*40]
264
+ 4.times do |i|
265
+ n = Named[i, n]
266
+ end
267
+ n
268
+ end
269
+
270
+ it { named.to_s.must_equal 'Named[a: 3, b: Named[a: 2, b: Named[a: 1, b: Named[a: 0, b: Named[a: -1, b: asasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasas]]]]]' }
271
+ it { named.inspect.must_equal named.to_s }
272
+ it do
273
+ named.pretty_inspect.must_equal <<-TXT
274
+ Named[
275
+ a: 3,
276
+ b:
277
+ Named[
278
+ a: 2,
279
+ b:
280
+ Named[
281
+ a: 1,
282
+ b:
283
+ Named[
284
+ a: 0,
285
+ b:
286
+ Named[
287
+ a: -1,
288
+ b:
289
+ "asasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasasas"]]]]]
290
+ TXT
291
+ end
292
+
293
+ #it do
294
+ # PTree[Integer].pretty_inspect.must_equal ''
295
+ #end
296
+
297
+ end
298
+
299
+ describe 'module including' do
300
+ type = Algebrick.type { fields Numeric }
301
+ type.module_eval do
302
+ include Comparable
303
+
304
+ def <=>(other)
305
+ value <=> other.value
306
+ end
307
+ end
308
+ it 'compares' do
309
+ type
310
+ assert type[1] < type[2]
311
+ end
312
+ end
313
+
314
+
315
+ describe 'tree' do
316
+ it { assert Leaf > Tree }
317
+ end
318
+
319
+ describe '#depth' do
320
+ it do
321
+ tree = Node[Node[Empty, Leaf[1]], Leaf[1]]
322
+ tree.depth.must_equal 3
323
+ end
324
+ it do
325
+ tree = Node[Empty, Leaf[1]]
326
+ tree.depth.must_equal 2
327
+ end
328
+ it do
329
+ tree = Empty
330
+ tree.depth.must_equal 0
331
+ end
332
+ end
333
+
334
+ describe '#sum' do
335
+ it do
336
+ tree = Node[Node[Empty, Leaf[1]], Leaf[1]]
337
+ tree.sum.must_equal 2
338
+ end
339
+ end
340
+
341
+ describe 'maybe' do
342
+ Maybe = Algebrick.type do
343
+ variants None = atom,
344
+ Some = type { fields Object }
345
+ end
346
+
347
+ module Maybe
348
+ def maybe(&block)
349
+ case self
350
+ when None
351
+ when Some
352
+ block.call self.value
353
+ end
354
+ end
355
+ end
356
+
357
+ it { refute None.maybe { true } }
358
+ it { assert Some[nil].maybe { true } }
359
+ end
360
+
361
+ describe 'parametrized types' do
362
+
363
+ PTree = Algebrick.type(:v) do |p_tree|
364
+ PEmpty = atom
365
+ PLeaf = type(:v) { fields value: :v }
366
+ PNode = type(:v) { fields left: p_tree, right: p_tree }
367
+
368
+ variants PEmpty, PLeaf, PNode
369
+ end
370
+
371
+ module PTree
372
+ def depth
373
+ match self,
374
+ PEmpty >> 0,
375
+ PLeaf >> 1,
376
+ PNode.(~any, ~any) >-> left, right do
377
+ 1 + [left.depth, right.depth].max
378
+ end
379
+ end
380
+ end
381
+
382
+ PTree[String].module_eval do
383
+ def glue
384
+ match self,
385
+ PEmpty >> '',
386
+ PLeaf.(value: ~any) >-> v { v },
387
+ PNode.(~any, ~any) >-> l, r { l.glue + r.glue }
388
+ end
389
+ end
390
+
391
+ it { [PTree, PLeaf, PNode].all? { |pt| pt > Algebrick::ParametrizedType } }
392
+
393
+ it { PLeaf[Integer].to_s.must_equal 'PLeaf[Integer](value: Integer)' }
394
+ it { PNode[Integer].to_s.must_equal 'PNode[Integer](left: PTree[Integer], right: PTree[Integer])' }
395
+ it { PTree[Integer].to_s.must_equal 'PTree[Integer](PEmpty | PLeaf[Integer] | PNode[Integer])' }
396
+
397
+ it { PLeaf[Integer].is_a? PLeaf }
398
+ it { PLeaf[Integer][1].is_a? PLeaf }
399
+
400
+ it { PLeaf[Integer][1].is_a? Tree }
401
+ it { PLeaf[Integer][1].to_s.must_equal 'PLeaf[Integer][value: 1]' }
402
+ it { PLeaf[Integer][1].value.must_equal 1 }
403
+ it { PNode[Integer][PEmpty, PLeaf[Integer][1]].is_a? Tree }
404
+
405
+ it { PLeaf[Integer][2].depth.must_equal 1 }
406
+ it do
407
+ PTree[Object] # FIXME without this it does not work
408
+ PLeaf[Object][2].depth.must_equal 1
409
+ end
410
+ it do
411
+ PNode[Integer][PLeaf[Integer][2],
412
+ PEmpty].depth.must_equal 2
413
+ end
414
+ it do
415
+ PTree[String]
416
+ PNode[String][PLeaf[String]['a'],
417
+ PNode[String][PLeaf[String]['b'],
418
+ PEmpty]].glue.must_equal 'ab'
419
+ refute PTree[Object].respond_to? :glue
420
+ end
421
+ end
422
+
423
+ extend Algebrick::Matching
424
+ include Algebrick::Matching
425
+
426
+ describe 'matchers' do
427
+ it 'assigns' do
428
+ m = ~Empty
429
+ m === 2
430
+ m.assigns.must_equal [nil]
431
+ m === Empty
432
+ m.assigns.must_equal [Empty]
433
+
434
+ m = ~String.to_m
435
+ m === 2
436
+ m.assigns.must_equal [nil]
437
+ m === 'a'
438
+ m.assigns.must_equal %w(a)
439
+
440
+ m = ~Leaf.(~any)
441
+ m === Leaf[5]
442
+ m.assigns.must_equal [Leaf[5], 5]
443
+ m === Leaf[3]
444
+ m.assigns.must_equal [Leaf[3], 3]
445
+
446
+ m = BTree.(value: ~any)
447
+ m === BTree[1, Empty, Empty]
448
+ m.assigns.must_equal [1]
449
+ end
450
+
451
+ it 'assigns in case' do
452
+ case Leaf[5]
453
+ when m = ~Leaf.(~any)
454
+ m.assigns.must_equal [Leaf[5], 5]
455
+ m.assigns do |leaf, value|
456
+ leaf.must_equal Leaf[5]
457
+ value.must_equal 5
458
+ end
459
+ else
460
+ raise
461
+ end
462
+ end
463
+
464
+ describe 'match' do
465
+ it 'returns value from executed block' do
466
+ r = Algebrick.match Empty,
467
+ Empty >-> { 1 }
468
+ r.must_equal 1
469
+ r = Algebrick.match(Empty,
470
+ on(Empty) { 1 })
471
+ r.must_equal 1
472
+ end
473
+
474
+ it 'passes assigned values' do
475
+ v = Algebrick.match Leaf[5],
476
+ Leaf.(~any).case { |value| value }
477
+ v.must_equal 5
478
+
479
+ v = Algebrick.match Leaf[5],
480
+ Leaf.(~any) => -> value { value }
481
+ v.must_equal 5
482
+
483
+ v = Algebrick.match(Leaf[5],
484
+ on(Leaf.(~any)) do |value|
485
+ value
486
+ end)
487
+ v.must_equal 5
488
+ end
489
+
490
+ it 'raises when no match' do
491
+ -> { Algebrick.match Empty,
492
+ Leaf.(any) >-> {} }.must_raise RuntimeError
493
+ end
494
+
495
+ it 'does not pass any values when no matcher' do
496
+ Algebrick.match(Empty, on(Empty) { |*a| a }).must_equal []
497
+ end
498
+
499
+ specify do
500
+ assert PTree.match(PEmpty, on(PEmpty, true))
501
+ -> { PLeaf.match(PEmpty, on(PEmpty, true)) }.must_raise TypeError
502
+
503
+ assert Tree.match(Leaf[1], on(~Leaf) { true })
504
+ -> { assert Empty.match(Leaf[1], on(~Leaf) { true }) }.must_raise TypeError
505
+ end
506
+ end
507
+
508
+ describe '#to_s' do
509
+ [Empty.to_m,
510
+ ~Leaf.(Integer),
511
+ ~Empty.to_m,
512
+ any,
513
+ ~any,
514
+ Leaf.(any),
515
+ ~Leaf.(any),
516
+ Node.(Leaf.(any), any),
517
+ ~Node.(Leaf.(any), any),
518
+ ~Leaf.(1) | Leaf.(~any),
519
+ ~Leaf.(1) & Leaf.(~any)
520
+ ].each do |matcher|
521
+ it matcher.to_s do
522
+ eval(matcher.to_s).must_equal matcher
523
+ end
524
+ end
525
+ end
526
+
527
+ { Empty.to_m => Empty,
528
+ any => Empty,
529
+ any => Leaf[1],
530
+
531
+ Empty => Empty,
532
+ Empty.to_m => Empty,
533
+
534
+ Leaf => Leaf[1],
535
+ Leaf.(any) => Leaf[5],
536
+ Leaf.(~any) => Leaf[5],
537
+
538
+ Node => Node[Empty, Empty],
539
+ Node.(any, any) => Node[Leaf[1], Empty],
540
+ Node.(Empty, any) => Node[Empty, Leaf[1]],
541
+ Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
542
+ Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
543
+
544
+ Tree.to_m => Node[Leaf[1], Empty],
545
+ Tree.to_m => Node[Leaf[1], Empty],
546
+ Node => Node[Leaf[1], Empty],
547
+
548
+ Tree & Leaf.(any) => Leaf[1],
549
+ Empty | Leaf.(any) => Leaf[1],
550
+ Empty | Leaf.(any) => Empty,
551
+ !Empty & Leaf.(any) => Leaf[1],
552
+ Empty & !Leaf.(any) => Empty,
553
+
554
+ Array.() => [],
555
+ Array.(1) => [1],
556
+ Array.(Empty, Leaf.(-> v { v > 0 })) => [Empty, Leaf[1]],
557
+ Array.(TrueClass) => [true],
558
+
559
+ BTree.(value: any) => BTree[1, Empty, Empty],
560
+ BTree.(value: 1) => BTree[1, Empty, Empty],
561
+ Named.(b: false) => Named[a: 1, b: false],
562
+ !Named.(b: false) => Named[a: 1, b: true],
563
+
564
+ }.each do |matcher, value|
565
+ it "#{matcher} === #{value}" do
566
+ assert matcher === value
567
+ end
568
+ end
569
+ end
570
+
571
+ it {
572
+ assert List.to_m === Empty
573
+ assert List === Empty
574
+ assert List.to_m === List[1, Empty]
575
+ assert List === List[1, Empty]
576
+ assert List.(1, any) === List[1, Empty]
577
+ refute List.(any, any) === Empty
578
+ }
579
+
580
+ describe 'and-or matching' do
581
+ def assert_assigns(matcher, values)
582
+ matcher.assigns.must_equal values
583
+ matcher.assigns { |*assigns| assigns.must_equal values }
584
+ end
585
+
586
+ it do
587
+ m = ~Leaf.(->(v) { v > 1 }) & Leaf.(~any)
588
+ assert m === Leaf[2]
589
+ assert_assigns m, [Leaf[2], 2]
590
+ end
591
+ it do
592
+ m = ~Leaf.(1) | ~Leaf.(~any)
593
+ assert m === Leaf[1]
594
+ assert_assigns m, [Leaf[1], nil]
595
+ end
596
+ it do
597
+ m = ~Leaf.(~->(v) { v > 1 }.to_m) | ~Leaf.(1)
598
+ assert m === Leaf[1]
599
+ assert_assigns m, [Leaf[1], nil]
600
+ end
601
+ it do
602
+ m = ~Leaf.(1) | ~Leaf.(~any)
603
+ assert m === Leaf[2]
604
+ assert_assigns m, [Leaf[2], 2]
605
+ end
606
+ end
607
+
608
+ describe 'equality' do
609
+ data = (0..1).map do
610
+ [Empty,
611
+ Leaf[1],
612
+ Node[Empty, Leaf[1]],
613
+ Node[Node[Empty, Leaf[1]], Leaf[1]]]
614
+ end
615
+ data[0].zip(data[1]).each do |tree1, tree2|
616
+ it "equals #{tree1}" do
617
+ refute tree1.object_id == tree2.object_id, [tree1.object_id, tree2.object_id] unless tree1 == Empty
618
+ assert tree1 == tree2
619
+ end
620
+ end
621
+ end
622
+
623
+ it 'multi assigns all fields' do
624
+ match Node[Empty, Empty],
625
+ (on ~Node do |(left, right)|
626
+ [left, right].must_equal [Empty, Empty]
627
+ end)
628
+
629
+ match Leaf[1],
630
+ (on ~Leaf do |(v)|
631
+ v.must_equal 1
632
+ end)
633
+
634
+ match Leaf[1],
635
+ (on ~Leaf do |v|
636
+ v.must_equal Leaf[1]
637
+ end)
638
+ end
639
+
640
+ describe 'list' do
641
+ it { List.(any, any) === List[1, Empty] }
642
+ it { List.(any, List) === List[1, Empty] }
643
+ end
644
+
645
+ require 'algebrick/serializer'
646
+
647
+ describe 'serializer' do
648
+ let(:serializer) { Algebrick::Serializer.new }
649
+
650
+ it { serializer.dump(Empty).must_equal :algebrick_type => 'Empty' }
651
+ it { serializer.dump(Leaf[1]).must_equal :algebrick_type => 'Leaf', :algebrick_fields => [1] }
652
+ it { serializer.dump(PLeaf[Integer][1]).must_equal :algebrick_type => 'PLeaf[Integer]', :value => 1 }
653
+ it { serializer.dump(Named[1, :a]).must_equal algebrick_type: 'Named', a: 1, b: :a }
654
+
655
+ [Empty, Leaf[1], PLeaf[Integer][1], Named[1, :a]].each do |v|
656
+ it "serializes and de-serializes #{v}" do
657
+ serializer.load(serializer.dump(v)).must_equal v
658
+ end
659
+ end
660
+
661
+ Person = Algebrick.type do |person|
662
+ person::Name = type do |name|
663
+ variants name::Normal = type { fields String, String },
664
+ name::AbNormal = type { fields String, String, String }
665
+ end
666
+
667
+ person::Address = type do |address|
668
+ variants address::Homeless = atom, address
669
+ fields street: String,
670
+ zip: Integer
671
+ end
672
+
673
+ fields name: person::Name,
674
+ address: person::Address
675
+ end
676
+
677
+ transformations = [
678
+ [{ name: %w(a b), address: 'homeless' },
679
+ { algebrick_type: "Person",
680
+ name: { algebrick_type: "Person::Name::Normal", algebrick_fields: %w(a b) },
681
+ address: { algebrick_type: "Person::Address::Homeless" } },
682
+ Person[Person::Name::Normal['a', 'b'], Person::Address::Homeless],
683
+ "{\"name\":[\"a\",\"b\"],\"address\":\"homeless\"}"
684
+ ],
685
+ [{ name: %w(a b c), address: 'homeless', metadata: :ignored },
686
+ { algebrick_type: "Person",
687
+ name: { algebrick_type: "Person::Name::AbNormal", algebrick_fields: %w(a b c) },
688
+ address: { algebrick_type: "Person::Address::Homeless" } },
689
+ Person[Person::Name::AbNormal['a', 'b', 'c'], Person::Address::Homeless],
690
+ "{\"name\":[\"a\",\"b\",\"c\"],\"address\":\"homeless\",\"metadata\":\"ignored\"}"
691
+ ],
692
+ [{ name: %w(a b c), address: { street: 'asd', zip: 15 } },
693
+ { algebrick_type: "Person",
694
+ name: { algebrick_type: "Person::Name::AbNormal", algebrick_fields: %w(a b c) },
695
+ address: { algebrick_type: "Person::Address", street: "asd", zip: 15 } },
696
+ Person[Person::Name::AbNormal['a', 'b', 'c'], Person::Address['asd', 15]],
697
+ "{\"name\":[\"a\",\"b\",\"c\"],\"address\":{\"street\":\"asd\",\"zip\":15}}"
698
+ ]
699
+ ]
700
+
701
+ transformations.each do |_, from, to, _|
702
+ it do
703
+ serializer.load(from).must_equal to
704
+ end
705
+ end
706
+ end
707
+
708
+ end