tapioca 0.5.3 → 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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +114 -23
  3. data/lib/tapioca/cli.rb +188 -65
  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_enum.rb +1 -1
  7. data/lib/tapioca/compilers/dsl/active_record_relations.rb +703 -0
  8. data/lib/tapioca/compilers/dsl/active_record_scope.rb +43 -13
  9. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +39 -33
  10. data/lib/tapioca/compilers/dsl/base.rb +26 -42
  11. data/lib/tapioca/compilers/dsl/extensions/frozen_record.rb +29 -0
  12. data/lib/tapioca/compilers/dsl/frozen_record.rb +37 -0
  13. data/lib/tapioca/compilers/dsl/helper/active_record_constants.rb +27 -0
  14. data/lib/tapioca/compilers/dsl/identity_cache.rb +0 -1
  15. data/lib/tapioca/compilers/dsl/param_helper.rb +52 -0
  16. data/lib/tapioca/compilers/dsl/rails_generators.rb +120 -0
  17. data/lib/tapioca/compilers/dsl_compiler.rb +34 -6
  18. data/lib/tapioca/compilers/sorbet.rb +2 -0
  19. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +51 -48
  20. data/lib/tapioca/executor.rb +79 -0
  21. data/lib/tapioca/gemfile.rb +28 -4
  22. data/lib/tapioca/generators/base.rb +11 -18
  23. data/lib/tapioca/generators/dsl.rb +33 -38
  24. data/lib/tapioca/generators/gem.rb +64 -34
  25. data/lib/tapioca/generators/init.rb +41 -16
  26. data/lib/tapioca/generators/todo.rb +6 -6
  27. data/lib/tapioca/helpers/cli_helper.rb +26 -0
  28. data/lib/tapioca/helpers/config_helper.rb +84 -0
  29. data/lib/tapioca/helpers/test/content.rb +51 -0
  30. data/lib/tapioca/helpers/test/isolation.rb +125 -0
  31. data/lib/tapioca/helpers/test/template.rb +34 -0
  32. data/lib/tapioca/internal.rb +3 -2
  33. data/lib/tapioca/rbi_ext/model.rb +13 -10
  34. data/lib/tapioca/reflection.rb +13 -0
  35. data/lib/tapioca/trackers/autoload.rb +70 -0
  36. data/lib/tapioca/trackers/constant_definition.rb +42 -0
  37. data/lib/tapioca/trackers/mixin.rb +78 -0
  38. data/lib/tapioca/trackers.rb +14 -0
  39. data/lib/tapioca/version.rb +1 -1
  40. data/lib/tapioca.rb +28 -2
  41. metadata +37 -13
  42. data/lib/tapioca/config.rb +0 -45
  43. data/lib/tapioca/config_builder.rb +0 -73
  44. data/lib/tapioca/constant_locator.rb +0 -34
@@ -37,7 +37,7 @@ module RBI
37
37
 
38
38
  sig { void }
39
39
  def set_empty_body_content
40
- comments << RBI::EmptyComment.new unless comments.empty?
40
+ comments << RBI::BlankLine.new unless comments.empty?
41
41
  comments << RBI::Comment.new("THIS IS AN EMPTY RBI FILE.")
42
42
  comments << RBI::Comment.new("see https://github.com/Shopify/tapioca/wiki/Manual-Gem-Requires")
43
43
  end
@@ -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.3"
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.3
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-10-21 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
@@ -45,58 +45,70 @@ dependencies:
45
45
  name: rbi
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: 0.0.0
48
51
  - - ">="
49
52
  - !ruby/object:Gem::Version
50
- version: '0'
53
+ version: 0.0.9
51
54
  type: :runtime
52
55
  prerelease: false
53
56
  version_requirements: !ruby/object:Gem::Requirement
54
57
  requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: 0.0.0
55
61
  - - ">="
56
62
  - !ruby/object:Gem::Version
57
- version: '0'
63
+ version: 0.0.9
58
64
  - !ruby/object:Gem::Dependency
59
65
  name: sorbet-static
60
66
  requirement: !ruby/object:Gem::Requirement
61
67
  requirements:
62
68
  - - ">="
63
69
  - !ruby/object:Gem::Version
64
- version: 0.5.6200
70
+ version: 0.5.9204
65
71
  type: :runtime
66
72
  prerelease: false
67
73
  version_requirements: !ruby/object:Gem::Requirement
68
74
  requirements:
69
75
  - - ">="
70
76
  - !ruby/object:Gem::Version
71
- version: 0.5.6200
77
+ version: 0.5.9204
72
78
  - !ruby/object:Gem::Dependency
73
79
  name: sorbet-runtime
74
80
  requirement: !ruby/object:Gem::Requirement
75
81
  requirements:
76
82
  - - ">="
77
83
  - !ruby/object:Gem::Version
78
- version: '0'
84
+ version: 0.5.9204
79
85
  type: :runtime
80
86
  prerelease: false
81
87
  version_requirements: !ruby/object:Gem::Requirement
82
88
  requirements:
83
89
  - - ">="
84
90
  - !ruby/object:Gem::Version
85
- version: '0'
91
+ version: 0.5.9204
86
92
  - !ruby/object:Gem::Dependency
87
93
  name: spoom
88
94
  requirement: !ruby/object:Gem::Requirement
89
95
  requirements:
96
+ - - "~>"
97
+ - !ruby/object:Gem::Version
98
+ version: 1.1.0
90
99
  - - ">="
91
100
  - !ruby/object:Gem::Version
92
- version: '0'
101
+ version: 1.1.4
93
102
  type: :runtime
94
103
  prerelease: false
95
104
  version_requirements: !ruby/object:Gem::Requirement
96
105
  requirements:
106
+ - - "~>"
107
+ - !ruby/object:Gem::Version
108
+ version: 1.1.0
97
109
  - - ">="
98
110
  - !ruby/object:Gem::Version
99
- version: '0'
111
+ version: 1.1.4
100
112
  - !ruby/object:Gem::Dependency
101
113
  name: thor
102
114
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +161,7 @@ files:
149
161
  - lib/tapioca/compilers/dsl/active_record_columns.rb
150
162
  - lib/tapioca/compilers/dsl/active_record_enum.rb
151
163
  - lib/tapioca/compilers/dsl/active_record_fixtures.rb
164
+ - lib/tapioca/compilers/dsl/active_record_relations.rb
152
165
  - lib/tapioca/compilers/dsl/active_record_scope.rb
153
166
  - lib/tapioca/compilers/dsl/active_record_typed_store.rb
154
167
  - lib/tapioca/compilers/dsl/active_resource.rb
@@ -157,10 +170,14 @@ files:
157
170
  - lib/tapioca/compilers/dsl/active_support_current_attributes.rb
158
171
  - lib/tapioca/compilers/dsl/base.rb
159
172
  - lib/tapioca/compilers/dsl/config.rb
173
+ - lib/tapioca/compilers/dsl/extensions/frozen_record.rb
160
174
  - lib/tapioca/compilers/dsl/frozen_record.rb
175
+ - lib/tapioca/compilers/dsl/helper/active_record_constants.rb
161
176
  - lib/tapioca/compilers/dsl/identity_cache.rb
162
177
  - lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb
178
+ - lib/tapioca/compilers/dsl/param_helper.rb
163
179
  - lib/tapioca/compilers/dsl/protobuf.rb
180
+ - lib/tapioca/compilers/dsl/rails_generators.rb
164
181
  - lib/tapioca/compilers/dsl/sidekiq_worker.rb
165
182
  - lib/tapioca/compilers/dsl/smart_properties.rb
166
183
  - lib/tapioca/compilers/dsl/state_machines.rb
@@ -173,9 +190,7 @@ files:
173
190
  - lib/tapioca/compilers/symbol_table/symbol_loader.rb
174
191
  - lib/tapioca/compilers/symbol_table_compiler.rb
175
192
  - lib/tapioca/compilers/todos_compiler.rb
176
- - lib/tapioca/config.rb
177
- - lib/tapioca/config_builder.rb
178
- - lib/tapioca/constant_locator.rb
193
+ - lib/tapioca/executor.rb
179
194
  - lib/tapioca/gemfile.rb
180
195
  - lib/tapioca/generators.rb
181
196
  - lib/tapioca/generators/base.rb
@@ -186,6 +201,11 @@ files:
186
201
  - lib/tapioca/generators/todo.rb
187
202
  - lib/tapioca/generic_type_registry.rb
188
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
189
209
  - lib/tapioca/internal.rb
190
210
  - lib/tapioca/loader.rb
191
211
  - lib/tapioca/rbi_ext/model.rb
@@ -193,6 +213,10 @@ files:
193
213
  - lib/tapioca/sorbet_ext/fixed_hash_patch.rb
194
214
  - lib/tapioca/sorbet_ext/generic_name_patch.rb
195
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
196
220
  - lib/tapioca/version.rb
197
221
  homepage: https://github.com/Shopify/tapioca
198
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,34 +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
- @class_files[key] ||= Set.new
21
- @class_files[key] << tp.path
22
- end
23
- end
24
-
25
- # Returns the files in which this class or module was opened. Doesn't know
26
- # about situations where the class was opened prior to +require+ing,
27
- # or where metaprogramming was used via +eval+, etc.
28
- def self.files_for(klass)
29
- name = String === klass ? klass : name_of(klass)
30
- files = @class_files[name]
31
- files || Set.new
32
- end
33
- end
34
- end