From 9c69859f990e91b56a1d5407d7a8aac9052fa0d8 Mon Sep 17 00:00:00 2001 From: Sam Ford <1584702+samford@users.noreply.github.com> Date: Mon, 16 Jun 2025 23:20:19 -0400 Subject: [PATCH] Add Cask::Config RBI compiler This is a naive attempt at creating an RBI compiler for the `Cask::Config` class. `Config` contains methods like `appdir` that are defined dynamically using the class's default values and Sorbet doesn't understand that these methods exist or what their return types are. This compiler works as expected and gets the job done but I know basically nothing about Tapioca, so there may be a better way of doing this. For what it's worth, this isn't an issue right now but Sorbet will surface an error once `Cask::DSL` is updated to `typed: strict` (i.e., `Method appdir does not exist on Cask::Config`). That's something I've been working on and this compiler is intended as a way of preemptively resolving that Sorbet error, so I can move forward with the `Cask::DSL` type signature work. --- .../Homebrew/sorbet/rbi/dsl/cask/config.rbi | 58 +++++++++++++++++++ .../sorbet/tapioca/compilers/cask/config.rb | 37 ++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 Library/Homebrew/sorbet/rbi/dsl/cask/config.rbi create mode 100644 Library/Homebrew/sorbet/tapioca/compilers/cask/config.rb diff --git a/Library/Homebrew/sorbet/rbi/dsl/cask/config.rbi b/Library/Homebrew/sorbet/rbi/dsl/cask/config.rbi new file mode 100644 index 0000000000..5e2f38940e --- /dev/null +++ b/Library/Homebrew/sorbet/rbi/dsl/cask/config.rbi @@ -0,0 +1,58 @@ +# typed: true + +# DO NOT EDIT MANUALLY +# This is an autogenerated file for dynamic methods in `Cask::Config`. +# Please instead update this file by running `bin/tapioca dsl Cask::Config`. + + +module Cask + class Config + sig { returns(String) } + def appdir; end + + sig { returns(String) } + def audio_unit_plugindir; end + + sig { returns(String) } + def colorpickerdir; end + + sig { returns(String) } + def dictionarydir; end + + sig { returns(String) } + def fontdir; end + + sig { returns(String) } + def input_methoddir; end + + sig { returns(String) } + def internet_plugindir; end + + sig { returns(String) } + def keyboard_layoutdir; end + + sig { returns(T::Array[String]) } + def languages; end + + sig { returns(String) } + def mdimporterdir; end + + sig { returns(String) } + def prefpanedir; end + + sig { returns(String) } + def qlplugindir; end + + sig { returns(String) } + def screen_saverdir; end + + sig { returns(String) } + def servicedir; end + + sig { returns(String) } + def vst3_plugindir; end + + sig { returns(String) } + def vst_plugindir; end + end +end diff --git a/Library/Homebrew/sorbet/tapioca/compilers/cask/config.rb b/Library/Homebrew/sorbet/tapioca/compilers/cask/config.rb new file mode 100644 index 0000000000..24984b3114 --- /dev/null +++ b/Library/Homebrew/sorbet/tapioca/compilers/cask/config.rb @@ -0,0 +1,37 @@ +# typed: strict +# frozen_string_literal: true + +require_relative "../../../../global" +require "cask/config" + +module Tapioca + module Compilers + class CaskConfig < Tapioca::Dsl::Compiler + ConstantType = type_member { { fixed: Module } } + + sig { override.returns(T::Enumerable[Module]) } + def self.gather_constants = [Cask::Config] + + sig { override.void } + def decorate + root.create_module("Cask") do |mod| + mod.create_class("Config") do |klass| + Cask::Config.defaults.each do |key, value| + return_type = if key == :languages + # :languages is a `LazyObject`, so it lazily evaluates to an + # array of strings when a method is called on it. + "T::Array[String]" + elsif key.end_with?("?") + "T::Boolean" + else + value.class.to_s + end + + klass.create_method(key.to_s, return_type:, class_method: false) + end + end + end + end + end + end +end