orthoses 1.4.0 → 1.5.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/Gemfile.lock +12 -12
- data/README.md +8 -0
- data/examples/rack-test/Gemfile +8 -0
- data/examples/rack-test/Gemfile.lock +30 -0
- data/examples/rack-test/Rakefile +7 -0
- data/examples/rack-test/generate.rb +31 -0
- data/lib/orthoses/call_tracer/capturable.rb +2 -2
- data/lib/orthoses/content.rb +20 -6
- data/lib/orthoses/sort.rb +18 -0
- data/lib/orthoses/trace/attribute.rb +85 -0
- data/lib/orthoses/trace/method.rb +197 -0
- data/lib/orthoses/trace/targetable.rb +17 -0
- data/lib/orthoses/trace.rb +21 -0
- data/lib/orthoses/utils/type_list.rb +73 -0
- data/lib/orthoses/utils.rb +14 -7
- data/lib/orthoses/version.rb +1 -1
- data/lib/orthoses.rb +4 -1
- data/sig/orthoses/content.rbs +2 -0
- data/sig/orthoses/sort.rbs +6 -0
- data/sig/orthoses/trace/attribute.rbs +8 -0
- data/sig/orthoses/trace/method/info.rbs +4 -0
- data/sig/orthoses/trace/method.rbs +11 -0
- data/sig/orthoses/trace/targetable.rbs +5 -0
- data/sig/orthoses/trace.rbs +6 -0
- data/sig/orthoses/utils/type_list.rbs +10 -0
- data/sig/orthoses/utils.rbs +1 -1
- data/sig/orthoses.rbs +1 -1
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 843da9ba9bba3cf5c84ec56041836cb9469ad5faffd188f8edc13a3920ca499e
|
4
|
+
data.tar.gz: 791b0d87a885b327a41fff090f9dadce9b377712e9d7d51bd52fbaa997c98242
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 81438b5d94ce56d7164cdc781eaaa2c526cbba21cab147fc91d4e1b0c9b7992e31259d9bda2f5e2441a3dc59e3f7ec940c910e1cf63bbec6ef84ca4b046af0ee
|
7
|
+
data.tar.gz: ec0049000f94a194747974233adaa1c51a7759c0d78fb84a11e543877ee15d01f212b59ed63c5cadbd221701de4bfa9c84c0f6fcc5feffdab0f954b1fd63e2d0
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
orthoses (1.
|
4
|
+
orthoses (1.5.0)
|
5
5
|
rbs (~> 2.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -14,30 +14,30 @@ GEM
|
|
14
14
|
tzinfo (~> 2.0)
|
15
15
|
ast (2.4.2)
|
16
16
|
concurrent-ruby (1.1.10)
|
17
|
-
csv (3.2.
|
17
|
+
csv (3.2.6)
|
18
18
|
ffi (1.15.5)
|
19
|
-
fileutils (1.
|
19
|
+
fileutils (1.7.0)
|
20
20
|
i18n (1.12.0)
|
21
21
|
concurrent-ruby (~> 1.0)
|
22
|
-
json (2.6.
|
23
|
-
language_server-protocol (3.17.0.
|
22
|
+
json (2.6.3)
|
23
|
+
language_server-protocol (3.17.0.2)
|
24
24
|
listen (3.7.1)
|
25
25
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
26
26
|
rb-inotify (~> 0.9, >= 0.9.10)
|
27
|
-
logger (1.5.
|
27
|
+
logger (1.5.2)
|
28
28
|
minitest (5.16.3)
|
29
29
|
parallel (1.22.1)
|
30
|
-
parser (3.1.
|
30
|
+
parser (3.1.3.0)
|
31
31
|
ast (~> 2.4.1)
|
32
32
|
rainbow (3.1.1)
|
33
33
|
rake (13.0.6)
|
34
34
|
rb-fsevent (0.11.2)
|
35
35
|
rb-inotify (0.10.1)
|
36
36
|
ffi (~> 1.0)
|
37
|
-
rbs (2.
|
37
|
+
rbs (2.8.1)
|
38
38
|
rgot (1.1.0)
|
39
|
-
securerandom (0.2.
|
40
|
-
steep (1.
|
39
|
+
securerandom (0.2.1)
|
40
|
+
steep (1.3.0)
|
41
41
|
activesupport (>= 5.1)
|
42
42
|
csv (>= 3.0.9)
|
43
43
|
fileutils (>= 1.1.0)
|
@@ -48,11 +48,11 @@ GEM
|
|
48
48
|
parallel (>= 1.0.0)
|
49
49
|
parser (>= 3.1)
|
50
50
|
rainbow (>= 2.2.2, < 4.0)
|
51
|
-
rbs (>= 2.
|
51
|
+
rbs (>= 2.8.0)
|
52
52
|
securerandom (>= 0.1)
|
53
53
|
strscan (>= 1.0.0)
|
54
54
|
terminal-table (>= 2, < 4)
|
55
|
-
strscan (3.0.
|
55
|
+
strscan (3.0.5)
|
56
56
|
terminal-table (3.0.2)
|
57
57
|
unicode-display_width (>= 1.1.1, < 3)
|
58
58
|
tzinfo (2.0.5)
|
data/README.md
CHANGED
@@ -169,6 +169,14 @@ Run `rbs prototype runtime` command process with `patterns` option string.
|
|
169
169
|
|
170
170
|
Force load const defined by `autoload`.
|
171
171
|
|
172
|
+
### Orthoses::Sort
|
173
|
+
|
174
|
+
Sort signatures by class/module.
|
175
|
+
|
176
|
+
## Orthoses::Trace
|
177
|
+
|
178
|
+
Trace the argument and return value objects when the method is actually called and determine the type.
|
179
|
+
|
172
180
|
## Development
|
173
181
|
|
174
182
|
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
PATH
|
2
|
+
remote: ../..
|
3
|
+
specs:
|
4
|
+
orthoses (1.4.0)
|
5
|
+
rbs (~> 2.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
cgi (0.3.6)
|
11
|
+
minitest (5.16.3)
|
12
|
+
minitest-global_expectations (1.0.1)
|
13
|
+
minitest (> 5)
|
14
|
+
rack (3.0.2)
|
15
|
+
rake (13.0.6)
|
16
|
+
rbs (2.8.1)
|
17
|
+
|
18
|
+
PLATFORMS
|
19
|
+
arm64-darwin-21
|
20
|
+
|
21
|
+
DEPENDENCIES
|
22
|
+
cgi
|
23
|
+
minitest
|
24
|
+
minitest-global_expectations
|
25
|
+
orthoses!
|
26
|
+
rack
|
27
|
+
rake
|
28
|
+
|
29
|
+
BUNDLED WITH
|
30
|
+
2.3.16
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'orthoses'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
include FileUtils
|
6
|
+
|
7
|
+
out = Pathname('out')
|
8
|
+
out.rmtree rescue nil
|
9
|
+
Orthoses.logger.level = :warn
|
10
|
+
Orthoses::Builder.new do
|
11
|
+
use Orthoses::CreateFileByName,
|
12
|
+
base_dir: out.to_s
|
13
|
+
# use Orthoses::Sort
|
14
|
+
use Orthoses::Filter do |name, content|
|
15
|
+
name.start_with?("Rack::Test")
|
16
|
+
end
|
17
|
+
use Orthoses::Trace,
|
18
|
+
patterns: ['Rack::Test*']
|
19
|
+
run ->(){
|
20
|
+
cd "src" do
|
21
|
+
load "spec/all.rb"
|
22
|
+
Minitest.run
|
23
|
+
# avoid to run on at_exit
|
24
|
+
module ::Minitest
|
25
|
+
def self.run args = []
|
26
|
+
0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
}
|
31
|
+
end.call
|
@@ -25,13 +25,13 @@ module Orthoses
|
|
25
25
|
else
|
26
26
|
hash[name] = tp.binding.local_variable_get(name).then do |var|
|
27
27
|
case var
|
28
|
-
when Module, Thread::Backtrace::Location
|
28
|
+
when Module, Thread::Backtrace::Location, IO, Encoding
|
29
29
|
var
|
30
30
|
else
|
31
31
|
var.dup
|
32
32
|
end
|
33
33
|
rescue => err
|
34
|
-
warn("#dup
|
34
|
+
warn("#{var.class}#dup failed with #{err.class}:#{err.message}")
|
35
35
|
var
|
36
36
|
end
|
37
37
|
end
|
data/lib/orthoses/content.rb
CHANGED
@@ -60,12 +60,17 @@ module Orthoses
|
|
60
60
|
end
|
61
61
|
|
62
62
|
def uniq!
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
63
|
+
lines = decl_to_lines(to_decl)
|
64
|
+
@body.replace(lines)
|
65
|
+
end
|
66
|
+
|
67
|
+
def sort!
|
68
|
+
require 'rbs/sorter'
|
69
|
+
sorter = ::RBS::Sorter.new(nil, stdout: nil)
|
70
|
+
decl = to_decl
|
71
|
+
sorter.sort_decl!(decl)
|
72
|
+
lines = decl_to_lines(decl)
|
73
|
+
@body.replace(lines)
|
69
74
|
end
|
70
75
|
|
71
76
|
def original_rbs
|
@@ -93,6 +98,15 @@ module Orthoses
|
|
93
98
|
end
|
94
99
|
end
|
95
100
|
|
101
|
+
def decl_to_lines(decl)
|
102
|
+
out = ArrayIO.new
|
103
|
+
writer = RBS::Writer.new(out: out)
|
104
|
+
decl.members.each do |member|
|
105
|
+
writer.write_member(member)
|
106
|
+
end
|
107
|
+
out.to_a
|
108
|
+
end
|
109
|
+
|
96
110
|
def uniqed_body_string
|
97
111
|
out = StringIO.new
|
98
112
|
writer = RBS::Writer.new(out: out)
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
# use Orthoses::Sort
|
5
|
+
class Sort
|
6
|
+
def initialize(loader)
|
7
|
+
@loader = loader
|
8
|
+
end
|
9
|
+
|
10
|
+
def call
|
11
|
+
@loader.call.tap do |store|
|
12
|
+
store.each do |name, content|
|
13
|
+
content.sort!
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
class Trace
|
5
|
+
class Attribute
|
6
|
+
include Targetable
|
7
|
+
|
8
|
+
def initialize(loader, patterns:)
|
9
|
+
@loader = loader
|
10
|
+
@patterns = patterns
|
11
|
+
|
12
|
+
@captured_dict = Hash.new { |h, k| h[k] = Hash.new { |hh, kk| hh[kk] = [] } }
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
::Module.prepend(Orthoses::Attribute::Hook)
|
17
|
+
store = nil
|
18
|
+
build_trace_hook.enable(target: Orthoses::Attribute::Hook.instance_method(:attr)) do
|
19
|
+
build_trace_hook.enable(target: Orthoses::Attribute::Hook.instance_method(:attr_accessor)) do
|
20
|
+
build_trace_hook.enable(target: Orthoses::Attribute::Hook.instance_method(:attr_reader)) do
|
21
|
+
build_trace_hook.enable(target: Orthoses::Attribute::Hook.instance_method(:attr_writer)) do
|
22
|
+
store = @loader.call
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
@captured_dict.each do |mod_name, captures|
|
29
|
+
captures.each do |(kind, prefix, name), types|
|
30
|
+
injected = Utils::TypeList.new(types).inject
|
31
|
+
store[mod_name] << "#{kind} #{prefix}#{name}: #{injected}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
store
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def build_trace_hook
|
41
|
+
TracePoint.new(:call) do |tp1|
|
42
|
+
mod_name = Orthoses::Utils.module_name(tp1.self)
|
43
|
+
if m = tp1.self.to_s.match(/#<Class:([\w:]+)>/)
|
44
|
+
mod_name = m[1]
|
45
|
+
end
|
46
|
+
next unless mod_name
|
47
|
+
next unless target?(mod_name)
|
48
|
+
is_singleton = tp1.self.singleton_class?
|
49
|
+
prefix = is_singleton ? "self." : ""
|
50
|
+
kind = tp1.method_id
|
51
|
+
|
52
|
+
tp1.binding.local_variable_get(:names).each do |name|
|
53
|
+
attr_module = Module.new{
|
54
|
+
if [:attr_accessor, :attr_reader, :attr].include?(kind)
|
55
|
+
define_method(name) do
|
56
|
+
super()
|
57
|
+
end
|
58
|
+
end
|
59
|
+
if [:attr_accessor, :attr_writer, :attr].include?(kind)
|
60
|
+
define_method("#{name}=") do |object|
|
61
|
+
super(object)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
}
|
65
|
+
|
66
|
+
tp1.self.prepend attr_module
|
67
|
+
|
68
|
+
if [:attr_accessor, :attr_reader, :attr].include?(kind)
|
69
|
+
TracePoint.new(:return) do |tp2|
|
70
|
+
type = Utils.object_to_rbs(tp2.return_value)
|
71
|
+
@captured_dict[mod_name][[kind, prefix, name]] << type
|
72
|
+
end.enable(target: attr_module.instance_method(name))
|
73
|
+
end
|
74
|
+
if [:attr_accessor, :attr_writer, :attr].include?(kind)
|
75
|
+
TracePoint.new(:call) do |tp2|
|
76
|
+
type = Utils.object_to_rbs(tp2.binding.local_variable_get(:object))
|
77
|
+
@captured_dict[mod_name][[kind, prefix, name]] << type
|
78
|
+
end.enable(target: attr_module.instance_method("#{name}="))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
class Trace
|
5
|
+
class Method
|
6
|
+
# internal
|
7
|
+
Info = Struct.new(:key, :op_name_types, :raised, keyword_init: true)
|
8
|
+
include Targetable
|
9
|
+
|
10
|
+
def initialize(loader, patterns:)
|
11
|
+
@loader = loader
|
12
|
+
@patterns = patterns
|
13
|
+
|
14
|
+
@stack = []
|
15
|
+
@args_return_map = Hash.new { |h, k| h[k] = [] }
|
16
|
+
@alias_map = {}
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
build_trace_point.enable do
|
21
|
+
@loader.call
|
22
|
+
end.tap do |store|
|
23
|
+
build_members.each do |(mod_name, member)|
|
24
|
+
out = StringIO.new
|
25
|
+
writer = ::RBS::Writer.new(out: out)
|
26
|
+
writer.write_member(member)
|
27
|
+
store[mod_name] << out.string
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def build_trace_point
|
35
|
+
TracePoint.new(:call, :return, :raise) do |tp|
|
36
|
+
case tp.event
|
37
|
+
when :call
|
38
|
+
if tp.defined_class.singleton_class?
|
39
|
+
# e.g. `Minitest::Spec::DSL#to_s`` may return `nil` with `#to_s`
|
40
|
+
m = tp.defined_class.to_s&.match(/#<Class:([\w:]+)>/) or next
|
41
|
+
mod_name = m[1] or next
|
42
|
+
kind = :singleton
|
43
|
+
else
|
44
|
+
mod_name = Utils.module_name(tp.defined_class) or next
|
45
|
+
kind = :instance
|
46
|
+
end
|
47
|
+
|
48
|
+
next unless target?(mod_name)
|
49
|
+
|
50
|
+
visibility = tp.self.private_methods.include?(tp.method_id) ? :private : nil
|
51
|
+
key = [mod_name, kind, visibility, tp.method_id]
|
52
|
+
op_name_types = tp.parameters.map do |op, name|
|
53
|
+
case name
|
54
|
+
when nil, :*, :**, :&
|
55
|
+
[op, name, 'untyped']
|
56
|
+
else
|
57
|
+
type = Utils.object_to_rbs(tp.binding.local_variable_get(name))
|
58
|
+
[op, name, type]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
@alias_map[[mod_name, kind, tp.method_id]] = tp.callee_id if tp.method_id != tp.callee_id
|
63
|
+
@stack.push(Info.new(key: key, op_name_types: op_name_types, raised: false))
|
64
|
+
when :raise
|
65
|
+
@stack.last&.raised = true
|
66
|
+
when :return
|
67
|
+
info = @stack.pop
|
68
|
+
if info && !info.raised
|
69
|
+
@args_return_map[info.key] << [info.op_name_types, Utils.object_to_rbs(tp.return_value)]
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def build_members
|
76
|
+
build_method_definitions.concat(build_aliases)
|
77
|
+
end
|
78
|
+
|
79
|
+
def build_method_definitions
|
80
|
+
untyped = ::RBS::Types::Bases::Any.new(location: nil)
|
81
|
+
|
82
|
+
@args_return_map.map do |(mod_name, kind, visibility, method_id), type_samples|
|
83
|
+
type_samples.uniq!
|
84
|
+
method_types = type_samples.map do |(op_name_types, return_type)|
|
85
|
+
required_positionals = []
|
86
|
+
optional_positionals = []
|
87
|
+
rest = nil
|
88
|
+
trailing_positionals = []
|
89
|
+
required_keywords = {}
|
90
|
+
optional_keywords = {}
|
91
|
+
rest_keywords = nil
|
92
|
+
|
93
|
+
requireds = required_positionals
|
94
|
+
|
95
|
+
block = nil
|
96
|
+
|
97
|
+
op_name_types.each do |op, name, string_type|
|
98
|
+
type = ::RBS::Parser.parse_type(string_type)
|
99
|
+
|
100
|
+
case op
|
101
|
+
when :req
|
102
|
+
requireds << ::RBS::Types::Function::Param.new(name: name, type: type)
|
103
|
+
when :opt
|
104
|
+
requireds = trailing_positionals
|
105
|
+
optional_positionals << ::RBS::Types::Function::Param.new(name: name, type: type)
|
106
|
+
when :rest
|
107
|
+
requireds = trailing_positionals
|
108
|
+
name = nil if name == :* # For `def f(...) end` syntax
|
109
|
+
rest = ::RBS::Types::Function::Param.new(name: name, type: type)
|
110
|
+
when :keyreq
|
111
|
+
required_keywords[name] = ::RBS::Types::Function::Param.new(name: nil, type: type)
|
112
|
+
when :key
|
113
|
+
optional_keywords[name] = ::RBS::Types::Function::Param.new(name: nil, type: type)
|
114
|
+
when :keyrest
|
115
|
+
rest_keywords = ::RBS::Types::Function::Param.new(name: nil, type: type)
|
116
|
+
when :block
|
117
|
+
block = ::RBS::Types::Block.new(
|
118
|
+
type: ::RBS::Types::Function.empty(untyped).update(rest_positionals: ::RBS::Types::Function::Param.new(name: nil, type: untyped)),
|
119
|
+
required: false,
|
120
|
+
self_type: nil
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
return_type = if method_id == :initialize
|
126
|
+
::RBS::Types::Bases::Void.new(location: nil)
|
127
|
+
else
|
128
|
+
::RBS::Parser.parse_type(return_type)
|
129
|
+
end
|
130
|
+
|
131
|
+
::RBS::MethodType.new(
|
132
|
+
location: nil,
|
133
|
+
type_params: [],
|
134
|
+
type: ::RBS::Types::Function.new(
|
135
|
+
required_positionals: required_positionals,
|
136
|
+
optional_positionals: optional_positionals,
|
137
|
+
rest_positionals: rest,
|
138
|
+
trailing_positionals: trailing_positionals,
|
139
|
+
required_keywords: required_keywords,
|
140
|
+
optional_keywords: optional_keywords,
|
141
|
+
rest_keywords: rest_keywords,
|
142
|
+
return_type: return_type,
|
143
|
+
),
|
144
|
+
block: block
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
# from:
|
149
|
+
# def foo: () -> true
|
150
|
+
# | () -> false
|
151
|
+
# | (Integer) -> Integer
|
152
|
+
# to:
|
153
|
+
# def foo: () -> bool
|
154
|
+
# | (Integer) -> Integer
|
155
|
+
functions_without_return_type_map = method_types.group_by do |method_type|
|
156
|
+
method_type.type.with_return_type(untyped)
|
157
|
+
end
|
158
|
+
types = functions_without_return_type_map.map do |func, method_types_by_arg|
|
159
|
+
injected = Utils::TypeList.new(method_types_by_arg.map(&:type).map(&:return_type)).inject
|
160
|
+
method_type = method_types_by_arg.first
|
161
|
+
method_type.update(type: method_type.type.with_return_type(injected))
|
162
|
+
end
|
163
|
+
|
164
|
+
[
|
165
|
+
mod_name,
|
166
|
+
RBS::AST::Members::MethodDefinition.new(
|
167
|
+
annotations: [],
|
168
|
+
comment: nil,
|
169
|
+
kind: kind,
|
170
|
+
location: nil,
|
171
|
+
name: method_id,
|
172
|
+
overload: false,
|
173
|
+
types: types,
|
174
|
+
visibility: visibility
|
175
|
+
)
|
176
|
+
]
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def build_aliases
|
181
|
+
@alias_map.map do |(mod_name, kind, method_id), callee_id|
|
182
|
+
[
|
183
|
+
mod_name,
|
184
|
+
RBS::AST::Members::Alias.new(
|
185
|
+
new_name: callee_id,
|
186
|
+
old_name: method_id,
|
187
|
+
kind: kind,
|
188
|
+
annotations: [],
|
189
|
+
location: nil,
|
190
|
+
comment: nil,
|
191
|
+
)
|
192
|
+
]
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
class Trace
|
5
|
+
module Targetable
|
6
|
+
def target?(name)
|
7
|
+
@patterns.any? do |pattern|
|
8
|
+
if pattern.end_with?("*")
|
9
|
+
(name || "").start_with?(pattern.chop)
|
10
|
+
else
|
11
|
+
name == pattern
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Orthoses
|
2
|
+
# Collect argument and return types during code running
|
3
|
+
# use Orthoses::Trace,
|
4
|
+
# patterns: ['Foo::Bar*']
|
5
|
+
class Trace
|
6
|
+
autoload :Attribute, 'orthoses/trace/attribute'
|
7
|
+
autoload :Method, 'orthoses/trace/method'
|
8
|
+
autoload :Targetable, 'orthoses/trace/targetable'
|
9
|
+
|
10
|
+
def initialize(loader, patterns:)
|
11
|
+
@loader = loader
|
12
|
+
@patterns = patterns
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
@loader = Trace::Attribute.new(@loader, patterns: @patterns)
|
17
|
+
@loader = Trace::Method.new(@loader, patterns: @patterns)
|
18
|
+
@loader.call
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Orthoses
|
4
|
+
module Utils
|
5
|
+
# internal
|
6
|
+
class TypeList
|
7
|
+
UNTYPED = ::RBS::Types::Bases::Any.new(location: nil)
|
8
|
+
NIL_TYPE = ::RBS::Types::Bases::Nil.new(location: nil)
|
9
|
+
TRUE_TYPE = ::RBS::Types::Literal.new(literal: true, location: nil)
|
10
|
+
FALSE_TYPE = ::RBS::Types::Literal.new(literal: false, location: nil)
|
11
|
+
|
12
|
+
def initialize(types)
|
13
|
+
@types = types.map do |type|
|
14
|
+
case type
|
15
|
+
when String
|
16
|
+
::RBS::Parser.parse_type(type)
|
17
|
+
else
|
18
|
+
type
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def inject
|
24
|
+
uniqed = @types.uniq
|
25
|
+
|
26
|
+
return UNTYPED if uniqed.find { |t| t == UNTYPED }
|
27
|
+
|
28
|
+
has_true = uniqed.delete(TRUE_TYPE)
|
29
|
+
has_false = uniqed.delete(FALSE_TYPE)
|
30
|
+
if has_true || has_false
|
31
|
+
uniqed << ::RBS::Types::Bases::Bool.new(location: nil)
|
32
|
+
end
|
33
|
+
|
34
|
+
return UNTYPED if uniqed.empty?
|
35
|
+
return uniqed.first if uniqed.length == 1
|
36
|
+
|
37
|
+
args_or_other = uniqed.group_by do |type|
|
38
|
+
type.respond_to?(:args) && !type.args.empty?
|
39
|
+
end
|
40
|
+
if args_or_other[true]
|
41
|
+
# { Array => [Array[Intger], Array[String]], Hash => [Hash[untyped, untyped]], ... }
|
42
|
+
type_by_name = args_or_other[true].group_by do |type|
|
43
|
+
type.name
|
44
|
+
end
|
45
|
+
type_by_name.each do |name, types|
|
46
|
+
if with_untyped_type = types.find { |type| type.args.include?(UNTYPED) }
|
47
|
+
types.replace([with_untyped_type])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
args_injected = type_by_name.values.flatten
|
51
|
+
args_injected.concat(args_or_other[false]) if args_or_other[false]
|
52
|
+
uniqed = args_injected
|
53
|
+
end
|
54
|
+
|
55
|
+
after_optional = uniqed.delete(NIL_TYPE)
|
56
|
+
injected = uniqed.inject do |r, type|
|
57
|
+
case r
|
58
|
+
when ::RBS::Types::Union
|
59
|
+
r.tap { r.types << type }
|
60
|
+
else
|
61
|
+
::RBS::Types::Union.new(types: [r, type], location: nil)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
if after_optional
|
66
|
+
return ::RBS::Types::Optional.new(type: injected, location: nil)
|
67
|
+
end
|
68
|
+
|
69
|
+
injected
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/orthoses/utils.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Orthoses
|
4
4
|
module Utils
|
5
|
+
autoload :TypeList, "orthoses/utils/type_list"
|
5
6
|
autoload :Underscore, "orthoses/utils/underscore"
|
6
7
|
|
7
8
|
def self.unautoload!
|
@@ -101,7 +102,7 @@ module Orthoses
|
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
|
-
def self.object_to_rbs(object, strict:)
|
105
|
+
def self.object_to_rbs(object, strict: false)
|
105
106
|
case object
|
106
107
|
when Class, Module
|
107
108
|
if name = module_name(object)
|
@@ -115,8 +116,14 @@ module Orthoses
|
|
115
116
|
else
|
116
117
|
module_name(object.class) || 'untyped'
|
117
118
|
end
|
118
|
-
when true, false
|
119
|
-
|
119
|
+
when true, false
|
120
|
+
if strict
|
121
|
+
object.inspect
|
122
|
+
else
|
123
|
+
"bool"
|
124
|
+
end
|
125
|
+
when nil
|
126
|
+
"nil"
|
120
127
|
when Set
|
121
128
|
if object.empty?
|
122
129
|
"Set[untyped]"
|
@@ -136,7 +143,7 @@ module Orthoses
|
|
136
143
|
if strict
|
137
144
|
"[#{ary.join(', ')}]"
|
138
145
|
else
|
139
|
-
"Array[#{
|
146
|
+
"Array[#{TypeList.new(ary).inject}]"
|
140
147
|
end
|
141
148
|
end
|
142
149
|
when Hash
|
@@ -146,9 +153,9 @@ module Orthoses
|
|
146
153
|
if strict && object.keys.all? { |key| key.is_a?(Symbol) && /\A\w+\z/.match?(key) }
|
147
154
|
"{ #{object.map { |k, v| "#{k}: #{object_to_rbs(v, strict: strict)}" }.join(', ')} }"
|
148
155
|
else
|
149
|
-
keys = object.keys.map { |k| object_to_rbs(k, strict: strict) }
|
150
|
-
values = object.values.map { |v| object_to_rbs(v, strict: strict) }
|
151
|
-
"Hash[#{
|
156
|
+
keys = object.keys.map { |k| object_to_rbs(k, strict: strict) }
|
157
|
+
values = object.values.map { |v| object_to_rbs(v, strict: strict) }
|
158
|
+
"Hash[#{TypeList.new(keys).inject}, #{TypeList.new(values).inject}]"
|
152
159
|
end
|
153
160
|
end
|
154
161
|
when Range
|
data/lib/orthoses/version.rb
CHANGED
data/lib/orthoses.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
require 'rbs'
|
4
4
|
require 'pathname'
|
5
5
|
|
6
|
+
require 'orthoses/utils'
|
7
|
+
|
6
8
|
module Orthoses
|
7
9
|
autoload :Attribute, 'orthoses/attribute'
|
8
10
|
autoload :Builder, 'orthoses/builder'
|
@@ -21,10 +23,11 @@ module Orthoses
|
|
21
23
|
autoload :PP, 'orthoses/pp'
|
22
24
|
autoload :RBSPrototypeRB, 'orthoses/rbs_prototype_rb'
|
23
25
|
autoload :RBSPrototypeRuntime, 'orthoses/rbs_prototype_runtime'
|
26
|
+
autoload :Sort, 'orthoses/sort'
|
24
27
|
autoload :Store, 'orthoses/store'
|
25
28
|
autoload :Tap, 'orthoses/tap'
|
29
|
+
autoload :Trace, 'orthoses/trace'
|
26
30
|
autoload :Autoload, 'orthoses/autoload'
|
27
|
-
autoload :Utils, 'orthoses/utils'
|
28
31
|
autoload :VERSION, 'orthoses/version'
|
29
32
|
autoload :Walk, 'orthoses/walk'
|
30
33
|
autoload :Writer, 'orthoses/writer'
|
data/sig/orthoses/content.rbs
CHANGED
@@ -10,7 +10,9 @@ class Orthoses::Content
|
|
10
10
|
def to_rbs: () -> String
|
11
11
|
def to_decl: () -> untyped
|
12
12
|
def uniq!: () -> untyped
|
13
|
+
def sort!: () -> untyped
|
13
14
|
def original_rbs: () -> untyped
|
15
|
+
private def decl_to_lines: (untyped decl) -> untyped
|
14
16
|
private def uniqed_body_string: () -> String
|
15
17
|
private def uniqed_body_decl: () -> RBS::AST::Declarations::t
|
16
18
|
private def auto_header: () -> (nil | untyped)
|
@@ -0,0 +1,8 @@
|
|
1
|
+
# THIS IS GENERATED CODE from `$ rake generate_self_sig`
|
2
|
+
|
3
|
+
class Orthoses::Trace::Attribute
|
4
|
+
def initialize: (untyped loader, patterns: untyped) -> void
|
5
|
+
def call: () -> untyped
|
6
|
+
private def build_trace_hook: () -> untyped
|
7
|
+
include Orthoses::Trace::Targetable
|
8
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# THIS IS GENERATED CODE from `$ rake generate_self_sig`
|
2
|
+
|
3
|
+
class Orthoses::Trace::Method
|
4
|
+
def initialize: (untyped loader, patterns: untyped) -> void
|
5
|
+
def call: () -> untyped
|
6
|
+
private def build_trace_point: () -> untyped
|
7
|
+
private def build_members: () -> untyped
|
8
|
+
private def build_method_definitions: () -> untyped
|
9
|
+
private def build_aliases: () -> untyped
|
10
|
+
include Orthoses::Trace::Targetable
|
11
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# THIS IS GENERATED CODE from `$ rake generate_self_sig`
|
2
|
+
|
3
|
+
class Orthoses::Utils::TypeList
|
4
|
+
def initialize: (untyped types) -> void
|
5
|
+
def inject: () -> untyped
|
6
|
+
FALSE_TYPE: RBS::Types::Literal
|
7
|
+
NIL_TYPE: RBS::Types::Bases::Nil
|
8
|
+
TRUE_TYPE: RBS::Types::Literal
|
9
|
+
UNTYPED: RBS::Types::Bases::Any
|
10
|
+
end
|
data/sig/orthoses/utils.rbs
CHANGED
@@ -13,7 +13,7 @@ module Orthoses::Utils
|
|
13
13
|
|
14
14
|
def self.rbs_environment: (?library: String | Array[String] | nil, ?collection: boolish, ?cache: boolish) -> RBS::Environment
|
15
15
|
|
16
|
-
def self.object_to_rbs: (untyped object, strict: bool) -> String
|
16
|
+
def self.object_to_rbs: (untyped object, ?strict: bool) -> String
|
17
17
|
|
18
18
|
def self.module_name: (Module mod) -> String?
|
19
19
|
|
data/sig/orthoses.rbs
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: orthoses
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ksss
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rbs
|
@@ -37,6 +37,10 @@ files:
|
|
37
37
|
- LICENSE.txt
|
38
38
|
- README.md
|
39
39
|
- examples/minitest/Rakefile
|
40
|
+
- examples/rack-test/Gemfile
|
41
|
+
- examples/rack-test/Gemfile.lock
|
42
|
+
- examples/rack-test/Rakefile
|
43
|
+
- examples/rack-test/generate.rb
|
40
44
|
- examples/simple_middleware.rb
|
41
45
|
- examples/simple_middleware.rbs
|
42
46
|
- lib/orthoses.rb
|
@@ -66,9 +70,15 @@ files:
|
|
66
70
|
- lib/orthoses/pp.rb
|
67
71
|
- lib/orthoses/rbs_prototype_rb.rb
|
68
72
|
- lib/orthoses/rbs_prototype_runtime.rb
|
73
|
+
- lib/orthoses/sort.rb
|
69
74
|
- lib/orthoses/store.rb
|
70
75
|
- lib/orthoses/tap.rb
|
76
|
+
- lib/orthoses/trace.rb
|
77
|
+
- lib/orthoses/trace/attribute.rb
|
78
|
+
- lib/orthoses/trace/method.rb
|
79
|
+
- lib/orthoses/trace/targetable.rb
|
71
80
|
- lib/orthoses/utils.rb
|
81
|
+
- lib/orthoses/utils/type_list.rb
|
72
82
|
- lib/orthoses/utils/underscore.rb
|
73
83
|
- lib/orthoses/version.rb
|
74
84
|
- lib/orthoses/walk.rb
|
@@ -112,9 +122,16 @@ files:
|
|
112
122
|
- sig/orthoses/pp.rbs
|
113
123
|
- sig/orthoses/rbs_prototype_rb.rbs
|
114
124
|
- sig/orthoses/rbs_prototype_runtime.rbs
|
125
|
+
- sig/orthoses/sort.rbs
|
115
126
|
- sig/orthoses/store.rbs
|
116
127
|
- sig/orthoses/tap.rbs
|
128
|
+
- sig/orthoses/trace.rbs
|
129
|
+
- sig/orthoses/trace/attribute.rbs
|
130
|
+
- sig/orthoses/trace/method.rbs
|
131
|
+
- sig/orthoses/trace/method/info.rbs
|
132
|
+
- sig/orthoses/trace/targetable.rbs
|
117
133
|
- sig/orthoses/utils.rbs
|
134
|
+
- sig/orthoses/utils/type_list.rbs
|
118
135
|
- sig/orthoses/utils/underscore.rbs
|
119
136
|
- sig/orthoses/walk.rbs
|
120
137
|
- sig/orthoses/writer.rbs
|
@@ -139,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
156
|
- !ruby/object:Gem::Version
|
140
157
|
version: '0'
|
141
158
|
requirements: []
|
142
|
-
rubygems_version: 3.3
|
159
|
+
rubygems_version: 3.4.3
|
143
160
|
signing_key:
|
144
161
|
specification_version: 4
|
145
162
|
summary: Framework for Generate RBS
|