low_type 0.2.2 → 0.3.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/lib/low_type.rb +17 -2
- data/lib/redefiner.rb +28 -25
- data/lib/type_expression.rb +10 -1
- data/lib/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b01f96320aa0543e44d8b4b40430903af4966174fb9ae1533ddf7240c1919ec1
|
|
4
|
+
data.tar.gz: 87094ba39f9755fce4befa350b7ce33d7bd807a9774f1366340a0c9003788933
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b4ff1cca9f7763084b3283a13b34955863a81074a6161703c3993aa6d0916180804f8b6058ee35779be159eec7000d9c2f676c656254a67039cb3548073f10d
|
|
7
|
+
data.tar.gz: 39aad0e4a488963333b31c8ec21fc6586e78e5d0ebf76a6546997183ada9ce6baacbd0107ecd0ed71ce5e5c9fa14d8597936b5db874edc48fdc6c082651ea72e
|
data/lib/low_type.rb
CHANGED
|
@@ -6,6 +6,19 @@ require_relative 'type_expression'
|
|
|
6
6
|
module LowType
|
|
7
7
|
# We do as much as possible on class load rather than on instantiation to be thread-safe and efficient.
|
|
8
8
|
def self.included(klass)
|
|
9
|
+
|
|
10
|
+
# Array[] class method returns a type expression only for the duration of this "included" hook.
|
|
11
|
+
array_class_method = Array.method('[]').unbind
|
|
12
|
+
Array.define_singleton_method('[]') do |expression|
|
|
13
|
+
TypeExpression.new(type: [(expression)])
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Hash[] class method returns a type expression only for the duration of this "included" hook.
|
|
17
|
+
hash_class_method = Hash.method('[]').unbind
|
|
18
|
+
Hash.define_singleton_method('[]') do |expression|
|
|
19
|
+
TypeExpression.new(type: expression)
|
|
20
|
+
end
|
|
21
|
+
|
|
9
22
|
class << klass
|
|
10
23
|
def low_params
|
|
11
24
|
@low_params ||= {}
|
|
@@ -24,8 +37,12 @@ module LowType
|
|
|
24
37
|
|
|
25
38
|
parser = Parser.new(file_path: LowType.file_path(klass:))
|
|
26
39
|
private_start_line = parser.private_start_line
|
|
40
|
+
|
|
27
41
|
klass.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.instance_methods, private_start_line:, klass:)
|
|
28
42
|
klass.singleton_class.prepend LowType::Redefiner.redefine_methods(method_nodes: parser.class_methods, private_start_line:, klass:)
|
|
43
|
+
ensure
|
|
44
|
+
Array.define_singleton_method('[]', array_class_method)
|
|
45
|
+
Hash.define_singleton_method('[]', hash_class_method)
|
|
29
46
|
end
|
|
30
47
|
|
|
31
48
|
class << self
|
|
@@ -44,6 +61,4 @@ module LowType
|
|
|
44
61
|
|
|
45
62
|
class ValueExpression; end
|
|
46
63
|
class Boolean; end # TrueClass or FalseClass
|
|
47
|
-
class KeyValue; end # KeyValue[String => Hash]
|
|
48
|
-
class MixedTypes; end # MixedTypes[String | Integer]
|
|
49
64
|
end
|
data/lib/redefiner.rb
CHANGED
|
@@ -8,12 +8,7 @@ module LowType
|
|
|
8
8
|
def redefine_methods(method_nodes:, private_start_line:, klass:)
|
|
9
9
|
Module.new do
|
|
10
10
|
method_nodes.each do |method_node|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
proxy_method = eval("-> (#{args}) {}")
|
|
14
|
-
required_args, required_kwargs = Redefiner.required_args(proxy_method)
|
|
15
|
-
|
|
16
|
-
klass.low_params[method_node.name] = Redefiner.type_expressions_from_params(proxy_method, args, required_args, required_kwargs)
|
|
11
|
+
klass.low_params[method_node.name] = Redefiner.param_proxy_with_type_expressions(method_node)
|
|
17
12
|
next if klass.low_params[method_node.name].empty?
|
|
18
13
|
|
|
19
14
|
define_method(method_node.name) do |*args, **kwargs|
|
|
@@ -34,28 +29,14 @@ module LowType
|
|
|
34
29
|
end
|
|
35
30
|
end
|
|
36
31
|
|
|
37
|
-
def
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
proxy_method.parameters.each do |param|
|
|
42
|
-
param_type, param_name = param
|
|
43
|
-
|
|
44
|
-
case param_type
|
|
45
|
-
when :req
|
|
46
|
-
required_args << nil
|
|
47
|
-
when :keyreq
|
|
48
|
-
required_kwargs[param_name] = nil
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
[required_args, required_kwargs]
|
|
53
|
-
end
|
|
32
|
+
def param_proxy_with_type_expressions(method_node)
|
|
33
|
+
params = method_node.parameters.slice
|
|
34
|
+
proxy_method = eval("-> (#{params}) {}")
|
|
35
|
+
required_args, required_kwargs = Redefiner.required_args(proxy_method)
|
|
54
36
|
|
|
55
|
-
def type_expressions_from_params(proxy_method, args, required_args, required_kwargs)
|
|
56
37
|
typed_method = eval(
|
|
57
38
|
<<~RUBY
|
|
58
|
-
-> (#{
|
|
39
|
+
-> (#{params}) {
|
|
59
40
|
param_proxies = []
|
|
60
41
|
|
|
61
42
|
proxy_method.parameters.each_with_index do |param, position|
|
|
@@ -78,6 +59,28 @@ module LowType
|
|
|
78
59
|
|
|
79
60
|
# Call method with only its required args to evaluate type expressions (which are stored as default values).
|
|
80
61
|
typed_method.call(*required_args, **required_kwargs)
|
|
62
|
+
|
|
63
|
+
# TODO: Write spec for this.
|
|
64
|
+
rescue ArgumentError => e
|
|
65
|
+
raise ArgumentError, "Incorrect param syntax"
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def required_args(proxy_method)
|
|
69
|
+
required_args = []
|
|
70
|
+
required_kwargs = {}
|
|
71
|
+
|
|
72
|
+
proxy_method.parameters.each do |param|
|
|
73
|
+
param_type, param_name = param
|
|
74
|
+
|
|
75
|
+
case param_type
|
|
76
|
+
when :req
|
|
77
|
+
required_args << nil
|
|
78
|
+
when :keyreq
|
|
79
|
+
required_kwargs[param_name] = nil
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
[required_args, required_kwargs]
|
|
81
84
|
end
|
|
82
85
|
end
|
|
83
86
|
end
|
data/lib/type_expression.rb
CHANGED
|
@@ -29,7 +29,16 @@ module LowType
|
|
|
29
29
|
raise ArgumentError, "Missing required argument of type '#{@types.join(', ')}' for '#{name}'"
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
@types.each do |type|
|
|
33
|
+
return true if LowType.type?(type) && type == arg.class
|
|
34
|
+
# TODO: Shallow validation of enumerables could be made deeper with user config.
|
|
35
|
+
return true if type.class == Array && arg.class == Array && type.first == arg.first.class
|
|
36
|
+
if type.class == Hash && arg.class == Hash && type.keys[0] == arg.keys[0].class && type.values[0] == arg.values[0].class
|
|
37
|
+
return true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
raise TypeError, "Invalid type '#{arg.class}' for '#{name}'"
|
|
33
42
|
end
|
|
34
43
|
end
|
|
35
44
|
end
|
data/lib/version.rb
CHANGED