algebrick 0.7.0 → 0.7.1
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/VERSION +1 -1
- data/doc/format.rb +3 -2
- metadata +4 -6
- data/spec/algebrick_test.rb +0 -780
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9299bb7379e63fdda3b5b346abca387c4151b429
|
4
|
+
data.tar.gz: b93d3b9515e9298a4b1d2dd3a67974ea30649986
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d7d6ac6ff9dd5c1f6f04314271ae2a487cce7cf175d99139934e5355f840765b627342c63c1ba36cdad0865f75fa2d1ec05fb27745426b45627f9a64fc05e42
|
7
|
+
data.tar.gz: 25875464076bdc7b603ac3586bd45a982c1a92d325ad8d0ee9a6625ba77e4b85c2d637cf8d3a9dd106ae4be8773fc8c00d93056828adf7376ed86e4b4f834b2e
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.1
|
data/doc/format.rb
CHANGED
@@ -3,8 +3,9 @@ require 'bundler/setup'
|
|
3
3
|
require 'pry'
|
4
4
|
require 'pp'
|
5
5
|
|
6
|
+
root = File.dirname(File.expand_path(Process.argv0))
|
6
7
|
input_paths = if ARGV.empty?
|
7
|
-
Dir.glob("#{
|
8
|
+
Dir.glob("#{root}/*.in.rb")
|
8
9
|
else
|
9
10
|
ARGV
|
10
11
|
end.map { |p| File.expand_path p }
|
@@ -12,7 +13,7 @@ input_paths = if ARGV.empty?
|
|
12
13
|
input_paths.each_with_index do |input_path, i|
|
13
14
|
|
14
15
|
pid = fork do
|
15
|
-
|
16
|
+
require File.join(root, 'init.rb')
|
16
17
|
|
17
18
|
begin
|
18
19
|
output_path = input_path.gsub /\.in\.rb$/, '.out.rb'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: algebrick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Petr Chalupa
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -214,7 +214,6 @@ files:
|
|
214
214
|
- lib/algebrick/type_check.rb
|
215
215
|
- lib/algebrick/types.rb
|
216
216
|
- lib/algebrick/value.rb
|
217
|
-
- spec/algebrick_test.rb
|
218
217
|
homepage: https://github.com/pitr-ch/algebrick
|
219
218
|
licenses:
|
220
219
|
- Apache License 2.0
|
@@ -235,10 +234,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
235
234
|
version: '0'
|
236
235
|
requirements: []
|
237
236
|
rubyforge_project:
|
238
|
-
rubygems_version: 2.
|
237
|
+
rubygems_version: 2.4.5
|
239
238
|
signing_key:
|
240
239
|
specification_version: 4
|
241
240
|
summary: Algebraic types and pattern matching for Ruby
|
242
|
-
test_files:
|
243
|
-
- spec/algebrick_test.rb
|
241
|
+
test_files: []
|
244
242
|
has_rdoc:
|
data/spec/algebrick_test.rb
DELETED
@@ -1,780 +0,0 @@
|
|
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
|
-
Array.(*any),
|
515
|
-
Array.(*~any),
|
516
|
-
Leaf.(any),
|
517
|
-
~Leaf.(any),
|
518
|
-
Node.(Leaf.(any), any),
|
519
|
-
~Node.(Leaf.(any), any),
|
520
|
-
~Leaf.(1) | Leaf.(~any),
|
521
|
-
~Leaf.(1) & Leaf.(~any)
|
522
|
-
].each do |matcher|
|
523
|
-
it matcher.to_s do
|
524
|
-
eval(matcher.to_s).must_equal matcher
|
525
|
-
end
|
526
|
-
end
|
527
|
-
end
|
528
|
-
|
529
|
-
{ Empty.to_m => Empty,
|
530
|
-
any => Empty,
|
531
|
-
any => Leaf[1],
|
532
|
-
|
533
|
-
Empty => Empty,
|
534
|
-
Empty.to_m => Empty,
|
535
|
-
|
536
|
-
Leaf => Leaf[1],
|
537
|
-
Leaf.(any) => Leaf[5],
|
538
|
-
Leaf.(~any) => Leaf[5],
|
539
|
-
|
540
|
-
Node => Node[Empty, Empty],
|
541
|
-
Node.(any, any) => Node[Leaf[1], Empty],
|
542
|
-
Node.(Empty, any) => Node[Empty, Leaf[1]],
|
543
|
-
Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
|
544
|
-
Node.(Leaf.(any), any) => Node[Leaf[1], Empty],
|
545
|
-
|
546
|
-
Tree.to_m => Node[Leaf[1], Empty],
|
547
|
-
Tree.to_m => Node[Leaf[1], Empty],
|
548
|
-
Node => Node[Leaf[1], Empty],
|
549
|
-
|
550
|
-
Tree & Leaf.(any) => Leaf[1],
|
551
|
-
Empty | Leaf.(any) => Leaf[1],
|
552
|
-
Empty | Leaf.(any) => Empty,
|
553
|
-
!Empty & Leaf.(any) => Leaf[1],
|
554
|
-
Empty & !Leaf.(any) => Empty,
|
555
|
-
|
556
|
-
Array.() => [],
|
557
|
-
Array.(1) => [1],
|
558
|
-
Array.(Empty, Leaf.(-> v { v > 0 })) => [Empty, Leaf[1]],
|
559
|
-
Array.(TrueClass) => [true],
|
560
|
-
Array.(1, *any) => [1],
|
561
|
-
Array.(1, *any) => [1, 2],
|
562
|
-
Array.(1, *any) => [1, 2, 3],
|
563
|
-
Array.(*any) => [1],
|
564
|
-
Array.(*any) => [1, 2],
|
565
|
-
|
566
|
-
BTree.(value: any) => BTree[1, Empty, Empty],
|
567
|
-
BTree.(value: 1) => BTree[1, Empty, Empty],
|
568
|
-
Named.(b: false) => Named[a: 1, b: false],
|
569
|
-
!Named.(b: false) => Named[a: 1, b: true],
|
570
|
-
|
571
|
-
}.each do |matcher, value|
|
572
|
-
it "#{matcher} === #{value}" do
|
573
|
-
assert matcher === value
|
574
|
-
end
|
575
|
-
end
|
576
|
-
end
|
577
|
-
|
578
|
-
it {
|
579
|
-
assert List.to_m === Empty
|
580
|
-
assert List === Empty
|
581
|
-
assert List.to_m === List[1, Empty]
|
582
|
-
assert List === List[1, Empty]
|
583
|
-
assert List.(1, any) === List[1, Empty]
|
584
|
-
refute List.(any, any) === Empty
|
585
|
-
}
|
586
|
-
|
587
|
-
describe 'and-or matching' do
|
588
|
-
def assert_assigns(matcher, values)
|
589
|
-
matcher.assigns.must_equal values
|
590
|
-
matcher.assigns { |*assigns| assigns.must_equal values }
|
591
|
-
end
|
592
|
-
|
593
|
-
it do
|
594
|
-
m = ~Leaf.(->(v) { v > 1 }) & Leaf.(~any)
|
595
|
-
assert m === Leaf[2]
|
596
|
-
assert_assigns m, [Leaf[2], 2]
|
597
|
-
end
|
598
|
-
it do
|
599
|
-
m = ~Leaf.(1) | ~Leaf.(~any)
|
600
|
-
assert m === Leaf[1]
|
601
|
-
assert_assigns m, [Leaf[1], nil]
|
602
|
-
end
|
603
|
-
it do
|
604
|
-
m = ~Leaf.(~->(v) { v > 1 }.to_m) | ~Leaf.(1)
|
605
|
-
assert m === Leaf[1]
|
606
|
-
assert_assigns m, [Leaf[1], nil]
|
607
|
-
end
|
608
|
-
it do
|
609
|
-
m = ~Leaf.(1) | ~Leaf.(~any)
|
610
|
-
assert m === Leaf[2]
|
611
|
-
assert_assigns m, [Leaf[2], 2]
|
612
|
-
end
|
613
|
-
end
|
614
|
-
|
615
|
-
describe 'equality' do
|
616
|
-
data = (0..1).map do
|
617
|
-
[Empty,
|
618
|
-
Leaf[1],
|
619
|
-
Node[Empty, Leaf[1]],
|
620
|
-
Node[Node[Empty, Leaf[1]], Leaf[1]]]
|
621
|
-
end
|
622
|
-
data[0].zip(data[1]).each do |tree1, tree2|
|
623
|
-
it "equals #{tree1}" do
|
624
|
-
refute tree1.object_id == tree2.object_id, [tree1.object_id, tree2.object_id] unless tree1 == Empty
|
625
|
-
assert tree1 == tree2
|
626
|
-
end
|
627
|
-
end
|
628
|
-
end
|
629
|
-
|
630
|
-
it 'multi assigns all fields' do
|
631
|
-
match Node[Empty, Empty],
|
632
|
-
(on ~Node do |(left, right)|
|
633
|
-
[left, right].must_equal [Empty, Empty]
|
634
|
-
end)
|
635
|
-
|
636
|
-
match Leaf[1],
|
637
|
-
(on ~Leaf do |(v)|
|
638
|
-
v.must_equal 1
|
639
|
-
end)
|
640
|
-
|
641
|
-
match Leaf[1],
|
642
|
-
(on ~Leaf do |v|
|
643
|
-
v.must_equal Leaf[1]
|
644
|
-
end)
|
645
|
-
|
646
|
-
match [1, 2],
|
647
|
-
(on ~Array.(*any) do |(left, right)|
|
648
|
-
[left, right].must_equal [1, 2]
|
649
|
-
end)
|
650
|
-
|
651
|
-
match [1, 2],
|
652
|
-
(on ~Array.to_m do |(left, right)|
|
653
|
-
[left, right].must_equal [1, 2]
|
654
|
-
end)
|
655
|
-
|
656
|
-
match [1, 2],
|
657
|
-
(on ~Array.(*any) do |(left, right)|
|
658
|
-
[left, right].must_equal [1, 2]
|
659
|
-
end)
|
660
|
-
|
661
|
-
match [1, 2],
|
662
|
-
(on (Array.(*~any)) do |(left, right)|
|
663
|
-
[left, right].must_equal [1, 2]
|
664
|
-
end)
|
665
|
-
end
|
666
|
-
|
667
|
-
describe 'list' do
|
668
|
-
it { List.(any, any) === List[1, Empty] }
|
669
|
-
it { List.(any, List) === List[1, Empty] }
|
670
|
-
end
|
671
|
-
|
672
|
-
describe 'LinkedList' do
|
673
|
-
specify do
|
674
|
-
Algebrick::List.build(Integer, 1, 2).must_equal(
|
675
|
-
Algebrick::List[Integer][
|
676
|
-
value: 1,
|
677
|
-
next: Algebrick::List[Integer][
|
678
|
-
value: 2,
|
679
|
-
next: Algebrick::Types::EmptyList]]
|
680
|
-
)
|
681
|
-
assert_equal %w[1 2],
|
682
|
-
Algebrick::List.build(Integer, 1, 2).map(&:to_s)
|
683
|
-
end
|
684
|
-
|
685
|
-
TreeList = Algebrick.type do
|
686
|
-
fields! tag: String, trees: Algebrick::List[Tree]
|
687
|
-
end
|
688
|
-
|
689
|
-
specify do
|
690
|
-
assert_equal 'TreeList(tag: String, trees: Algebrick::Types::List[Tree(Empty | Leaf | Node)])',
|
691
|
-
TreeList.to_s
|
692
|
-
assert_equal 'TreeList[tag: tag, trees: Algebrick::Types::List[Tree(Empty | Leaf | Node)][value: Node[Empty, Empty], next: Algebrick::Types::EmptyList]]',
|
693
|
-
TreeList['tag', Algebrick::List.build(Tree, Node[Empty, Empty])].to_s
|
694
|
-
end
|
695
|
-
end
|
696
|
-
|
697
|
-
require 'algebrick/serializer'
|
698
|
-
|
699
|
-
describe 'serializer' do
|
700
|
-
let(:serializer) { Algebrick::Serializer.new }
|
701
|
-
|
702
|
-
it { serializer.dump(Empty).must_equal :algebrick_type => 'Empty' }
|
703
|
-
it { serializer.dump(Leaf[1]).must_equal :algebrick_type => 'Leaf', :algebrick_fields => [1] }
|
704
|
-
it { serializer.dump(PLeaf[Integer][1]).must_equal :algebrick_type => 'PLeaf[Integer]', :value => 1 }
|
705
|
-
it { serializer.dump(Named[1, :a]).must_equal algebrick_type: 'Named', a: 1, b: :a }
|
706
|
-
|
707
|
-
[Empty, Leaf[1], PLeaf[Integer][1], Named[1, :a]].each do |v|
|
708
|
-
it "serializes and de-serializes #{v}" do
|
709
|
-
serializer.load(serializer.dump(v)).must_equal v
|
710
|
-
end
|
711
|
-
end
|
712
|
-
|
713
|
-
Person = Algebrick.type do |person|
|
714
|
-
person::Name = type do |name|
|
715
|
-
variants name::Normal = type { fields String, String },
|
716
|
-
name::AbNormal = type { fields String, String, String }
|
717
|
-
end
|
718
|
-
|
719
|
-
person::Address = type do |address|
|
720
|
-
variants address::Homeless = atom, address
|
721
|
-
fields street: String,
|
722
|
-
zip: Integer
|
723
|
-
end
|
724
|
-
|
725
|
-
fields name: person::Name,
|
726
|
-
address: person::Address
|
727
|
-
end
|
728
|
-
|
729
|
-
transformations = [
|
730
|
-
[{ name: %w(a b), address: 'homeless' },
|
731
|
-
{ algebrick_type: "Person",
|
732
|
-
name: { algebrick_type: "Person::Name::Normal", algebrick_fields: %w(a b) },
|
733
|
-
address: { algebrick_type: "Person::Address::Homeless" } },
|
734
|
-
Person[Person::Name::Normal['a', 'b'], Person::Address::Homeless],
|
735
|
-
"{\"name\":[\"a\",\"b\"],\"address\":\"homeless\"}"
|
736
|
-
],
|
737
|
-
[{ name: %w(a b c), address: 'homeless', metadata: :ignored },
|
738
|
-
{ algebrick_type: "Person",
|
739
|
-
name: { algebrick_type: "Person::Name::AbNormal", algebrick_fields: %w(a b c) },
|
740
|
-
address: { algebrick_type: "Person::Address::Homeless" } },
|
741
|
-
Person[Person::Name::AbNormal['a', 'b', 'c'], Person::Address::Homeless],
|
742
|
-
"{\"name\":[\"a\",\"b\",\"c\"],\"address\":\"homeless\",\"metadata\":\"ignored\"}"
|
743
|
-
],
|
744
|
-
[{ name: %w(a b c), address: { street: 'asd', zip: 15 } },
|
745
|
-
{ algebrick_type: "Person",
|
746
|
-
name: { algebrick_type: "Person::Name::AbNormal", algebrick_fields: %w(a b c) },
|
747
|
-
address: { algebrick_type: "Person::Address", street: "asd", zip: 15 } },
|
748
|
-
Person[Person::Name::AbNormal['a', 'b', 'c'], Person::Address['asd', 15]],
|
749
|
-
"{\"name\":[\"a\",\"b\",\"c\"],\"address\":{\"street\":\"asd\",\"zip\":15}}"
|
750
|
-
]
|
751
|
-
]
|
752
|
-
|
753
|
-
transformations.each do |_, from, to, _|
|
754
|
-
it do
|
755
|
-
serializer.load(from).must_equal to
|
756
|
-
end
|
757
|
-
end
|
758
|
-
|
759
|
-
describe 'no name types' do
|
760
|
-
WithNoName = Algebrick.type do |t|
|
761
|
-
fields a: String, v: t
|
762
|
-
variants t,
|
763
|
-
type { |it| variants TrueClass, FalseClass, it },
|
764
|
-
type { fields string: String },
|
765
|
-
atom
|
766
|
-
end
|
767
|
-
|
768
|
-
it 'prints reasonably' do
|
769
|
-
assert_equal 'WithNoName(WithNoName(a: String, v: WithNoName) | (TrueClass | FalseClass | (recursive)) | (string: String) | nameless-atom)',
|
770
|
-
WithNoName.to_s
|
771
|
-
assert_equal '(TrueClass | FalseClass | (recursive))', WithNoName.variants[1].to_s
|
772
|
-
assert_equal '(string: String)', WithNoName.variants[2].to_s
|
773
|
-
assert_equal 'nameless-atom', WithNoName.variants[3].to_s
|
774
|
-
|
775
|
-
end
|
776
|
-
end
|
777
|
-
|
778
|
-
end
|
779
|
-
|
780
|
-
end
|