Skip to content

Commit

Permalink
Add a Delegator DSL compiler
Browse files Browse the repository at this point in the history
  • Loading branch information
dduugg committed Oct 6, 2024
1 parent 3c51d0c commit 9f13ddc
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 51 deletions.
64 changes: 37 additions & 27 deletions Library/Homebrew/cask/url.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,23 @@ module Cask
# Class corresponding to the `url` stanza.
class URL < Delegator
class DSL
attr_reader :uri, :specs,
:verified, :using,
:tag, :branch, :revisions, :revision,
:trust_cert, :cookies, :referer, :header, :user_agent,
:data, :only_path
attr_reader :uri, :tag, :branch, :revisions, :revision,
:trust_cert, :cookies, :header, :data, :only_path

sig { returns(T.nilable(T.any(URI::Generic, String))) }
attr_reader :referer

sig { returns(T::Hash[Symbol, T.untyped]) }
attr_reader :specs

sig { returns(T.nilable(T.any(Symbol, String))) }
attr_reader :user_agent

sig { returns(T.any(T::Class[T.anything], Symbol, NilClass)) }
attr_reader :using

sig { returns(T.nilable(String)) }
attr_reader :verified

extend Forwardable
def_delegators :uri, :path, :scheme, :to_s
Expand Down Expand Up @@ -137,6 +149,8 @@ def call
end
end

private

# Allows calling a nested `url` stanza in a `url do` block.
#
# @api public
Expand All @@ -150,7 +164,6 @@ def call
def url(uri, &block)
self.class.new(uri, dsl: @dsl, &block).call
end
private :url

# This allows calling DSL methods from inside a `url` block.
#
Expand All @@ -162,12 +175,10 @@ def method_missing(method, *args, &block)
super
end
end
private :method_missing

def respond_to_missing?(method, include_all)
@dsl.respond_to?(method, include_all) || super
end
private :respond_to_missing?
end

sig {
Expand Down Expand Up @@ -244,30 +255,11 @@ def initialize(
@caller_location = caller_location
end

def __getobj__
@dsl
end

def __setobj__(dsl)
@dsl = dsl
end

sig { returns(Homebrew::SourceLocation) }
def location
Homebrew::SourceLocation.new(@caller_location.lineno, raw_url_line&.index("url"))
end

sig { returns(T.nilable(String)) }
def raw_url_line
return @raw_url_line if defined?(@raw_url_line)

@raw_url_line = Pathname(T.must(@caller_location.path))
.each_line
.drop(@caller_location.lineno - 1)
.first
end
private :raw_url_line

sig { params(ignore_major_version: T::Boolean).returns(T::Boolean) }
def unversioned?(ignore_major_version: false)
interpolated_url = raw_url_line&.then { |line| line[/url\s+"([^"]+)"/, 1] }
Expand All @@ -283,5 +275,23 @@ def unversioned?(ignore_major_version: false)
def from_block?
@from_block
end

private

def __getobj__ = @dsl

def __setobj__(dsl)
@dsl = dsl
end

sig { returns(T.nilable(String)) }
def raw_url_line
return @raw_url_line if defined?(@raw_url_line)

@raw_url_line = Pathname(T.must(@caller_location.path))
.each_line
.drop(@caller_location.lineno - 1)
.first
end
end
end
24 changes: 0 additions & 24 deletions Library/Homebrew/cask/url.rbi

This file was deleted.

64 changes: 64 additions & 0 deletions Library/Homebrew/sorbet/rbi/dsl/cask/url.rbi

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

37 changes: 37 additions & 0 deletions Library/Homebrew/sorbet/tapioca/compilers/delegators.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# typed: strict
# frozen_string_literal: true

require_relative "../../../global"
require "cask/url"

module Tapioca
module Compilers
# A compiler for subclasses of Delegator.
# To add a new delegator: require it above add add it to the DELEGATIONS hash below.
class Delegators < Tapioca::Dsl::Compiler
# Mapping of delegator classes to the classes they delegate to (as defined in `__getobj__`).
DELEGATIONS = T.let({
Cask::URL => Cask::URL::DSL,
}.freeze, T::Hash[Module, Module])
ConstantType = type_member { { fixed: Module } }

sig { override.returns(T::Enumerable[Module]) }
def self.gather_constants = DELEGATIONS.keys

sig { override.void }
def decorate
root.create_path(constant) do |klass|
klass.create_include("Kernel")
delegated = DELEGATIONS.fetch(constant)

delegated.instance_methods(false).each do |method|
signature = T::Utils.signature_for_method(delegated.instance_method(method))
# TODO: handle methods with parameters
return_type = signature&.return_type&.to_s || "T.untyped"
klass.create_method(method.to_s, return_type:)
end
end
end
end
end
end

0 comments on commit 9f13ddc

Please sign in to comment.