algebrick 0.4.0 → 0.5.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 +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
|