algebrick 0.5.0 → 0.6.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 +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
|
[![Build Status](https://travis-ci.org/pitr-ch/algebrick.png?branch=master)](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
|