tapioca 0.5.6 → 0.6.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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +114 -23
  3. data/lib/tapioca/cli.rb +188 -64
  4. data/lib/tapioca/compilers/dsl/active_record_associations.rb +94 -8
  5. data/lib/tapioca/compilers/dsl/active_record_columns.rb +5 -4
  6. data/lib/tapioca/compilers/dsl/active_record_relations.rb +703 -0
  7. data/lib/tapioca/compilers/dsl/active_record_scope.rb +43 -13
  8. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +2 -4
  9. data/lib/tapioca/compilers/dsl/base.rb +25 -42
  10. data/lib/tapioca/compilers/dsl/extensions/frozen_record.rb +29 -0
  11. data/lib/tapioca/compilers/dsl/frozen_record.rb +37 -0
  12. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +27 -0
  13. data/lib/tapioca/compilers/dsl/param_helper.rb +52 -0
  14. data/lib/tapioca/compilers/dsl/rails_generators.rb +120 -0
  15. data/lib/tapioca/compilers/dsl_compiler.rb +32 -6
  16. data/lib/tapioca/compilers/sorbet.rb +2 -0
  17. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +47 -46
  18. data/lib/tapioca/executor.rb +79 -0
  19. data/lib/tapioca/gemfile.rb +23 -0
  20. data/lib/tapioca/generators/base.rb +11 -18
  21. data/lib/tapioca/generators/dsl.rb +33 -38
  22. data/lib/tapioca/generators/gem.rb +50 -29
  23. data/lib/tapioca/generators/init.rb +41 -16
  24. data/lib/tapioca/generators/todo.rb +6 -6
  25. data/lib/tapioca/helpers/cli_helper.rb +26 -0
  26. data/lib/tapioca/helpers/config_helper.rb +84 -0
  27. data/lib/tapioca/helpers/test/content.rb +51 -0
  28. data/lib/tapioca/helpers/test/isolation.rb +125 -0
  29. data/lib/tapioca/helpers/test/template.rb +34 -0
  30. data/lib/tapioca/internal.rb +3 -2
  31. data/lib/tapioca/rbi_ext/model.rb +12 -9
  32. data/lib/tapioca/reflection.rb +13 -0
  33. data/lib/tapioca/trackers/autoload.rb +70 -0
  34. data/lib/tapioca/trackers/constant_definition.rb +42 -0
  35. data/lib/tapioca/trackers/mixin.rb +78 -0
  36. data/lib/tapioca/trackers.rb +14 -0
  37. data/lib/tapioca/version.rb +1 -1
  38. data/lib/tapioca.rb +28 -2
  39. metadata +19 -7
  40. data/lib/tapioca/config.rb +0 -45
  41. data/lib/tapioca/config_builder.rb +0 -73
  42. data/lib/tapioca/constant_locator.rb +0 -40
@@ -67,10 +67,11 @@ module RBI
67
67
  end
68
68
  end
69
69
 
70
- sig { params(name: String, block: T.nilable(T.proc.params(scope: Scope).void)).void }
70
+ sig { params(name: String, block: T.nilable(T.proc.params(scope: Scope).void)).returns(Scope) }
71
71
  def create_module(name, &block)
72
- node = create_node(RBI::Module.new(name))
73
- block&.call(T.cast(node, RBI::Scope))
72
+ T.cast(create_node(RBI::Module.new(name)), RBI::Scope).tap do |node|
73
+ block&.call(node)
74
+ end
74
75
  end
75
76
 
76
77
  sig do
@@ -78,11 +79,12 @@ module RBI
78
79
  name: String,
79
80
  superclass_name: T.nilable(String),
80
81
  block: T.nilable(T.proc.params(scope: RBI::Scope).void)
81
- ).void
82
+ ).returns(Scope)
82
83
  end
83
84
  def create_class(name, superclass_name: nil, &block)
84
- node = create_node(RBI::Class.new(name, superclass_name: superclass_name))
85
- block&.call(T.cast(node, RBI::Scope))
85
+ T.cast(create_node(RBI::Class.new(name, superclass_name: superclass_name)), RBI::Scope).tap do |node|
86
+ block&.call(node)
87
+ end
86
88
  end
87
89
 
88
90
  sig { params(name: String, value: String).void }
@@ -115,14 +117,15 @@ module RBI
115
117
  name: String,
116
118
  parameters: T::Array[TypedParam],
117
119
  return_type: String,
118
- class_method: T::Boolean
120
+ class_method: T::Boolean,
121
+ visibility: RBI::Visibility
119
122
  ).void
120
123
  end
121
- def create_method(name, parameters: [], return_type: "T.untyped", class_method: false)
124
+ def create_method(name, parameters: [], return_type: "T.untyped", class_method: false, visibility: RBI::Public.new)
122
125
  return unless valid_method_name?(name)
123
126
 
124
127
  sig = RBI::Sig.new(return_type: return_type)
125
- method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method)
128
+ method = RBI::Method.new(name, sigs: [sig], is_singleton: class_method, visibility: visibility)
126
129
  parameters.each do |param|
127
130
  method << param.param
128
131
  sig << RBI::SigParam.new(param.param.name, param.type)
@@ -19,6 +19,19 @@ module Tapioca
19
19
  PRIVATE_INSTANCE_METHODS_METHOD = T.let(Module.instance_method(:private_instance_methods), UnboundMethod)
20
20
  METHOD_METHOD = T.let(Kernel.instance_method(:method), UnboundMethod)
21
21
 
22
+ sig do
23
+ params(
24
+ symbol: String,
25
+ inherit: T::Boolean,
26
+ namespace: Module
27
+ ).returns(BasicObject).checked(:never)
28
+ end
29
+ def constantize(symbol, inherit: false, namespace: Object)
30
+ namespace.const_get(symbol, inherit)
31
+ rescue NameError, LoadError, RuntimeError, ArgumentError, TypeError
32
+ nil
33
+ end
34
+
22
35
  sig { params(object: BasicObject).returns(Class).checked(:never) }
23
36
  def class_of(object)
24
37
  CLASS_METHOD.bind(object).call
@@ -0,0 +1,70 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Trackers
6
+ module Autoload
7
+ extend T::Sig
8
+
9
+ NOOP_METHOD = -> (*_args, **_kwargs, &_block) {}
10
+
11
+ @constant_names_registered_for_autoload = T.let([], T::Array[String])
12
+
13
+ class << self
14
+ extend T::Sig
15
+
16
+ sig { void }
17
+ def eager_load_all!
18
+ with_disabled_exits do
19
+ until @constant_names_registered_for_autoload.empty?
20
+ # Grab the next constant name
21
+ constant_name = T.must(@constant_names_registered_for_autoload.shift)
22
+ # Trigger autoload by constantizing the registered name
23
+ Reflection.constantize(constant_name, inherit: true)
24
+ end
25
+ end
26
+ end
27
+
28
+ sig { params(constant_name: String).void }
29
+ def register(constant_name)
30
+ @constant_names_registered_for_autoload << constant_name
31
+ end
32
+
33
+ sig do
34
+ type_parameters(:Result)
35
+ .params(block: T.proc.returns(T.type_parameter(:Result)))
36
+ .returns(T.type_parameter(:Result))
37
+ end
38
+ def with_disabled_exits(&block)
39
+ original_abort = Kernel.instance_method(:abort)
40
+ original_exit = Kernel.instance_method(:exit)
41
+
42
+ begin
43
+ Kernel.define_method(:abort, NOOP_METHOD)
44
+ Kernel.define_method(:exit, NOOP_METHOD)
45
+
46
+ block.call
47
+ ensure
48
+ Kernel.define_method(:exit, original_exit)
49
+ Kernel.define_method(:abort, original_abort)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+
57
+ # We need to do the alias-method-chain dance since Bootsnap does the same,
58
+ # and prepended modules and alias-method-chain don't play well together.
59
+ #
60
+ # So, why does Bootsnap do alias-method-chain and not prepend? Glad you asked!
61
+ # That's because RubyGems does alias-method-chain for Kernel#require and such,
62
+ # so, if Bootsnap were to do prepend, it might end up breaking RubyGems.
63
+ class Module
64
+ alias_method(:autoload_without_tapioca, :autoload)
65
+
66
+ def autoload(const_name, path)
67
+ Tapioca::Trackers::Autoload.register("#{self}::#{const_name}")
68
+ autoload_without_tapioca(const_name, path)
69
+ end
70
+ end
@@ -0,0 +1,42 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ require "set"
5
+
6
+ module Tapioca
7
+ module Trackers
8
+ # Registers a TracePoint immediately upon load to track points at which
9
+ # classes and modules are opened for definition. This is used to track
10
+ # correspondence between classes/modules and files, as this information isn't
11
+ # available in the ruby runtime without extra accounting.
12
+ module ConstantDefinition
13
+ extend Reflection
14
+
15
+ @class_files = {}
16
+
17
+ # Immediately activated upon load. Observes class/module definition.
18
+ TracePoint.trace(:class) do |tp|
19
+ unless tp.self.singleton_class?
20
+ key = name_of(tp.self)
21
+ file = tp.path
22
+ if file == "(eval)"
23
+ file = T.must(caller_locations)
24
+ .drop_while { |loc| loc.path == "(eval)" }
25
+ .first&.path
26
+ end
27
+ @class_files[key] ||= Set.new
28
+ @class_files[key] << file
29
+ end
30
+ end
31
+
32
+ # Returns the files in which this class or module was opened. Doesn't know
33
+ # about situations where the class was opened prior to +require+ing,
34
+ # or where metaprogramming was used via +eval+, etc.
35
+ def self.files_for(klass)
36
+ name = String === klass ? klass : name_of(klass)
37
+ files = @class_files[name]
38
+ files || Set.new
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,78 @@
1
+ # typed: true
2
+ # frozen_string_literal: true
3
+
4
+ module Tapioca
5
+ module Trackers
6
+ module Mixin
7
+ extend T::Sig
8
+
9
+ @mixin_map = {}.compare_by_identity
10
+
11
+ class Type < T::Enum
12
+ enums do
13
+ Prepend = new
14
+ Include = new
15
+ Extend = new
16
+ end
17
+ end
18
+
19
+ sig do
20
+ params(
21
+ constant: Module,
22
+ mod: Module,
23
+ mixin_type: Type,
24
+ locations: T.nilable(T::Array[Thread::Backtrace::Location])
25
+ ).void
26
+ end
27
+ def self.register(constant, mod, mixin_type, locations)
28
+ locations ||= []
29
+ locations.map!(&:absolute_path).uniq!
30
+ locs = mixin_locations_for(constant)
31
+ locs.fetch(mixin_type).store(mod, T.cast(locations, T::Array[String]))
32
+ end
33
+
34
+ sig { params(constant: Module).returns(T::Hash[Type, T::Hash[Module, T::Array[String]]]) }
35
+ def self.mixin_locations_for(constant)
36
+ @mixin_map[constant] ||= {
37
+ Type::Prepend => {}.compare_by_identity,
38
+ Type::Include => {}.compare_by_identity,
39
+ Type::Extend => {}.compare_by_identity,
40
+ }
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ class Module
47
+ prepend(Module.new do
48
+ def prepend_features(constant)
49
+ Tapioca::Trackers::Mixin.register(
50
+ constant,
51
+ self,
52
+ Tapioca::Trackers::Mixin::Type::Prepend,
53
+ caller_locations
54
+ )
55
+ super
56
+ end
57
+
58
+ def append_features(constant)
59
+ Tapioca::Trackers::Mixin.register(
60
+ constant,
61
+ self,
62
+ Tapioca::Trackers::Mixin::Type::Include,
63
+ caller_locations
64
+ )
65
+ super
66
+ end
67
+
68
+ def extend_object(obj)
69
+ Tapioca::Trackers::Mixin.register(
70
+ obj,
71
+ self,
72
+ Tapioca::Trackers::Mixin::Type::Extend,
73
+ caller_locations
74
+ ) if Module === obj
75
+ super
76
+ end
77
+ end)
78
+ end
@@ -0,0 +1,14 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # The load order below is important:
5
+ # ----------------------------------
6
+ # We want the mixin tracker to be the first thing that is
7
+ # loaded because other trackers might apply their own mixins
8
+ # into core types (like `Module` and `Kernel`). In order to
9
+ # catch and filter those mixins as coming from Tapioca, we need
10
+ # the mixin tracker to be in place, before any mixin operations
11
+ # are performed.
12
+ require "tapioca/trackers/mixin"
13
+ require "tapioca/trackers/constant_definition"
14
+ require "tapioca/trackers/autoload"
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Tapioca
5
- VERSION = "0.5.6"
5
+ VERSION = "0.6.0"
6
6
  end
data/lib/tapioca.rb CHANGED
@@ -1,9 +1,16 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
5
5
 
6
6
  module Tapioca
7
+ extend T::Sig
8
+
9
+ sig do
10
+ type_parameters(:Result)
11
+ .params(blk: T.proc.returns(T.type_parameter(:Result)))
12
+ .returns(T.type_parameter(:Result))
13
+ end
7
14
  def self.silence_warnings(&blk)
8
15
  original_verbosity = $VERBOSE
9
16
  $VERBOSE = nil
@@ -15,10 +22,29 @@ module Tapioca
15
22
  end
16
23
 
17
24
  class Error < StandardError; end
25
+
26
+ SORBET_DIR = T.let("sorbet", String)
27
+ SORBET_CONFIG_FILE = T.let("#{SORBET_DIR}/config", String)
28
+ TAPIOCA_DIR = T.let("#{SORBET_DIR}/tapioca", String)
29
+ TAPIOCA_CONFIG_FILE = T.let("#{TAPIOCA_DIR}/config.yml", String)
30
+
31
+ DEFAULT_COMMAND = T.let("bin/tapioca", String)
32
+ DEFAULT_POSTREQUIRE_FILE = T.let("#{TAPIOCA_DIR}/require.rb", String)
33
+ DEFAULT_RBI_DIR = T.let("#{SORBET_DIR}/rbi", String)
34
+ DEFAULT_DSL_DIR = T.let("#{DEFAULT_RBI_DIR}/dsl", String)
35
+ DEFAULT_GEM_DIR = T.let("#{DEFAULT_RBI_DIR}/gems", String)
36
+ DEFAULT_SHIM_DIR = T.let("#{DEFAULT_RBI_DIR}/shims", String)
37
+ DEFAULT_TODO_FILE = T.let("#{DEFAULT_RBI_DIR}/todo.rbi", String)
38
+
39
+ DEFAULT_OVERRIDES = T.let({
40
+ # ActiveSupport overrides some core methods with different signatures
41
+ # so we generate a typed: false RBI for it to suppress errors
42
+ "activesupport" => "false",
43
+ }.freeze, T::Hash[String, String])
18
44
  end
19
45
 
20
46
  require "tapioca/reflection"
21
- require "tapioca/constant_locator"
47
+ require "tapioca/trackers"
22
48
  require "tapioca/compilers/dsl/base"
23
49
  require "tapioca/compilers/dynamic_mixin_compiler"
24
50
  require "tapioca/helpers/active_record_column_type_helper"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tapioca
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.6
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ufuk Kayserilioglu
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: exe
13
13
  cert_chain: []
14
- date: 2021-12-03 00:00:00.000000000 Z
14
+ date: 2021-12-17 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -50,7 +50,7 @@ dependencies:
50
50
  version: 0.0.0
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: 0.0.8
53
+ version: 0.0.9
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -60,7 +60,7 @@ dependencies:
60
60
  version: 0.0.0
61
61
  - - ">="
62
62
  - !ruby/object:Gem::Version
63
- version: 0.0.8
63
+ version: 0.0.9
64
64
  - !ruby/object:Gem::Dependency
65
65
  name: sorbet-static
66
66
  requirement: !ruby/object:Gem::Requirement
@@ -161,6 +161,7 @@ files:
161
161
  - lib/tapioca/compilers/dsl/active_record_columns.rb
162
162
  - lib/tapioca/compilers/dsl/active_record_enum.rb
163
163
  - lib/tapioca/compilers/dsl/active_record_fixtures.rb
164
+ - lib/tapioca/compilers/dsl/active_record_relations.rb
164
165
  - lib/tapioca/compilers/dsl/active_record_scope.rb
165
166
  - lib/tapioca/compilers/dsl/active_record_typed_store.rb
166
167
  - lib/tapioca/compilers/dsl/active_resource.rb
@@ -169,10 +170,14 @@ files:
169
170
  - lib/tapioca/compilers/dsl/active_support_current_attributes.rb
170
171
  - lib/tapioca/compilers/dsl/base.rb
171
172
  - lib/tapioca/compilers/dsl/config.rb
173
+ - lib/tapioca/compilers/dsl/extensions/frozen_record.rb
172
174
  - lib/tapioca/compilers/dsl/frozen_record.rb
175
+ - lib/tapioca/compilers/dsl/helper/active_record_constants.rb
173
176
  - lib/tapioca/compilers/dsl/identity_cache.rb
174
177
  - lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb
178
+ - lib/tapioca/compilers/dsl/param_helper.rb
175
179
  - lib/tapioca/compilers/dsl/protobuf.rb
180
+ - lib/tapioca/compilers/dsl/rails_generators.rb
176
181
  - lib/tapioca/compilers/dsl/sidekiq_worker.rb
177
182
  - lib/tapioca/compilers/dsl/smart_properties.rb
178
183
  - lib/tapioca/compilers/dsl/state_machines.rb
@@ -185,9 +190,7 @@ files:
185
190
  - lib/tapioca/compilers/symbol_table/symbol_loader.rb
186
191
  - lib/tapioca/compilers/symbol_table_compiler.rb
187
192
  - lib/tapioca/compilers/todos_compiler.rb
188
- - lib/tapioca/config.rb
189
- - lib/tapioca/config_builder.rb
190
- - lib/tapioca/constant_locator.rb
193
+ - lib/tapioca/executor.rb
191
194
  - lib/tapioca/gemfile.rb
192
195
  - lib/tapioca/generators.rb
193
196
  - lib/tapioca/generators/base.rb
@@ -198,6 +201,11 @@ files:
198
201
  - lib/tapioca/generators/todo.rb
199
202
  - lib/tapioca/generic_type_registry.rb
200
203
  - lib/tapioca/helpers/active_record_column_type_helper.rb
204
+ - lib/tapioca/helpers/cli_helper.rb
205
+ - lib/tapioca/helpers/config_helper.rb
206
+ - lib/tapioca/helpers/test/content.rb
207
+ - lib/tapioca/helpers/test/isolation.rb
208
+ - lib/tapioca/helpers/test/template.rb
201
209
  - lib/tapioca/internal.rb
202
210
  - lib/tapioca/loader.rb
203
211
  - lib/tapioca/rbi_ext/model.rb
@@ -205,6 +213,10 @@ files:
205
213
  - lib/tapioca/sorbet_ext/fixed_hash_patch.rb
206
214
  - lib/tapioca/sorbet_ext/generic_name_patch.rb
207
215
  - lib/tapioca/sorbet_ext/name_patch.rb
216
+ - lib/tapioca/trackers.rb
217
+ - lib/tapioca/trackers/autoload.rb
218
+ - lib/tapioca/trackers/constant_definition.rb
219
+ - lib/tapioca/trackers/mixin.rb
208
220
  - lib/tapioca/version.rb
209
221
  homepage: https://github.com/Shopify/tapioca
210
222
  licenses:
@@ -1,45 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- module Tapioca
5
- class Config < T::Struct
6
- extend(T::Sig)
7
-
8
- const(:outdir, String)
9
- const(:prerequire, T.nilable(String))
10
- const(:postrequire, String)
11
- const(:exclude, T::Array[String])
12
- const(:exclude_generators, T::Array[String])
13
- const(:typed_overrides, T::Hash[String, String])
14
- const(:todos_path, String)
15
- const(:generators, T::Array[String])
16
- const(:file_header, T::Boolean, default: true)
17
- const(:doc, T::Boolean, default: false)
18
-
19
- sig { returns(Pathname) }
20
- def outpath
21
- @outpath = T.let(@outpath, T.nilable(Pathname))
22
- @outpath ||= Pathname.new(outdir)
23
- end
24
-
25
- private_class_method :new
26
-
27
- SORBET_PATH = T.let("sorbet", String)
28
- SORBET_CONFIG = T.let("#{SORBET_PATH}/config", String)
29
- TAPIOCA_PATH = T.let("#{SORBET_PATH}/tapioca", String)
30
- TAPIOCA_CONFIG = T.let("#{TAPIOCA_PATH}/config.yml", String)
31
-
32
- DEFAULT_COMMAND = T.let("bin/tapioca", String)
33
- DEFAULT_POSTREQUIRE = T.let("#{TAPIOCA_PATH}/require.rb", String)
34
- DEFAULT_RBIDIR = T.let("#{SORBET_PATH}/rbi", String)
35
- DEFAULT_DSLDIR = T.let("#{DEFAULT_RBIDIR}/dsl", String)
36
- DEFAULT_GEMDIR = T.let("#{DEFAULT_RBIDIR}/gems", String)
37
- DEFAULT_TODOSPATH = T.let("#{DEFAULT_RBIDIR}/todo.rbi", String)
38
-
39
- DEFAULT_OVERRIDES = T.let({
40
- # ActiveSupport overrides some core methods with different signatures
41
- # so we generate a typed: false RBI for it to suppress errors
42
- "activesupport" => "false",
43
- }.freeze, T::Hash[String, String])
44
- end
45
- end
@@ -1,73 +0,0 @@
1
- # typed: strict
2
- # frozen_string_literal: true
3
-
4
- require "yaml"
5
-
6
- module Tapioca
7
- class ConfigBuilder
8
- class << self
9
- extend(T::Sig)
10
-
11
- sig { params(command: Symbol, options: T::Hash[String, T.untyped]).returns(Config) }
12
- def from_options(command, options)
13
- merged_options = merge_options(default_options(command), config_options, options)
14
-
15
- puts(<<~MSG) if merged_options.include?("generate_command")
16
- DEPRECATION: The `-c` and `--cmd` flags will be removed in a future release.
17
- MSG
18
-
19
- Config.from_hash(merged_options)
20
- end
21
-
22
- private
23
-
24
- sig { returns(T::Hash[String, T.untyped]) }
25
- def config_options
26
- if File.exist?(Config::TAPIOCA_CONFIG)
27
- YAML.load_file(Config::TAPIOCA_CONFIG, fallback: {})
28
- else
29
- {}
30
- end
31
- end
32
-
33
- sig { params(command: Symbol).returns(T::Hash[String, T.untyped]) }
34
- def default_options(command)
35
- default_outdir = case command
36
- when :sync, :generate, :gem
37
- Config::DEFAULT_GEMDIR
38
- when :dsl
39
- Config::DEFAULT_DSLDIR
40
- else
41
- Config::SORBET_PATH
42
- end
43
-
44
- DEFAULT_OPTIONS.merge("outdir" => default_outdir)
45
- end
46
-
47
- sig { params(options: T::Hash[String, T.untyped]).returns(T::Hash[String, T.untyped]) }
48
- def merge_options(*options)
49
- options.each_with_object({}) do |option, result|
50
- result.merge!(option) do |_, this_val, other_val|
51
- if this_val.is_a?(Hash) && other_val.is_a?(Hash)
52
- this_val.merge(other_val)
53
- else
54
- other_val
55
- end
56
- end
57
- end
58
- end
59
- end
60
-
61
- DEFAULT_OPTIONS = T.let({
62
- "postrequire" => Config::DEFAULT_POSTREQUIRE,
63
- "outdir" => nil,
64
- "exclude" => [],
65
- "exclude_generators" => [],
66
- "typed_overrides" => Config::DEFAULT_OVERRIDES,
67
- "todos_path" => Config::DEFAULT_TODOSPATH,
68
- "generators" => [],
69
- "file_header" => true,
70
- "doc" => false,
71
- }.freeze, T::Hash[String, T.untyped])
72
- end
73
- end
@@ -1,40 +0,0 @@
1
- # typed: true
2
- # frozen_string_literal: true
3
-
4
- require "set"
5
-
6
- module Tapioca
7
- # Registers a TracePoint immediately upon load to track points at which
8
- # classes and modules are opened for definition. This is used to track
9
- # correspondence between classes/modules and files, as this information isn't
10
- # available in the ruby runtime without extra accounting.
11
- module ConstantLocator
12
- extend Reflection
13
-
14
- @class_files = {}
15
-
16
- # Immediately activated upon load. Observes class/module definition.
17
- TracePoint.trace(:class) do |tp|
18
- unless tp.self.singleton_class?
19
- key = name_of(tp.self)
20
- file = tp.path
21
- if file == "(eval)"
22
- file = T.must(caller_locations)
23
- .drop_while { |loc| loc.path == "(eval)" }
24
- .first&.path
25
- end
26
- @class_files[key] ||= Set.new
27
- @class_files[key] << file
28
- end
29
- end
30
-
31
- # Returns the files in which this class or module was opened. Doesn't know
32
- # about situations where the class was opened prior to +require+ing,
33
- # or where metaprogramming was used via +eval+, etc.
34
- def self.files_for(klass)
35
- name = String === klass ? klass : name_of(klass)
36
- files = @class_files[name]
37
- files || Set.new
38
- end
39
- end
40
- end