tapioca 0.4.27 → 0.5.3

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 (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