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.
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