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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4ee37ddf25be5bbed113698301a2aeafb3b50e7af1da412b9a1fc6afad18d8c2
4
- data.tar.gz: '075957101080441e02f4129303e766ecdfe1e7f30616177bc41a2cbf41f521f8'
3
+ metadata.gz: 843da9ba9bba3cf5c84ec56041836cb9469ad5faffd188f8edc13a3920ca499e
4
+ data.tar.gz: 791b0d87a885b327a41fff090f9dadce9b377712e9d7d51bd52fbaa997c98242
5
5
  SHA512:
6
- metadata.gz: 98c1cff14563ecf14713890e56bddb053d6f128aacad7ff23b6f96cc8b2c338cbea511cc668ac18079ec921cb0183b145f6b26a3c04403a98e8aa0bf734942f7
7
- data.tar.gz: 5dd573a63a6998e3a1fac1dd94f292dd80742185277124f6449ded149be662b74995815bad629157fc553cb8bef15bb31b123fdbcdccb1af3dff4d2645bc0da2
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.0)
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.5)
17
+ csv (3.2.6)
18
18
  ffi (1.15.5)
19
- fileutils (1.6.0)
19
+ fileutils (1.7.0)
20
20
  i18n (1.12.0)
21
21
  concurrent-ruby (~> 1.0)
22
- json (2.6.2)
23
- language_server-protocol (3.17.0.1)
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.1)
27
+ logger (1.5.2)
28
28
  minitest (5.16.3)
29
29
  parallel (1.22.1)
30
- parser (3.1.2.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.7.0)
37
+ rbs (2.8.1)
38
38
  rgot (1.1.0)
39
- securerandom (0.2.0)
40
- steep (1.2.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.7.0)
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.4)
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,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rack"
4
+ gem "rake"
5
+ gem "cgi"
6
+ gem "minitest"
7
+ gem "minitest-global_expectations"
8
+ gem "orthoses", path: "../../"
@@ -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,7 @@
1
+ file :src do
2
+ sh "git clone --depth 1 https://github.com/rack/rack-test.git src"
3
+ end
4
+
5
+ task :generate => :src do
6
+ load "generate.rb"
7
+ end
@@ -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 fail (#{err.class}) #{err.message}")
34
+ warn("#{var.class}#dup failed with #{err.class}:#{err.message}")
35
35
  var
36
36
  end
37
37
  end
@@ -60,12 +60,17 @@ module Orthoses
60
60
  end
61
61
 
62
62
  def uniq!
63
- out = ArrayIO.new
64
- writer = RBS::Writer.new(out: out)
65
- to_decl.members.each do |member|
66
- writer.write_member(member)
67
- end
68
- @body.replace(out.to_a)
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
@@ -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, nil
119
- object.inspect
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[#{ary.uniq.join(' | ')}]"
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) }.uniq
150
- values = object.values.map { |v| object_to_rbs(v, strict: strict) }.uniq
151
- "Hash[#{keys.join(' | ')}, #{values.join(' | ')}]"
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Orthoses
4
- VERSION = "1.4.0"
4
+ VERSION = "1.5.0"
5
5
  end
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'
@@ -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,6 @@
1
+ # THIS IS GENERATED CODE from `$ rake generate_self_sig`
2
+
3
+ class Orthoses::Sort
4
+ def initialize: (untyped loader) -> void
5
+ def call: () -> untyped
6
+ end
@@ -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,4 @@
1
+ # THIS IS GENERATED CODE from `$ rake generate_self_sig`
2
+
3
+ class Orthoses::Trace::Method::Info < ::Struct[untyped]
4
+ 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,5 @@
1
+ # THIS IS GENERATED CODE from `$ rake generate_self_sig`
2
+
3
+ module Orthoses::Trace::Targetable
4
+ def target?: (untyped name) -> untyped
5
+ end
@@ -0,0 +1,6 @@
1
+ # THIS IS GENERATED CODE from `$ rake generate_self_sig`
2
+
3
+ class Orthoses::Trace
4
+ def initialize: (untyped loader, patterns: untyped) -> void
5
+ def call: () -> untyped
6
+ 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
@@ -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
@@ -1,7 +1,7 @@
1
1
  # THIS IS GENERATED CODE from `$ rake generate_self_sig`
2
2
 
3
3
  module Orthoses
4
- VERSION: "1.4.0"
4
+ VERSION: "1.5.0"
5
5
 
6
6
  attr_accessor self.logger: ::Logger
7
7
 
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.0
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: 2022-10-22 00:00:00.000000000 Z
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.16
159
+ rubygems_version: 3.4.3
143
160
  signing_key:
144
161
  specification_version: 4
145
162
  summary: Framework for Generate RBS