algebrick 0.5.0 → 0.6.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 +3 -6
- data/README_FULL.md +1 -1
- data/VERSION +1 -1
- data/doc/format.rb +3 -2
- data/doc/json.out.rb +1 -1
- data/doc/pattern_matching.in.rb +28 -0
- data/doc/pattern_matching.out.rb +28 -0
- data/lib/algebrick/matchers/abstract.rb +7 -1
- data/lib/algebrick/matchers/any.rb +9 -0
- data/lib/algebrick/matchers/array.rb +15 -3
- data/lib/algebrick/matchers/many.rb +37 -0
- data/lib/algebrick/matchers.rb +1 -0
- data/lib/algebrick/types.rb +3 -3
- data/lib/algebrick.rb +21 -0
- data/spec/algebrick_test.rb +27 -0
- 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: c10eb07ed10cdcc7fd01fda3b2dccf42786db60f
|
|
4
|
+
data.tar.gz: 72b0ecfd3d3ce1bc20c5683adeabb3d2b5915bfe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3d1dfceee22b44ed971953d37d3cb9e8e5caf03a2cdbda3be251c9e778f1a5e3ae7be41f2dfc17f3ea1ba7dc63f5a908ff481571957fe18b6267d4670f8d8be7
|
|
7
|
+
data.tar.gz: a0ed769069be44d01001a2657a07db0aa3ad3d184afb290d38bc2a82c0c72237737867f972380cc496689f4ee9169f1b3b6081eea7a6a792976c1a10b1621f7c
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://travis-ci.org/pitr-ch/algebrick)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It's a gem providing **algebraic types** and **pattern matching** seamlessly integrates with standard features Ruby.
|
|
6
6
|
|
|
7
7
|
- Documentation: <http://blog.pitr.ch/algebrick>
|
|
8
8
|
- Source: <https://github.com/pitr-ch/algebrick>
|
|
@@ -10,11 +10,8 @@ Typed structs on steroids based on algebraic types and pattern matching seamless
|
|
|
10
10
|
|
|
11
11
|
## What is it good for?
|
|
12
12
|
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
in [concurrent-ruby](concurrent-ruby.com).
|
|
16
|
-
- Describing message protocols in message-based cross-process communication.
|
|
17
|
-
Algebraic types play nice with JSON de/serialization.
|
|
13
|
+
- Defining data structures.
|
|
14
|
+
- Algebraic types play nice with JSON serialization and deserialization. It is ideal for defining message-based cross-process communication.
|
|
18
15
|
- and more...
|
|
19
16
|
|
|
20
17
|
## Quick example
|
data/README_FULL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Algebrick
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
It's a gem providing **algebraic types** and **pattern matching** and seamlessly integrating with standard features of Ruby.
|
|
4
4
|
|
|
5
5
|
- Documentation: <http://blog.pitr.ch/algebrick>
|
|
6
6
|
- Source: <https://github.com/pitr-ch/algebrick>
|
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.6.0
|
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'
|
data/doc/json.out.rb
CHANGED
|
@@ -20,7 +20,7 @@ require 'algebrick/serializer' # => true
|
|
|
20
20
|
require 'multi_json' # => true
|
|
21
21
|
|
|
22
22
|
# Prepare a message for sending.
|
|
23
|
-
serializer = Algebrick::Serializer.new # => #<Algebrick::Serializer:
|
|
23
|
+
serializer = Algebrick::Serializer.new # => #<Algebrick::Serializer:0x007fafcc96f6a8>
|
|
24
24
|
request = CreateUser[User['root', 'lajDh4']]
|
|
25
25
|
# => CreateUser[User[login: root, password: lajDh4]]
|
|
26
26
|
raw_request = MultiJson.dump serializer.dump(request)
|
data/doc/pattern_matching.in.rb
CHANGED
|
@@ -107,6 +107,34 @@ match BTree[0, Empty, BTree[1, Empty, Empty]],
|
|
|
107
107
|
{ left: left, value: value, right: right }
|
|
108
108
|
end)
|
|
109
109
|
|
|
110
|
+
# It also supports matching against Ruby Arrays
|
|
111
|
+
Array.() === []
|
|
112
|
+
Array.() === [1]
|
|
113
|
+
Array.(*any) === []
|
|
114
|
+
Array.(*any) === [1]
|
|
115
|
+
Array.(*any) === [1, 2]
|
|
116
|
+
Array.(1, *any) === []
|
|
117
|
+
Array.(1, *any) === [1]
|
|
118
|
+
Array.(1, *any) === [1, 2]
|
|
119
|
+
|
|
120
|
+
match [],
|
|
121
|
+
on(~Array.to_m) { |v| v }
|
|
122
|
+
match [],
|
|
123
|
+
on(~Array.()) { |v| v }
|
|
124
|
+
match [1, 2],
|
|
125
|
+
on(~Array.(*any)) { |v| v }
|
|
126
|
+
match [1, 2],
|
|
127
|
+
on(~Array.(*any)) { |(v, _)| v }
|
|
128
|
+
match [1, 2, 3],
|
|
129
|
+
on(Array.(any, *~any)) { |v| v }
|
|
130
|
+
match [:first, 1, 2, 3],
|
|
131
|
+
on(Array.(:first, ~any, *any)) { |v| v }
|
|
132
|
+
match [:+, 1, 2, :foo, :bar],
|
|
133
|
+
(on Array.(:+, ~Integer.to_m, ~Integer.to_m, *~any) do |int1, int2, rest|
|
|
134
|
+
{ sum: int1 + int2, rest: rest }
|
|
135
|
+
end)
|
|
136
|
+
|
|
137
|
+
|
|
110
138
|
# There is also a more funky syntax for matching
|
|
111
139
|
# using #>, #>> and Ruby 1.9 syntax for lambdas `-> {}`.
|
|
112
140
|
match Leaf[1],
|
data/doc/pattern_matching.out.rb
CHANGED
|
@@ -113,6 +113,34 @@ match BTree[0, Empty, BTree[1, Empty, Empty]],
|
|
|
113
113
|
{ left: left, value: value, right: right }
|
|
114
114
|
end) # => {:left=>nil, :value=>0, :right=>1}
|
|
115
115
|
|
|
116
|
+
# It also supports matching against Ruby Arrays
|
|
117
|
+
Array.() === [] # => true
|
|
118
|
+
Array.() === [1] # => false
|
|
119
|
+
Array.(*any) === [] # => true
|
|
120
|
+
Array.(*any) === [1] # => true
|
|
121
|
+
Array.(*any) === [1, 2] # => true
|
|
122
|
+
Array.(1, *any) === [] # => false
|
|
123
|
+
Array.(1, *any) === [1] # => true
|
|
124
|
+
Array.(1, *any) === [1, 2] # => true
|
|
125
|
+
|
|
126
|
+
match [],
|
|
127
|
+
on(~Array.to_m) { |v| v } # => []
|
|
128
|
+
match [],
|
|
129
|
+
on(~Array.()) { |v| v } # => []
|
|
130
|
+
match [1, 2],
|
|
131
|
+
on(~Array.(*any)) { |v| v } # => [1, 2]
|
|
132
|
+
match [1, 2],
|
|
133
|
+
on(~Array.(*any)) { |(v, _)| v } # => 1
|
|
134
|
+
match [1, 2, 3],
|
|
135
|
+
on(Array.(any, *~any)) { |v| v } # => [2, 3]
|
|
136
|
+
match [:first, 1, 2, 3],
|
|
137
|
+
on(Array.(:first, ~any, *any)) { |v| v } # => 1
|
|
138
|
+
match [:+, 1, 2, :foo, :bar],
|
|
139
|
+
(on Array.(:+, ~Integer.to_m, ~Integer.to_m, *~any) do |int1, int2, rest|
|
|
140
|
+
{ sum: int1 + int2, rest: rest }
|
|
141
|
+
end) # => {:sum=>3, :rest=>[:foo, :bar]}
|
|
142
|
+
|
|
143
|
+
|
|
116
144
|
# There is also a more funky syntax for matching
|
|
117
145
|
# using #>, #>> and Ruby 1.9 syntax for lambdas `-> {}`.
|
|
118
146
|
match Leaf[1],
|
|
@@ -34,11 +34,13 @@ module Algebrick
|
|
|
34
34
|
|
|
35
35
|
alias_method :>>, :>
|
|
36
36
|
|
|
37
|
-
def
|
|
37
|
+
def assign!
|
|
38
38
|
@assign = true
|
|
39
39
|
self
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
alias_method :~, :assign!
|
|
43
|
+
|
|
42
44
|
def &(matcher)
|
|
43
45
|
And.new self, matcher
|
|
44
46
|
end
|
|
@@ -55,6 +57,10 @@ module Algebrick
|
|
|
55
57
|
@assign
|
|
56
58
|
end
|
|
57
59
|
|
|
60
|
+
def assigned?
|
|
61
|
+
!!@value
|
|
62
|
+
end
|
|
63
|
+
|
|
58
64
|
def matched?
|
|
59
65
|
@matched
|
|
60
66
|
end
|
|
@@ -24,6 +24,7 @@ module Algebrick
|
|
|
24
24
|
def initialize(*matchers)
|
|
25
25
|
super()
|
|
26
26
|
@matchers = matchers
|
|
27
|
+
raise ArgumentError, 'many can be only last' if @matchers[0..-2].any? { |v| v.is_a?(Many) }
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def children
|
|
@@ -39,12 +40,21 @@ module Algebrick
|
|
|
39
40
|
self.matchers == other.matchers
|
|
40
41
|
end
|
|
41
42
|
|
|
43
|
+
def rest?
|
|
44
|
+
matchers.last.is_a?(Many)
|
|
45
|
+
end
|
|
46
|
+
|
|
42
47
|
protected
|
|
43
48
|
|
|
44
49
|
def matching?(other)
|
|
45
|
-
other.kind_of? ::Array
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
return false unless other.kind_of? ::Array
|
|
51
|
+
if rest?
|
|
52
|
+
matchers[0..-2].zip(other).all? { |m, v| m === v } and
|
|
53
|
+
matchers.last === other[(matchers.size-1)..-1]
|
|
54
|
+
else
|
|
55
|
+
matchers.size == other.size and
|
|
56
|
+
matchers.zip(other).all? { |m, v| m === v }
|
|
57
|
+
end
|
|
48
58
|
end
|
|
49
59
|
end
|
|
50
60
|
|
|
@@ -53,5 +63,7 @@ module Algebrick
|
|
|
53
63
|
Matchers::Array.new *matchers
|
|
54
64
|
end
|
|
55
65
|
end
|
|
66
|
+
|
|
67
|
+
# TODO consider: class Array; def ===(other); zip(other).all? {|m,v| m===v}; end; end
|
|
56
68
|
end
|
|
57
69
|
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright 2013 Petr Chalupa <git+algebrick@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
|
+
module Algebrick
|
|
16
|
+
module Matchers
|
|
17
|
+
class Many < Abstract
|
|
18
|
+
def children
|
|
19
|
+
[]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
"*#{assign_to_s}any"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def ==(other)
|
|
27
|
+
other.kind_of? self.class
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
protected
|
|
31
|
+
|
|
32
|
+
def matching?(other)
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/algebrick/matchers.rb
CHANGED
|
@@ -21,6 +21,7 @@ module Algebrick
|
|
|
21
21
|
require 'algebrick/matchers/or'
|
|
22
22
|
require 'algebrick/matchers/not'
|
|
23
23
|
require 'algebrick/matchers/any'
|
|
24
|
+
require 'algebrick/matchers/many'
|
|
24
25
|
require 'algebrick/matchers/wrapper'
|
|
25
26
|
require 'algebrick/matchers/array'
|
|
26
27
|
require 'algebrick/matchers/product'
|
data/lib/algebrick/types.rb
CHANGED
data/lib/algebrick.rb
CHANGED
|
@@ -21,6 +21,26 @@
|
|
|
21
21
|
# TODO gemmify reclude
|
|
22
22
|
# TODO gemmify typecheck
|
|
23
23
|
|
|
24
|
+
# TODO add default field values
|
|
25
|
+
# Person = Algebrick.type do
|
|
26
|
+
# fields! age: Integer,
|
|
27
|
+
# address: [Maybe[String], None]#,
|
|
28
|
+
# # address: Maybe[String] >> None
|
|
29
|
+
#
|
|
30
|
+
# field! :age, Integer
|
|
31
|
+
# field! :address, Maybe[String], None
|
|
32
|
+
# end
|
|
33
|
+
# Person[1]
|
|
34
|
+
# Person[1, Some['Praha']]
|
|
35
|
+
|
|
36
|
+
# TODO use benevolent deserializer to allow:
|
|
37
|
+
# Person[address: Address[name: 'asd']]
|
|
38
|
+
# Person[address: { name: 'asd' }]
|
|
39
|
+
|
|
40
|
+
# TODO maybe should behave as monad
|
|
41
|
+
|
|
42
|
+
# TODO anonymous types ? missing tests
|
|
43
|
+
|
|
24
44
|
|
|
25
45
|
# Provides Algebraic types and pattern matching
|
|
26
46
|
#
|
|
@@ -47,4 +67,5 @@ module Algebrick
|
|
|
47
67
|
require 'algebrick/matchers'
|
|
48
68
|
require 'algebrick/types'
|
|
49
69
|
|
|
70
|
+
# require 'algebrick/serializer'
|
|
50
71
|
end
|
data/spec/algebrick_test.rb
CHANGED
|
@@ -511,6 +511,8 @@ Named[
|
|
|
511
511
|
~Empty.to_m,
|
|
512
512
|
any,
|
|
513
513
|
~any,
|
|
514
|
+
Array.(*any),
|
|
515
|
+
Array.(*~any),
|
|
514
516
|
Leaf.(any),
|
|
515
517
|
~Leaf.(any),
|
|
516
518
|
Node.(Leaf.(any), any),
|
|
@@ -555,6 +557,11 @@ Named[
|
|
|
555
557
|
Array.(1) => [1],
|
|
556
558
|
Array.(Empty, Leaf.(-> v { v > 0 })) => [Empty, Leaf[1]],
|
|
557
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],
|
|
558
565
|
|
|
559
566
|
BTree.(value: any) => BTree[1, Empty, Empty],
|
|
560
567
|
BTree.(value: 1) => BTree[1, Empty, Empty],
|
|
@@ -635,6 +642,26 @@ Named[
|
|
|
635
642
|
(on ~Leaf do |v|
|
|
636
643
|
v.must_equal Leaf[1]
|
|
637
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)
|
|
638
665
|
end
|
|
639
666
|
|
|
640
667
|
describe 'list' do
|
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.
|
|
4
|
+
version: 0.6.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Petr Chalupa
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2015-01-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: minitest
|
|
@@ -194,6 +194,7 @@ files:
|
|
|
194
194
|
- lib/algebrick/matchers/any.rb
|
|
195
195
|
- lib/algebrick/matchers/array.rb
|
|
196
196
|
- lib/algebrick/matchers/atom.rb
|
|
197
|
+
- lib/algebrick/matchers/many.rb
|
|
197
198
|
- lib/algebrick/matchers/not.rb
|
|
198
199
|
- lib/algebrick/matchers/or.rb
|
|
199
200
|
- lib/algebrick/matchers/product.rb
|