orthoses 0.8.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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