emery 0.0.2 → 0.0.8

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.
data/lib/emery/type.rb CHANGED
@@ -1,187 +1,185 @@
1
- module Emery
2
- module T
3
- def T.check_not_nil(type, value)
4
- if value == nil
5
- raise TypeError.new("Type #{type.to_s} does not allow nil value")
6
- end
1
+ module T
2
+ def T.check_not_nil(type, value)
3
+ if value == nil
4
+ raise TypeError.new("Type #{type.to_s} does not allow nil value")
7
5
  end
6
+ end
8
7
 
9
- class UntypedType
10
- def to_s
11
- "Untyped"
12
- end
13
- def check(value)
14
- T.check_not_nil(self, value)
15
- end
8
+ class UntypedType
9
+ def to_s
10
+ "Untyped"
16
11
  end
12
+ def check(value)
13
+ T.check_not_nil(self, value)
14
+ end
15
+ end
17
16
 
18
- class Nilable
19
- attr_reader :type
20
- def initialize(type)
21
- @type = type
22
- end
23
- def to_s
24
- "Nilable[#{type.to_s}]"
25
- end
26
- def check(value)
27
- if value != nil
28
- T.check(type, value)
29
- end
30
- end
31
- def ==(other)
32
- T.instance_of?(Nilable, other) and self.type == other.type
17
+ class Nilable
18
+ attr_reader :type
19
+ def initialize(type)
20
+ @type = type
21
+ end
22
+ def to_s
23
+ "Nilable[#{type.to_s}]"
24
+ end
25
+ def check(value)
26
+ if value != nil
27
+ T.check(type, value)
33
28
  end
34
29
  end
30
+ def ==(other)
31
+ T.instance_of?(Nilable, other) and self.type == other.type
32
+ end
33
+ end
35
34
 
36
- class AnyType
37
- attr_reader :types
38
- def initialize(*types)
39
- @types = types
40
- end
41
- def to_s
42
- "Any[#{types.map { |t| t.to_s}.join(', ')}]"
43
- end
44
- def check(value)
45
- type = types.find {|t| T.instance_of?(t, value) }
46
- if type == nil
47
- raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - any of #{@types.map { |t| t.to_s}.join(', ')} required")
48
- end
49
- end
50
- def ==(other)
51
- T.instance_of?(AnyType, other) and (self.types - other.types).empty?
35
+ class AnyType
36
+ attr_reader :types
37
+ def initialize(*types)
38
+ @types = types
39
+ end
40
+ def to_s
41
+ "Any[#{types.map { |t| t.to_s}.join(', ')}]"
42
+ end
43
+ def check(value)
44
+ type = types.find {|t| T.instance_of?(t, value) }
45
+ if type == nil
46
+ raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - any of #{@types.map { |t| t.to_s}.join(', ')} required")
52
47
  end
53
48
  end
49
+ def ==(other)
50
+ T.instance_of?(AnyType, other) and (self.types - other.types).empty?
51
+ end
52
+ end
54
53
 
55
- class UnionType < AnyType
56
- attr_reader :cases
57
- def initialize(cases)
58
- @cases = cases
59
- super(*cases.values)
60
- end
61
- def to_s
62
- "Union[#{cases.map { |k, t| "#{k}: #{t}"}.join(', ')}]"
63
- end
54
+ class UnionType < AnyType
55
+ attr_reader :cases
56
+ def initialize(cases)
57
+ @cases = cases
58
+ super(*cases.values)
64
59
  end
60
+ def to_s
61
+ "Union[#{cases.map { |k, t| "#{k}: #{t}"}.join(', ')}]"
62
+ end
63
+ end
65
64
 
66
- class ArrayType
67
- attr_reader :item_type
68
- def initialize(item_type)
69
- @item_type = item_type
70
- end
71
- def to_s
72
- "Array[#{item_type.to_s}]"
73
- end
74
- def check(value)
75
- T.check_not_nil(self, value)
76
- if !value.is_a? Array
77
- raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Array is required")
78
- end
79
- value.each { |item_value| T.check(item_type, item_value) }
80
- end
81
- def ==(other)
82
- T.instance_of?(ArrayType, other) and self.item_type == other.item_type
65
+ class ArrayType
66
+ attr_reader :item_type
67
+ def initialize(item_type)
68
+ @item_type = item_type
69
+ end
70
+ def to_s
71
+ "Array[#{item_type.to_s}]"
72
+ end
73
+ def check(value)
74
+ T.check_not_nil(self, value)
75
+ if !value.is_a? Array
76
+ raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Array is required")
83
77
  end
78
+ value.each { |item_value| T.check(item_type, item_value) }
84
79
  end
80
+ def ==(other)
81
+ T.instance_of?(ArrayType, other) and self.item_type == other.item_type
82
+ end
83
+ end
85
84
 
86
- class HashType
87
- attr_reader :key_type
88
- attr_reader :value_type
89
- def initialize(key_type, value_type)
90
- @key_type = key_type
91
- @value_type = value_type
92
- end
93
- def to_s
94
- "Hash[#{@key_type.to_s}, #{@value_type.to_s}]"
95
- end
96
- def check(value)
97
- T.check_not_nil(self, value)
98
- if !value.is_a? Hash
99
- raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Hash is required")
100
- end
101
- value.each do |item_key, item_value|
102
- T.check(@key_type, item_key)
103
- T.check(@value_type, item_value)
104
- end
85
+ class HashType
86
+ attr_reader :key_type
87
+ attr_reader :value_type
88
+ def initialize(key_type, value_type)
89
+ @key_type = key_type
90
+ @value_type = value_type
91
+ end
92
+ def to_s
93
+ "Hash[#{@key_type.to_s}, #{@value_type.to_s}]"
94
+ end
95
+ def check(value)
96
+ T.check_not_nil(self, value)
97
+ if !value.is_a? Hash
98
+ raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - Hash is required")
105
99
  end
106
- def ==(other)
107
- T.instance_of?(HashType, other) and self.key_type == other.key_type and self.value_type == other.value_type
100
+ value.each do |item_key, item_value|
101
+ T.check(@key_type, item_key)
102
+ T.check(@value_type, item_value)
108
103
  end
109
104
  end
105
+ def ==(other)
106
+ T.instance_of?(HashType, other) and self.key_type == other.key_type and self.value_type == other.value_type
107
+ end
108
+ end
110
109
 
111
- class StringFormatted
112
- attr_reader :regex
113
- def initialize(regex)
114
- @regex = regex
115
- end
116
- def to_s
117
- "String<#@regex>"
110
+ class StringFormatted
111
+ attr_reader :regex
112
+ def initialize(regex)
113
+ @regex = regex
114
+ end
115
+ def to_s
116
+ "String<#@regex>"
117
+ end
118
+ def check(value)
119
+ T.check_not_nil(self, value)
120
+ if !value.is_a? String
121
+ raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - String is required for StringFormatted")
118
122
  end
119
- def check(value)
120
- T.check_not_nil(self, value)
121
- if !value.is_a? String
122
- raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - String is required for StringFormatted")
123
- end
124
- if !@regex.match?(value)
125
- raise TypeError.new("Value '#{value.inspect.to_s}' is not in required format '#{@regex}'")
126
- end
123
+ if !@regex.match?(value)
124
+ raise TypeError.new("Value '#{value.inspect.to_s}' is not in required format '#{@regex}'")
127
125
  end
128
126
  end
127
+ end
129
128
 
130
- def T.check(type, value)
131
- if type.methods.include? :check
132
- type.check(value)
133
- else
134
- if type != NilClass
135
- T.check_not_nil(type, value)
136
- end
137
- if !value.is_a? type
138
- raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - #{type} is required")
139
- end
129
+ def T.check(type, value)
130
+ if type.methods.include? :check
131
+ type.check(value)
132
+ else
133
+ if type != NilClass
134
+ T.check_not_nil(type, value)
140
135
  end
141
- return value
142
- end
143
-
144
- def T.instance_of?(type, value)
145
- begin
146
- T.check(type, value)
147
- true
148
- rescue TypeError
149
- false
136
+ if !value.is_a? type
137
+ raise TypeError.new("Value '#{value.inspect.to_s}' type is #{value.class} - #{type} is required")
150
138
  end
151
139
  end
140
+ return value
141
+ end
152
142
 
153
- def T.nilable(value_type)
154
- Nilable.new(value_type)
143
+ def T.instance_of?(type, value)
144
+ begin
145
+ T.check(type, value)
146
+ true
147
+ rescue TypeError
148
+ false
155
149
  end
150
+ end
156
151
 
157
- def T.array(item_type)
158
- ArrayType.new(item_type)
159
- end
152
+ def T.nilable(value_type)
153
+ Nilable.new(value_type)
154
+ end
160
155
 
161
- def T.hash(key_type, value_type)
162
- HashType.new(key_type, value_type)
163
- end
156
+ def T.array(item_type)
157
+ ArrayType.new(item_type)
158
+ end
164
159
 
165
- def T.any(*typdefs)
166
- AnyType.new(*typdefs)
167
- end
160
+ def T.hash(key_type, value_type)
161
+ HashType.new(key_type, value_type)
162
+ end
168
163
 
169
- def T.union(*cases)
170
- UnionType.new(*cases)
171
- end
164
+ def T.any(*typdefs)
165
+ AnyType.new(*typdefs)
166
+ end
172
167
 
173
- def T.check_var(var_name, type, value)
174
- begin
175
- check(type, value)
176
- return value
177
- rescue TypeError => e
178
- raise TypeError.new("Variable #{var_name} type check failed, expected type: #{type.to_s}, value: #{value}")
179
- end
168
+ def T.union(*cases)
169
+ UnionType.new(*cases)
170
+ end
171
+
172
+ def T.check_var(var_name, type, value)
173
+ begin
174
+ check(type, value)
175
+ return value
176
+ rescue TypeError => e
177
+ raise TypeError.new("Variable #{var_name} type check failed, expected type: #{type.to_s}, value: #{value}")
180
178
  end
181
179
  end
180
+ end
182
181
 
183
- Boolean = T.any(TrueClass, FalseClass)
184
- Untyped = T::UntypedType.new
185
- NilableUntyped = T.nilable(Untyped)
186
- UUID = T::StringFormatted.new(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
187
- end
182
+ Boolean = T.any(TrueClass, FalseClass)
183
+ Untyped = T::UntypedType.new
184
+ NilableUntyped = T.nilable(Untyped)
185
+ UUID = T::StringFormatted.new(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/)
@@ -1,115 +1,112 @@
1
1
  require "test/unit/runner/junitxml"
2
2
 
3
- require 'emery/dataclass'
4
- require 'emery/jsoner'
3
+ require 'emery'
5
4
 
6
- module Emery
7
- class DataClassTypeEquality < Test::Unit::TestCase
8
- def test_equals
9
- assert_true TheClass == TheClass
10
- end
5
+ class DataClassTypeEquality < Test::Unit::TestCase
6
+ def test_equals
7
+ assert_true TheClass == TheClass
8
+ end
11
9
 
12
- def test_not_equals
13
- assert_false TheClass == TheClassWithNested
14
- end
10
+ def test_not_equals
11
+ assert_false TheClass == TheClassWithNested
15
12
  end
13
+ end
16
14
 
17
- class DataClassFields < Test::Unit::TestCase
18
- def test_fields_meta
19
- assert_equal ({:string => String, :int => Integer}), TheClass.json_attributes, "Attributes with types should be available on data class"
20
- end
15
+ class DataClassFields < Test::Unit::TestCase
16
+ def test_fields_meta
17
+ assert_equal ({:string => String, :int => Integer}), TheClass.json_attributes, "Attributes with types should be available on data class"
18
+ end
21
19
 
22
- def test_read
23
- obj = TheClass.new(string: "the string", int: 123)
24
- assert_equal "the string", obj.string, "Immutable field should be readable"
25
- assert_equal 123, obj.int, "Mutable field should be readable"
26
- end
20
+ def test_read
21
+ obj = TheClass.new(string: "the string", int: 123)
22
+ assert_equal "the string", obj.string, "Immutable field should be readable"
23
+ assert_equal 123, obj.int, "Mutable field should be readable"
24
+ end
27
25
 
28
- def test_write_mutable
29
- obj = TheClass.new(string: "the string", int: 123)
30
- obj.int = 124
31
- assert_equal 124, obj.int, "Mutable field should be writable"
32
- end
26
+ def test_write_mutable
27
+ obj = TheClass.new(string: "the string", int: 123)
28
+ obj.int = 124
29
+ assert_equal 124, obj.int, "Mutable field should be writable"
30
+ end
33
31
 
34
- def test_write_immutable
35
- obj = TheClass.new(string: "the string", int: 123)
36
- assert_raise NoMethodError do
37
- obj.string = "the other string"
38
- end
32
+ def test_write_immutable
33
+ obj = TheClass.new(string: "the string", int: 123)
34
+ assert_raise NoMethodError do
35
+ obj.string = "the other string"
39
36
  end
40
37
  end
38
+ end
41
39
 
42
- class DataClassEquality < Test::Unit::TestCase
43
- def test_nil
44
- assert_not_equal nil, TheClass.new(string: "the string", int: 123), "Object should not be equal to nil"
45
- end
40
+ class DataClassEquality < Test::Unit::TestCase
41
+ def test_nil
42
+ assert_not_equal nil, TheClass.new(string: "the string", int: 123), "Object should not be equal to nil"
43
+ end
46
44
 
47
- def test_same_fields_values
48
- assert_equal TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string", int: 123), "Objects with same fields should be equal"
49
- end
45
+ def test_same_fields_values
46
+ assert_equal TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string", int: 123), "Objects with same fields should be equal"
47
+ end
50
48
 
51
- def test_different_fields_values
52
- assert_not_equal TheClass.new(string: "the string 2", int: 123), TheClass.new(string: "the string", int: 123), "Objects with different fields should not be equal"
53
- end
49
+ def test_different_fields_values
50
+ assert_not_equal TheClass.new(string: "the string 2", int: 123), TheClass.new(string: "the string", int: 123), "Objects with different fields should not be equal"
54
51
  end
52
+ end
55
53
 
56
- class DataClassDeserialization < Test::Unit::TestCase
57
- def test_deserialize_object
58
- data = Jsoner.from_json(TheClass, '{"string": "the string", "int": 123}')
59
- T.check(TheClass, data)
60
- assert_equal TheClass.new(string: "the string", int: 123), data, "Should parse data class object"
61
- end
54
+ class DataClassDeserialization < Test::Unit::TestCase
55
+ def test_deserialize_object
56
+ data = Jsoner.from_json(TheClass, '{"string": "the string", "int": 123}')
57
+ T.check(TheClass, data)
58
+ assert_equal TheClass.new(string: "the string", int: 123), data, "Should parse data class object"
59
+ end
62
60
 
63
- def test_deserialize_nested_object
64
- data = Jsoner.from_json(TheClassWithNested, '{"nested": {"string": "the string", "int": 123}}')
65
- T.check(TheClassWithNested, data)
66
- assert_equal TheClassWithNested.new(nested: TheClass.new(string: "the string", int: 123)), data, "Should parse nested data class object"
67
- end
61
+ def test_deserialize_nested_object
62
+ data = Jsoner.from_json(TheClassWithNested, '{"nested": {"string": "the string", "int": 123}}')
63
+ T.check(TheClassWithNested, data)
64
+ assert_equal TheClassWithNested.new(nested: TheClass.new(string: "the string", int: 123)), data, "Should parse nested data class object"
65
+ end
68
66
 
69
- def test_deserialize_object_fail
70
- assert_raise JsonerError do
71
- Jsoner.from_json(TheClass, '"string"')
72
- end
67
+ def test_deserialize_object_fail
68
+ assert_raise JsonerError do
69
+ Jsoner.from_json(TheClass, '"string"')
73
70
  end
74
-
75
71
  end
76
72
 
77
- class DataClassSerialization < Test::Unit::TestCase
78
- def test_serialize_object
79
- assert_equal '{"string":"the string","int":123}', Jsoner.to_json(TheClass, TheClass.new(string: "the string", int: 123)), "nil should be serializable to JSON"
80
- end
73
+ end
81
74
 
82
- def test_serialize_array_of_objects
83
- assert_equal '[{"string":"the string","int":123},{"string":"the string 2","int":456}]', Jsoner.to_json(T.array(TheClass), [TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string 2", int: 456)]), "Array of objects should be serializable to JSON"
84
- end
75
+ class DataClassSerialization < Test::Unit::TestCase
76
+ def test_serialize_object
77
+ assert_equal '{"string":"the string","int":123}', Jsoner.to_json(TheClass, TheClass.new(string: "the string", int: 123)), "nil should be serializable to JSON"
85
78
  end
86
79
 
87
- class DataClassCopy < Test::Unit::TestCase
88
- def test_copy
89
- a = TheClass.new(string: "the string", int: 123)
90
- b = a.copy(string: "the other string")
91
- assert_equal "the string", a.string
92
- assert_equal "the other string", b.string
93
- end
80
+ def test_serialize_array_of_objects
81
+ assert_equal '[{"string":"the string","int":123},{"string":"the string 2","int":456}]', Jsoner.to_json(T.array(TheClass), [TheClass.new(string: "the string", int: 123), TheClass.new(string: "the string 2", int: 456)]), "Array of objects should be serializable to JSON"
82
+ end
83
+ end
84
+
85
+ class DataClassCopy < Test::Unit::TestCase
86
+ def test_copy
87
+ a = TheClass.new(string: "the string", int: 123)
88
+ b = a.copy(string: "the other string")
89
+ assert_equal "the string", a.string
90
+ assert_equal "the other string", b.string
91
+ end
94
92
 
95
- def test_copy_non_existing_field
96
- assert_raise TypeError do
97
- a = TheClass.new(string: "the string", int: 123)
98
- a.copy(non_existing: "the other string")
99
- end
93
+ def test_copy_non_existing_field
94
+ assert_raise TypeError do
95
+ a = TheClass.new(string: "the string", int: 123)
96
+ a.copy(non_existing: "the other string")
100
97
  end
101
98
  end
99
+ end
102
100
 
103
- class TheClass
104
- include DataClass
101
+ class TheClass
102
+ include DataClass
105
103
 
106
- val :string, String
107
- var :int, Integer
108
- end
104
+ val :string, String
105
+ var :int, Integer
106
+ end
109
107
 
110
- class TheClassWithNested
111
- include DataClass
108
+ class TheClassWithNested
109
+ include DataClass
112
110
 
113
- val :nested, TheClass
114
- end
111
+ val :nested, TheClass
115
112
  end