algebrick 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/README_FULL.md +13 -21
  4. data/VERSION +1 -1
  5. data/doc/actor.rb +21 -0
  6. data/doc/data.in.rb +99 -0
  7. data/doc/data.out.rb +103 -0
  8. data/doc/extending_behavior.in.rb +61 -0
  9. data/doc/extending_behavior.out.rb +62 -0
  10. data/doc/format.rb +75 -0
  11. data/doc/init.rb +1 -0
  12. data/doc/json.in.rb +39 -0
  13. data/doc/json.out.rb +43 -0
  14. data/doc/null.in.rb +36 -0
  15. data/doc/null.out.rb +40 -0
  16. data/doc/parametrized.in.rb +37 -0
  17. data/doc/parametrized.out.rb +41 -0
  18. data/doc/pattern_matching.in.rb +116 -0
  19. data/doc/pattern_matching.out.rb +122 -0
  20. data/doc/quick_example.in.rb +27 -0
  21. data/doc/quick_example.out.rb +27 -0
  22. data/doc/tree1.in.rb +10 -0
  23. data/doc/tree1.out.rb +10 -0
  24. data/doc/type_def.in.rb +21 -0
  25. data/doc/type_def.out.rb +21 -0
  26. data/doc/values.in.rb +52 -0
  27. data/doc/values.out.rb +58 -0
  28. data/lib/algebrick/atom.rb +49 -0
  29. data/lib/algebrick/dsl.rb +104 -0
  30. data/lib/algebrick/field_method_readers.rb +43 -0
  31. data/lib/algebrick/matcher_delegations.rb +45 -0
  32. data/lib/algebrick/matchers/abstract.rb +127 -0
  33. data/lib/algebrick/matchers/abstract_logic.rb +38 -0
  34. data/lib/algebrick/matchers/and.rb +29 -0
  35. data/lib/algebrick/matchers/any.rb +37 -0
  36. data/lib/algebrick/matchers/array.rb +57 -0
  37. data/lib/algebrick/matchers/atom.rb +28 -0
  38. data/lib/algebrick/matchers/not.rb +44 -0
  39. data/lib/algebrick/matchers/or.rb +51 -0
  40. data/lib/algebrick/matchers/product.rb +73 -0
  41. data/lib/algebrick/matchers/variant.rb +29 -0
  42. data/lib/algebrick/matchers/wrapper.rb +57 -0
  43. data/lib/algebrick/matchers.rb +31 -0
  44. data/lib/algebrick/matching.rb +62 -0
  45. data/lib/algebrick/parametrized_type.rb +122 -0
  46. data/lib/algebrick/product_constructors/abstract.rb +70 -0
  47. data/lib/algebrick/product_constructors/basic.rb +47 -0
  48. data/lib/algebrick/product_constructors/named.rb +58 -0
  49. data/lib/algebrick/product_constructors.rb +25 -0
  50. data/lib/algebrick/product_variant.rb +195 -0
  51. data/lib/algebrick/reclude.rb +39 -0
  52. data/lib/algebrick/serializer.rb +129 -0
  53. data/lib/algebrick/serializers.rb +25 -0
  54. data/lib/algebrick/type.rb +61 -0
  55. data/lib/algebrick/type_check.rb +58 -0
  56. data/lib/algebrick/types.rb +59 -0
  57. data/lib/algebrick/value.rb +41 -0
  58. data/lib/algebrick.rb +14 -1170
  59. data/spec/algebrick_test.rb +708 -0
  60. 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