algebrick 0.4.0 → 0.5.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 +6 -3
- data/README_FULL.md +13 -21
- data/VERSION +1 -1
- data/doc/actor.rb +21 -0
- data/doc/data.in.rb +99 -0
- data/doc/data.out.rb +103 -0
- data/doc/extending_behavior.in.rb +61 -0
- data/doc/extending_behavior.out.rb +62 -0
- data/doc/format.rb +75 -0
- data/doc/init.rb +1 -0
- data/doc/json.in.rb +39 -0
- data/doc/json.out.rb +43 -0
- data/doc/null.in.rb +36 -0
- data/doc/null.out.rb +40 -0
- data/doc/parametrized.in.rb +37 -0
- data/doc/parametrized.out.rb +41 -0
- data/doc/pattern_matching.in.rb +116 -0
- data/doc/pattern_matching.out.rb +122 -0
- data/doc/quick_example.in.rb +27 -0
- data/doc/quick_example.out.rb +27 -0
- data/doc/tree1.in.rb +10 -0
- data/doc/tree1.out.rb +10 -0
- data/doc/type_def.in.rb +21 -0
- data/doc/type_def.out.rb +21 -0
- data/doc/values.in.rb +52 -0
- data/doc/values.out.rb +58 -0
- data/lib/algebrick/atom.rb +49 -0
- data/lib/algebrick/dsl.rb +104 -0
- data/lib/algebrick/field_method_readers.rb +43 -0
- data/lib/algebrick/matcher_delegations.rb +45 -0
- data/lib/algebrick/matchers/abstract.rb +127 -0
- data/lib/algebrick/matchers/abstract_logic.rb +38 -0
- data/lib/algebrick/matchers/and.rb +29 -0
- data/lib/algebrick/matchers/any.rb +37 -0
- data/lib/algebrick/matchers/array.rb +57 -0
- data/lib/algebrick/matchers/atom.rb +28 -0
- data/lib/algebrick/matchers/not.rb +44 -0
- data/lib/algebrick/matchers/or.rb +51 -0
- data/lib/algebrick/matchers/product.rb +73 -0
- data/lib/algebrick/matchers/variant.rb +29 -0
- data/lib/algebrick/matchers/wrapper.rb +57 -0
- data/lib/algebrick/matchers.rb +31 -0
- data/lib/algebrick/matching.rb +62 -0
- data/lib/algebrick/parametrized_type.rb +122 -0
- data/lib/algebrick/product_constructors/abstract.rb +70 -0
- data/lib/algebrick/product_constructors/basic.rb +47 -0
- data/lib/algebrick/product_constructors/named.rb +58 -0
- data/lib/algebrick/product_constructors.rb +25 -0
- data/lib/algebrick/product_variant.rb +195 -0
- data/lib/algebrick/reclude.rb +39 -0
- data/lib/algebrick/serializer.rb +129 -0
- data/lib/algebrick/serializers.rb +25 -0
- data/lib/algebrick/type.rb +61 -0
- data/lib/algebrick/type_check.rb +58 -0
- data/lib/algebrick/types.rb +59 -0
- data/lib/algebrick/value.rb +41 -0
- data/lib/algebrick.rb +14 -1170
- data/spec/algebrick_test.rb +708 -0
- metadata +105 -27
@@ -0,0 +1,39 @@
|
|
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
|
+
# fix module to re-include itself to where it was already included when a module is included into it
|
17
|
+
#noinspection RubySuperCallWithoutSuperclassInspection
|
18
|
+
module Reclude
|
19
|
+
def included(base)
|
20
|
+
included_into << base
|
21
|
+
super(base)
|
22
|
+
end
|
23
|
+
|
24
|
+
def include(*modules)
|
25
|
+
super(*modules)
|
26
|
+
modules.reverse.each do |module_being_included|
|
27
|
+
included_into.each do |mod|
|
28
|
+
mod.send :include, module_being_included
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def included_into
|
36
|
+
@included_into ||= []
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,129 @@
|
|
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
|
+
|
16
|
+
module Algebrick
|
17
|
+
class Serializer
|
18
|
+
include TypeCheck
|
19
|
+
|
20
|
+
TYPE_KEY = :algebrick_type
|
21
|
+
FIELD_KEY = :algebrick_fields
|
22
|
+
|
23
|
+
def load(data, options = {})
|
24
|
+
case data
|
25
|
+
when ::Hash
|
26
|
+
parse_value(data, options)
|
27
|
+
when Numeric, String, ::Array, Symbol, TrueClass, FalseClass, NilClass
|
28
|
+
data
|
29
|
+
else
|
30
|
+
parse_other(data, options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def dump(object, options = {})
|
35
|
+
case object
|
36
|
+
when Value
|
37
|
+
generate_value object, options
|
38
|
+
when Numeric, String, ::Array, ::Hash, Symbol, TrueClass, FalseClass, NilClass
|
39
|
+
object
|
40
|
+
else
|
41
|
+
generate_other(object, options)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def constantize(camel_cased_word)
|
46
|
+
names = camel_cased_word.split('::')
|
47
|
+
names.shift if names.empty? || names.first.empty?
|
48
|
+
|
49
|
+
parameter = nil
|
50
|
+
names.last.tap do |last|
|
51
|
+
name, parameter = last.split /\[|\]/
|
52
|
+
last.replace name
|
53
|
+
end
|
54
|
+
|
55
|
+
constant = Object
|
56
|
+
names.each do |name|
|
57
|
+
constant = if constant.const_defined?(name)
|
58
|
+
constant.const_get(name)
|
59
|
+
else
|
60
|
+
constant.const_missing(name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
constant = constant[constantize(parameter)] if parameter
|
64
|
+
constant
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
|
69
|
+
def parse_other(other, options = {})
|
70
|
+
other
|
71
|
+
end
|
72
|
+
|
73
|
+
def generate_other(object, options = {})
|
74
|
+
case
|
75
|
+
when object.respond_to?(:to_h)
|
76
|
+
object.to_h
|
77
|
+
when object.respond_to?(:to_hash)
|
78
|
+
object.to_hash
|
79
|
+
else
|
80
|
+
raise "do not know how to convert (#{object.class}) #{object}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
|
86
|
+
def parse_value(value, options)
|
87
|
+
type_name = value[TYPE_KEY] || value[TYPE_KEY.to_s]
|
88
|
+
if type_name
|
89
|
+
type = constantize(type_name)
|
90
|
+
|
91
|
+
fields = value[FIELD_KEY] || value[FIELD_KEY.to_s] ||
|
92
|
+
value.dup.tap { |h| h.delete TYPE_KEY; h.delete TYPE_KEY.to_s }
|
93
|
+
Type! fields, Hash, Array
|
94
|
+
|
95
|
+
if type.is_a? Atom
|
96
|
+
type
|
97
|
+
else
|
98
|
+
case fields
|
99
|
+
when Array
|
100
|
+
type[*fields.map { |value| load value, options }]
|
101
|
+
when Hash
|
102
|
+
type[fields.inject({}) do |h, (name, value)|
|
103
|
+
raise ArgumentError unless type.field_names.map(&:to_s).include? name.to_s
|
104
|
+
h.update name.to_sym => load(value, options)
|
105
|
+
end]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
else
|
109
|
+
parse_other value, options
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def generate_value(value, options)
|
114
|
+
{ TYPE_KEY => value.type.name }.
|
115
|
+
update(case value
|
116
|
+
when Atom
|
117
|
+
{}
|
118
|
+
when ProductConstructors::Basic
|
119
|
+
{ FIELD_KEY => value.fields.map { |v| dump v, options } }
|
120
|
+
when ProductConstructors::Named
|
121
|
+
value.type.field_names.inject({}) do |h, name|
|
122
|
+
h.update name => dump(value[name], options)
|
123
|
+
end
|
124
|
+
else
|
125
|
+
raise
|
126
|
+
end)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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 Serializers
|
17
|
+
|
18
|
+
require 'algebrick/serializers/abstract'
|
19
|
+
require 'algebrick/serializers/abstract_to_hash'
|
20
|
+
require 'algebrick/serializers/chain'
|
21
|
+
require 'algebrick/serializers/strict_to_hash'
|
22
|
+
require 'algebrick/serializers/benevolent_to_hash'
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,61 @@
|
|
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
|
+
# Any Algebraic type defined by Algebrick is kind of Type
|
17
|
+
class Type < Module
|
18
|
+
include TypeCheck
|
19
|
+
include Matching
|
20
|
+
include MatcherDelegations
|
21
|
+
include Reclude
|
22
|
+
|
23
|
+
def initialize(name, &definition)
|
24
|
+
super &definition
|
25
|
+
@name = name
|
26
|
+
end
|
27
|
+
|
28
|
+
def name
|
29
|
+
super || @name || 'NoName'
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_m(*args)
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def ==(other)
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def be_kind_of(type)
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def to_s
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
def inspect
|
49
|
+
to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
def match(value, *cases)
|
53
|
+
Type! value, self
|
54
|
+
super value, *cases
|
55
|
+
end
|
56
|
+
|
57
|
+
#def pretty_print(q) TODO
|
58
|
+
# raise NotImplementedError
|
59
|
+
#end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,58 @@
|
|
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
|
+
#noinspection RubyInstanceMethodNamingConvention
|
17
|
+
module TypeCheck
|
18
|
+
# FIND: type checking of collections?
|
19
|
+
|
20
|
+
def Type?(value, *types)
|
21
|
+
types.any? { |t| value.is_a? t }
|
22
|
+
end
|
23
|
+
|
24
|
+
def Type!(value, *types)
|
25
|
+
Type?(value, *types) or
|
26
|
+
TypeCheck.error(value, 'is not', types)
|
27
|
+
value
|
28
|
+
end
|
29
|
+
|
30
|
+
def Match?(value, *types)
|
31
|
+
types.any? { |t| t === value }
|
32
|
+
end
|
33
|
+
|
34
|
+
def Match!(value, *types)
|
35
|
+
Match?(value, *types) or
|
36
|
+
TypeCheck.error(value, 'is not matching', types)
|
37
|
+
value
|
38
|
+
end
|
39
|
+
|
40
|
+
def Child?(value, *types)
|
41
|
+
Type?(value, Class) &&
|
42
|
+
types.any? { |t| value <= t }
|
43
|
+
end
|
44
|
+
|
45
|
+
def Child!(value, *types)
|
46
|
+
Child?(value, *types) or
|
47
|
+
TypeCheck.error(value, 'is not child', types)
|
48
|
+
value
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def self.error(value, message, types)
|
54
|
+
raise TypeError,
|
55
|
+
"Value (#{value.class}) '#{value}' #{message} any of: #{types.join('; ')}."
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,59 @@
|
|
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
|
+
#noinspection RubyConstantNamingConvention
|
17
|
+
module Types
|
18
|
+
Maybe = Algebrick.type(:v) do
|
19
|
+
variants None = atom,
|
20
|
+
Some = type(:v) { fields :v }
|
21
|
+
end
|
22
|
+
|
23
|
+
module Maybe
|
24
|
+
def maybe
|
25
|
+
match self,
|
26
|
+
on(None, nil),
|
27
|
+
on(Some) { yield value }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Boolean = Algebrick.type do
|
32
|
+
variants TrueClass, FalseClass
|
33
|
+
end
|
34
|
+
|
35
|
+
LinkedList = Algebrick.type(:value_type) do |list|
|
36
|
+
fields! value: :value_type, next: list
|
37
|
+
variants EmptyLinkedList = atom, list
|
38
|
+
end
|
39
|
+
|
40
|
+
module LinkedList
|
41
|
+
include Enumerable
|
42
|
+
|
43
|
+
def each(&block)
|
44
|
+
it = self
|
45
|
+
loop do
|
46
|
+
break if LinkedListEmpty === it
|
47
|
+
block.call it.value
|
48
|
+
it = it.next
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.empty
|
53
|
+
LinkedListEmpty
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
include Types
|
59
|
+
end
|
@@ -0,0 +1,41 @@
|
|
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
|
+
# Any value of Algebraic type is kind of Value
|
17
|
+
module Value
|
18
|
+
include TypeCheck
|
19
|
+
include Matching
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
raise NotImplementedError
|
23
|
+
end
|
24
|
+
|
25
|
+
def type
|
26
|
+
raise NotImplementedError
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_s
|
30
|
+
raise NotImplementedError
|
31
|
+
end
|
32
|
+
|
33
|
+
def pretty_print(q)
|
34
|
+
raise NotImplementedError
|
35
|
+
end
|
36
|
+
|
37
|
+
def inspect
|
38
|
+
to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|