low_type 1.1.6 → 1.1.7
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/adapters/adapter_loader.rb +1 -1
- data/lib/adapters/sinatra_adapter.rb +2 -2
- data/lib/definitions/redefiner.rb +27 -21
- data/lib/definitions/repository.rb +1 -1
- data/lib/definitions/type_accessors.rb +13 -13
- data/lib/expressions/expressions.rb +1 -1
- data/lib/expressions/type_expression.rb +26 -19
- data/lib/factories/expression_factory.rb +1 -1
- data/lib/factories/proxy_factory.rb +24 -17
- data/lib/factories/type_factory.rb +1 -1
- data/lib/interfaces/adapter_interface.rb +1 -1
- data/lib/interfaces/error_interface.rb +1 -1
- data/lib/low_type.rb +16 -9
- data/lib/proxies/class_proxy.rb +1 -1
- data/lib/proxies/file_proxy.rb +1 -1
- data/lib/proxies/local_proxy.rb +1 -1
- data/lib/proxies/method_proxy.rb +1 -1
- data/lib/proxies/param_proxy.rb +6 -6
- data/lib/proxies/return_proxy.rb +1 -1
- data/lib/queries/file_parser.rb +1 -1
- data/lib/queries/file_query.rb +1 -1
- data/lib/queries/type_query.rb +2 -2
- data/lib/syntax/syntax.rb +4 -2
- data/lib/syntax/union_types.rb +2 -10
- data/lib/types/complex_type.rb +1 -1
- data/lib/types/complex_types.rb +1 -1
- data/lib/types/error_types.rb +1 -1
- data/lib/types/status.rb +1 -1
- data/lib/version.rb +2 -2
- metadata +19 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a6cfbec60ebbfe9ff5d9a3dd68a00c201b1b8cc8aea52f08f290c3b34131fb89
|
|
4
|
+
data.tar.gz: 4e745a28edb5c3da913b4fde7e1346ba62352469a27a1b259225ca6df62350fa
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ee8a741df349ef64d5d133a553339aef6c2ecf8d2238adedc7890c41e3e4b6a2bb71556fc5eac488fdb9d8a875cdee8a251bd78d268fe05ac36ecc71d0d5c31b
|
|
7
|
+
data.tar.gz: 3397ec0c358d4643b3c2ea3cf1a12243ba667ba4ea536c6aaac59eb7b067d5fdfea2850a0d121765f6fbbe3b2da49dc08123320d8e100c53ec2ee3865c0d678a
|
|
@@ -7,7 +7,7 @@ require_relative '../interfaces/adapter_interface'
|
|
|
7
7
|
require_relative '../proxies/return_proxy'
|
|
8
8
|
require_relative '../types/error_types'
|
|
9
9
|
|
|
10
|
-
module
|
|
10
|
+
module Low
|
|
11
11
|
module Adapter
|
|
12
12
|
# We don't use https://sinatrarb.com/extensions.html because we need to type check all Ruby methods (not just Sinatra) at a lower level.
|
|
13
13
|
class Sinatra < AdapterInterface
|
|
@@ -31,7 +31,7 @@ module LowType
|
|
|
31
31
|
next unless (return_proxy = return_proxy(method_node: method_call, pattern:, file:))
|
|
32
32
|
|
|
33
33
|
route = "#{method_call.name.upcase} #{pattern}"
|
|
34
|
-
params = [ParamProxy.new(
|
|
34
|
+
params = [ParamProxy.new(expression: nil, name: :route, type: :req, position: 0, file:)]
|
|
35
35
|
@klass.low_methods[route] = MethodProxy.new(name: method_call.name, params:, return_proxy:)
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -6,7 +6,7 @@ require_relative '../proxies/method_proxy'
|
|
|
6
6
|
require_relative '../queries/type_query'
|
|
7
7
|
require_relative 'repository'
|
|
8
8
|
|
|
9
|
-
module
|
|
9
|
+
module Low
|
|
10
10
|
# Redefine methods to have their arguments and return values type checked.
|
|
11
11
|
class Redefiner
|
|
12
12
|
class << self
|
|
@@ -21,20 +21,7 @@ module LowType
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def redefinable?(method_proxy:, class_proxy:)
|
|
24
|
-
|
|
25
|
-
if method_proxy.params == [] && method_proxy.return_proxy.nil?
|
|
26
|
-
LowType::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
27
|
-
return false
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Method outside class bounds.
|
|
31
|
-
within_bounds = method_proxy.start_line > class_proxy.start_line && method_proxy.end_line <= class_proxy.end_line
|
|
32
|
-
if method_proxy.lines? && class_proxy.lines? && !within_bounds
|
|
33
|
-
LowType::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
34
|
-
return false
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
true
|
|
24
|
+
method_has_types?(method_proxy:, class_proxy:) && method_within_class_bounds?(method_proxy:, class_proxy:)
|
|
38
25
|
end
|
|
39
26
|
|
|
40
27
|
def untyped_args(args:, kwargs:, method_proxy:) # rubocop:disable Metrics/AbcSize
|
|
@@ -44,7 +31,7 @@ module LowType
|
|
|
44
31
|
next unless value.nil?
|
|
45
32
|
raise param_proxy.error_type, param_proxy.error_message(value:) if param_proxy.required?
|
|
46
33
|
|
|
47
|
-
value = param_proxy.
|
|
34
|
+
value = param_proxy.expression.default_value # Default value can still be `nil`.
|
|
48
35
|
value = value.value if value.is_a?(ValueExpression)
|
|
49
36
|
param_proxy.position ? args[param_proxy.position] = value : kwargs[param_proxy.name] = value
|
|
50
37
|
end
|
|
@@ -76,7 +63,7 @@ module LowType
|
|
|
76
63
|
def typed_methods(method_proxies:, class_proxy:) # rubocop:disable Metrics
|
|
77
64
|
Module.new do
|
|
78
65
|
method_proxies.each do |name, method_proxy|
|
|
79
|
-
next unless
|
|
66
|
+
next unless Low::Redefiner.redefinable?(method_proxy:, class_proxy:)
|
|
80
67
|
|
|
81
68
|
# You are now in the binding of the includer class (`name` is also available here).
|
|
82
69
|
define_method(name) do |*args, **kwargs|
|
|
@@ -85,9 +72,9 @@ module LowType
|
|
|
85
72
|
|
|
86
73
|
method_proxy.params.each do |param_proxy|
|
|
87
74
|
value = param_proxy.position ? args[param_proxy.position] : kwargs[param_proxy.name]
|
|
88
|
-
value = param_proxy.
|
|
75
|
+
value = param_proxy.expression.default_value if value.nil? && !param_proxy.required?
|
|
89
76
|
|
|
90
|
-
param_proxy.
|
|
77
|
+
param_proxy.expression.validate!(value:, proxy: param_proxy)
|
|
91
78
|
value = value.value if value.is_a?(ValueExpression)
|
|
92
79
|
param_proxy.position ? args[param_proxy.position] = value : kwargs[param_proxy.name] = value
|
|
93
80
|
end
|
|
@@ -109,13 +96,13 @@ module LowType
|
|
|
109
96
|
def untyped_methods(method_proxies:, class_proxy:)
|
|
110
97
|
Module.new do
|
|
111
98
|
method_proxies.each do |name, method_proxy|
|
|
112
|
-
next unless
|
|
99
|
+
next unless Low::Redefiner.redefinable?(method_proxy:, class_proxy:)
|
|
113
100
|
|
|
114
101
|
# You are now in the binding of the includer class (`name` is also available here).
|
|
115
102
|
define_method(name) do |*args, **kwargs|
|
|
116
103
|
# NOTE: Type checking is currently disabled. See 'config.type_checking'.
|
|
117
104
|
method_proxy = instance_of?(Class) ? low_methods[name] : self.class.low_methods[name] || Object.low_methods[name]
|
|
118
|
-
args, kwargs =
|
|
105
|
+
args, kwargs = Low::Redefiner.untyped_args(args:, kwargs:, method_proxy:)
|
|
119
106
|
super(*args, **kwargs)
|
|
120
107
|
end
|
|
121
108
|
|
|
@@ -123,6 +110,25 @@ module LowType
|
|
|
123
110
|
end
|
|
124
111
|
end
|
|
125
112
|
end
|
|
113
|
+
|
|
114
|
+
def method_has_types?(method_proxy:, class_proxy:)
|
|
115
|
+
if method_proxy.params == [] && method_proxy.return_proxy.nil?
|
|
116
|
+
Low::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
117
|
+
return false
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def method_within_class_bounds?(method_proxy:, class_proxy:)
|
|
124
|
+
within_bounds = method_proxy.start_line > class_proxy.start_line && method_proxy.end_line <= class_proxy.end_line
|
|
125
|
+
if method_proxy.lines? && class_proxy.lines? && !within_bounds
|
|
126
|
+
Low::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
127
|
+
return false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
true
|
|
131
|
+
end
|
|
126
132
|
end
|
|
127
133
|
end
|
|
128
134
|
end
|
|
@@ -4,36 +4,36 @@ require_relative '../expressions/type_expression'
|
|
|
4
4
|
require_relative '../proxies/return_proxy'
|
|
5
5
|
require_relative '../queries/type_query'
|
|
6
6
|
|
|
7
|
-
module
|
|
7
|
+
module Low
|
|
8
8
|
module TypeAccessors
|
|
9
9
|
def type_reader(named_expressions)
|
|
10
|
-
named_expressions.each do |name,
|
|
10
|
+
named_expressions.each do |name, exp|
|
|
11
11
|
last_caller = caller_locations(1, 1).first
|
|
12
|
-
type_expression = type_expression(expression)
|
|
13
12
|
file = FileProxy.new(path: last_caller.path, start_line: last_caller.lineno, scope: "#{self}##{name}")
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
expression = expression(exp)
|
|
15
|
+
@low_methods[name] = MethodProxy.new(name:, return_proxy: ReturnProxy.new(type_expression: expression, name:, file:))
|
|
16
16
|
|
|
17
17
|
define_method(name) do
|
|
18
18
|
method_proxy = self.class.low_methods[name]
|
|
19
19
|
value = instance_variable_get("@#{name}")
|
|
20
|
-
|
|
20
|
+
expression.validate!(value:, proxy: method_proxy.return_proxy)
|
|
21
21
|
value
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
def type_writer(named_expressions)
|
|
27
|
-
named_expressions.each do |name,
|
|
26
|
+
def type_writer(named_expressions) # rubocop:disable Metrics/AbcSize
|
|
27
|
+
named_expressions.each do |name, exp|
|
|
28
28
|
last_caller = caller_locations(1, 1).first
|
|
29
|
-
type_expression = type_expression(expression)
|
|
30
29
|
file = FileProxy.new(path: last_caller.path, start_line: last_caller.lineno, scope: "#{self}##{name}")
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
params = [ParamProxy.new(expression: expression(exp), name:, type: :hashreq, file:)]
|
|
32
|
+
@low_methods["#{name}="] = MethodProxy.new(name:, params:)
|
|
33
33
|
|
|
34
34
|
define_method("#{name}=") do |value|
|
|
35
35
|
method_proxy = self.class.low_methods["#{name}="]
|
|
36
|
-
|
|
36
|
+
method_proxy.params.first.expression.validate!(value:, proxy: method_proxy.params.first)
|
|
37
37
|
instance_variable_set("@#{name}", value)
|
|
38
38
|
end
|
|
39
39
|
end
|
|
@@ -48,10 +48,10 @@ module LowType
|
|
|
48
48
|
|
|
49
49
|
private
|
|
50
50
|
|
|
51
|
-
def
|
|
52
|
-
if expression.
|
|
51
|
+
def expression(expression)
|
|
52
|
+
if expression.is_a?(::Expressions::Expression)
|
|
53
53
|
expression
|
|
54
|
-
elsif ::
|
|
54
|
+
elsif ::Low::TypeQuery.type?(expression)
|
|
55
55
|
TypeExpression.new(type: expression)
|
|
56
56
|
end
|
|
57
57
|
end
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'expressions'
|
|
4
|
+
|
|
3
5
|
require_relative '../proxies/param_proxy'
|
|
4
6
|
require_relative '../queries/type_query'
|
|
5
7
|
|
|
6
|
-
module
|
|
8
|
+
module Low
|
|
7
9
|
root_path = File.expand_path(__dir__)
|
|
8
10
|
adapter_paths = Dir.chdir(root_path) { Dir.glob('adapters/*') }.map { |path| File.join(root_path, path) }
|
|
9
11
|
module_paths = %w[expressions/expressions instance_types redefiner].map { |path| File.join(root_path, "#{path}.rb") }
|
|
@@ -11,7 +13,7 @@ module LowType
|
|
|
11
13
|
HIDDEN_PATHS = [File.expand_path(__FILE__), *adapter_paths, *module_paths].freeze
|
|
12
14
|
|
|
13
15
|
# Represent types and default values as a series of chainable expressions.
|
|
14
|
-
class TypeExpression
|
|
16
|
+
class TypeExpression < ::Expressions::Expression
|
|
15
17
|
attr_reader :types, :default_value
|
|
16
18
|
|
|
17
19
|
# @param type - A literal type or an instance representation of a typed structure.
|
|
@@ -23,19 +25,6 @@ module LowType
|
|
|
23
25
|
@deep_type_check = LowType.config.deep_type_check
|
|
24
26
|
end
|
|
25
27
|
|
|
26
|
-
def |(expression)
|
|
27
|
-
if expression.instance_of?(::LowType::TypeExpression)
|
|
28
|
-
@types += expression.types
|
|
29
|
-
@default_value = expression.default_value
|
|
30
|
-
elsif ::LowType::TypeQuery.value?(expression)
|
|
31
|
-
@default_value = expression
|
|
32
|
-
else
|
|
33
|
-
@types << expression
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
self
|
|
37
|
-
end
|
|
38
|
-
|
|
39
28
|
def required?
|
|
40
29
|
@default_value == :LOW_TYPE_UNDEFINED
|
|
41
30
|
end
|
|
@@ -62,7 +51,7 @@ module LowType
|
|
|
62
51
|
if type.is_a?(Array)
|
|
63
52
|
"[#{type.map { |subtype| valid_subtype(subtype:) }.join(', ')}]"
|
|
64
53
|
else
|
|
65
|
-
type.inspect.to_s.delete_prefix('
|
|
54
|
+
type.inspect.to_s.delete_prefix('Low::')
|
|
66
55
|
end
|
|
67
56
|
end
|
|
68
57
|
|
|
@@ -72,13 +61,31 @@ module LowType
|
|
|
72
61
|
|
|
73
62
|
private
|
|
74
63
|
|
|
64
|
+
def union_expression(expression)
|
|
65
|
+
@types += expression.types
|
|
66
|
+
@default_value = expression.default_value
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def union_type(type)
|
|
70
|
+
@types << type
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def union_value(value)
|
|
74
|
+
@default_value = value
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Override Expressions as LowType supports complex types which are implemented as values.
|
|
78
|
+
def value?(expression)
|
|
79
|
+
::Low::TypeQuery.value?(expression) || expression.nil?
|
|
80
|
+
end
|
|
81
|
+
|
|
75
82
|
def valid_subtype(subtype:)
|
|
76
83
|
if subtype.is_a?(TypeExpression)
|
|
77
84
|
types = subtype.types
|
|
78
85
|
types << 'nil' if subtype.default_value.nil?
|
|
79
86
|
types.join(' | ')
|
|
80
87
|
else
|
|
81
|
-
subtype.to_s.delete_prefix('
|
|
88
|
+
subtype.to_s.delete_prefix('Low::')
|
|
82
89
|
end
|
|
83
90
|
end
|
|
84
91
|
|
|
@@ -122,10 +129,10 @@ module LowType
|
|
|
122
129
|
|
|
123
130
|
def type_matches_value?(type:, value:, proxy:)
|
|
124
131
|
if type.instance_of?(Class)
|
|
125
|
-
return type.match?(value:) if
|
|
132
|
+
return type.match?(value:) if Low::TypeQuery.complex_type?(expression: type)
|
|
126
133
|
|
|
127
134
|
return type == value.class
|
|
128
|
-
elsif type.instance_of?(::
|
|
135
|
+
elsif type.instance_of?(::Low::TypeExpression)
|
|
129
136
|
type.validate!(value:, proxy:)
|
|
130
137
|
return true
|
|
131
138
|
end
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'expressions'
|
|
4
|
+
|
|
3
5
|
require_relative '../expressions/expressions'
|
|
4
6
|
require_relative '../expressions/type_expression'
|
|
5
7
|
require_relative '../proxies/file_proxy'
|
|
@@ -8,7 +10,7 @@ require_relative '../proxies/return_proxy'
|
|
|
8
10
|
require_relative '../queries/file_parser'
|
|
9
11
|
require_relative '../syntax/syntax'
|
|
10
12
|
|
|
11
|
-
module
|
|
13
|
+
module Low
|
|
12
14
|
class ProxyFactory
|
|
13
15
|
using ::LowType::Syntax
|
|
14
16
|
|
|
@@ -22,25 +24,24 @@ module LowType
|
|
|
22
24
|
FileProxy.new(path:, start_line:, end_line:, scope:)
|
|
23
25
|
end
|
|
24
26
|
|
|
27
|
+
# The evals below aren't a security risk because the code comes from a trusted source; the file itself that did the include.
|
|
25
28
|
def param_proxies(method_node:, file:)
|
|
26
29
|
return [] if method_node.parameters.nil?
|
|
27
30
|
|
|
28
31
|
params_without_block = method_node.parameters.slice.delete_suffix(', &block')
|
|
29
32
|
|
|
30
|
-
# Not a security risk because the code comes from a trusted source; the file that did the include. Does the file trust itself?
|
|
31
33
|
ruby_method = eval("-> (#{params_without_block}) {}", binding, __FILE__, __LINE__) # rubocop:disable Security/Eval
|
|
32
34
|
|
|
33
|
-
#
|
|
34
|
-
# Local variable names are prefixed with __lt or __rb where necessary to avoid being overridden by method parameters.
|
|
35
|
+
# Local variable names are prefixed with __lt or __rb where needed to avoid being overridden by method parameters.
|
|
35
36
|
typed_method = <<~RUBY
|
|
36
37
|
-> (#{params_without_block}, __rb_method:, __lt_file:) {
|
|
37
|
-
|
|
38
|
+
param_proxies_for_expressions(ruby_method: __rb_method, file: __lt_file, method_binding: binding)
|
|
38
39
|
}
|
|
39
40
|
RUBY
|
|
40
41
|
|
|
41
|
-
# Called with only required args (as nil) and optional args omitted, to evaluate type expressions (from default values).
|
|
42
|
-
# Passes internal variables with namespaced names to avoid conflicts with the method parameters.
|
|
43
42
|
required_args, required_kwargs = required_args(ruby_method:)
|
|
43
|
+
|
|
44
|
+
# Called with only required args (as nil) and optional args omitted, to evaluate expressions stored as default values.
|
|
44
45
|
eval(typed_method, binding, __FILE__, __LINE__) # rubocop:disable Security/Eval
|
|
45
46
|
.call(*required_args, **required_kwargs, __rb_method: ruby_method, __lt_file: file)
|
|
46
47
|
|
|
@@ -85,22 +86,28 @@ module LowType
|
|
|
85
86
|
[required_args, required_kwargs]
|
|
86
87
|
end
|
|
87
88
|
|
|
88
|
-
def
|
|
89
|
+
def param_proxies_for_expressions(ruby_method:, file:, method_binding:)
|
|
89
90
|
param_proxies = []
|
|
90
91
|
|
|
91
92
|
ruby_method.parameters.each_with_index do |param, position|
|
|
92
93
|
type, name = param
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
94
|
+
|
|
95
|
+
# We don't support splatted *positional and **keyword arguments as by definition they are untyped.
|
|
96
|
+
next if type == :rest
|
|
97
|
+
|
|
98
|
+
position = nil unless %i[opt req].include?(type)
|
|
99
|
+
local_variable = method_binding.local_variable_get(name)
|
|
100
|
+
|
|
101
|
+
expression = nil
|
|
102
|
+
if local_variable.is_a?(::Expressions::Expression)
|
|
103
|
+
expression = local_variable
|
|
104
|
+
elsif local_variable.instance_of?(Class) && local_variable < ::Expressions::Expression
|
|
105
|
+
expression = local_variable.new(provider_key: name)
|
|
106
|
+
elsif ::Low::TypeQuery.type?(local_variable)
|
|
107
|
+
expression = TypeExpression.new(type: local_variable)
|
|
101
108
|
end
|
|
102
109
|
|
|
103
|
-
param_proxies << ParamProxy.new(
|
|
110
|
+
param_proxies << ParamProxy.new(expression:, name:, type:, position:, file:) if expression
|
|
104
111
|
end
|
|
105
112
|
|
|
106
113
|
param_proxies
|
data/lib/low_type.rb
CHANGED
|
@@ -20,25 +20,32 @@ module LowType
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
file_path = FileQuery.file_path(klass:)
|
|
23
|
+
file_path = Low::FileQuery.file_path(klass:)
|
|
24
24
|
return unless File.exist?(file_path)
|
|
25
25
|
|
|
26
|
-
parser = FileParser.new(klass:, file_path:)
|
|
26
|
+
parser = Low::FileParser.new(klass:, file_path:)
|
|
27
27
|
|
|
28
|
-
klass.extend TypeAccessors
|
|
29
|
-
klass.include Expressions
|
|
30
|
-
klass.prepend Redefiner.redefine(method_nodes: parser.instance_methods, class_proxy: parser.class_proxy, file_path:)
|
|
31
|
-
klass.singleton_class.prepend Redefiner.redefine(method_nodes: parser.class_methods, class_proxy: parser.class_proxy, file_path:)
|
|
28
|
+
klass.extend Low::TypeAccessors
|
|
29
|
+
klass.include Low::Expressions
|
|
30
|
+
klass.prepend Low::Redefiner.redefine(method_nodes: parser.instance_methods, class_proxy: parser.class_proxy, file_path:)
|
|
31
|
+
klass.singleton_class.prepend Low::Redefiner.redefine(method_nodes: parser.class_methods, class_proxy: parser.class_proxy, file_path:)
|
|
32
32
|
|
|
33
|
-
if (adapter = Adapter::Loader.load(klass:, parser:, file_path:))
|
|
33
|
+
if (adapter = Low::Adapter::Loader.load(klass:, parser:, file_path:))
|
|
34
34
|
adapter.process
|
|
35
|
-
klass.prepend Adapter::Methods
|
|
35
|
+
klass.prepend Low::Adapter::Methods
|
|
36
36
|
end
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
class << self
|
|
40
40
|
def config
|
|
41
|
-
config = Struct.new(
|
|
41
|
+
config = Struct.new(
|
|
42
|
+
:type_checking,
|
|
43
|
+
:error_mode,
|
|
44
|
+
:output_mode,
|
|
45
|
+
:output_size,
|
|
46
|
+
:deep_type_check,
|
|
47
|
+
:union_type_expressions
|
|
48
|
+
)
|
|
42
49
|
@config ||= config.new(true, :error, :type, 100, false, true)
|
|
43
50
|
end
|
|
44
51
|
|
data/lib/proxies/class_proxy.rb
CHANGED
data/lib/proxies/file_proxy.rb
CHANGED
data/lib/proxies/local_proxy.rb
CHANGED
data/lib/proxies/method_proxy.rb
CHANGED
data/lib/proxies/param_proxy.rb
CHANGED
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
require_relative '../interfaces/error_interface'
|
|
4
4
|
require_relative '../types/error_types'
|
|
5
5
|
|
|
6
|
-
module
|
|
6
|
+
module Low
|
|
7
7
|
class ParamProxy < ErrorInterface
|
|
8
|
-
attr_reader :
|
|
8
|
+
attr_reader :expression, :name, :type, :position
|
|
9
9
|
|
|
10
|
-
def initialize(
|
|
10
|
+
def initialize(expression:, name:, type:, file:, position: nil)
|
|
11
11
|
super()
|
|
12
12
|
|
|
13
|
-
@
|
|
13
|
+
@expression = expression
|
|
14
14
|
@name = name
|
|
15
15
|
@type = type
|
|
16
16
|
@position = position
|
|
@@ -18,7 +18,7 @@ module LowType
|
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def required?
|
|
21
|
-
@
|
|
21
|
+
@expression.required?
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
def error_type
|
|
@@ -26,7 +26,7 @@ module LowType
|
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
def error_message(value:)
|
|
29
|
-
"Invalid argument type '#{output(value:)}' for parameter '#{@name}'. Valid types: '#{@
|
|
29
|
+
"Invalid argument type '#{output(value:)}' for parameter '#{@name}'. Valid types: '#{@expression.valid_types}'"
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
32
|
end
|
data/lib/proxies/return_proxy.rb
CHANGED
data/lib/queries/file_parser.rb
CHANGED
data/lib/queries/file_query.rb
CHANGED
data/lib/queries/type_query.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative '../expressions/type_expression'
|
|
4
4
|
|
|
5
|
-
module
|
|
5
|
+
module Low
|
|
6
6
|
# TODO: Unit test.
|
|
7
7
|
class TypeQuery
|
|
8
8
|
class << self
|
|
@@ -19,7 +19,7 @@ module LowType
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def complex_type?(expression:)
|
|
22
|
-
|
|
22
|
+
Low::COMPLEX_TYPES.include?(expression) || typed_array?(expression:) || typed_hash?(expression:)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
private
|
data/lib/syntax/syntax.rb
CHANGED
|
@@ -6,7 +6,9 @@ module LowType
|
|
|
6
6
|
module Syntax
|
|
7
7
|
refine Array.singleton_class do
|
|
8
8
|
def [](*expression)
|
|
9
|
-
|
|
9
|
+
if Low::TypeQuery.type?(expression.first) || Low::TypeQuery.typed_array?(expression:)
|
|
10
|
+
return Low::TypeExpression.new(type: [*expression])
|
|
11
|
+
end
|
|
10
12
|
|
|
11
13
|
super
|
|
12
14
|
end
|
|
@@ -14,7 +16,7 @@ module LowType
|
|
|
14
16
|
|
|
15
17
|
refine Hash.singleton_class do
|
|
16
18
|
def [](type)
|
|
17
|
-
return TypeExpression.new(type:) if TypeQuery.type?(type)
|
|
19
|
+
return Low::TypeExpression.new(type:) if Low::TypeQuery.type?(type)
|
|
18
20
|
|
|
19
21
|
super
|
|
20
22
|
end
|
data/lib/syntax/union_types.rb
CHANGED
|
@@ -8,21 +8,13 @@
|
|
|
8
8
|
# @see LowType.config.union_type_expressions
|
|
9
9
|
###
|
|
10
10
|
class Object
|
|
11
|
-
# For "Type | [type_expression/type/value]" situations,
|
|
11
|
+
# For "Type | [type_expression/type/value]" situations, convert type into a type expression to continue the chain.
|
|
12
12
|
# "|" is not defined on Object class and this is the most compute-efficient way to achieve our goal (world peace).
|
|
13
13
|
# "|" is overridable by any child object. While we could def/undef this method, this approach is actually lighter.
|
|
14
14
|
# "|" bitwise operator on Integer is not defined when the receiver is an Integer class, so we are not in conflict.
|
|
15
15
|
class << self
|
|
16
16
|
def |(expression)
|
|
17
|
-
|
|
18
|
-
# We pass our type into their type expression.
|
|
19
|
-
expression | self
|
|
20
|
-
expression
|
|
21
|
-
else
|
|
22
|
-
# We turn our type into a type expression and pass in their type/value.
|
|
23
|
-
type_expression = ::LowType::TypeExpression.new(type: self)
|
|
24
|
-
type_expression | expression
|
|
25
|
-
end
|
|
17
|
+
::Low::TypeExpression.new(type: self) | expression
|
|
26
18
|
end
|
|
27
19
|
end
|
|
28
20
|
end
|
data/lib/types/complex_type.rb
CHANGED
data/lib/types/complex_types.rb
CHANGED
data/lib/types/error_types.rb
CHANGED
data/lib/types/status.rb
CHANGED
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,28 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: low_type
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.1.
|
|
4
|
+
version: 1.1.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
8
8
|
bindir: exe
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
-
dependencies:
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: expressions
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.1'
|
|
12
26
|
description: An elegant and simple way to define types in Ruby, only when you need
|
|
13
27
|
them.
|
|
14
28
|
email:
|
|
@@ -47,11 +61,11 @@ files:
|
|
|
47
61
|
- lib/types/error_types.rb
|
|
48
62
|
- lib/types/status.rb
|
|
49
63
|
- lib/version.rb
|
|
50
|
-
homepage: https://
|
|
64
|
+
homepage: https://github.com/low-rb/low_type
|
|
51
65
|
licenses: []
|
|
52
66
|
metadata:
|
|
53
|
-
homepage_uri: https://
|
|
54
|
-
source_code_uri: https://
|
|
67
|
+
homepage_uri: https://github.com/low-rb/low_type
|
|
68
|
+
source_code_uri: https://github.com/low-rb/low_type/src/branch/main
|
|
55
69
|
rdoc_options: []
|
|
56
70
|
require_paths:
|
|
57
71
|
- lib
|