tapioca 0.4.10 → 0.4.15

Sign up to get free protection for your applications and to get access to all the features.
@@ -15,8 +15,7 @@ module Tapioca
15
15
  module Compilers
16
16
  module Dsl
17
17
  # `Tapioca::Compilers::Dsl::ActiveRecordEnum` decorates RBI files for subclasses of
18
- # `ActiveRecord::Base` which declare `enum` fields
19
- # (see https://api.rubyonrails.org/classes/ActiveRecord/Enum.html).
18
+ # `ActiveRecord::Base` which declare [`enum` fields](https://api.rubyonrails.org/classes/ActiveRecord/Enum.html).
20
19
  #
21
20
  # For example, with the following `ActiveRecord::Base` subclass:
22
21
  #
@@ -32,26 +31,30 @@ module Tapioca
32
31
  # # post.rbi
33
32
  # # typed: true
34
33
  # class Post
35
- # sig { void }
36
- # def all_title!; end
34
+ # include EnumMethodsModule
37
35
  #
38
- # sig { returns(T::Boolean) }
39
- # def all_title?; end
36
+ # module EnumMethodsModule
37
+ # sig { void }
38
+ # def all_title!; end
40
39
  #
41
- # sig { returns(T::Hash[T.any(String, Symbol), Integer]) }
42
- # def self.title_types; end
40
+ # sig { returns(T::Boolean) }
41
+ # def all_title?; end
43
42
  #
44
- # sig { void }
45
- # def book_title!; end
43
+ # sig { returns(T::Hash[T.any(String, Symbol), Integer]) }
44
+ # def self.title_types; end
46
45
  #
47
- # sig { returns(T::Boolean) }
48
- # def book_title?; end
46
+ # sig { void }
47
+ # def book_title!; end
49
48
  #
50
- # sig { void }
51
- # def web_title!; end
49
+ # sig { returns(T::Boolean) }
50
+ # def book_title?; end
52
51
  #
53
- # sig { returns(T::Boolean) }
54
- # def web_title?; end
52
+ # sig { void }
53
+ # def web_title!; end
54
+ #
55
+ # sig { returns(T::Boolean) }
56
+ # def web_title?; end
57
+ # end
55
58
  # end
56
59
  # ~~~
57
60
  class ActiveRecordEnum < Base
@@ -61,17 +64,18 @@ module Tapioca
61
64
  def decorate(root, constant)
62
65
  return if constant.defined_enums.empty?
63
66
 
64
- module_name = "#{constant}::EnumMethodsModule"
65
- root.create_module(module_name) do |mod|
66
- generate_instance_methods(constant, mod)
67
- end
67
+ root.path(constant) do |model|
68
+ module_name = "EnumMethodsModule"
69
+
70
+ model.create_module(module_name) do |mod|
71
+ generate_instance_methods(constant, mod)
72
+ end
68
73
 
69
- root.path(constant) do |k|
70
- k.create_include(module_name)
74
+ model.create_include(module_name)
71
75
 
72
76
  constant.defined_enums.each do |name, enum_map|
73
77
  type = type_for_enum(enum_map)
74
- create_method(k, name.pluralize, class_method: true, return_type: type)
78
+ create_method(model, name.pluralize, class_method: true, return_type: type)
75
79
  end
76
80
  end
77
81
  end
@@ -12,9 +12,9 @@ end
12
12
  module Tapioca
13
13
  module Compilers
14
14
  module Dsl
15
- # `Tapioca::Compilers::Dsl::ActiveRecordScope` decorates RBI files for subclasses of
16
- # `ActiveRecord::Base` which declare `scope` fields
17
- # (see https://api.rubyonrails.org).
15
+ # `Tapioca::Compilers::Dsl::ActiveRecordScope` decorates RBI files for
16
+ # subclasses of `ActiveRecord::Base` which declare
17
+ # [`scope` fields](https://api.rubyonrails.org/classes/ActiveRecord/Scoping/Named/ClassMethods.html#method-i-scope).
18
18
  #
19
19
  # For example, with the following `ActiveRecord::Base` subclass:
20
20
  #
@@ -31,15 +31,15 @@ module Tapioca
31
31
  # # post.rbi
32
32
  # # typed: true
33
33
  # class Post
34
- # extend Post::GeneratedRelationMethods
35
- # end
34
+ # extend GeneratedRelationMethods
36
35
  #
37
- # module Post::GeneratedRelationMethods
38
- # sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
39
- # def private_kind(*args, &blk); end
36
+ # module GeneratedRelationMethods
37
+ # sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
38
+ # def private_kind(*args, &blk); end
40
39
  #
41
- # sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
42
- # def public_kind(*args, &blk); end
40
+ # sig { params(args: T.untyped, blk: T.untyped).returns(T.untyped) }
41
+ # def public_kind(*args, &blk); end
42
+ # end
43
43
  # end
44
44
  # ~~~
45
45
  class ActiveRecordScope < Base
@@ -55,15 +55,16 @@ module Tapioca
55
55
  scope_method_names = constant.send(:generated_relation_methods).instance_methods(false)
56
56
  return if scope_method_names.empty?
57
57
 
58
- module_name = "#{constant}::GeneratedRelationMethods"
59
- root.create_module(module_name) do |mod|
60
- scope_method_names.each do |scope_method|
61
- generate_scope_method(scope_method, mod)
58
+ root.path(constant) do |model|
59
+ module_name = "GeneratedRelationMethods"
60
+
61
+ model.create_module(module_name) do |mod|
62
+ scope_method_names.each do |scope_method|
63
+ generate_scope_method(scope_method, mod)
64
+ end
62
65
  end
63
- end
64
66
 
65
- root.path(constant) do |k|
66
- k.create_extend(module_name)
67
+ model.create_extend(module_name)
67
68
  end
68
69
  end
69
70
 
@@ -15,8 +15,8 @@ end
15
15
  module Tapioca
16
16
  module Compilers
17
17
  module Dsl
18
- # `Tapioca::Compilers::DSL::ActiveRecordTypedStore` generates RBI files for ActiveRecord models that use
19
- # `ActiveRecord::TypedStore` features (see https://github.com/byroot/activerecord-typedstore).
18
+ # `Tapioca::Compilers::DSL::ActiveRecordTypedStore` generates RBI files for Active Record models that use
19
+ # [`ActiveRecord::TypedStore`](https://github.com/byroot/activerecord-typedstore) features.
20
20
  #
21
21
  # For example, with the following ActiveRecord class:
22
22
  #
@@ -101,13 +101,14 @@ module Tapioca
101
101
  stores = constant.typed_stores
102
102
  return if stores.values.flat_map(&:accessors).empty?
103
103
 
104
- root.path(constant) do |k|
104
+ root.path(constant) do |model|
105
105
  stores.values.each do |store_data|
106
106
  store_data.accessors.each do |accessor|
107
107
  field = store_data.fields[accessor]
108
108
  type = type_for(field.type_sym)
109
109
  type = "T.nilable(#{type})" if field.null && type != "T.untyped"
110
- generate_methods(field.name.to_s, type, k)
110
+
111
+ generate_methods(model, field.name.to_s, type)
111
112
  end
112
113
  end
113
114
  end
@@ -141,13 +142,13 @@ module Tapioca
141
142
 
142
143
  sig do
143
144
  params(
145
+ klass: Parlour::RbiGenerator::Namespace,
144
146
  name: String,
145
- type: String,
146
- klass: Parlour::RbiGenerator::Namespace
147
+ type: String
147
148
  )
148
149
  .void
149
150
  end
150
- def generate_methods(name, type, klass)
151
+ def generate_methods(klass, name, type)
151
152
  klass.create_method(
152
153
  "#{name}=",
153
154
  parameters: [Parlour::RbiGenerator::Parameter.new(name, type: type)],
@@ -13,8 +13,8 @@ module Tapioca
13
13
  module Compilers
14
14
  module Dsl
15
15
  # `Tapioca::Compilers::Dsl::ActiveResource` decorates RBI files for subclasses of
16
- # `ActiveResource::Base` which declare `schema` fields
17
- # (see https://github.com/rails/activeresource).
16
+ # [`ActiveResource::Base`](https://github.com/rails/activeresource) which declare
17
+ # `schema` fields.
18
18
  #
19
19
  # For example, with the following `ActiveResource::Base` subclass:
20
20
  #
@@ -71,9 +71,10 @@ module Tapioca
71
71
  end
72
72
  def decorate(root, constant)
73
73
  return if constant.schema.blank?
74
- root.path(constant) do |klass|
74
+
75
+ root.path(constant) do |resource|
75
76
  constant.schema.each do |attribute, type|
76
- create_schema_methods(klass, attribute, type)
77
+ create_schema_methods(resource, attribute, type)
77
78
  end
78
79
  end
79
80
  end
@@ -13,9 +13,8 @@ module Tapioca
13
13
  module Compilers
14
14
  module Dsl
15
15
  # `Tapioca::Compilers::Dsl::ActiveSupportCurrentAttributes` decorates RBI files for all
16
- # subclasses of `ActiveSupport::CurrentAttributes`
17
- #
18
- # To add attributes see https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html
16
+ # subclasses of
17
+ # [`ActiveSupport::CurrentAttributes`](https://api.rubyonrails.org/classes/ActiveSupport/CurrentAttributes.html).
19
18
  #
20
19
  # For example, with the following singleton class
21
20
  #
@@ -76,20 +75,20 @@ module Tapioca
76
75
  instance_methods = instance_methods_for(constant) - dynamic_methods
77
76
  return if dynamic_methods.empty? && instance_methods.empty?
78
77
 
79
- root.path(constant) do |k|
78
+ root.path(constant) do |current_attributes|
80
79
  dynamic_methods.each do |method|
81
80
  method = method.to_s
82
81
  # We want to generate each method both on the class
83
- generate_method(k, method, class_method: true)
82
+ generate_method(current_attributes, method, class_method: true)
84
83
  # and on the instance
85
- generate_method(k, method, class_method: false)
84
+ generate_method(current_attributes, method, class_method: false)
86
85
  end
87
86
 
88
87
  instance_methods.each do |method|
89
88
  # instance methods are only elevated to class methods
90
89
  # no need to add separate instance methods for them
91
90
  method = constant.instance_method(method)
92
- create_method_from_def(k, method, class_method: true)
91
+ create_method_from_def(current_attributes, method, class_method: true)
93
92
  end
94
93
  end
95
94
  end
@@ -61,7 +61,7 @@ module Tapioca
61
61
  end
62
62
  def create_method(namespace, name, options = {})
63
63
  return unless valid_method_name?(name)
64
- T.unsafe(namespace).create_method(name, options)
64
+ T.unsafe(namespace).create_method(name, **options)
65
65
  end
66
66
 
67
67
  # Create a Parlour method inside `namespace` from its Ruby definition
@@ -12,8 +12,8 @@ end
12
12
  module Tapioca
13
13
  module Compilers
14
14
  module Dsl
15
- # `Tapioca::Compilers::Dsl::FrozenRecord` generates RBI files for subclasses of `FrozenRecord::Base`
16
- # (see https://github.com/byroot/frozen_record).
15
+ # `Tapioca::Compilers::Dsl::FrozenRecord` generates RBI files for subclasses of
16
+ # [`FrozenRecord::Base`](https://github.com/byroot/frozen_record).
17
17
  #
18
18
  # For example, with the following FrozenRecord class:
19
19
  #
@@ -41,27 +41,27 @@ module Tapioca
41
41
  # # Student.rbi
42
42
  # # typed: strong
43
43
  # class Student
44
- # include Student::FrozenRecordAttributeMethods
45
- # end
44
+ # include FrozenRecordAttributeMethods
46
45
  #
47
- # module Student::FrozenRecordAttributeMethods
48
- # sig { returns(T.untyped) }
49
- # def first_name; end
46
+ # module FrozenRecordAttributeMethods
47
+ # sig { returns(T.untyped) }
48
+ # def first_name; end
50
49
  #
51
- # sig { returns(T::Boolean) }
52
- # def first_name?; end
50
+ # sig { returns(T::Boolean) }
51
+ # def first_name?; end
53
52
  #
54
- # sig { returns(T.untyped) }
55
- # def id; end
53
+ # sig { returns(T.untyped) }
54
+ # def id; end
56
55
  #
57
- # sig { returns(T::Boolean) }
58
- # def id?; end
56
+ # sig { returns(T::Boolean) }
57
+ # def id?; end
59
58
  #
60
- # sig { returns(T.untyped) }
61
- # def last_name; end
59
+ # sig { returns(T.untyped) }
60
+ # def last_name; end
62
61
  #
63
- # sig { returns(T::Boolean) }
64
- # def last_name?; end
62
+ # sig { returns(T::Boolean) }
63
+ # def last_name?; end
64
+ # end
65
65
  # end
66
66
  # ~~~
67
67
  class FrozenRecord < Base
@@ -72,17 +72,17 @@ module Tapioca
72
72
  attributes = constant.attributes
73
73
  return if attributes.empty?
74
74
 
75
- module_name = "#{constant}::FrozenRecordAttributeMethods"
75
+ root.path(constant) do |record|
76
+ module_name = "FrozenRecordAttributeMethods"
76
77
 
77
- root.create_module(module_name) do |mod|
78
- attributes.each do |attribute|
79
- create_method(mod, "#{attribute}?", return_type: 'T::Boolean')
80
- create_method(mod, attribute.to_s, return_type: 'T.untyped')
78
+ record.create_module(module_name) do |mod|
79
+ attributes.each do |attribute|
80
+ create_method(mod, "#{attribute}?", return_type: 'T::Boolean')
81
+ create_method(mod, attribute.to_s, return_type: 'T.untyped')
82
+ end
81
83
  end
82
- end
83
84
 
84
- root.path(constant) do |klass|
85
- klass.create_include(module_name)
85
+ record.create_include(module_name)
86
86
  end
87
87
  end
88
88
 
@@ -15,11 +15,12 @@ end
15
15
  module Tapioca
16
16
  module Compilers
17
17
  module Dsl
18
- # `Tapioca::Compilers::DSL::ActiveRecordIdentityCache` generates RBI files for ActiveRecord models
18
+ # `Tapioca::Compilers::DSL::IdentityCache` generates RBI files for Active Record models
19
19
  # that use `include IdentityCache`.
20
- # `IdentityCache` is a blob level caching solution to plug into ActiveRecord. (see https://github.com/Shopify/identity_cache).
20
+ # [`IdentityCache`](https://github.com/Shopify/identity_cache) is a blob level caching solution
21
+ # to plug into Active Record.
21
22
  #
22
- # For example, with the following ActiveRecord class:
23
+ # For example, with the following Active Record class:
23
24
  #
24
25
  # ~~~rb
25
26
  # # post.rb
@@ -61,7 +62,7 @@ module Tapioca
61
62
  # def fetch_by_title_and_review_date(title, review_date, includes: nil); end
62
63
  # end
63
64
  # ~~~
64
- class ActiveRecordIdentityCache < Base
65
+ class IdentityCache < Base
65
66
  extend T::Sig
66
67
 
67
68
  COLLECTION_TYPE = T.let(
@@ -82,25 +83,25 @@ module Tapioca
82
83
  cache_indexes = constant.send(:cache_indexes)
83
84
  return if caches.empty? && cache_indexes.empty?
84
85
 
85
- root.path(constant) do |k|
86
+ root.path(constant) do |model|
86
87
  cache_manys = constant.send(:cached_has_manys)
87
88
  cache_ones = constant.send(:cached_has_ones)
88
89
  cache_belongs = constant.send(:cached_belongs_tos)
89
90
 
90
91
  cache_indexes.each do |field|
91
- create_fetch_by_methods(field, k, constant)
92
+ create_fetch_by_methods(field, model, constant)
92
93
  end
93
94
 
94
95
  cache_manys.values.each do |field|
95
- create_fetch_field_methods(field, k, returns_collection: true)
96
+ create_fetch_field_methods(field, model, returns_collection: true)
96
97
  end
97
98
 
98
99
  cache_ones.values.each do |field|
99
- create_fetch_field_methods(field, k, returns_collection: false)
100
+ create_fetch_field_methods(field, model, returns_collection: false)
100
101
  end
101
102
 
102
103
  cache_belongs.values.each do |field|
103
- create_fetch_field_methods(field, k, returns_collection: false)
104
+ create_fetch_field_methods(field, model, returns_collection: false)
104
105
  end
105
106
  end
106
107
  end
@@ -108,7 +109,7 @@ module Tapioca
108
109
  sig { override.returns(T::Enumerable[Module]) }
109
110
  def gather_constants
110
111
  ::ActiveRecord::Base.descendants.select do |klass|
111
- klass < IdentityCache::WithoutPrimaryIndex
112
+ klass < ::IdentityCache::WithoutPrimaryIndex
112
113
  end
113
114
  end
114
115
 
@@ -12,7 +12,7 @@ module Tapioca
12
12
  module Compilers
13
13
  module Dsl
14
14
  # `Tapioca::Compilers::Dsl::Protobuf` decorates RBI files for subclasses of
15
- # `Google::Protobuf::MessageExts` (see https://github.com/protocolbuffers/protobuf/tree/master/ruby).
15
+ # [`Google::Protobuf::MessageExts`](https://github.com/protocolbuffers/protobuf/tree/master/ruby).
16
16
  #
17
17
  # For example, with the following "cart.rb" file:
18
18
  #
@@ -0,0 +1,83 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ require "parlour"
5
+
6
+ begin
7
+ require "sidekiq"
8
+ rescue LoadError
9
+ return
10
+ end
11
+
12
+ module Tapioca
13
+ module Compilers
14
+ module Dsl
15
+ # `Tapioca::Compilers::Dsl::SidekiqWorker` generates RBI files classes that include
16
+ # [`Sidekiq::Worker`](https://github.com/mperham/sidekiq/wiki/Getting-Started).
17
+ #
18
+ # For example, with the following class that includes `Sidekiq::Worker`:
19
+ #
20
+ # ~~~rb
21
+ # class NotifierWorker
22
+ # include Sidekiq::Worker
23
+ # def perform(customer_id)
24
+ # # ...
25
+ # end
26
+ # end
27
+ # ~~~
28
+ #
29
+ # this generator will produce the RBI file `notifier_worker.rbi` with the following content:
30
+ #
31
+ # ~~~rbi
32
+ # # notifier_worker.rbi
33
+ # # typed: true
34
+ # class NotifierWorker
35
+ # sig { params(customer_id: T.untyped).returns(String) }
36
+ # def self.perform_async(customer_id); end
37
+ #
38
+ # sig { params(interval: T.any(DateTime, Time), customer_id: T.untyped).returns(String) }
39
+ # def self.perform_at(interval, customer_id); end
40
+ #
41
+ # sig { params(interval: Numeric, customer_id: T.untyped).returns(String) }
42
+ # def self.perform_in(interval, customer_id); end
43
+ # end
44
+ # ~~~
45
+ class SidekiqWorker < Base
46
+ extend T::Sig
47
+
48
+ sig { override.params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(::Sidekiq::Worker)).void }
49
+ def decorate(root, constant)
50
+ return unless constant.instance_methods.include?(:perform)
51
+
52
+ root.path(constant) do |worker|
53
+ method_def = constant.instance_method(:perform)
54
+
55
+ async_params = compile_method_parameters_to_parlour(method_def)
56
+
57
+ # `perform_at` and is just an alias for `perform_in` so both methods technically
58
+ # accept a datetime, time, or numeric but we're typing them differently so they
59
+ # semantically make sense.
60
+ at_params = [
61
+ Parlour::RbiGenerator::Parameter.new('interval', type: 'T.any(DateTime, Time)'),
62
+ *async_params,
63
+ ]
64
+ in_params = [
65
+ Parlour::RbiGenerator::Parameter.new('interval', type: 'Numeric'),
66
+ *async_params,
67
+ ]
68
+
69
+ create_method(worker, 'perform_async', parameters: async_params, return_type: 'String', class_method: true)
70
+ create_method(worker, 'perform_at', parameters: at_params, return_type: 'String', class_method: true)
71
+ create_method(worker, 'perform_in', parameters: in_params, return_type: 'String', class_method: true)
72
+ end
73
+ end
74
+
75
+ sig { override.returns(T::Enumerable[Module]) }
76
+ def gather_constants
77
+ classes = T.cast(ObjectSpace.each_object(Class), T::Enumerable[Class])
78
+ classes.select { |c| c < Sidekiq::Worker }
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end