low_type 1.0.6 → 1.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.
- checksums.yaml +4 -4
- data/lib/factories/expression_factory.rb +14 -0
- data/lib/factories/proxy_factory.rb +1 -1
- data/lib/instance_types.rb +2 -1
- data/lib/interfaces/error_interface.rb +17 -0
- data/lib/local_types.rb +2 -3
- data/lib/low_type.rb +8 -42
- data/lib/proxies/local_proxy.rb +3 -1
- data/lib/proxies/param_proxy.rb +3 -1
- data/lib/proxies/return_proxy.rb +3 -1
- data/lib/{file_parser.rb → queries/file_parser.rb} +1 -1
- data/lib/queries/file_query.rb +23 -0
- data/lib/queries/type_query.rb +28 -0
- data/lib/redefiner.rb +6 -5
- data/lib/syntax/syntax.rb +6 -2
- data/lib/syntax/union_types.rb +2 -0
- data/lib/type_expression.rb +3 -2
- data/lib/version.rb +1 -1
- metadata +5 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e3e1dca0d960082a4de505f3422e00c648f660306c22d24db65590db0543f5e
|
|
4
|
+
data.tar.gz: a87156e750aee311a9afb2a95166a9d00f99a744c05fc1dac0d9ab7120882760
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f8e3054ab427c0635aa27f78ae966e3a90c9f78ec660651d6025956ddc83582a1b46f66268e7a335d8ff72ed87bf92a09672a38509067d42d3b79253a97e8d49
|
|
7
|
+
data.tar.gz: 4698ae94c57a2de408ba085029f18b1bc100375972f3f253294dfcef71741d959da1db6773544f4bf55133d5a95d3e2eee44f274f167c503e7f462489e247153
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative '../type_expression'
|
|
4
|
+
require_relative '../value_expression'
|
|
5
|
+
|
|
6
|
+
module LowType
|
|
7
|
+
class ExpressionFactory
|
|
8
|
+
class << self
|
|
9
|
+
def type_expression_with_value(type:)
|
|
10
|
+
TypeExpression.new(default_value: ValueExpression.new(value: type))
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/instance_types.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'proxies/return_proxy'
|
|
4
|
+
require_relative 'queries/type_query'
|
|
4
5
|
require_relative 'type_expression'
|
|
5
6
|
|
|
6
7
|
module LowType
|
|
@@ -50,7 +51,7 @@ module LowType
|
|
|
50
51
|
def type_expression(expression)
|
|
51
52
|
if expression.instance_of?(TypeExpression)
|
|
52
53
|
expression
|
|
53
|
-
elsif ::LowType.type?(expression)
|
|
54
|
+
elsif ::LowType::TypeQuery.type?(expression)
|
|
54
55
|
TypeExpression.new(type: expression)
|
|
55
56
|
end
|
|
56
57
|
end
|
|
@@ -4,6 +4,23 @@ module LowType
|
|
|
4
4
|
class ErrorInterface
|
|
5
5
|
attr_reader :file
|
|
6
6
|
|
|
7
|
+
def initialize
|
|
8
|
+
@file = nil
|
|
9
|
+
@output_mode = LowType.config.output_mode
|
|
10
|
+
@output_size = LowType.config.output_size
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def output(value:)
|
|
14
|
+
case @output_mode
|
|
15
|
+
when :type
|
|
16
|
+
value.class
|
|
17
|
+
when :value
|
|
18
|
+
value.inspect[0...@output_size]
|
|
19
|
+
else
|
|
20
|
+
'REDACTED'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
7
24
|
def error_type
|
|
8
25
|
raise NotImplementedError
|
|
9
26
|
end
|
data/lib/local_types.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'factories/expression_factory'
|
|
3
4
|
require_relative 'proxies/file_proxy'
|
|
4
5
|
require_relative 'proxies/local_proxy'
|
|
5
6
|
require_relative 'types/error_types'
|
|
6
|
-
require_relative 'type_expression'
|
|
7
|
-
require_relative 'value_expression'
|
|
8
7
|
|
|
9
8
|
module LowType
|
|
10
9
|
module LocalTypes
|
|
@@ -26,7 +25,7 @@ module LowType
|
|
|
26
25
|
alias low_type type
|
|
27
26
|
|
|
28
27
|
def value(type)
|
|
29
|
-
|
|
28
|
+
ExpressionFactory.type_expression_with_value(type:)
|
|
30
29
|
end
|
|
31
30
|
alias low_value value
|
|
32
31
|
end
|
data/lib/low_type.rb
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'adapters/adapter_loader'
|
|
4
|
+
require_relative 'syntax/syntax'
|
|
4
5
|
require_relative 'types/complex_types'
|
|
6
|
+
require_relative 'queries/file_parser'
|
|
7
|
+
require_relative 'queries/file_query'
|
|
5
8
|
require_relative 'instance_types'
|
|
6
9
|
require_relative 'local_types'
|
|
7
10
|
require_relative 'redefiner'
|
|
8
|
-
require_relative 'syntax/syntax'
|
|
9
|
-
require_relative 'type_expression'
|
|
10
|
-
require_relative 'value_expression'
|
|
11
11
|
|
|
12
12
|
module LowType
|
|
13
13
|
# We do as much as possible on class load rather than on instantiation to be thread-safe and efficient.
|
|
@@ -20,14 +20,14 @@ module LowType
|
|
|
20
20
|
end
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
file_path =
|
|
23
|
+
file_path = FileQuery.file_path(klass:)
|
|
24
24
|
parser = FileParser.new(klass:, file_path:)
|
|
25
25
|
line_numbers = parser.line_numbers
|
|
26
26
|
|
|
27
27
|
klass.extend InstanceTypes
|
|
28
28
|
klass.include LocalTypes
|
|
29
|
-
klass.prepend
|
|
30
|
-
klass.singleton_class.prepend
|
|
29
|
+
klass.prepend Redefiner.redefine(method_nodes: parser.instance_methods, klass:, line_numbers:, file_path:)
|
|
30
|
+
klass.singleton_class.prepend Redefiner.redefine(method_nodes: parser.class_methods, klass:, line_numbers:, file_path:)
|
|
31
31
|
|
|
32
32
|
if (adapter = Adapter::Loader.load(klass:, parser:, file_path:))
|
|
33
33
|
adapter.process
|
|
@@ -36,47 +36,13 @@ module LowType
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
class << self
|
|
39
|
-
# Public API.
|
|
40
|
-
|
|
41
39
|
def config
|
|
42
|
-
config = Struct.new(:
|
|
43
|
-
@config ||= config.new(
|
|
40
|
+
config = Struct.new(:error_mode, :output_mode, :output_size, :deep_type_check, :union_type_expressions)
|
|
41
|
+
@config ||= config.new(:error, :type, 100, false, true)
|
|
44
42
|
end
|
|
45
43
|
|
|
46
44
|
def configure
|
|
47
45
|
yield(config)
|
|
48
46
|
end
|
|
49
|
-
|
|
50
|
-
# Internal API.
|
|
51
|
-
|
|
52
|
-
def file_path
|
|
53
|
-
includer_file = caller.find { |callee| callee.end_with?("include'") }
|
|
54
|
-
includer_file.split(':').first
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# TODO: Unit test.
|
|
58
|
-
def type?(type)
|
|
59
|
-
LowType.basic_type?(type:) || LowType.complex_type?(type:)
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
def basic_type?(type:)
|
|
63
|
-
type.class == Class
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
def complex_type?(type:)
|
|
67
|
-
!basic_type?(type:) && LowType.typed_hash?(type:)
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
def typed_hash?(type:)
|
|
71
|
-
type.is_a?(::Hash) && LowType.basic_type?(type: type.keys.first) && LowType.basic_type?(type: type.values.first)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
def value?(expression)
|
|
75
|
-
!expression.respond_to?(:new) && expression != Integer
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def value(type:)
|
|
79
|
-
TypeExpression.new(default_value: ValueExpression.new(value: type))
|
|
80
|
-
end
|
|
81
47
|
end
|
|
82
48
|
end
|
data/lib/proxies/local_proxy.rb
CHANGED
|
@@ -8,6 +8,8 @@ module LowType
|
|
|
8
8
|
attr_reader :type_expression, :name
|
|
9
9
|
|
|
10
10
|
def initialize(type_expression:, name:, file:)
|
|
11
|
+
super()
|
|
12
|
+
|
|
11
13
|
@type_expression = type_expression
|
|
12
14
|
@name = name
|
|
13
15
|
@file = file
|
|
@@ -18,7 +20,7 @@ module LowType
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def error_message(value:)
|
|
21
|
-
"Invalid variable type #{value
|
|
23
|
+
"Invalid variable type #{output(value:)} in '#{@name.class}' on line #{@file.line}. Valid types: '#{@type_expression.valid_types}'"
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|
data/lib/proxies/param_proxy.rb
CHANGED
|
@@ -8,6 +8,8 @@ module LowType
|
|
|
8
8
|
attr_reader :type_expression, :name, :type, :position
|
|
9
9
|
|
|
10
10
|
def initialize(type_expression:, name:, type:, file:, position: nil)
|
|
11
|
+
super()
|
|
12
|
+
|
|
11
13
|
@type_expression = type_expression
|
|
12
14
|
@name = name
|
|
13
15
|
@type = type
|
|
@@ -20,7 +22,7 @@ module LowType
|
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def error_message(value:)
|
|
23
|
-
"Invalid argument type '#{value
|
|
25
|
+
"Invalid argument type '#{output(value:)}' for parameter '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
data/lib/proxies/return_proxy.rb
CHANGED
|
@@ -8,6 +8,8 @@ module LowType
|
|
|
8
8
|
attr_reader :type_expression, :name
|
|
9
9
|
|
|
10
10
|
def initialize(type_expression:, name:, file:)
|
|
11
|
+
super()
|
|
12
|
+
|
|
11
13
|
@type_expression = type_expression
|
|
12
14
|
@name = name
|
|
13
15
|
@file = file
|
|
@@ -18,7 +20,7 @@ module LowType
|
|
|
18
20
|
end
|
|
19
21
|
|
|
20
22
|
def error_message(value:)
|
|
21
|
-
"Invalid return type '#{value
|
|
23
|
+
"Invalid return type '#{output(value:)}' for method '#{@name}'. Valid types: '#{@type_expression.valid_types}'"
|
|
22
24
|
end
|
|
23
25
|
end
|
|
24
26
|
end
|
|
@@ -62,7 +62,7 @@ module LowType
|
|
|
62
62
|
|
|
63
63
|
@instance_methods = []
|
|
64
64
|
@class_methods = []
|
|
65
|
-
@line_numbers = { class_start: 0, class_end: root_node.respond_to?(:end_line) ? root_node.end_line : nil}
|
|
65
|
+
@line_numbers = { class_start: 0, class_end: root_node.respond_to?(:end_line) ? root_node.end_line : nil }
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def visit_def_node(node)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LowType
|
|
4
|
+
class FileQuery
|
|
5
|
+
class << self
|
|
6
|
+
def file_path(klass:)
|
|
7
|
+
includer_line = line_from_class(klass:) || line_from_include || ''
|
|
8
|
+
includer_line.split(':').first || ''
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
private
|
|
12
|
+
|
|
13
|
+
def line_from_class(klass:)
|
|
14
|
+
class_name = klass.to_s.split(':').last # Also remove the module namespaces from the class.
|
|
15
|
+
caller.find { |callee| callee.end_with?("<class:#{class_name}>'") }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def line_from_include
|
|
19
|
+
caller.find { |callee| callee.end_with?("include'") }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LowType
|
|
4
|
+
# TODO: Unit test.
|
|
5
|
+
class TypeQuery
|
|
6
|
+
class << self
|
|
7
|
+
def type?(type)
|
|
8
|
+
basic_type?(type:) || complex_type?(type:)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def basic_type?(type:)
|
|
12
|
+
type.instance_of?(Class)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def complex_type?(type:)
|
|
16
|
+
!basic_type?(type:) && typed_hash?(type:)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def typed_hash?(type:)
|
|
20
|
+
type.is_a?(::Hash) && basic_type?(type: type.keys.first) && basic_type?(type: type.values.first)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def value?(expression)
|
|
24
|
+
!expression.respond_to?(:new) && expression != Integer
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
data/lib/redefiner.rb
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative 'factories/expression_factory'
|
|
3
4
|
require_relative 'factories/proxy_factory'
|
|
4
5
|
require_relative 'proxies/file_proxy'
|
|
5
6
|
require_relative 'proxies/method_proxy'
|
|
6
7
|
require_relative 'proxies/param_proxy'
|
|
8
|
+
require_relative 'queries/type_query'
|
|
7
9
|
require_relative 'syntax/syntax'
|
|
8
10
|
require_relative 'type_expression'
|
|
11
|
+
require_relative 'value_expression'
|
|
9
12
|
|
|
10
13
|
module LowType
|
|
11
14
|
# Redefine methods to have their arguments and return values type checked.
|
|
@@ -42,9 +45,7 @@ module LowType
|
|
|
42
45
|
method_start = method_node.respond_to?(:start_line) ? method_node.start_line : nil
|
|
43
46
|
method_end = method_node.respond_to?(:end_line) ? method_node.end_line : nil
|
|
44
47
|
|
|
45
|
-
if method_start && method_end && class_end
|
|
46
|
-
next unless method_start > class_start && method_end <= class_end
|
|
47
|
-
end
|
|
48
|
+
next if method_start && method_end && class_end && !(method_start > class_start && method_end <= class_end)
|
|
48
49
|
|
|
49
50
|
name = method_node.name
|
|
50
51
|
|
|
@@ -96,7 +97,7 @@ module LowType
|
|
|
96
97
|
|
|
97
98
|
if expression.is_a?(TypeExpression)
|
|
98
99
|
param_proxies << ParamProxy.new(type_expression: expression, name:, type:, position:, file:)
|
|
99
|
-
elsif ::LowType.type?(expression)
|
|
100
|
+
elsif ::LowType::TypeQuery.type?(expression)
|
|
100
101
|
param_proxies << ParamProxy.new(type_expression: TypeExpression.new(type: expression), name:, type:, position:, file:)
|
|
101
102
|
end
|
|
102
103
|
end
|
|
@@ -139,7 +140,7 @@ module LowType
|
|
|
139
140
|
|
|
140
141
|
# Value expressions are eval()'d in the context of this module class (the instance doesn't exist yet) so alias API.
|
|
141
142
|
def value(type)
|
|
142
|
-
|
|
143
|
+
ExpressionFactory.type_expression_with_value(type:)
|
|
143
144
|
end
|
|
144
145
|
end
|
|
145
146
|
end
|
data/lib/syntax/syntax.rb
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../queries/type_query'
|
|
4
|
+
|
|
3
5
|
module LowType
|
|
4
6
|
module Syntax
|
|
5
7
|
refine Array.singleton_class do
|
|
6
8
|
def [](*types)
|
|
7
|
-
return
|
|
9
|
+
return TypeExpression.new(type: [*types]) if types.all? { |type| TypeQuery.type?(type) }
|
|
10
|
+
|
|
8
11
|
super
|
|
9
12
|
end
|
|
10
13
|
end
|
|
11
14
|
|
|
12
15
|
refine Hash.singleton_class do
|
|
13
16
|
def [](type)
|
|
14
|
-
return
|
|
17
|
+
return TypeExpression.new(type:) if TypeQuery.type?(type)
|
|
18
|
+
|
|
15
19
|
super
|
|
16
20
|
end
|
|
17
21
|
end
|
data/lib/syntax/union_types.rb
CHANGED
data/lib/type_expression.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'proxies/param_proxy'
|
|
4
|
+
require_relative 'queries/type_query'
|
|
4
5
|
|
|
5
6
|
module LowType
|
|
6
7
|
root_path = File.expand_path(__dir__)
|
|
@@ -24,7 +25,7 @@ module LowType
|
|
|
24
25
|
if expression.instance_of?(::LowType::TypeExpression)
|
|
25
26
|
@types += expression.types
|
|
26
27
|
@default_value = expression.default_value
|
|
27
|
-
elsif ::LowType.value?(expression)
|
|
28
|
+
elsif ::LowType::TypeQuery.value?(expression)
|
|
28
29
|
@default_value = expression
|
|
29
30
|
else
|
|
30
31
|
@types << expression
|
|
@@ -45,7 +46,7 @@ module LowType
|
|
|
45
46
|
|
|
46
47
|
@types.each do |type|
|
|
47
48
|
# Example: HTML is a subclass of String and should pass as a String.
|
|
48
|
-
return true if LowType.basic_type?(type:) && type <= value.class
|
|
49
|
+
return true if LowType::TypeQuery.basic_type?(type:) && type <= value.class
|
|
49
50
|
return true if type.is_a?(::Array) && value.is_a?(::Array) && array_types_match_values?(types: type, values: value)
|
|
50
51
|
return true if type.is_a?(::Hash) && value.is_a?(::Hash) && hash_types_match_values?(type:, value:)
|
|
51
52
|
end
|
data/lib/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: low_type
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -19,8 +19,8 @@ extra_rdoc_files: []
|
|
|
19
19
|
files:
|
|
20
20
|
- lib/adapters/adapter_loader.rb
|
|
21
21
|
- lib/adapters/sinatra_adapter.rb
|
|
22
|
+
- lib/factories/expression_factory.rb
|
|
22
23
|
- lib/factories/proxy_factory.rb
|
|
23
|
-
- lib/file_parser.rb
|
|
24
24
|
- lib/instance_types.rb
|
|
25
25
|
- lib/interfaces/adapter_interface.rb
|
|
26
26
|
- lib/interfaces/error_interface.rb
|
|
@@ -31,6 +31,9 @@ files:
|
|
|
31
31
|
- lib/proxies/method_proxy.rb
|
|
32
32
|
- lib/proxies/param_proxy.rb
|
|
33
33
|
- lib/proxies/return_proxy.rb
|
|
34
|
+
- lib/queries/file_parser.rb
|
|
35
|
+
- lib/queries/file_query.rb
|
|
36
|
+
- lib/queries/type_query.rb
|
|
34
37
|
- lib/redefiner.rb
|
|
35
38
|
- lib/syntax/syntax.rb
|
|
36
39
|
- lib/syntax/union_types.rb
|