Class: Tapioca::Dsl::Compilers::Protobuf

Inherits:
Tapioca::Dsl::Compiler show all
Extended by:
T::Sig
Defined in:
lib/tapioca/dsl/compilers/protobuf.rb

Overview

Tapioca::Dsl::Compilers::Protobuf decorates RBI files for subclasses of Google::Protobuf::MessageExts.

For example, with the following "cart.rb" file:

Google::Protobuf::DescriptorPool.generated_pool.build do
  add_file("cart.proto", :syntax => :proto3) do
    add_message "MyCart" do
      optional :shop_id, :int32, 1
      optional :customer_id, :int64, 2
      optional :number_value, :double, 3
      optional :string_value, :string, 4
    end
  end
end

this compiler will produce the RBI file cart.rbi with the following content:

# cart.rbi
# typed: strong
class Cart
  sig { returns(Integer) }
  def customer_id; end

  sig { params(month: Integer).returns(Integer) }
  def customer_id=(value); end

  sig { returns(Integer) }
  def shop_id; end

  sig { params(value: Integer).returns(Integer) }
  def shop_id=(value); end

  sig { returns(String) }
  def string_value; end

  sig { params(value: String).returns(String) }
  def string_value=(value); end


  sig { returns(Float) }
  def number_value; end

  sig { params(value: Float).returns(Float) }
  def number_value=(value); end
end

Please note that you might have to ignore the originally generated Protobuf Ruby files to avoid Redefining constant issues when doing type checking. Do this by extending your Sorbet config file:

--ignore=/path/to/proto/cart_pb.rb

Defined Under Namespace

Classes: Field

Constant Summary collapse

ConstantType =
type_member { { fixed: Module } }
FIELD_RE =
/^[a-z_][a-zA-Z0-9_]*$/

Constants included from Runtime::Reflection

Runtime::Reflection::ANCESTORS_METHOD, Runtime::Reflection::CLASS_METHOD, Runtime::Reflection::CONSTANTS_METHOD, Runtime::Reflection::EQUAL_METHOD, Runtime::Reflection::METHOD_METHOD, Runtime::Reflection::NAME_METHOD, Runtime::Reflection::OBJECT_ID_METHOD, Runtime::Reflection::PRIVATE_INSTANCE_METHODS_METHOD, Runtime::Reflection::PROTECTED_INSTANCE_METHODS_METHOD, Runtime::Reflection::PUBLIC_INSTANCE_METHODS_METHOD, Runtime::Reflection::REQUIRED_FROM_LABELS, Runtime::Reflection::SINGLETON_CLASS_METHOD, Runtime::Reflection::SUPERCLASS_METHOD

Constants included from SorbetHelper

SorbetHelper::FEATURE_REQUIREMENTS, SorbetHelper::SORBET_BIN, SorbetHelper::SORBET_EXE_PATH_ENV_VAR, SorbetHelper::SORBET_GEM_SPEC, SorbetHelper::SORBET_PAYLOAD_URL

Instance Attribute Summary

Attributes inherited from Tapioca::Dsl::Compiler

#constant, #root

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Tapioca::Dsl::Compiler

#add_error, #compiler_enabled?, handles?, #initialize, processable_constants

Methods included from T::Generic::TypeStoragePatch

#[], #type_member, #type_template

Methods included from Runtime::Reflection

#ancestors_of, #are_equal?, #attached_class_of, #class_of, #constantize, #constants_of, #descendants_of, #inherited_ancestors_of, #method_of, #name_of, #name_of_type, #object_id_of, #private_instance_methods_of, #protected_instance_methods_of, #public_instance_methods_of, #qualified_name_of, #resolve_loc, #signature_of, #singleton_class_of, #superclass_of

Methods included from RBIHelper

#create_block_param, #create_kw_opt_param, #create_kw_param, #create_kw_rest_param, #create_opt_param, #create_param, #create_rest_param, #create_typed_param, #sanitize_signature_types, serialize_type_variable, #valid_method_name?, #valid_parameter_name?

Methods included from SorbetHelper

#sorbet, #sorbet_path, #sorbet_supports?

Constructor Details

This class inherits a constructor from Tapioca::Dsl::Compiler

Class Method Details

.gather_constants ⇒ Object



116
117
118
119
120
# File 'lib/tapioca/dsl/compilers/protobuf.rb', line 116

def self.gather_constants
  marker = Google::Protobuf::MessageExts::ClassMethods
  results = T.cast(ObjectSpace.each_object(marker).to_a, T::Array[Module])
  results.any? ? results + [Google::Protobuf::RepeatedField, Google::Protobuf::Map] : []
end

Instance Method Details

#decorate ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/tapioca/dsl/compilers/protobuf.rb', line 86

def decorate
  root.create_path(constant) do |klass|
    if constant == Google::Protobuf::RepeatedField
      create_type_members(klass, "Elem")
    elsif constant == Google::Protobuf::Map
      create_type_members(klass, "Key", "Value")
    else
      descriptor = T.let(T.unsafe(constant).descriptor, Google::Protobuf::Descriptor)
      descriptor.each_oneof { |oneof| create_oneof_method(klass, oneof) }
      fields = descriptor.map { |desc| create_descriptor_method(klass, desc) }
      fields.sort_by!(&:name)

      parameters = fields.map do |field|
        create_kw_opt_param(field.name, type: field.init_type, default: field.default)
      end

      if fields.all? { |field| FIELD_RE.match?(field.name) }
        klass.create_method("initialize", parameters: parameters, return_type: "void")
      else
        # One of the fields has an incorrect name for a named parameter so creating the default initialize for
        # it would create a RBI with a syntax error.
        # The workaround is to create an initialize that takes a **kwargs instead.
        kwargs_parameter = create_kw_rest_param("fields", type: "T.untyped")
        klass.create_method("initialize", parameters: [kwargs_parameter], return_type: "void")
      end
    end
  end
end