orthoses 1.7.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +10 -3
  3. data/lib/orthoses/attribute.rb +28 -55
  4. data/lib/orthoses/builder.rb +7 -3
  5. data/lib/orthoses/constant.rb +0 -1
  6. data/lib/orthoses/content/duplication_checker.rb +67 -35
  7. data/lib/orthoses/content/environment.rb +1 -1
  8. data/lib/orthoses/content.rb +20 -13
  9. data/lib/orthoses/create_file_by_name.rb +38 -7
  10. data/lib/orthoses/lazy_trace_point.rb +37 -43
  11. data/lib/orthoses/missing_name.rb +81 -0
  12. data/lib/orthoses/mixin.rb +29 -34
  13. data/lib/orthoses/rbs_prototype_runtime.rb +23 -4
  14. data/lib/orthoses/trace/attribute.rb +26 -8
  15. data/lib/orthoses/utils.rb +2 -2
  16. data/lib/orthoses/version.rb +1 -1
  17. data/lib/orthoses.rb +1 -0
  18. data/sig/orthoses/_call.rbs +1 -1
  19. data/sig/orthoses/_middle_ware.rbs +1 -1
  20. data/sig/orthoses/attribute/hook.rbs +1 -1
  21. data/sig/orthoses/attribute.rbs +3 -3
  22. data/sig/orthoses/autoload/hook.rbs +1 -1
  23. data/sig/orthoses/autoload.rbs +2 -1
  24. data/sig/orthoses/builder/call_logable.rbs +1 -1
  25. data/sig/orthoses/builder.rbs +7 -4
  26. data/sig/orthoses/call_tracer/capturable.rbs +1 -1
  27. data/sig/orthoses/call_tracer/capture.rbs +2 -2
  28. data/sig/orthoses/call_tracer/lazy.rbs +4 -2
  29. data/sig/orthoses/call_tracer.rbs +3 -1
  30. data/sig/orthoses/const_load_error.rbs +4 -1
  31. data/sig/orthoses/constant.rbs +3 -3
  32. data/sig/orthoses/content/array_io.rbs +2 -1
  33. data/sig/orthoses/content/duplication_checker.rbs +10 -3
  34. data/sig/orthoses/content/environment.rbs +11 -6
  35. data/sig/orthoses/content/header_builder.rbs +3 -1
  36. data/sig/orthoses/content.rbs +7 -1
  37. data/sig/orthoses/create_file_by_name.rbs +8 -3
  38. data/sig/orthoses/delegate_class/hook.rbs +1 -1
  39. data/sig/orthoses/delegate_class.rbs +2 -2
  40. data/sig/orthoses/filter.rbs +4 -3
  41. data/sig/orthoses/lazy_trace_point/method_added_hook.rbs +6 -0
  42. data/sig/orthoses/lazy_trace_point/signleton_method_added_hook.rbs +5 -0
  43. data/sig/orthoses/lazy_trace_point.rbs +7 -7
  44. data/sig/orthoses/load_rbs.rbs +3 -3
  45. data/sig/orthoses/missing_name/missing_class.rbs +8 -0
  46. data/sig/orthoses/missing_name/missing_module.rbs +8 -0
  47. data/sig/orthoses/missing_name.rbs +7 -0
  48. data/sig/orthoses/mixin/hook.rbs +2 -2
  49. data/sig/orthoses/mixin.rbs +6 -4
  50. data/sig/orthoses/name_space_error.rbs +1 -1
  51. data/sig/orthoses/object_space_all.rbs +2 -2
  52. data/sig/orthoses/outputable/avoid_recursive_ancestor_error.rbs +2 -2
  53. data/sig/orthoses/outputable/constantizable_filter.rbs +2 -1
  54. data/sig/orthoses/outputable/uniq_content_body.rbs +2 -1
  55. data/sig/orthoses/outputable.rbs +3 -1
  56. data/sig/orthoses/path_helper.rbs +3 -1
  57. data/sig/orthoses/pp.rbs +2 -1
  58. data/sig/orthoses/rbs_prototype_rb.rbs +6 -4
  59. data/sig/orthoses/rbs_prototype_runtime.rbs +10 -3
  60. data/sig/orthoses/sort.rbs +2 -1
  61. data/sig/orthoses/store.rbs +2 -1
  62. data/sig/orthoses/tap.rbs +3 -2
  63. data/sig/orthoses/trace/attribute/hook.rbs +11 -0
  64. data/sig/orthoses/trace/attribute.rbs +4 -1
  65. data/sig/orthoses/trace/method/info.rbs +1 -1
  66. data/sig/orthoses/trace/method.rbs +6 -1
  67. data/sig/orthoses/trace/targetable.rbs +1 -1
  68. data/sig/orthoses/trace.rbs +3 -1
  69. data/sig/orthoses/utils/type_list.rbs +2 -1
  70. data/sig/orthoses/utils/underscore.rbs +1 -1
  71. data/sig/orthoses/utils.rbs +4 -2
  72. data/sig/orthoses/walk.rbs +3 -3
  73. data/sig/orthoses/writer.rbs +3 -2
  74. data/sig/orthoses.rbs +6 -6
  75. metadata +9 -21
  76. data/Gemfile +0 -16
  77. data/Gemfile.lock +0 -86
  78. data/examples/minitest/Rakefile +0 -56
  79. data/examples/rack-test/Gemfile +0 -8
  80. data/examples/rack-test/Gemfile.lock +0 -30
  81. data/examples/rack-test/Rakefile +0 -7
  82. data/examples/rack-test/generate.rb +0 -31
  83. data/examples/rack-test/out/rack/test/cookie.rbs +0 -28
  84. data/examples/rack-test/out/rack/test/cookie_jar.rbs +0 -28
  85. data/examples/rack-test/out/rack/test/fake_app.rbs +0 -13
  86. data/examples/rack-test/out/rack/test/input_rewinder.rbs +0 -8
  87. data/examples/rack-test/out/rack/test/methods.rbs +0 -98
  88. data/examples/rack-test/out/rack/test/session.rbs +0 -186
  89. data/examples/rack-test/out/rack/test/uploaded_file.rbs +0 -18
  90. data/examples/rack-test/out/rack/test/utils.rbs +0 -112
  91. data/examples/rack-test/out/rack/test.rbs +0 -3
  92. data/examples/simple_middleware.rb +0 -11
  93. data/examples/simple_middleware.rbs +0 -7
  94. data/orthoses.gemspec +0 -36
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e2915ad2b524676ac4ea67e61fcc90713bdaa8e79cb2ff01aeba74fe54b4885d
4
- data.tar.gz: 0f8823a7e88b4030eb6554ac9f35a068730ac944378832f923c99cf3b4e8e6be
3
+ metadata.gz: dd4d2682b08812b2f8fa633aa299702d38fd509439e4e2ac0b8751a64358b32a
4
+ data.tar.gz: 28118eed7d772c490670f83277ccdabc4d2938ca329f5051f8aebd40be1f08a6
5
5
  SHA512:
6
- metadata.gz: '06038e9dd28433a1c9358915720fe942f597caee2d68651ce7c54b47136633cc1d55288c7b8053766f393bacda9974b1ee662337f80d78b0796d405453b2cc32'
7
- data.tar.gz: 92074fd8665515453126f44627604f7fd3da1dcb7a85ec25b1ef51424c6797f9b1f67925d2349db05b7ce7aace06dc7f3f2d2be737cfb5399383bed4f846b11f
6
+ metadata.gz: 1f4262320cb3d9ef5304cbdb53af7cb0e0895bac03e7d98697cf38fc73dabc25b579c6fd4a213ae5c0d97d1763f88dabde2f7f1e6455a084c424ef6b042a3acb
7
+ data.tar.gz: 35e2b8378b602ad6b853ba7f543d807aab514d0f2a7d8b931230912084d40c7222e45d09cfe4b3eddd614f62bcce578cac2b6e14dac08f5578089ecbb7d7895c
data/README.md CHANGED
@@ -29,11 +29,13 @@ For example, You can write script in Rakefile.
29
29
  require 'orthoses'
30
30
 
31
31
  namespace :rbs do
32
- desc "build RBS to sig/out"
32
+ desc "build RBS to sig/orthoses"
33
33
  task :build do
34
34
  Orthoses::Builder.new do
35
35
  use Orthoses::CreateFileByName,
36
- base_dir: Rails.root.join("sig/out"),
36
+ depth: 1,
37
+ to: "sig/orthoses",
38
+ rmtree: true,
37
39
  header: "# !!! GENERATED CODE !!!"
38
40
  use Orthoses::Filter do |name, _content|
39
41
  path, _lineno = Object.const_source_location(name)
@@ -53,7 +55,7 @@ namespace :rbs do
53
55
  end
54
56
  ```
55
57
 
56
- Then, you can see the result files under `sig/out`.
58
+ Then, you can see the result files under `sig/orthoses`.
57
59
 
58
60
  ## Utils
59
61
 
@@ -177,6 +179,11 @@ Sort signatures by class/module.
177
179
 
178
180
  Trace the argument and return value objects when the method is actually called and determine the type.
179
181
 
182
+ ## Orthoses::MissingName
183
+
184
+ Completes undefined class/module names.
185
+ If it is unknown whether it is a class or a module, it is defined as an empty module, and if it is a superclass, it is defined as an empty class.
186
+
180
187
  ## Development
181
188
 
182
189
  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.
@@ -1,98 +1,71 @@
1
1
  module Orthoses
2
2
  class Attribute
3
+ CALL_GRAPH = {}
4
+
3
5
  module Hook
4
6
  def attr(*names)
7
+ (CALL_GRAPH[self]||=[]) << [:attr, names]
5
8
  super
6
9
  end
7
10
 
8
11
  def attr_accessor(*names)
12
+ (CALL_GRAPH[self]||=[]) << [:attr_accessor, names]
9
13
  super
10
14
  end
11
15
 
12
16
  def attr_reader(*names)
17
+ (CALL_GRAPH[self]||=[]) << [:attr_reader, names]
13
18
  super
14
19
  end
15
20
 
16
21
  def attr_writer(*names)
22
+ (CALL_GRAPH[self]||=[]) << [:attr_writer, names]
17
23
  super
18
24
  end
19
25
  end
20
26
 
21
27
  def initialize(loader)
28
+ CALL_GRAPH.clear
22
29
  @loader = loader
23
30
  end
24
31
 
25
32
  def call
26
33
  ::Module.prepend(Hook)
27
34
 
28
- attr = CallTracer.new
29
- attr_accessor = CallTracer.new
30
- attr_reader = CallTracer.new
31
- attr_writer = CallTracer.new
32
-
33
- store = attr.trace(Hook.instance_method(:attr)) do
34
- attr_accessor.trace(Hook.instance_method(:attr_accessor)) do
35
- attr_reader.trace(Hook.instance_method(:attr_reader)) do
36
- attr_writer.trace(Hook.instance_method(:attr_writer)) do
37
- @loader.call
38
- end
39
- end
40
- end
41
- end
35
+ store = @loader.call
42
36
 
43
- attr.captures.each do |capture|
44
- m = capture.method.receiver.to_s.match(/#<Class:([\w:]+)>/)
37
+ CALL_GRAPH.dup.each do |base_mod, calls|
38
+ m = base_mod.to_s.match(/#<Class:([\w:]+)>/)
45
39
  if m && m[1]
46
40
  receiver_name = m[1]
47
41
  prefix = "self."
48
42
  else
49
- receiver_name = Utils.module_name(capture.method.receiver) or next
43
+ receiver_name = Utils.module_name(base_mod) or next
50
44
  prefix = nil
51
45
  end
52
46
  content = store[receiver_name]
53
- names = capture.argument[:names]
54
- if names[1].equal?(true)
55
- content << "attr_accessor #{prefix}#{names[0]}: untyped"
56
- elsif names[1].equal?(false)
57
- content << "attr_reader #{prefix}#{names[0]}: untyped"
58
- else
59
- names.each do |name|
60
- content << "attr_reader #{prefix}#{name}: untyped"
47
+
48
+ calls.each do |(a, names)|
49
+ case a
50
+ when :attr
51
+ if names[1].equal?(true)
52
+ content << "attr_accessor #{prefix}#{names[0]}: untyped"
53
+ elsif names[1].equal?(false)
54
+ content << "attr_reader #{prefix}#{names[0]}: untyped"
55
+ else
56
+ names.each do |name|
57
+ content << "attr_reader #{prefix}#{name}: untyped"
58
+ end
59
+ end
60
+ else
61
+ names.each do |name|
62
+ content << "#{a} #{prefix}#{name}: untyped"
63
+ end
61
64
  end
62
65
  end
63
66
  end
64
67
 
65
- each_definition(attr_accessor) do |receiver_name, name|
66
- store[receiver_name] << "attr_accessor #{name}: untyped"
67
- end
68
- each_definition(attr_reader) do |receiver_name, name|
69
- store[receiver_name] << "attr_reader #{name}: untyped"
70
- end
71
- each_definition(attr_writer) do |receiver_name, name|
72
- store[receiver_name] << "attr_writer #{name}: untyped"
73
- end
74
-
75
68
  store
76
69
  end
77
-
78
- private
79
-
80
- def each_definition(call_tracer)
81
- call_tracer.captures.each do |capture|
82
- m = capture.method.receiver.to_s.match(/#<Class:([\w:]+)>/)
83
- names = capture.argument[:names]
84
- if m && m[1]
85
- receiver_name = m[1]
86
- names.each do |name|
87
- yield [receiver_name, "self.#{name}"]
88
- end
89
- else
90
- receiver_name = Utils.module_name(capture.method.receiver) or next
91
- names.each do |name|
92
- yield [receiver_name, name]
93
- end
94
- end
95
- end
96
- end
97
70
  end
98
71
  end
@@ -13,7 +13,7 @@ module Orthoses
13
13
  class Builder
14
14
  def initialize(&block)
15
15
  @use = []
16
- @run = nil
16
+ @runner = nil
17
17
  instance_eval(&block) if block
18
18
  end
19
19
 
@@ -37,7 +37,11 @@ module Orthoses
37
37
 
38
38
  def run(loader)
39
39
  use Store
40
- @run = proc do
40
+ reset_runner(loader)
41
+ end
42
+
43
+ def reset_runner(loader)
44
+ @runner = proc do
41
45
  Orthoses.logger.info("[loader].call start")
42
46
  loader.call.tap do
43
47
  Orthoses.logger.info("[loader].call end")
@@ -46,7 +50,7 @@ module Orthoses
46
50
  end
47
51
 
48
52
  def to_loader
49
- @use.reverse.inject(@run) { |current, next_proc| next_proc[current] }
53
+ @use.reverse.inject(@runner) { |current, next_proc| next_proc[current] }
50
54
  end
51
55
 
52
56
  def call
@@ -14,7 +14,6 @@ module Orthoses
14
14
  @loader.call.tap do |store|
15
15
  will_add_key_and_content = []
16
16
  store.each do |name, _|
17
- next if name == :Module
18
17
  next if name.start_with?('#<')
19
18
 
20
19
  begin
@@ -4,71 +4,103 @@ module Orthoses
4
4
  class DuplicationChecker
5
5
  def initialize(decl, env: nil)
6
6
  @decl = decl
7
- @env = env || Utils.rbs_environment
7
+ @known_env = env || Utils.rbs_environment
8
+ @builder = RBS::DefinitionBuilder.new(env: @known_env)
9
+ @uniq_map = {}
8
10
  end
9
11
 
10
12
  def update_decl
11
13
  return unless @decl.respond_to?(:members)
12
14
 
13
- uniq_map = uniq_members
14
- drop_set_method_definition(uniq_map)
15
- drop_known_method_definition(uniq_map)
15
+ uniq_members
16
+ drop_set_method_definition
17
+ drop_by_singleton_instance
18
+ drop_known_method_definition
19
+ drop_known_const_definition
16
20
 
17
- @decl.members.replace(uniq_map.values)
21
+ @decl.members.replace(@uniq_map.values)
22
+
23
+ @uniq_map.clear
18
24
  end
19
25
 
20
26
  private
21
27
 
22
28
  def uniq_members
23
- {}.tap do |uniq_map|
24
- @decl.members.each do |member|
25
- if member.instance_of?(RBS::AST::Members::MethodDefinition) && member.overloading?
26
- # avoid to duplicate and keep order
27
- uniq_map[Object.new] = member
28
- else
29
- key = member_key(member)
30
- drop_member = uniq_map[key]
31
- uniq_map[key] = member
32
- if drop_member
33
- Orthoses.logger.info("#{@decl.name} \"#{member.location.source}\" was droped since duplication")
34
- end
29
+ @decl.members.each do |member|
30
+ if member.instance_of?(RBS::AST::Members::MethodDefinition) && member.overloading?
31
+ # avoid to duplicate and keep order
32
+ @uniq_map[Object.new] = member
33
+ else
34
+ key = member_key(member)
35
+ drop_member = @uniq_map[key]
36
+ @uniq_map[key] = member
37
+ if drop_member
38
+ Orthoses.logger.info("#{@decl.name} \"#{member.location.source}\" was droped since duplication")
35
39
  end
36
40
  end
37
41
  end
38
42
  end
39
43
 
40
- def drop_set_method_definition(uniq_map)
41
- attr_accessors = uniq_map.values.grep(RBS::AST::Members::AttrAccessor)
44
+ def drop_by_singleton_instance
45
+ singleton_instances = @uniq_map.values.select { |v| v.instance_of?(RBS::AST::Members::MethodDefinition) && v.kind == :singleton_instance }
46
+ singleton_instances.each do |member|
47
+ @uniq_map.delete([member.class, member.name, :instance])
48
+ @uniq_map.delete([member.class, member.name, :singleton])
49
+ end
50
+ end
51
+
52
+ def drop_set_method_definition
53
+ attr_accessors = @uniq_map.values.grep(RBS::AST::Members::AttrAccessor)
42
54
  attr_accessors.each do |member|
43
- uniq_map.delete([RBS::AST::Members::MethodDefinition, :"#{member.name}=", member.kind])
55
+ @uniq_map.delete([RBS::AST::Members::MethodDefinition, :"#{member.name}=", member.kind])
44
56
  end
45
57
  end
46
58
 
47
- def drop_known_method_definition(uniq_map)
59
+ def drop_known_method_definition
48
60
  decl_name = @decl.name.absolute!
49
- if m_entry = @env.class_decls[decl_name]
61
+ if m_entry = @known_env.class_decls[decl_name]
50
62
  m_entry.decls.each do |d|
51
- d.decl.members.each do |member|
52
- case member
53
- when RBS::AST::Members::LocationOnly
54
- # ignore
55
- when RBS::AST::Members::AttrAccessor
56
- uniq_map.delete([RBS::AST::Members::MethodDefinition, member.name, member.kind])
57
- uniq_map.delete([RBS::AST::Members::MethodDefinition, :"#{member.name}=", member.kind])
58
- else
59
- uniq_map.delete(member_key(member))
60
- end
63
+ drop_known_method_definition_recur(d)
64
+ end
65
+ end
66
+ end
67
+
68
+ def drop_known_method_definition_recur(d)
69
+ d.decl.members.each do |member|
70
+ case member
71
+ when RBS::AST::Members::MethodDefinition
72
+ if member.kind == :singleton_instance
73
+ @uniq_map.delete([member.class, member.name, :instance])
74
+ @uniq_map.delete([member.class, member.name, :singleton])
75
+ end
76
+ @uniq_map.delete(member_key(member))
77
+ when RBS::AST::Members::LocationOnly
78
+ # ignore
79
+ when RBS::AST::Members::AttrAccessor
80
+ @uniq_map.delete([RBS::AST::Members::MethodDefinition, member.name, member.kind])
81
+ @uniq_map.delete([RBS::AST::Members::MethodDefinition, :"#{member.name}=", member.kind])
82
+ when RBS::AST::Members::Include
83
+ if member.name.interface?
84
+ # If interface is included, it is shared in the same namespace.
85
+ drop_known_method_definition_recur(@known_env.interface_decls[member.name])
86
+ else
87
+ @uniq_map.delete(member_key(member))
61
88
  end
89
+ else
90
+ @uniq_map.delete(member_key(member))
62
91
  end
63
92
  end
93
+ end
64
94
 
65
- constants_in_uniq_map = uniq_map.select do |key, value|
95
+ def drop_known_const_definition
96
+ decl_name = @decl.name.absolute!
97
+ constants_in_uniq_map = @uniq_map.select do |key, value|
66
98
  value.kind_of?(RBS::AST::Declarations::Constant)
67
99
  end
68
100
  constants_in_uniq_map.each do |key, value|
69
101
  type_name = decl_name + value.name
70
- if @env.constant_decls[type_name]
71
- uniq_map.delete(key)
102
+ if @known_env.constant_decls[type_name]
103
+ @uniq_map.delete(key)
72
104
  end
73
105
  end
74
106
  end
@@ -42,7 +42,7 @@ module Orthoses
42
42
  def write_to(store:)
43
43
  each do |add_content|
44
44
  content = store[add_content.name]
45
- content.header ||= add_content.header
45
+ content.header = add_content.header
46
46
  content.comment ||= add_content.comment
47
47
  content.concat(add_content.body)
48
48
  end
@@ -102,19 +102,7 @@ module Orthoses
102
102
 
103
103
  case val
104
104
  when Class
105
- superclass =
106
- if val.superclass && val.superclass != Object
107
- super_module_name = Utils.module_name(val.superclass)
108
-
109
- if super_module_name && super_module_name != "Random::Base" # https://github.com/ruby/rbs/pull/977
110
- " < ::#{super_module_name}#{temporary_type_params(super_module_name)}"
111
- else
112
- nil
113
- end
114
- else
115
- nil
116
- end
117
- self.header = "class #{Utils.module_name(val)}#{type_params(name)}#{superclass}"
105
+ self.header = "class #{Utils.module_name(val)}#{type_params(name)}#{build_super_class(val)}"
118
106
  when Module
119
107
  self.header = "module #{Utils.module_name(val)}#{type_params(name)}"
120
108
  else
@@ -124,6 +112,25 @@ module Orthoses
124
112
 
125
113
  private
126
114
 
115
+ def build_super_class(val)
116
+ return nil unless val.superclass && val.superclass != Object
117
+
118
+ begin
119
+ # check private const
120
+ eval(val.superclass.to_s)
121
+ rescue NameError
122
+ return nil
123
+ end
124
+
125
+ super_module_name = Utils.module_name(val.superclass)
126
+ return nil unless super_module_name
127
+
128
+ # https://github.com/ruby/rbs/pull/977
129
+ return nil unless super_module_name != "Random::Base"
130
+
131
+ " < ::#{super_module_name}#{temporary_type_params(super_module_name)}"
132
+ end
133
+
127
134
  class ArrayIO
128
135
  def initialize
129
136
  @outs = []
@@ -6,31 +6,62 @@ module Orthoses
6
6
  class CreateFileByName
7
7
  prepend Outputable
8
8
 
9
- def initialize(loader, base_dir:, header: nil, if: nil)
9
+ def initialize(loader, base_dir: nil, to: nil, header: nil, if: nil, depth: nil, rmtree: false)
10
+ unless base_dir.nil?
11
+ warn "[Orthoses::CreateFileByName] base_dir: option is deprecated. Please use to: option instead."
12
+ end
13
+
14
+ to = to || base_dir
15
+ unless to
16
+ raise ArgumentError, "should set to: option"
17
+ end
18
+
19
+ relative_path_from_pwd = Pathname(to).expand_path.relative_path_from(Pathname.pwd).to_s
20
+ unless relative_path_from_pwd == "." || !relative_path_from_pwd.match?(%r{\A[/\.]})
21
+ raise ArgumentError, "to=\"#{to}\" should be under current dir=\"#{Pathname.pwd}\"."
22
+ end
23
+
10
24
  @loader = loader
11
- @base_dir = base_dir
25
+ @to = to
12
26
  @header = header
27
+ @depth = depth
28
+ @rmtree = rmtree
13
29
  @if = binding.local_variable_get(:if)
14
30
  end
15
31
 
16
32
  using Utils::Underscore
17
33
 
18
34
  def call
35
+ if @rmtree
36
+ Orthoses.logger.debug("Remove dir #{@to} since `rmtree: true`")
37
+ Pathname(@to).rmtree rescue nil
38
+ end
39
+
19
40
  store = @loader.call
20
41
 
21
- store.each do |name, content|
22
- next unless @if.nil? || @if.call(name, content)
42
+ store.select! do |name, content|
43
+ @if.nil? || @if.call(name, content)
44
+ end
45
+ grouped = store.group_by do |name, _|
46
+ splitted = name.to_s.split('::')
47
+ (@depth ? splitted[0, @depth] : splitted).join('::')
48
+ end
23
49
 
24
- file_path = Pathname("#{@base_dir}/#{name.to_s.split('::').map(&:underscore).join('/')}.rbs")
50
+ grouped.each do |group_name, group|
51
+ file_path = Pathname("#{@to}/#{group_name.split('::').map(&:underscore).join('/')}.rbs")
25
52
  file_path.dirname.mkpath
26
53
  file_path.open('w+') do |out|
27
54
  if @header
28
55
  out.puts @header
29
56
  out.puts
30
57
  end
31
- out.puts content.to_rbs
58
+ group.sort!
59
+ contents = group.map do |(name, content)|
60
+ content.to_rbs
61
+ end.join("\n")
62
+ out.puts contents
63
+ Orthoses.logger.info("Generate file to #{file_path.to_s}")
32
64
  end
33
- Orthoses.logger.info("Generate file to #{file_path.to_s}")
34
65
  end
35
66
  end
36
67
  end
@@ -10,32 +10,44 @@ module Orthoses
10
10
  # ...
11
11
  # end
12
12
  class LazyTracePoint < TracePoint
13
+ METHOD_METHOD = ::Kernel.instance_method(:method)
14
+ INSTANCE_METHOD_METHOD = ::Module.instance_method(:instance_method)
15
+ UNBOUND_NAME_METHOD = ::Module.instance_method(:name)
16
+ METHOD_ADDED_HOOKS = {}
17
+ SINGLETON_METHOD_ADDED_HOOKS = {}
18
+
13
19
  # for TracePoint target
14
- ::Module.prepend(Module.new{
20
+ module MethodAddedHook
15
21
  def method_added(id)
22
+ begin
23
+ if h = METHOD_ADDED_HOOKS[id]
24
+ if mod_name = UNBOUND_NAME_METHOD.bind(self).call
25
+ h[mod_name]&.call(self, id)
26
+ end
27
+ end
28
+ rescue TypeError => e
29
+ end
16
30
  super
17
31
  end
18
- })
19
- ::BasicObject.prepend(Module.new{
32
+ end
33
+ ::Module.prepend MethodAddedHook
34
+
35
+ module SignletonMethodAddedHook
20
36
  def singleton_method_added(id)
37
+ begin
38
+ if h = SINGLETON_METHOD_ADDED_HOOKS[id]
39
+ if mod_name = UNBOUND_NAME_METHOD.bind(self).call
40
+ h[mod_name]&.call(self, id)
41
+ end
42
+ end
43
+ rescue TypeError => e
44
+ end
21
45
  super
22
46
  end
23
- })
24
-
25
- METHOD_METHOD = ::Kernel.instance_method(:method)
26
- INSTANCE_METHOD_METHOD = ::Module.instance_method(:instance_method)
27
- UNBOUND_NAME_METHOD = ::Module.instance_method(:name)
28
- METHOD_ADDED_METHOD = ::Module.instance_method(:method_added)
29
- SINGLETON_METHOD_ADDED_METHOD = ::BasicObject.instance_method(:singleton_method_added)
30
-
31
- def initialize(*events, &block)
32
- @mod_name = nil
33
- @instance_method_id = nil
34
- @singleton_method_id = nil
35
- super
36
47
  end
48
+ ::BasicObject.prepend SignletonMethodAddedHook
37
49
 
38
- def enable(target: nil, target_line: nil, target_thread: nil, &block)
50
+ def enable(target: nil, &block)
39
51
  return super unless target.kind_of?(String)
40
52
 
41
53
  case
@@ -59,43 +71,25 @@ module Orthoses
59
71
  private
60
72
 
61
73
  def trace_instance_method(&block)
62
- # try to load
63
74
  target = Object.const_get(@mod_name).instance_method(@instance_method_id)
64
75
  enable(target: target, &block)
65
76
  rescue NameError
66
- TracePoint.new(:call) do |tp|
67
- id = tp.binding.local_variable_get(:id)
68
- next unless id == @instance_method_id
69
-
70
- mod_name = UNBOUND_NAME_METHOD.bind(tp.self).call
71
-
72
- next unless mod_name
73
- next unless mod_name == @mod_name
74
-
75
- enable(target: INSTANCE_METHOD_METHOD.bind(tp.self).call(id))
76
- tp.disable
77
- end.enable(target: METHOD_ADDED_METHOD, &block)
77
+ (METHOD_ADDED_HOOKS[@instance_method_id] ||= {})[@mod_name] = ->(const, id) {
78
+ enable(target: INSTANCE_METHOD_METHOD.bind(const).call(id))
79
+ }
80
+ block&.call
78
81
  ensure
79
82
  disable
80
83
  end
81
84
 
82
85
  def trace_singleton_method(&block)
83
- # try to load
84
86
  target = Object.const_get(@mod_name).method(@singleton_method_id)
85
87
  enable(target: target, &block)
86
88
  rescue NameError
87
- TracePoint.new(:call) do |tp|
88
- id = tp.binding.local_variable_get(:id)
89
- next unless id == @singleton_method_id
90
-
91
- mod_name = UNBOUND_NAME_METHOD.bind(tp.self).call
92
-
93
- next unless mod_name
94
- next unless mod_name == @mod_name
95
-
96
- enable(target: METHOD_METHOD.bind(tp.self).call(id))
97
- tp.disable
98
- end.enable(target: SINGLETON_METHOD_ADDED_METHOD, &block)
89
+ (SINGLETON_METHOD_ADDED_HOOKS[@singleton_method_id] ||= {})[@mod_name] = ->(const, id) {
90
+ enable(target: METHOD_METHOD.bind(const).call(id))
91
+ }
92
+ block&.call
99
93
  ensure
100
94
  disable
101
95
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ class MissingName
5
+ def initialize(loader)
6
+ @loader = loader
7
+ end
8
+
9
+ def call
10
+ @loader.call.tap do |store|
11
+ MissingClass.new(store).call
12
+ MissingModule.new(store).call
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ class MissingClass
19
+ def initialize(store)
20
+ @store = store
21
+ end
22
+
23
+ def call
24
+ @store.values.each do |content|
25
+ recur(content)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def recur(content)
32
+ content.auto_header
33
+ if content.header && content.header.include?("<")
34
+ _, superclass = content.header.split(/\s*<\s*/, 2)
35
+ superclass.sub!(/\[.*/, "")
36
+ new_name = TypeName(superclass).relative!.to_s
37
+ recur(@store[new_name])
38
+ end
39
+ end
40
+ end
41
+
42
+ class MissingModule
43
+ def initialize(store)
44
+ @store = store
45
+ end
46
+
47
+ def call
48
+ missings = []
49
+ @store.keys.each do |key_name|
50
+ missings.concat split_name(key_name)
51
+ end
52
+ missings.uniq!
53
+ missings.each do |missing|
54
+ @store[missing].header = "module #{missing}"
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def split_name(key_name)
61
+ ret = []
62
+
63
+ type_name = TypeName(key_name).relative!
64
+ if !Utils.rbs_defined_class?(type_name.to_s) && !@store.has_key?(type_name.to_s)
65
+ ret << type_name.to_s
66
+ end
67
+
68
+ path = type_name.namespace.path
69
+ path.each_with_index do |sym, index|
70
+ name = path[0, index + 1].join("::")
71
+ next if name.empty?
72
+ if !Utils.rbs_defined_class?(name) && !@store.has_key?(name)
73
+ ret << name
74
+ end
75
+ end
76
+
77
+ ret
78
+ end
79
+ end
80
+ end
81
+ end