tapioca 0.4.27 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +15 -15
  3. data/README.md +2 -2
  4. data/Rakefile +5 -7
  5. data/exe/tapioca +2 -2
  6. data/lib/tapioca/cli.rb +172 -2
  7. data/lib/tapioca/compilers/dsl/aasm.rb +122 -0
  8. data/lib/tapioca/compilers/dsl/action_controller_helpers.rb +52 -12
  9. data/lib/tapioca/compilers/dsl/action_mailer.rb +6 -9
  10. data/lib/tapioca/compilers/dsl/active_job.rb +8 -12
  11. data/lib/tapioca/compilers/dsl/active_model_attributes.rb +131 -0
  12. data/lib/tapioca/compilers/dsl/active_model_secure_password.rb +101 -0
  13. data/lib/tapioca/compilers/dsl/active_record_associations.rb +33 -54
  14. data/lib/tapioca/compilers/dsl/active_record_columns.rb +10 -105
  15. data/lib/tapioca/compilers/dsl/active_record_enum.rb +8 -10
  16. data/lib/tapioca/compilers/dsl/active_record_fixtures.rb +86 -0
  17. data/lib/tapioca/compilers/dsl/active_record_scope.rb +7 -10
  18. data/lib/tapioca/compilers/dsl/active_record_typed_store.rb +5 -8
  19. data/lib/tapioca/compilers/dsl/active_resource.rb +9 -37
  20. data/lib/tapioca/compilers/dsl/active_storage.rb +98 -0
  21. data/lib/tapioca/compilers/dsl/active_support_concern.rb +106 -0
  22. data/lib/tapioca/compilers/dsl/active_support_current_attributes.rb +13 -8
  23. data/lib/tapioca/compilers/dsl/base.rb +108 -82
  24. data/lib/tapioca/compilers/dsl/config.rb +111 -0
  25. data/lib/tapioca/compilers/dsl/frozen_record.rb +5 -7
  26. data/lib/tapioca/compilers/dsl/identity_cache.rb +66 -29
  27. data/lib/tapioca/compilers/dsl/mixed_in_class_attributes.rb +74 -0
  28. data/lib/tapioca/compilers/dsl/protobuf.rb +19 -69
  29. data/lib/tapioca/compilers/dsl/sidekiq_worker.rb +25 -12
  30. data/lib/tapioca/compilers/dsl/smart_properties.rb +21 -33
  31. data/lib/tapioca/compilers/dsl/state_machines.rb +56 -78
  32. data/lib/tapioca/compilers/dsl/url_helpers.rb +7 -10
  33. data/lib/tapioca/compilers/dsl_compiler.rb +25 -40
  34. data/lib/tapioca/compilers/dynamic_mixin_compiler.rb +198 -0
  35. data/lib/tapioca/compilers/requires_compiler.rb +2 -2
  36. data/lib/tapioca/compilers/sorbet.rb +25 -5
  37. data/lib/tapioca/compilers/symbol_table/symbol_generator.rb +122 -206
  38. data/lib/tapioca/compilers/symbol_table/symbol_loader.rb +4 -4
  39. data/lib/tapioca/compilers/symbol_table_compiler.rb +5 -11
  40. data/lib/tapioca/compilers/todos_compiler.rb +1 -1
  41. data/lib/tapioca/config.rb +3 -0
  42. data/lib/tapioca/config_builder.rb +5 -2
  43. data/lib/tapioca/constant_locator.rb +6 -8
  44. data/lib/tapioca/gemfile.rb +14 -11
  45. data/lib/tapioca/generators/base.rb +61 -0
  46. data/lib/tapioca/generators/dsl.rb +362 -0
  47. data/lib/tapioca/generators/gem.rb +345 -0
  48. data/lib/tapioca/generators/init.rb +79 -0
  49. data/lib/tapioca/generators/require.rb +52 -0
  50. data/lib/tapioca/generators/todo.rb +76 -0
  51. data/lib/tapioca/generators.rb +9 -0
  52. data/lib/tapioca/generic_type_registry.rb +25 -98
  53. data/lib/tapioca/helpers/active_record_column_type_helper.rb +98 -0
  54. data/lib/tapioca/internal.rb +2 -10
  55. data/lib/tapioca/loader.rb +11 -31
  56. data/lib/tapioca/rbi_ext/model.rb +166 -0
  57. data/lib/tapioca/reflection.rb +138 -0
  58. data/lib/tapioca/sorbet_ext/fixed_hash_patch.rb +1 -1
  59. data/lib/tapioca/sorbet_ext/generic_name_patch.rb +72 -4
  60. data/lib/tapioca/sorbet_ext/name_patch.rb +1 -1
  61. data/lib/tapioca/version.rb +1 -1
  62. data/lib/tapioca.rb +3 -0
  63. metadata +45 -23
  64. data/lib/tapioca/cli/main.rb +0 -146
  65. data/lib/tapioca/core_ext/class.rb +0 -28
  66. data/lib/tapioca/core_ext/string.rb +0 -18
  67. data/lib/tapioca/generator.rb +0 -633
  68. data/lib/tapioca/rbi/model.rb +0 -405
  69. data/lib/tapioca/rbi/printer.rb +0 -410
  70. data/lib/tapioca/rbi/rewriters/group_nodes.rb +0 -106
  71. data/lib/tapioca/rbi/rewriters/nest_non_public_methods.rb +0 -65
  72. data/lib/tapioca/rbi/rewriters/nest_singleton_methods.rb +0 -42
  73. data/lib/tapioca/rbi/rewriters/sort_nodes.rb +0 -86
  74. data/lib/tapioca/rbi/visitor.rb +0 -21
@@ -0,0 +1,86 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ begin
5
+ require "rails"
6
+ require "active_record"
7
+ require "active_record/fixtures"
8
+ require "active_support/test_case"
9
+ rescue LoadError
10
+ return
11
+ end
12
+
13
+ module Tapioca
14
+ module Compilers
15
+ module Dsl
16
+ # `Tapioca::Compilers::Dsl::ActiveRecordFixtures` decorates RBIs for test fixture methods
17
+ # that are created dynamically by Rails.
18
+ #
19
+ # For example, given an application with a posts table, we can have a fixture file
20
+ #
21
+ # ~~~yaml
22
+ # first_post:
23
+ # author: John
24
+ # title: My post
25
+ # ~~~
26
+ #
27
+ # Rails will allow us to invoke `posts(:first_post)` in tests to get the fixture record.
28
+ # The generated RBI by this generator will produce the following
29
+ #
30
+ # ~~~rbi
31
+ # # test_case.rbi
32
+ # # typed: true
33
+ # class ActiveSupport::TestCase
34
+ # sig { params(fixture_names: Symbol).returns(T.untyped) }
35
+ # def posts(*fixture_names); end
36
+ # end
37
+ # ~~~
38
+ class ActiveRecordFixtures < Base
39
+ extend T::Sig
40
+
41
+ sig { override.params(root: RBI::Tree, constant: T.class_of(ActiveSupport::TestCase)).void }
42
+ def decorate(root, constant)
43
+ method_names = fixture_loader.ancestors # get all ancestors from class that includes AR fixtures
44
+ .drop(1) # drop the anonymous class itself from the array
45
+ .reject(&:name) # only collect anonymous ancestors because fixture methods are always on an anonymous module
46
+ .map! do |mod|
47
+ [mod.private_instance_methods(false), mod.instance_methods(false)]
48
+ end
49
+ .flatten # merge methods into a single list
50
+ return if method_names.empty?
51
+
52
+ root.create_path(constant) do |mod|
53
+ method_names.each do |name|
54
+ create_fixture_method(mod, name.to_s)
55
+ end
56
+ end
57
+ end
58
+
59
+ sig { override.returns(T::Enumerable[Module]) }
60
+ def gather_constants
61
+ [ActiveSupport::TestCase]
62
+ end
63
+
64
+ private
65
+
66
+ sig { returns(Class) }
67
+ def fixture_loader
68
+ Class.new do
69
+ T.unsafe(self).include(ActiveRecord::TestFixtures)
70
+ T.unsafe(self).fixture_path = Rails.root.join("test", "fixtures")
71
+ T.unsafe(self).fixtures(:all)
72
+ end
73
+ end
74
+
75
+ sig { params(mod: RBI::Scope, name: String).void }
76
+ def create_fixture_method(mod, name)
77
+ mod.create_method(
78
+ name,
79
+ parameters: [create_rest_param("fixture_names", type: "Symbol")],
80
+ return_type: "T.untyped"
81
+ )
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -1,8 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "parlour"
5
-
6
4
  begin
7
5
  require "active_record"
8
6
  rescue LoadError
@@ -47,7 +45,7 @@ module Tapioca
47
45
 
48
46
  sig do
49
47
  override.params(
50
- root: Parlour::RbiGenerator::Namespace,
48
+ root: RBI::Tree,
51
49
  constant: T.class_of(::ActiveRecord::Base)
52
50
  ).void
53
51
  end
@@ -55,7 +53,7 @@ module Tapioca
55
53
  scope_method_names = constant.send(:generated_relation_methods).instance_methods(false)
56
54
  return if scope_method_names.empty?
57
55
 
58
- root.path(constant) do |model|
56
+ root.create_path(constant) do |model|
59
57
  module_name = "GeneratedRelationMethods"
60
58
 
61
59
  model.create_module(module_name) do |mod|
@@ -70,7 +68,7 @@ module Tapioca
70
68
 
71
69
  sig { override.returns(T::Enumerable[Module]) }
72
70
  def gather_constants
73
- ::ActiveRecord::Base.descendants.reject(&:abstract_class?)
71
+ descendants_of(::ActiveRecord::Base).reject(&:abstract_class?)
74
72
  end
75
73
 
76
74
  private
@@ -78,19 +76,18 @@ module Tapioca
78
76
  sig do
79
77
  params(
80
78
  scope_method: String,
81
- mod: Parlour::RbiGenerator::Namespace,
79
+ mod: RBI::Scope,
82
80
  ).void
83
81
  end
84
82
  def generate_scope_method(scope_method, mod)
85
83
  # This return type should actually be Model::ActiveRecord_Relation
86
84
  return_type = "T.untyped"
87
85
 
88
- create_method(
89
- mod,
86
+ mod.create_method(
90
87
  scope_method,
91
88
  parameters: [
92
- Parlour::RbiGenerator::Parameter.new("*args", type: "T.untyped"),
93
- Parlour::RbiGenerator::Parameter.new("&blk", type: "T.untyped"),
89
+ create_rest_param("args", type: "T.untyped"),
90
+ create_block_param("blk", type: "T.untyped"),
94
91
  ],
95
92
  return_type: return_type,
96
93
  )
@@ -1,9 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "parlour"
5
- require "tapioca/core_ext/class"
6
-
7
4
  begin
8
5
  require "activerecord-typedstore"
9
6
  rescue LoadError
@@ -92,7 +89,7 @@ module Tapioca
92
89
  sig do
93
90
  override
94
91
  .params(
95
- root: Parlour::RbiGenerator::Namespace,
92
+ root: RBI::Tree,
96
93
  constant: T.class_of(::ActiveRecord::Base)
97
94
  )
98
95
  .void
@@ -101,7 +98,7 @@ module Tapioca
101
98
  stores = constant.typed_stores
102
99
  return if stores.values.flat_map(&:accessors).empty?
103
100
 
104
- root.path(constant) do |model|
101
+ root.create_path(constant) do |model|
105
102
  stores.values.each do |store_data|
106
103
  store_data.accessors.each do |accessor|
107
104
  field = store_data.fields[accessor]
@@ -116,7 +113,7 @@ module Tapioca
116
113
 
117
114
  sig { override.returns(T::Enumerable[Module]) }
118
115
  def gather_constants
119
- ::ActiveRecord::Base.descendants.select do |klass|
116
+ descendants_of(::ActiveRecord::Base).select do |klass|
120
117
  klass.include?(ActiveRecord::TypedStore::Behavior)
121
118
  end
122
119
  end
@@ -142,7 +139,7 @@ module Tapioca
142
139
 
143
140
  sig do
144
141
  params(
145
- klass: Parlour::RbiGenerator::Namespace,
142
+ klass: RBI::Scope,
146
143
  name: String,
147
144
  type: String
148
145
  )
@@ -151,7 +148,7 @@ module Tapioca
151
148
  def generate_methods(klass, name, type)
152
149
  klass.create_method(
153
150
  "#{name}=",
154
- parameters: [Parlour::RbiGenerator::Parameter.new(name, type: type)],
151
+ parameters: [create_param(name, type: type)],
155
152
  return_type: type
156
153
  )
157
154
  klass.create_method(name, return_type: type)
@@ -1,8 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "parlour"
5
-
6
4
  begin
7
5
  require "active_resource"
8
6
  rescue LoadError
@@ -63,16 +61,11 @@ module Tapioca
63
61
  class ActiveResource < Base
64
62
  extend T::Sig
65
63
 
66
- sig do
67
- override.params(
68
- root: Parlour::RbiGenerator::Namespace,
69
- constant: T.class_of(::ActiveResource::Base)
70
- ).void
71
- end
64
+ sig { override.params(root: RBI::Tree, constant: T.class_of(::ActiveResource::Base)).void }
72
65
  def decorate(root, constant)
73
66
  return if constant.schema.blank?
74
67
 
75
- root.path(constant) do |resource|
68
+ root.create_path(constant) do |resource|
76
69
  constant.schema.each do |attribute, type|
77
70
  create_schema_methods(resource, attribute, type)
78
71
  end
@@ -81,7 +74,7 @@ module Tapioca
81
74
 
82
75
  sig { override.returns(T::Enumerable[Module]) }
83
76
  def gather_constants
84
- ::ActiveResource::Base.descendants
77
+ descendants_of(::ActiveResource::Base)
85
78
  end
86
79
 
87
80
  private
@@ -104,36 +97,15 @@ module Tapioca
104
97
  TYPES.fetch(attr_type, "T.untyped")
105
98
  end
106
99
 
107
- sig do
108
- params(
109
- klass: Parlour::RbiGenerator::Namespace,
110
- attribute: String,
111
- type: String
112
- ).void
113
- end
100
+ sig { params(klass: RBI::Scope, attribute: String, type: String).void }
114
101
  def create_schema_methods(klass, attribute, type)
115
102
  return_type = type_for(type.to_sym)
116
103
 
117
- create_method(
118
- klass,
119
- attribute,
120
- return_type: return_type
121
- )
122
-
123
- create_method(
124
- klass,
125
- "#{attribute}?",
126
- return_type: "T::Boolean"
127
- )
128
-
129
- create_method(
130
- klass,
131
- "#{attribute}=",
132
- parameters: [
133
- Parlour::RbiGenerator::Parameter.new("value", type: return_type),
134
- ],
135
- return_type: return_type
136
- )
104
+ klass.create_method(attribute, return_type: return_type)
105
+ klass.create_method("#{attribute}?", return_type: "T::Boolean")
106
+ klass.create_method("#{attribute}=", parameters: [
107
+ create_param("value", type: return_type),
108
+ ], return_type: return_type)
137
109
  end
138
110
  end
139
111
  end
@@ -0,0 +1,98 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ begin
5
+ require "active_storage"
6
+ require "active_storage/reflection"
7
+ rescue LoadError
8
+ return
9
+ end
10
+
11
+ module Tapioca
12
+ module Compilers
13
+ module Dsl
14
+ # `Tapioca::Compilers::Dsl::ActiveStorage` decorates RBI files for subclasses of
15
+ # `ActiveRecord::Base` that declare [one](https://edgeguides.rubyonrails.org/active_storage_overview.html#has-one-attached)
16
+ # or [many](https://edgeguides.rubyonrails.org/active_storage_overview.html#has-many-attached) attachments.
17
+ #
18
+ # For example, with the following `ActiveRecord::Base` subclass:
19
+ #
20
+ # ~~~rb
21
+ # class Post < ApplicationRecord
22
+ # has_one_attached :photo
23
+ # has_many_attached :blogs
24
+ # end
25
+ # ~~~
26
+ #
27
+ # this generator will produce the RBI file `post.rbi` with the following content:
28
+ #
29
+ # ~~~rbi
30
+ # # typed: strong
31
+ #
32
+ # class Post
33
+ # sig { returns(ActiveStorage::Attached::Many) }
34
+ # def blogs; end
35
+ #
36
+ # sig { params(attachable: T.untyped).returns(T.untyped) }
37
+ # def blogs=(attachable); end
38
+ #
39
+ # sig { returns(ActiveStorage::Attached::One) }
40
+ # def photo; end
41
+ #
42
+ # sig { params(attachable: T.untyped).returns(T.untyped) }
43
+ # def photo=(attachable); end
44
+ # end
45
+ # ~~~
46
+ class ActiveStorage < Base
47
+ extend T::Sig
48
+
49
+ sig do
50
+ override.params(root: RBI::Tree,
51
+ constant: T.all(Module, ::ActiveStorage::Reflection::ActiveRecordExtensions::ClassMethods)).void
52
+ end
53
+ def decorate(root, constant)
54
+ return if constant.reflect_on_all_attachments.empty?
55
+
56
+ root.create_path(constant) do |scope|
57
+ constant.reflect_on_all_attachments.each do |reflection|
58
+ type = type_of(reflection)
59
+ name = reflection.name.to_s
60
+ scope.create_method(
61
+ name,
62
+ return_type: type
63
+ )
64
+ scope.create_method(
65
+ "#{name}=",
66
+ parameters: [create_param("attachable", type: "T.untyped")],
67
+ return_type: "T.untyped"
68
+ )
69
+ end
70
+ end
71
+ end
72
+
73
+ sig { override.returns(T::Enumerable[Module]) }
74
+ def gather_constants
75
+ descendants_of(::ActiveRecord::Base)
76
+ .reject(&:abstract_class?)
77
+ .grep(::ActiveStorage::Reflection::ActiveRecordExtensions::ClassMethods)
78
+ end
79
+
80
+ private
81
+
82
+ sig do
83
+ params(reflection: ActiveRecord::Reflection::MacroReflection).returns(String)
84
+ end
85
+ def type_of(reflection)
86
+ case reflection
87
+ when ::ActiveStorage::Reflection::HasOneAttachedReflection
88
+ "ActiveStorage::Attached::One"
89
+ when ::ActiveStorage::Reflection::HasManyAttachedReflection
90
+ "ActiveStorage::Attached::Many"
91
+ else
92
+ "T.untyped"
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,106 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "tapioca/compilers/sorbet"
5
+
6
+ begin
7
+ require "active_support"
8
+ rescue LoadError
9
+ return
10
+ end
11
+
12
+ module Tapioca
13
+ module Compilers
14
+ module Dsl
15
+ # `Tapioca::Compilers::Dsl::ActiveSupportConcern` generates RBI files for classes that both `extend`
16
+ # `ActiveSupport::Concern` and `include` another class that extends `ActiveSupport::Concern`
17
+ #
18
+ # For example for the following hierarchy:
19
+ #
20
+ # ~~~rb
21
+ # # concern.rb
22
+ # module Foo
23
+ # extend ActiveSupport::Concern
24
+ # module ClassMethods; end
25
+ # end
26
+ #
27
+ # module Bar
28
+ # extend ActiveSupport::Concern
29
+ # module ClassMethods; end
30
+ # include Foo
31
+ # end
32
+ #
33
+ # class Baz
34
+ # include Bar
35
+ # end
36
+ # ~~~
37
+ #
38
+ # this generator will produce the RBI file `concern.rbi` with the following content:
39
+ #
40
+ # ~~~rbi
41
+ # # typed: true
42
+ # module Bar
43
+ # mixes_in_class_methods(::Foo::ClassMethods)
44
+ # end
45
+ # ~~~
46
+ class ActiveSupportConcern < Base
47
+ extend T::Sig
48
+
49
+ sig { override.params(root: RBI::Tree, constant: Module).void }
50
+ def decorate(root, constant)
51
+ dependencies = linearized_dependencies_of(constant)
52
+
53
+ mixed_in_class_methods = dependencies
54
+ .uniq # Deduplicate
55
+ .map do |concern| # Map to class methods module name, if exists
56
+ "#{qualified_name_of(concern)}::ClassMethods" if concern.const_defined?(:ClassMethods)
57
+ end
58
+ .compact # Remove non-existent records
59
+
60
+ return if mixed_in_class_methods.empty?
61
+
62
+ root.create_path(constant) do |mod|
63
+ mixed_in_class_methods.each do |mix|
64
+ mod.create_mixes_in_class_methods(mix)
65
+ end
66
+ end
67
+ end
68
+
69
+ sig { override.returns(T::Enumerable[Module]) }
70
+ def gather_constants
71
+ # Find all Modules that are:
72
+ all_modules.select do |mod|
73
+ # named (i.e. not anonymous)
74
+ name_of(mod) &&
75
+ # not singleton classes
76
+ !mod.singleton_class? &&
77
+ # extend ActiveSupport::Concern, and
78
+ mod.singleton_class < ActiveSupport::Concern &&
79
+ # have dependencies (i.e. include another concern)
80
+ !dependencies_of(mod).empty?
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ sig { params(concern: Module).returns(T::Array[Module]) }
87
+ def dependencies_of(concern)
88
+ concern.instance_variable_get(:@_dependencies)
89
+ end
90
+
91
+ sig { params(concern: Module).returns(T::Array[Module]) }
92
+ def linearized_dependencies_of(concern)
93
+ # Grab all the dependencies of the concern
94
+ dependencies = dependencies_of(concern)
95
+
96
+ # Flatten this concern's dependencies and all of their dependencies
97
+ dependencies.flat_map do |dependency|
98
+ # Linearize dependencies of the current dependency,
99
+ # which, itself, is a concern
100
+ linearized_dependencies_of(dependency) << dependency
101
+ end
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -1,10 +1,10 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "parlour"
5
-
6
4
  begin
7
5
  require "active_support"
6
+ # The following is needed due to https://github.com/rails/rails/pull/41610
7
+ require "active_support/core_ext/module/delegation"
8
8
  rescue LoadError
9
9
  return
10
10
  end
@@ -65,7 +65,7 @@ module Tapioca
65
65
  sig do
66
66
  override
67
67
  .params(
68
- root: Parlour::RbiGenerator::Namespace,
68
+ root: RBI::Tree,
69
69
  constant: T.class_of(::ActiveSupport::CurrentAttributes)
70
70
  )
71
71
  .void
@@ -75,7 +75,7 @@ module Tapioca
75
75
  instance_methods = instance_methods_for(constant) - dynamic_methods
76
76
  return if dynamic_methods.empty? && instance_methods.empty?
77
77
 
78
- root.path(constant) do |current_attributes|
78
+ root.create_path(constant) do |current_attributes|
79
79
  dynamic_methods.each do |method|
80
80
  method = method.to_s
81
81
  # We want to generate each method both on the class
@@ -95,7 +95,7 @@ module Tapioca
95
95
 
96
96
  sig { override.returns(T::Enumerable[Module]) }
97
97
  def gather_constants
98
- ::ActiveSupport::CurrentAttributes.descendants
98
+ descendants_of(::ActiveSupport::CurrentAttributes)
99
99
  end
100
100
 
101
101
  private
@@ -110,11 +110,16 @@ module Tapioca
110
110
  constant.instance_methods(false)
111
111
  end
112
112
 
113
- sig { params(klass: Parlour::RbiGenerator::Namespace, method: String, class_method: T::Boolean).void }
113
+ sig { params(klass: RBI::Scope, method: String, class_method: T::Boolean).void }
114
114
  def generate_method(klass, method, class_method:)
115
115
  if method.end_with?("=")
116
- parameter = Parlour::RbiGenerator::Parameter.new("value", type: "T.untyped")
117
- klass.create_method(method, class_method: class_method, parameters: [parameter], return_type: "T.untyped")
116
+ parameter = create_param("value", type: "T.untyped")
117
+ klass.create_method(
118
+ method,
119
+ class_method: class_method,
120
+ parameters: [parameter],
121
+ return_type: "T.untyped"
122
+ )
118
123
  else
119
124
  klass.create_method(method, class_method: class_method, return_type: "T.untyped")
120
125
  end