orthoses 0.8.0 → 0.11.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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +12 -12
  4. data/README.md +41 -1
  5. data/lib/orthoses/attribute.rb +0 -2
  6. data/lib/orthoses/autoload.rb +37 -0
  7. data/lib/orthoses/call_tracer/capturable.rb +42 -0
  8. data/lib/orthoses/call_tracer/lazy.rb +22 -0
  9. data/lib/orthoses/call_tracer.rb +9 -33
  10. data/lib/orthoses/content/duplication_checker.rb +15 -9
  11. data/lib/orthoses/content/header_builder.rb +12 -7
  12. data/lib/orthoses/content.rb +41 -11
  13. data/lib/orthoses/create_file_by_name.rb +12 -4
  14. data/lib/orthoses/lazy_trace_point.rb +103 -0
  15. data/lib/orthoses/load_rbs.rb +3 -1
  16. data/lib/orthoses/mixin.rb +2 -2
  17. data/lib/orthoses/object_space_all.rb +1 -3
  18. data/lib/orthoses/outputable/avoid_recursive_ancestor_error.rb +37 -0
  19. data/lib/orthoses/outputable.rb +21 -0
  20. data/lib/orthoses/path_helper.rb +38 -0
  21. data/lib/orthoses/rbs_prototype_runtime.rb +32 -0
  22. data/lib/orthoses/utils.rb +9 -4
  23. data/lib/orthoses/version.rb +1 -1
  24. data/lib/orthoses/writer.rb +2 -0
  25. data/lib/orthoses.rb +10 -1
  26. data/sig/orthoses/attribute/hook.rbs +0 -3
  27. data/sig/orthoses/autoload/hook.rbs +5 -0
  28. data/sig/orthoses/autoload.rbs +6 -0
  29. data/sig/orthoses/builder.rbs +0 -1
  30. data/sig/orthoses/call_tracer/capturable.rbs +7 -0
  31. data/sig/orthoses/call_tracer/lazy.rbs +6 -0
  32. data/sig/orthoses/call_tracer.rbs +0 -1
  33. data/sig/orthoses/content/array_io.rbs +7 -0
  34. data/sig/orthoses/content/duplication_checker.rbs +2 -3
  35. data/sig/orthoses/content/environment.rbs +0 -1
  36. data/sig/orthoses/content/header_builder.rbs +1 -0
  37. data/sig/orthoses/content.rbs +4 -2
  38. data/sig/orthoses/lazy_trace_point.rbs +15 -0
  39. data/sig/orthoses/load_rbs.rbs +3 -2
  40. data/sig/orthoses/mixin/hook.rbs +0 -2
  41. data/sig/orthoses/{avoid_recursive_ancestor_error.rbs → outputable/avoid_recursive_ancestor_error.rbs} +2 -2
  42. data/sig/orthoses/outputable.rbs +5 -0
  43. data/sig/orthoses/path_helper.rbs +9 -0
  44. data/sig/orthoses/rbs_prototype_runtime.rbs +6 -0
  45. data/sig/orthoses/utils.rbs +1 -13
  46. data/sig/orthoses.rbs +3 -3
  47. metadata +21 -5
  48. data/lib/orthoses/avoid_recursive_ancestor_error.rb +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2941ebbe45d7ab2dc9ad009628db52419a6a3b18a1fd1ad870164ab017bbb5e1
4
- data.tar.gz: 5a33b4b63f62b820f4642d56661cebd393c3381363a8f727655f123568b2784b
3
+ metadata.gz: 1bbebf8271fbe9859e0e322e0e2d12fbf7a03dc30663309771edeba678674679
4
+ data.tar.gz: bfdfabbb3110a7c159a7763463077768d76b9cfd14ae77537a87d0abbd8fda74
5
5
  SHA512:
6
- metadata.gz: bd9a27c8a8f6752fc73c2c65b8dbb0edcb9885425667a8a067a6d56cc2bb32473db565ea41089ad0f8b26c598275afa83e2fb3bbde6f668fc095c942bb75af01
7
- data.tar.gz: 4b6c157a129e1e3dfab42737ba1a4ba0f9c1c5ffe25defb693de3bce39f63fdcc746b155d030e273162e550ada315281553d921475bd4a333bf362a46e5a58bd
6
+ metadata.gz: e1093d5bbc23bf0577d915afd70fa34907316bcdd2062e34cdc7506f455636e47e02bb046048e4682c16feeba2bc045985fbae2636bd2e220fc90a66f30e957b
7
+ data.tar.gz: 84fe1da94bfe208b46ddc1b3607ba7962e1133150fe454ffc8d4e40ca0dd6bc99c4b7e24f41a18f0217913eedd6e5b08e45329d07455e1e5fb913d102c13b67e
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in orthoses.gemspec
6
6
  gemspec
7
7
 
8
+ gem "rbs"
8
9
  gem "rake", "~> 13.0"
9
10
  gem "rgot", "~> 1.1"
10
11
  gem "steep"
11
- gem "activesupport"
data/Gemfile.lock CHANGED
@@ -1,13 +1,13 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- orthoses (0.8.0)
4
+ orthoses (0.11.0)
5
5
  rbs (~> 2.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (7.0.3)
10
+ activesupport (7.0.3.1)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  i18n (>= 1.6, < 2)
13
13
  minitest (>= 5.1)
@@ -15,45 +15,45 @@ GEM
15
15
  ast (2.4.2)
16
16
  concurrent-ruby (1.1.10)
17
17
  ffi (1.15.5)
18
- i18n (1.10.0)
18
+ i18n (1.12.0)
19
19
  concurrent-ruby (~> 1.0)
20
- language_server-protocol (3.16.0.3)
20
+ language_server-protocol (3.17.0.0)
21
21
  listen (3.7.1)
22
22
  rb-fsevent (~> 0.10, >= 0.10.3)
23
23
  rb-inotify (~> 0.9, >= 0.9.10)
24
- minitest (5.15.0)
24
+ minitest (5.16.3)
25
25
  parallel (1.22.1)
26
- parser (3.1.2.0)
26
+ parser (3.1.2.1)
27
27
  ast (~> 2.4.1)
28
28
  rainbow (3.1.1)
29
29
  rake (13.0.6)
30
30
  rb-fsevent (0.11.1)
31
31
  rb-inotify (0.10.1)
32
32
  ffi (~> 1.0)
33
- rbs (2.5.0)
33
+ rbs (2.6.0)
34
34
  rgot (1.1.0)
35
- steep (1.0.0)
35
+ steep (1.1.1)
36
36
  activesupport (>= 5.1)
37
37
  language_server-protocol (>= 3.15, < 4.0)
38
38
  listen (~> 3.0)
39
39
  parallel (>= 1.0.0)
40
- parser (>= 3.0)
40
+ parser (>= 3.1)
41
41
  rainbow (>= 2.2.2, < 4.0)
42
42
  rbs (>= 2.3.2)
43
43
  terminal-table (>= 2, < 4)
44
44
  terminal-table (3.0.2)
45
45
  unicode-display_width (>= 1.1.1, < 3)
46
- tzinfo (2.0.4)
46
+ tzinfo (2.0.5)
47
47
  concurrent-ruby (~> 1.0)
48
- unicode-display_width (2.1.0)
48
+ unicode-display_width (2.2.0)
49
49
 
50
50
  PLATFORMS
51
51
  ruby
52
52
 
53
53
  DEPENDENCIES
54
- activesupport
55
54
  orthoses!
56
55
  rake (~> 13.0)
56
+ rbs
57
57
  rgot (~> 1.1)
58
58
  steep
59
59
 
data/README.md CHANGED
@@ -41,6 +41,34 @@ Orthoses::Builder.new do
41
41
  end.call
42
42
  ```
43
43
 
44
+ ## Utils
45
+
46
+ `Orthoses::Utils` is a collection of useful methods.
47
+
48
+ ### Orthoses::Utils.each_const_recursive
49
+
50
+ Yield const by recursive.
51
+
52
+ ### Orthoses::Utils.rbs_defined_const?
53
+
54
+ Checks if the const name is already defined.
55
+
56
+ ### Orthoses::Utils.rbs_defined_class?
57
+
58
+ Checks if the class name is already defined.
59
+
60
+ ### Orthoses::Utils.rbs_environment
61
+
62
+ Fetch cached `RBS::Environment`.
63
+
64
+ ### Orthoses::Utils.object_to_rbs
65
+
66
+ Convert Ruby object to RBS string.
67
+
68
+ ### Orthoses::Utils.module_name
69
+
70
+ Get true module name by `Module.instance_method(:name).bind(mod).call`.
71
+
44
72
  ## Middlewares
45
73
 
46
74
  ### Orthoses::Constant
@@ -48,10 +76,14 @@ end.call
48
76
  Add constant signature to class/module.
49
77
  Signatures are predicted from constant values.
50
78
 
79
+ ### Orthoses::Attribute
80
+
81
+ Add `attr`, `attr_accessor`, `attr_reader` and `attr_writer` to output RBS.
82
+ All type set `untyped`.
83
+
51
84
  ### Orthoses::Mixin
52
85
 
53
86
  Add module include/extend/prepend definition.
54
- It use `Module#{includeed,extended,prepended}` for capture.
55
87
 
56
88
  ### Orthoses::ObjectSpaceAll
57
89
 
@@ -115,11 +147,19 @@ Run `rbs prototype rb` command process to `paths` option files.
115
147
  `content_filter` option could filter with content decl.
116
148
  `mixin_filter` option could filter with mixin(include, extend, prepend) decl.
117
149
 
150
+ ### Orthoses::RBSPrototypeRuntime
151
+
152
+ Run `rbs prototype runtime` command process with `patterns` option string.
153
+
118
154
  ### Orthoses::AvoidRecursiveAncestorError
119
155
 
120
156
  Mixin a module into an Object class raises `RBS::RecursiveAncestorError` when validation.
121
157
  Please add this middleware then.
122
158
 
159
+ ### Orthoses::Autoload
160
+
161
+ Force load const defined by `autoload`.
162
+
123
163
  ## Development
124
164
 
125
165
  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.
@@ -40,8 +40,6 @@ module Orthoses
40
40
  end
41
41
  end
42
42
 
43
- store["Module"].body.delete("prepend Orthoses::Attribute::Hook")
44
-
45
43
  attr.captures.each do |capture|
46
44
  m = capture.method.receiver.to_s.match(/#<Class:([\w:]+)>/)
47
45
  if m && m[1]
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ class Autoload
5
+ module Hook
6
+ def autoload(name, path)
7
+ super
8
+ end
9
+ end
10
+
11
+ def initialize(loader)
12
+ @loader = loader
13
+ end
14
+
15
+ def call
16
+ ::Module.prepend(Hook)
17
+
18
+ autoload = CallTracer.new
19
+
20
+ store = autoload.trace(Hook.instance_method(:autoload)) do
21
+ @loader.call
22
+ end
23
+
24
+ autoload.captures.each do |capture|
25
+ base_mod = capture.method.receiver
26
+ name = capture.argument[:name]
27
+ begin
28
+ base_mod.const_get(name)
29
+ rescue NameError, LoadError, ArgumentError => e
30
+ Orthoses.logger.warn("[Orthoses::Autoload] raise `#{e.message} (#{e.class})` when try to unautoload `#{base_mod}::#{name}`")
31
+ end
32
+ end
33
+
34
+ store
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ class CallTracer
5
+ module Capturable
6
+ def build_capture(tp)
7
+ Capture.new(
8
+ method: build_method(tp),
9
+ argument: build_argument(tp),
10
+ )
11
+ end
12
+
13
+ private
14
+
15
+ def build_method(tp)
16
+ METHOD_METHOD.bind(tp.self).call(tp.method_id)
17
+ end
18
+
19
+ def build_argument(tp)
20
+ tp.parameters.each_with_object({}) do |op_name, hash|
21
+ name = op_name[1]
22
+ case name
23
+ when :*, :**, :&, nil
24
+ # skip
25
+ else
26
+ hash[name] = tp.binding.local_variable_get(name).then do |var|
27
+ case var
28
+ when Module, Thread::Backtrace::Location
29
+ var
30
+ else
31
+ var.dup
32
+ end
33
+ rescue => err
34
+ warn("#dup fail (#{err.class}) #{err.message}")
35
+ var
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ class CallTracer
5
+ class Lazy
6
+ include Capturable
7
+
8
+ attr_reader :captures
9
+
10
+ def initialize
11
+ @captures = []
12
+ @lazy_trace_point = LazyTracePoint.new(:call) do |tp|
13
+ @captures << build_capture(tp)
14
+ end
15
+ end
16
+
17
+ def trace(name, &block)
18
+ @lazy_trace_point.enable(target: name, &block)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -16,46 +16,22 @@ module Orthoses
16
16
  class Capture < Struct.new(:method, :argument, keyword_init: true)
17
17
  end
18
18
 
19
+ autoload :Lazy, 'orthoses/call_tracer/lazy'
20
+ require_relative 'call_tracer/capturable'
21
+
22
+ include Capturable
23
+
19
24
  attr_accessor :captures
20
25
 
21
26
  def initialize
22
27
  @captures = []
28
+ @target_tp = TracePoint.new(:call) do |tp|
29
+ @captures << build_capture(tp)
30
+ end
23
31
  end
24
32
 
25
33
  def trace(target, &block)
26
- t = TracePoint.new(:call) do |tp|
27
- called_method = tp.self.method(tp.method_id)
28
- argument = tp.parameters.each_with_object({}) do |op_name, hash|
29
- name = op_name[1]
30
- case name
31
- when :*, :**, :&, nil
32
- # skip
33
- else
34
- hash[name] = tp.binding.local_variable_get(name).then do |var|
35
- case var
36
- when Module
37
- var # avoid missing name
38
- else
39
- var.dup
40
- end
41
- rescue => err
42
- case var
43
- when Thread::Backtrace::Location
44
- # known
45
- else
46
- warn("#dup fail (#{err.class}) #{err.message}")
47
- end
48
- var
49
- end
50
- end
51
- end
52
-
53
- @captures << Capture.new(
54
- method: called_method,
55
- argument: argument,
56
- )
57
- end
58
- t.enable(target: target, &block)
34
+ @target_tp.enable(target: target, &block)
59
35
  end
60
36
  end
61
37
  end
@@ -2,18 +2,20 @@ module Orthoses
2
2
  class Content
3
3
  # Check and drop duplication method, const etc...
4
4
  class DuplicationChecker
5
- def initialize(decl)
5
+ def initialize(decl, env: nil)
6
6
  @decl = decl
7
+ @env = env || Utils.rbs_environment(collection: true)
7
8
  end
8
9
 
9
10
  def update_decl
11
+ return unless @decl.respond_to?(:members)
10
12
  uniq_map = {}
11
13
  @decl.members.each do |member|
12
14
  key = member_key(member)
13
15
  drop_member = uniq_map[key]
14
16
  uniq_map[key] = member
15
17
  if drop_member
16
- Orthoses.logger.warn("#{@decl.name}::#{drop_member} was droped since duplication")
18
+ Orthoses.logger.info("#{@decl.name} \"#{member.location.source}\" was droped since duplication")
17
19
  end
18
20
  end
19
21
  drop_known_method_definition(uniq_map)
@@ -23,20 +25,24 @@ module Orthoses
23
25
  private
24
26
 
25
27
  def drop_known_method_definition(uniq_map)
26
- env = Utils.rbs_environment(collection: true)
27
- if m_entry = env.class_decls[@decl.name.absolute!]
28
+ decl_name = @decl.name.absolute!
29
+ if m_entry = @env.class_decls[decl_name]
28
30
  m_entry.decls.each do |d|
29
31
  d.decl.members.grep_v(RBS::AST::Members::LocationOnly).each do |member|
30
32
  uniq_map.delete(member_key(member))
31
33
  end
32
34
  end
33
35
  end
34
- end
35
36
 
36
- def member_to_s(member)
37
- out = StringIO.new
38
- RBS::Writer.new(out: out).write_member(member)
39
- out.string.chomp
37
+ constants_in_uniq_map = uniq_map.select do |key, value|
38
+ value.kind_of?(RBS::AST::Declarations::Constant)
39
+ end
40
+ constants_in_uniq_map.each do |key, value|
41
+ type_name = decl_name + value.name
42
+ if @env.constant_decls[type_name]
43
+ uniq_map.delete(key)
44
+ end
45
+ end
40
46
  end
41
47
 
42
48
  def member_key(member)
@@ -43,13 +43,9 @@ module Orthoses
43
43
  end
44
44
 
45
45
  def build_super_class(primary)
46
- return nil if primary.decl.super_class.then { |s| s.nil? || s.name.relative!.to_s.then { |n| n == "Object" || n == "Random::Base" } }
47
-
48
- context = primary.outer.length.times.map do |i|
49
- primary.outer[0, i + 1].map(&:name).inject(:+).to_namespace.absolute!
50
- end
51
- context.push(RBS::Namespace.root)
46
+ return nil if primary.decl.super_class.then { |s| s.nil? || s.name.relative!.to_s.then { |n| n == "Object" || n == "Random::Base" || n.start_with?("RBS::Unnamed") } }
52
47
 
48
+ context = build_context(entry: primary)
53
49
  super_class_name = @resolver.resolve(primary.decl.super_class.name, context: context) || primary.decl.super_class.name
54
50
  if primary.decl.super_class.args.empty?
55
51
  if super_class_entry = @env.class_decls[super_class_name]
@@ -65,7 +61,16 @@ module Orthoses
65
61
 
66
62
  def build_interface(entry:, name_hint: nil)
67
63
  full_name = name_hint || entry.decl.name.relative!
68
- "interface #{name_and_params(full_name, entry.decl.type_params)}"
64
+ context = build_context(entry: entry)
65
+ resolved_name = @resolver.resolve(full_name, context: context) || full_name
66
+ "interface #{name_and_params(resolved_name.relative!, entry.decl.type_params)}"
67
+ end
68
+
69
+ def build_context(entry:)
70
+ context = entry.outer.length.times.map do |i|
71
+ entry.outer[0, i + 1].map(&:name).inject(:+).to_namespace.absolute!
72
+ end
73
+ context.push(RBS::Namespace.root)
69
74
  end
70
75
 
71
76
  def name_and_params(name, params)
@@ -35,6 +35,14 @@ module Orthoses
35
35
  @body.concat(other)
36
36
  end
37
37
 
38
+ def empty?
39
+ @body.empty?
40
+ end
41
+
42
+ def delete(val)
43
+ @body.delete(val)
44
+ end
45
+
38
46
  def to_rbs
39
47
  auto_header
40
48
  uniqed_body_string
@@ -45,14 +53,36 @@ module Orthoses
45
53
  uniqed_body_decl
46
54
  end
47
55
 
48
- private
56
+ def uniq!
57
+ out = ArrayIO.new
58
+ writer = RBS::Writer.new(out: out)
59
+ to_decl.members.each do |member|
60
+ writer.write_member(member)
61
+ end
62
+ @body.replace(out.to_a)
63
+ end
49
64
 
50
65
  def original_rbs
51
- <<~RBS
52
- #{@header}
53
- #{@body.join("\n")}
54
- end
55
- RBS
66
+ a = [@header]
67
+ a << " #{@body.join("\n ")}" if @body.length > 0
68
+ a << "end"
69
+ a.join("\n")
70
+ end
71
+
72
+ private
73
+
74
+ class ArrayIO
75
+ def initialize
76
+ @outs = []
77
+ end
78
+
79
+ def puts(line)
80
+ @outs << line
81
+ end
82
+
83
+ def to_a
84
+ @outs
85
+ end
56
86
  end
57
87
 
58
88
  def uniqed_body_string
@@ -81,11 +111,6 @@ module Orthoses
81
111
  end
82
112
 
83
113
  def auto_header
84
- if name.split('::').last.start_with?('_')
85
- self.header = "interface #{name}"
86
- return
87
- end
88
-
89
114
  env = Utils.rbs_environment(collection: true)
90
115
  if entry = env.class_decls[TypeName(name).absolute!]
91
116
  @header = Content::HeaderBuilder.new(env: env).build(entry: entry)
@@ -94,6 +119,11 @@ module Orthoses
94
119
 
95
120
  return unless @header.nil?
96
121
 
122
+ if name.split('::').last.start_with?('_')
123
+ self.header = "interface #{name}"
124
+ return
125
+ end
126
+
97
127
  val = Object.const_get(name)
98
128
 
99
129
  case val
@@ -1,11 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'orthoses/outputable'
4
+
3
5
  module Orthoses
4
6
  class CreateFileByName
5
- def initialize(loader, base_dir:, header: nil)
7
+ prepend Outputable
8
+
9
+ def initialize(loader, base_dir:, header: nil, if: nil)
6
10
  @loader = loader
7
11
  @base_dir = base_dir
8
12
  @header = header
13
+ @if = binding.local_variable_get(:if)
9
14
  end
10
15
 
11
16
  using(Module.new {
@@ -28,12 +33,15 @@ module Orthoses
28
33
  store = @loader.call
29
34
 
30
35
  store.each do |name, content|
31
- rbs = begin
32
- content.to_rbs
36
+ begin
37
+ content.uniq!
33
38
  rescue NameError, LoadError => err
34
39
  Orthoses.logger.error(err.inspect)
35
40
  next
36
41
  end
42
+
43
+ next unless @if.nil? || @if.call(name, content)
44
+
37
45
  file_path = Pathname("#{@base_dir}/#{name.to_s.split('::').map(&:underscore).join('/')}.rbs")
38
46
  file_path.dirname.mkpath
39
47
  file_path.open('w+') do |out|
@@ -41,7 +49,7 @@ module Orthoses
41
49
  out.puts @header
42
50
  out.puts
43
51
  end
44
- out.puts rbs
52
+ out.puts content.original_rbs
45
53
  end
46
54
  Orthoses.logger.info("Generate file to #{file_path.to_s}")
47
55
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orthoses
4
+ # TracePoint wrapper that allows setting hooks
5
+ # even if the target is undefined
6
+ # LazyTracePoint.new(:call) do |tp|
7
+ # ...
8
+ # end.enable(target: 'Class#class_attribute') do
9
+ # require 'active_support/core_ext/class/attribute'
10
+ # ...
11
+ # end
12
+ class LazyTracePoint < TracePoint
13
+ # for TracePoint target
14
+ ::Module.prepend(Module.new{
15
+ def method_added(id)
16
+ super
17
+ end
18
+ })
19
+ ::BasicObject.prepend(Module.new{
20
+ def singleton_method_added(id)
21
+ super
22
+ 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
+ end
37
+
38
+ def enable(target: nil, target_line: nil, target_thread: nil, &block)
39
+ return super unless target.kind_of?(String)
40
+
41
+ case
42
+ when target.include?('#')
43
+ @mod_name, instance_method_id = target.split('#', 2)
44
+ @instance_method_id = instance_method_id.to_sym
45
+ @singleton_method_id = nil
46
+
47
+ trace_instance_method(&block)
48
+ when target.include?('.')
49
+ @mod_name, singleton_method_id = target.split('.', 2)
50
+ @singleton_method_id = singleton_method_id.to_sym
51
+ @instance_method_id = nil
52
+
53
+ trace_singleton_method(&block)
54
+ else
55
+ raise ArgumentError, "argument shuold be 'Foo#foo' or 'Foo.foo' format"
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ def trace_instance_method(&block)
62
+ # try to load
63
+ target = Object.const_get(@mod_name).instance_method(@instance_method_id)
64
+ enable(target: target, &block)
65
+ 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)
78
+ ensure
79
+ disable
80
+ end
81
+
82
+ def trace_singleton_method(&block)
83
+ # try to load
84
+ target = Object.const_get(@mod_name).method(@singleton_method_id)
85
+ enable(target: target, &block)
86
+ 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)
99
+ ensure
100
+ disable
101
+ end
102
+ end
103
+ end
@@ -11,7 +11,9 @@ module Orthoses
11
11
 
12
12
  def call
13
13
  @loader.call.tap do |store|
14
- env = Content::Environment.load_from_paths(@paths)
14
+ paths = @paths
15
+ paths = paths.call if paths.instance_of?(Proc)
16
+ env = Content::Environment.load_from_paths(paths.to_a)
15
17
  env.write_to(store: store)
16
18
  end
17
19
  end
@@ -34,8 +34,6 @@ module Orthoses
34
34
  end
35
35
  end
36
36
 
37
- store["Module"].body.delete("prepend Orthoses::Mixin::Hook")
38
-
39
37
  collect_definitions(store, include, :include)
40
38
  collect_definitions(store, extend, :extend)
41
39
  collect_definitions(store, prepend, :prepend)
@@ -58,6 +56,8 @@ module Orthoses
58
56
  mod_name = Utils.module_name(mod)
59
57
  next unless mod_name
60
58
 
59
+ next if mod_name.start_with?("Orthoses")
60
+
61
61
  known_type_params = Utils.known_type_params(mod)
62
62
  next unless known_type_params.nil? || known_type_params.empty?
63
63