low_type 1.1.0 → 1.1.2
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/sinatra_adapter.rb +2 -3
- data/lib/{redefiner.rb → definitions/redefiner.rb} +48 -38
- data/lib/definitions/repository.rb +32 -0
- data/lib/{instance_types.rb → definitions/type_accessors.rb} +6 -6
- data/lib/{local_types.rb → expressions/expressions.rb} +6 -6
- data/lib/{type_expression.rb → expressions/type_expression.rb} +4 -4
- data/lib/factories/expression_factory.rb +2 -2
- data/lib/factories/proxy_factory.rb +9 -1
- data/lib/interfaces/error_interface.rb +1 -1
- data/lib/low_type.rb +9 -10
- data/lib/proxies/class_proxy.rb +20 -0
- data/lib/proxies/file_proxy.rb +9 -3
- data/lib/proxies/local_proxy.rb +1 -1
- data/lib/proxies/method_proxy.rb +10 -2
- data/lib/queries/file_parser.rb +18 -21
- data/lib/queries/type_query.rb +14 -14
- data/lib/syntax/syntax.rb +2 -2
- data/lib/version.rb +1 -1
- metadata +8 -6
- /data/lib/{value_expression.rb → expressions/value_expression.rb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f2ff86050dbdbbaf494210b5ccb0ca36735305cae2a90701d406ee41830eb8b1
|
|
4
|
+
data.tar.gz: 5345157740d454fa13dbf8d78c37e989b1e1a5a7e0e76cf914b5d9b8da324c58
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 75b594af3ac1947a5adda7a9b56d1e31a2fecb95098f48be0b0af54f16364d3c43cad27412e19f3f525f06864a9c5e7b74f45f6f41734641287bb76160e4c17d
|
|
7
|
+
data.tar.gz: 423c63f4242bb7c4bf3fdbea6786eba6fc8408fd1c16ba26cd2400e6963e86e2f5ba38882bbe1cba167e42a334bf8fd85a5b320b7d5a1975b0c8a756886643f8
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'prism'
|
|
4
4
|
|
|
5
|
+
require_relative '../factories/proxy_factory'
|
|
5
6
|
require_relative '../interfaces/adapter_interface'
|
|
6
|
-
require_relative '../proxies/file_proxy'
|
|
7
7
|
require_relative '../proxies/return_proxy'
|
|
8
8
|
require_relative '../types/error_types'
|
|
9
9
|
|
|
@@ -27,8 +27,7 @@ module LowType
|
|
|
27
27
|
|
|
28
28
|
pattern = arguments_node.arguments.first.content
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
file = FileProxy.new(path: @file_path, line:, scope: "#{@klass}##{method_call.name}")
|
|
30
|
+
file = ProxyFactory.file_proxy(node: method_call, path: @file_path, scope: "#{@klass}##{method_call.name}")
|
|
32
31
|
next unless (return_proxy = return_proxy(method_node: method_call, pattern:, file:))
|
|
33
32
|
|
|
34
33
|
route = "#{method_call.name.upcase} #{pattern}"
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative '
|
|
5
|
-
require_relative '
|
|
6
|
-
require_relative '
|
|
7
|
-
require_relative '
|
|
8
|
-
require_relative '
|
|
9
|
-
require_relative '
|
|
10
|
-
require_relative '
|
|
11
|
-
require_relative '
|
|
3
|
+
require_relative '../expressions/expressions'
|
|
4
|
+
require_relative '../expressions/type_expression'
|
|
5
|
+
require_relative '../expressions/value_expression'
|
|
6
|
+
require_relative '../factories/expression_factory'
|
|
7
|
+
require_relative '../factories/proxy_factory'
|
|
8
|
+
require_relative '../proxies/file_proxy'
|
|
9
|
+
require_relative '../proxies/method_proxy'
|
|
10
|
+
require_relative '../proxies/param_proxy'
|
|
11
|
+
require_relative '../queries/type_query'
|
|
12
|
+
require_relative '../syntax/syntax'
|
|
13
|
+
require_relative 'repository'
|
|
12
14
|
|
|
13
15
|
module LowType
|
|
14
16
|
# Redefine methods to have their arguments and return values type checked.
|
|
@@ -16,44 +18,57 @@ module LowType
|
|
|
16
18
|
using Syntax
|
|
17
19
|
|
|
18
20
|
class << self
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
include Expressions
|
|
22
|
+
|
|
23
|
+
def redefine(method_nodes:, class_proxy:, file_path:)
|
|
24
|
+
method_proxies = create_method_proxies(method_nodes:, klass: class_proxy.klass, file_path:)
|
|
25
|
+
define_methods(method_proxies:, class_proxy:)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def redefinable?(method_proxy:, class_proxy:)
|
|
29
|
+
# Method has no types.
|
|
30
|
+
if method_proxy.params == [] && method_proxy.return_proxy.nil?
|
|
31
|
+
LowType::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
32
|
+
return false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Method outside class bounds.
|
|
36
|
+
within_bounds = method_proxy.start_line > class_proxy.start_line && method_proxy.end_line <= class_proxy.end_line
|
|
37
|
+
if method_proxy.lines? && class_proxy.lines? && !within_bounds
|
|
38
|
+
LowType::Repository.delete(name: method_proxy.name, klass: class_proxy.klass)
|
|
39
|
+
return false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
true
|
|
22
43
|
end
|
|
23
44
|
|
|
24
45
|
private
|
|
25
46
|
|
|
26
|
-
def
|
|
27
|
-
method_nodes.each do |method_node|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
params = param_proxies(method_node:, file:)
|
|
47
|
+
def create_method_proxies(method_nodes:, klass:, file_path:)
|
|
48
|
+
method_nodes.each do |name, method_node|
|
|
49
|
+
file = ProxyFactory.file_proxy(path: file_path, node: method_node, scope: "#{klass}##{name}")
|
|
50
|
+
|
|
51
|
+
param_proxies = param_proxies(method_node:, file:)
|
|
32
52
|
return_proxy = ProxyFactory.return_proxy(method_node:, file:)
|
|
53
|
+
method_proxy = MethodProxy.new(name:, params: param_proxies, return_proxy:, file:)
|
|
33
54
|
|
|
34
|
-
|
|
55
|
+
Repository.save(method: method_proxy, klass:)
|
|
35
56
|
end
|
|
36
|
-
end
|
|
37
57
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class_end = line_numbers[:class_end]
|
|
41
|
-
private_start = line_numbers[:private_start]
|
|
58
|
+
Repository.all(klass:)
|
|
59
|
+
end
|
|
42
60
|
|
|
61
|
+
def define_methods(method_proxies:, class_proxy:) # rubocop:disable Metrics
|
|
43
62
|
Module.new do
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
method_end = method_node.respond_to?(:end_line) ? method_node.end_line : nil
|
|
47
|
-
|
|
48
|
-
next if method_start && method_end && class_end && !(method_start > class_start && method_end <= class_end)
|
|
49
|
-
|
|
50
|
-
name = method_node.name
|
|
63
|
+
method_proxies.each do |name, method_proxy|
|
|
64
|
+
next unless LowType::Redefiner.redefinable?(method_proxy:, class_proxy:)
|
|
51
65
|
|
|
66
|
+
# NOTE: You are now in the binding of the includer class (`name` is also available here).
|
|
52
67
|
define_method(name) do |*args, **kwargs|
|
|
68
|
+
# Inlined version of Repository.load() for performance increase.
|
|
53
69
|
method_proxy = instance_of?(Class) ? low_methods[name] : self.class.low_methods[name] || Object.low_methods[name]
|
|
54
70
|
|
|
55
71
|
method_proxy.params.each do |param_proxy|
|
|
56
|
-
# Get argument value or default value.
|
|
57
72
|
value = param_proxy.position ? args[param_proxy.position] : kwargs[param_proxy.name]
|
|
58
73
|
if value.nil? && param_proxy.type_expression.default_value != :LOW_TYPE_UNDEFINED
|
|
59
74
|
value = param_proxy.type_expression.default_value
|
|
@@ -73,7 +88,7 @@ module LowType
|
|
|
73
88
|
super(*args, **kwargs)
|
|
74
89
|
end
|
|
75
90
|
|
|
76
|
-
private name if
|
|
91
|
+
private name if class_proxy.private_start_line && method_proxy.start_line > class_proxy.private_start_line
|
|
77
92
|
end
|
|
78
93
|
end
|
|
79
94
|
end
|
|
@@ -137,11 +152,6 @@ module LowType
|
|
|
137
152
|
|
|
138
153
|
[required_args, required_kwargs]
|
|
139
154
|
end
|
|
140
|
-
|
|
141
|
-
# Value expressions are eval()'d in the context of this module class (the instance doesn't exist yet) so alias API.
|
|
142
|
-
def value(type)
|
|
143
|
-
ExpressionFactory.type_expression_with_value(type:)
|
|
144
|
-
end
|
|
145
155
|
end
|
|
146
156
|
end
|
|
147
157
|
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module LowType
|
|
4
|
+
class Repository
|
|
5
|
+
class << self
|
|
6
|
+
def all(klass:)
|
|
7
|
+
klass.low_methods
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def save(method:, klass:)
|
|
11
|
+
klass.low_methods[method.name] = method
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def delete(name:, klass:)
|
|
15
|
+
klass.low_methods.delete(name)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Redefiner inlines this method in define_method() for better performance. TODO: Test this assumption.
|
|
19
|
+
def load(name:, object:)
|
|
20
|
+
singleton(object:).low_methods[name]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# TODO: export() to RBS
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def singleton(object:)
|
|
28
|
+
object.instance_of?(Class) ? object : object.class || Object
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '
|
|
4
|
-
require_relative '
|
|
5
|
-
require_relative '
|
|
3
|
+
require_relative '../expressions/type_expression'
|
|
4
|
+
require_relative '../proxies/return_proxy'
|
|
5
|
+
require_relative '../queries/type_query'
|
|
6
6
|
|
|
7
7
|
module LowType
|
|
8
|
-
module
|
|
8
|
+
module TypeAccessors
|
|
9
9
|
def type_reader(named_expressions)
|
|
10
10
|
named_expressions.each do |name, expression|
|
|
11
11
|
last_caller = caller_locations(1, 1).first
|
|
12
12
|
type_expression = type_expression(expression)
|
|
13
|
-
file = FileProxy.new(path: last_caller.path,
|
|
13
|
+
file = FileProxy.new(path: last_caller.path, start_line: last_caller.lineno, scope: "#{self}##{name}")
|
|
14
14
|
|
|
15
15
|
@low_methods[name] = MethodProxy.new(name:, return_proxy: ReturnProxy.new(type_expression:, name:, file:))
|
|
16
16
|
|
|
@@ -27,7 +27,7 @@ module LowType
|
|
|
27
27
|
named_expressions.each do |name, expression|
|
|
28
28
|
last_caller = caller_locations(1, 1).first
|
|
29
29
|
type_expression = type_expression(expression)
|
|
30
|
-
file = FileProxy.new(path: last_caller.path,
|
|
30
|
+
file = FileProxy.new(path: last_caller.path, start_line: last_caller.lineno, scope: "#{self}##{name}")
|
|
31
31
|
|
|
32
32
|
@low_methods["#{name}="] = MethodProxy.new(name:, params: [ParamProxy.new(type_expression:, name:, type: :hashreq, file:)])
|
|
33
33
|
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'factories/expression_factory'
|
|
4
|
-
require_relative 'proxies/file_proxy'
|
|
5
|
-
require_relative 'proxies/local_proxy'
|
|
6
|
-
require_relative 'types/error_types'
|
|
3
|
+
require_relative '../factories/expression_factory'
|
|
4
|
+
require_relative '../proxies/file_proxy'
|
|
5
|
+
require_relative '../proxies/local_proxy'
|
|
6
|
+
require_relative '../types/error_types'
|
|
7
7
|
|
|
8
8
|
module LowType
|
|
9
|
-
module
|
|
9
|
+
module Expressions
|
|
10
10
|
def type(type_expression)
|
|
11
11
|
value = type_expression.default_value
|
|
12
12
|
|
|
13
13
|
last_caller = caller_locations(1, 1).first
|
|
14
|
-
file = FileProxy.new(path: last_caller.path,
|
|
14
|
+
file = FileProxy.new(path: last_caller.path, start_line: last_caller.lineno, scope: 'local type')
|
|
15
15
|
proxy = LocalProxy.new(type_expression:, name: self, file:)
|
|
16
16
|
|
|
17
17
|
type_expression.validate!(value:, proxy:)
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative 'proxies/param_proxy'
|
|
4
|
-
require_relative 'queries/type_query'
|
|
3
|
+
require_relative '../proxies/param_proxy'
|
|
4
|
+
require_relative '../queries/type_query'
|
|
5
5
|
|
|
6
6
|
module LowType
|
|
7
7
|
root_path = File.expand_path(__dir__)
|
|
8
8
|
adapter_paths = Dir.chdir(root_path) { Dir.glob('adapters/*') }.map { |path| File.join(root_path, path) }
|
|
9
|
-
module_paths = %w[instance_types
|
|
9
|
+
module_paths = %w[expressions/expressions instance_types redefiner].map { |path| File.join(root_path, "#{path}.rb") }
|
|
10
10
|
|
|
11
11
|
HIDDEN_PATHS = [File.expand_path(__FILE__), *adapter_paths, *module_paths].freeze
|
|
12
12
|
|
|
@@ -122,7 +122,7 @@ module LowType
|
|
|
122
122
|
|
|
123
123
|
def type_matches_value?(type:, value:, proxy:)
|
|
124
124
|
if type.instance_of?(Class)
|
|
125
|
-
return type.match?(value:) if LowType::TypeQuery.complex_type?(type
|
|
125
|
+
return type.match?(value:) if LowType::TypeQuery.complex_type?(expression: type)
|
|
126
126
|
|
|
127
127
|
return type == value.class
|
|
128
128
|
elsif type.instance_of?(::LowType::TypeExpression)
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative '../expressions/type_expression'
|
|
4
|
+
require_relative '../proxies/file_proxy'
|
|
3
5
|
require_relative '../proxies/return_proxy'
|
|
4
6
|
require_relative '../queries/file_parser'
|
|
5
|
-
require_relative '../type_expression'
|
|
6
7
|
|
|
7
8
|
module LowType
|
|
8
9
|
class ProxyFactory
|
|
9
10
|
class << self
|
|
11
|
+
def file_proxy(node:, path:, scope:)
|
|
12
|
+
start_line = node.respond_to?(:start_line) ? node.start_line : nil
|
|
13
|
+
end_line = node.respond_to?(:end_line) ? node.end_line : nil
|
|
14
|
+
|
|
15
|
+
FileProxy.new(path:, start_line:, end_line:, scope:)
|
|
16
|
+
end
|
|
17
|
+
|
|
10
18
|
def return_proxy(method_node:, file:)
|
|
11
19
|
return_type = FileParser.return_type(method_node:)
|
|
12
20
|
return nil if return_type.nil?
|
|
@@ -35,7 +35,7 @@ module LowType
|
|
|
35
35
|
filtered_backtrace = backtrace.reject { |line| hidden_paths.find { |file_path| line.include?(file_path) } }
|
|
36
36
|
|
|
37
37
|
# Add the proxied file to the backtrace.
|
|
38
|
-
proxy_file_backtrace = "#{file.path}:#{file.
|
|
38
|
+
proxy_file_backtrace = "#{file.path}:#{file.start_line}:in '#{file.scope}'"
|
|
39
39
|
from_prefix = filtered_backtrace.first.match(/\s+from /)
|
|
40
40
|
proxy_file_backtrace = "#{from_prefix}#{proxy_file_backtrace}" if from_prefix
|
|
41
41
|
|
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 '
|
|
5
|
-
require_relative '
|
|
4
|
+
require_relative 'definitions/redefiner'
|
|
5
|
+
require_relative 'definitions/type_accessors'
|
|
6
|
+
require_relative 'expressions/expressions'
|
|
6
7
|
require_relative 'queries/file_parser'
|
|
7
8
|
require_relative 'queries/file_query'
|
|
8
|
-
require_relative '
|
|
9
|
-
require_relative '
|
|
10
|
-
require_relative 'redefiner'
|
|
9
|
+
require_relative 'syntax/syntax'
|
|
10
|
+
require_relative 'types/complex_types'
|
|
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.
|
|
@@ -22,12 +22,11 @@ module LowType
|
|
|
22
22
|
|
|
23
23
|
file_path = FileQuery.file_path(klass:)
|
|
24
24
|
parser = FileParser.new(klass:, file_path:)
|
|
25
|
-
line_numbers = parser.line_numbers
|
|
26
25
|
|
|
27
|
-
klass.extend
|
|
28
|
-
klass.include
|
|
29
|
-
klass.prepend Redefiner.redefine(method_nodes: parser.instance_methods,
|
|
30
|
-
klass.singleton_class.prepend Redefiner.redefine(method_nodes: parser.class_methods,
|
|
26
|
+
klass.extend TypeAccessors
|
|
27
|
+
klass.include Expressions
|
|
28
|
+
klass.prepend Redefiner.redefine(method_nodes: parser.instance_methods, class_proxy: parser.class_proxy, file_path:)
|
|
29
|
+
klass.singleton_class.prepend Redefiner.redefine(method_nodes: parser.class_methods, class_proxy: parser.class_proxy, file_path:)
|
|
31
30
|
|
|
32
31
|
if (adapter = Adapter::Loader.load(klass:, parser:, file_path:))
|
|
33
32
|
adapter.process
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
5
|
+
module LowType
|
|
6
|
+
class ClassProxy
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader :name, :klass, :file, :private_start_line
|
|
10
|
+
|
|
11
|
+
def_delegators :@file, :start_line, :end_line, :lines?
|
|
12
|
+
|
|
13
|
+
def initialize(klass:, file:, private_start_line:)
|
|
14
|
+
@name = klass.to_s
|
|
15
|
+
@klass = klass
|
|
16
|
+
@file = file
|
|
17
|
+
@private_start_line = private_start_line
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/proxies/file_proxy.rb
CHANGED
|
@@ -2,12 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
module LowType
|
|
4
4
|
class FileProxy
|
|
5
|
-
attr_reader :path, :
|
|
5
|
+
attr_reader :path, :scope
|
|
6
|
+
attr_accessor :start_line, :end_line
|
|
6
7
|
|
|
7
|
-
def initialize(path:,
|
|
8
|
+
def initialize(path:, scope:, start_line:, end_line: nil)
|
|
8
9
|
@path = path
|
|
9
|
-
@
|
|
10
|
+
@start_line = start_line
|
|
11
|
+
@end_line = end_line || start_line
|
|
10
12
|
@scope = scope
|
|
11
13
|
end
|
|
14
|
+
|
|
15
|
+
def lines?
|
|
16
|
+
start_line && end_line
|
|
17
|
+
end
|
|
12
18
|
end
|
|
13
19
|
end
|
data/lib/proxies/local_proxy.rb
CHANGED
|
@@ -20,7 +20,7 @@ module LowType
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def error_message(value:)
|
|
23
|
-
"Invalid variable type #{output(value:)} in '#{
|
|
23
|
+
"Invalid variable type #{output(value:)} in '#{name.class}:#{@file.start_line}'. Valid types: '#{type_expression.valid_types}'"
|
|
24
24
|
end
|
|
25
25
|
end
|
|
26
26
|
end
|
data/lib/proxies/method_proxy.rb
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'forwardable'
|
|
4
|
+
|
|
3
5
|
module LowType
|
|
4
6
|
class MethodProxy
|
|
5
|
-
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader :name, :file, :params, :return_proxy
|
|
10
|
+
|
|
11
|
+
# File is queried by redefiner but not sinatra adapter nor type accessors.
|
|
12
|
+
def_delegators :@file, :start_line, :end_line, :lines?
|
|
6
13
|
|
|
7
|
-
def initialize(name:, params: [], return_proxy: nil)
|
|
14
|
+
def initialize(name:, file: nil, params: [], return_proxy: nil)
|
|
8
15
|
@name = name
|
|
16
|
+
@file = file
|
|
9
17
|
@params = params
|
|
10
18
|
@return_proxy = return_proxy
|
|
11
19
|
end
|
data/lib/queries/file_parser.rb
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'prism'
|
|
4
|
+
require_relative '../proxies/class_proxy'
|
|
4
5
|
|
|
5
6
|
module LowType
|
|
6
7
|
class FileParser
|
|
7
|
-
attr_reader :parent_map, :instance_methods, :class_methods, :
|
|
8
|
+
attr_reader :parent_map, :instance_methods, :class_methods, :class_proxy
|
|
8
9
|
|
|
9
10
|
def initialize(klass:, file_path:)
|
|
10
11
|
@root_node = Prism.parse_file(file_path).value
|
|
@@ -13,12 +14,12 @@ module LowType
|
|
|
13
14
|
parent_mapper.visit(@root_node)
|
|
14
15
|
@parent_map = parent_mapper.parent_map
|
|
15
16
|
|
|
16
|
-
method_visitor = MethodDefVisitor.new(root_node: @root_node, parent_map:, klass:)
|
|
17
|
+
method_visitor = MethodDefVisitor.new(root_node: @root_node, parent_map:, klass:, file_path:)
|
|
17
18
|
@root_node.accept(method_visitor)
|
|
18
19
|
|
|
19
20
|
@instance_methods = method_visitor.instance_methods
|
|
20
21
|
@class_methods = method_visitor.class_methods
|
|
21
|
-
@
|
|
22
|
+
@class_proxy = ClassProxy.new(klass:, file: method_visitor.file_proxy, private_start_line: method_visitor.private_start_line)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
def method_calls(method_names:)
|
|
@@ -46,50 +47,46 @@ module LowType
|
|
|
46
47
|
|
|
47
48
|
nil
|
|
48
49
|
end
|
|
49
|
-
|
|
50
|
-
def line_number(node:)
|
|
51
|
-
node.respond_to?(:start_line) ? node.start_line : nil
|
|
52
|
-
end
|
|
53
50
|
end
|
|
54
51
|
end
|
|
55
52
|
|
|
56
53
|
class MethodDefVisitor < Prism::Visitor
|
|
57
|
-
attr_reader :class_methods, :instance_methods, :
|
|
54
|
+
attr_reader :class_methods, :instance_methods, :file_proxy, :private_start_line
|
|
58
55
|
|
|
59
|
-
def initialize(root_node:, parent_map:, klass:)
|
|
56
|
+
def initialize(root_node:, parent_map:, klass:, file_path:)
|
|
60
57
|
@parent_map = parent_map
|
|
61
58
|
@klass = klass
|
|
62
59
|
|
|
63
|
-
@instance_methods =
|
|
64
|
-
@class_methods =
|
|
65
|
-
|
|
60
|
+
@instance_methods = {}
|
|
61
|
+
@class_methods = {}
|
|
62
|
+
|
|
63
|
+
end_line = root_node.respond_to?(:end_line) ? root_node.end_line : nil
|
|
64
|
+
@file_proxy = FileProxy.new(path: file_path, start_line: 0, end_line:, scope: klass.to_s)
|
|
65
|
+
@private_start_line = nil
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def visit_def_node(node)
|
|
69
69
|
if class_method?(node)
|
|
70
|
-
@class_methods
|
|
70
|
+
@class_methods[node.name] = node
|
|
71
71
|
else
|
|
72
|
-
@instance_methods
|
|
72
|
+
@instance_methods[node.name] = node
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
super # Continue walking the tree.
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def visit_call_node(node)
|
|
79
|
-
|
|
80
|
-
class_start = @line_numbers[:class_start]
|
|
81
|
-
class_end = @line_numbers[:class_end]
|
|
79
|
+
return super unless node.name == :private && node.respond_to?(:start_line) && file_proxy.start_line && file_proxy.end_line
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
@line_numbers[:private_start] = node.start_line
|
|
85
|
-
end
|
|
81
|
+
@private_start_line = node.start_line if node.start_line > file_proxy.start_line && node.start_line < file_proxy.end_line
|
|
86
82
|
|
|
87
83
|
super
|
|
88
84
|
end
|
|
89
85
|
|
|
90
86
|
def visit_class_node(node)
|
|
91
87
|
if node.name == @klass.to_s.to_sym
|
|
92
|
-
|
|
88
|
+
file_proxy.start_line = node.class_keyword_loc.start_line
|
|
89
|
+
file_proxy.end_line = node.end_keyword_loc.end_line
|
|
93
90
|
end
|
|
94
91
|
|
|
95
92
|
super
|
data/lib/queries/type_query.rb
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require_relative '../type_expression'
|
|
3
|
+
require_relative '../expressions/type_expression'
|
|
4
4
|
|
|
5
5
|
module LowType
|
|
6
6
|
# TODO: Unit test.
|
|
7
7
|
class TypeQuery
|
|
8
8
|
class << self
|
|
9
|
-
def type?(
|
|
10
|
-
basic_type?(
|
|
9
|
+
def type?(expression)
|
|
10
|
+
basic_type?(expression:) || complex_type?(expression:)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def typed_array?(expression:)
|
|
14
|
+
expression.is_a?(Array) && (basic_type?(expression: expression.first) || expression.first.is_a?(TypeExpression))
|
|
11
15
|
end
|
|
12
16
|
|
|
13
17
|
def value?(value)
|
|
14
|
-
!basic_type?(
|
|
18
|
+
!basic_type?(expression: value) && !complex_type?(expression: value)
|
|
15
19
|
end
|
|
16
20
|
|
|
17
|
-
def complex_type?(
|
|
18
|
-
LowType::COMPLEX_TYPES.include?(
|
|
21
|
+
def complex_type?(expression:)
|
|
22
|
+
LowType::COMPLEX_TYPES.include?(expression) || typed_array?(expression:) || typed_hash?(expression:)
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
private
|
|
22
26
|
|
|
23
|
-
def basic_type?(
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def typed_array?(type:)
|
|
28
|
-
type.is_a?(Array) && (basic_type?(type: type.first) || type.first.is_a?(TypeExpression))
|
|
27
|
+
def basic_type?(expression:)
|
|
28
|
+
expression.instance_of?(Class)
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def typed_hash?(
|
|
32
|
-
|
|
31
|
+
def typed_hash?(expression:)
|
|
32
|
+
expression.is_a?(Hash) && basic_type?(expression: expression.keys.first) && basic_type?(expression: expression.values.first)
|
|
33
33
|
end
|
|
34
34
|
end
|
|
35
35
|
end
|
data/lib/syntax/syntax.rb
CHANGED
|
@@ -5,8 +5,8 @@ require_relative '../queries/type_query'
|
|
|
5
5
|
module LowType
|
|
6
6
|
module Syntax
|
|
7
7
|
refine Array.singleton_class do
|
|
8
|
-
def [](*
|
|
9
|
-
return TypeExpression.new(type: [*
|
|
8
|
+
def [](*expression)
|
|
9
|
+
return TypeExpression.new(type: [*expression]) if TypeQuery.type?(expression.first) || TypeQuery.typed_array?(expression:)
|
|
10
10
|
|
|
11
11
|
super
|
|
12
12
|
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.1.
|
|
4
|
+
version: 1.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- maedi
|
|
@@ -19,14 +19,19 @@ extra_rdoc_files: []
|
|
|
19
19
|
files:
|
|
20
20
|
- lib/adapters/adapter_loader.rb
|
|
21
21
|
- lib/adapters/sinatra_adapter.rb
|
|
22
|
+
- lib/definitions/redefiner.rb
|
|
23
|
+
- lib/definitions/repository.rb
|
|
24
|
+
- lib/definitions/type_accessors.rb
|
|
25
|
+
- lib/expressions/expressions.rb
|
|
26
|
+
- lib/expressions/type_expression.rb
|
|
27
|
+
- lib/expressions/value_expression.rb
|
|
22
28
|
- lib/factories/expression_factory.rb
|
|
23
29
|
- lib/factories/proxy_factory.rb
|
|
24
30
|
- lib/factories/type_factory.rb
|
|
25
|
-
- lib/instance_types.rb
|
|
26
31
|
- lib/interfaces/adapter_interface.rb
|
|
27
32
|
- lib/interfaces/error_interface.rb
|
|
28
|
-
- lib/local_types.rb
|
|
29
33
|
- lib/low_type.rb
|
|
34
|
+
- lib/proxies/class_proxy.rb
|
|
30
35
|
- lib/proxies/file_proxy.rb
|
|
31
36
|
- lib/proxies/local_proxy.rb
|
|
32
37
|
- lib/proxies/method_proxy.rb
|
|
@@ -35,13 +40,10 @@ files:
|
|
|
35
40
|
- lib/queries/file_parser.rb
|
|
36
41
|
- lib/queries/file_query.rb
|
|
37
42
|
- lib/queries/type_query.rb
|
|
38
|
-
- lib/redefiner.rb
|
|
39
43
|
- lib/syntax/syntax.rb
|
|
40
44
|
- lib/syntax/union_types.rb
|
|
41
|
-
- lib/type_expression.rb
|
|
42
45
|
- lib/types/complex_types.rb
|
|
43
46
|
- lib/types/error_types.rb
|
|
44
|
-
- lib/value_expression.rb
|
|
45
47
|
- lib/version.rb
|
|
46
48
|
homepage: https://codeberg.org/low_ruby/low_type
|
|
47
49
|
licenses: []
|
|
File without changes
|