brew vendor-gems: commit updates.

This commit is contained in:
BrewTestBot 2025-07-11 17:02:23 +00:00
parent d4325c0137
commit f3db247045
No known key found for this signature in database
99 changed files with 896 additions and 273 deletions

View File

@ -167,6 +167,7 @@ GEM
PLATFORMS
aarch64-linux
arm-linux
arm64-darwin
x86_64-darwin
x86_64-linux

View File

@ -37,21 +37,21 @@ end
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/public_suffix-6.0.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/addressable-2.8.7/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ast-2.4.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/base64-0.2.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/benchmark-0.4.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/bigdecimal-3.1.9")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bigdecimal-3.1.9/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/base64-0.3.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/benchmark-0.4.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/bigdecimal-3.2.2")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bigdecimal-3.2.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/bindata-2.5.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/coderay-1.1.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/concurrent-ruby-1.3.5/lib/concurrent-ruby")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/csv-3.3.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/csv-3.3.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/diff-lcs-1.6.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/docile-1.4.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/elftools-1.3.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/erubi-1.13.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/hana-1.3.7/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/json-2.12.0")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/json-2.12.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/json-2.12.2")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/json-2.12.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/regexp_parser-2.10.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simpleidn-0.2.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/json_schemer-2.4.0/lib")
@ -64,7 +64,7 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/minitest-5.25.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/netrc-0.11.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parallel-1.27.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parallel_tests-5.2.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parallel_tests-5.3.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/racc-1.8.1")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/racc-1.8.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/parser-3.3.8.0/lib")
@ -76,48 +76,49 @@ $:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/pycall-1.5.2")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/pycall-1.5.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rainbow-3.1.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/rbs-3.9.4")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rbs-3.9.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-runtime-0.5.12117/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rbi-0.3.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/rbs-4.0.0.dev.4")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rbs-4.0.0.dev.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rbi-0.3.6/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/redcarpet-3.6.1")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/redcarpet-3.6.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-support-3.13.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-core-3.13.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-expectations-3.13.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-mocks-3.13.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-3.13.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/require-hooks-0.2.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-support-3.13.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-core-3.13.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-expectations-3.13.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-mocks-3.13.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-3.13.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-github-3.0.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-retry-0.6.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-runtime-0.5.12222/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec-sorbet-1.9.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rspec_junit_formatter-0.6.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-ast-1.44.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-ast-1.45.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-progressbar-1.13.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/unicode-emoji-4.0.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/unicode-display_width-3.1.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-1.75.6/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-1.77.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-md-2.0.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-performance-1.25.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-rspec-3.6.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.10.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-lsp-0.23.21/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/rubocop-sorbet-0.10.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-lsp-0.24.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-macho-4.1.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/ruby-prof-1.7.1")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-prof-1.7.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/ruby-prof-1.7.2")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/ruby-prof-1.7.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov-html-0.13.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov_json_formatter-0.1.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov-0.22.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/simplecov-cobertura-2.1.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-static-0.5.12117-universal-darwin/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-0.5.12117/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-static-and-runtime-0.5.12117/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-static-0.5.12222-universal-darwin/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-0.5.12222/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/sorbet-static-and-runtime-0.5.12222/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/thor-1.3.2/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/spoom-1.6.3/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/spoom-1.7.4/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/stackprof-0.2.27")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/stackprof-0.2.27/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/yard-0.9.37/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/yard-sorbet-0.9.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/tapioca-0.16.11/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/vernier-1.7.1")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/vernier-1.7.1/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/tapioca-0.17.5/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/extensions/arm64-darwin-20/#{Gem.extension_api_version}/vernier-1.8.0")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/vernier-1.8.0/lib")
$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{Gem.ruby_api_version}/gems/warning-1.5.0/lib")

View File

@ -1,22 +0,0 @@
Copyright (C) 1993-2013 Yukihiro Matsumoto. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

View File

@ -2,7 +2,7 @@
#
# \Module \Base64 provides methods for:
#
# - Encoding a binary string (containing non-ASCII characters)
# - \Encoding a binary string (containing non-ASCII characters)
# as a string of printable ASCII characters.
# - Decoding such an encoded string.
#
@ -27,7 +27,7 @@
#
# require 'base64'
#
# == Encoding Character Sets
# == \Encoding Character Sets
#
# A \Base64-encoded string consists only of characters from a 64-character set:
#
@ -140,7 +140,7 @@
# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
# Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError
#
# \Method Base64.urlsafe_decode64 allows padding in +str+,
# \Method Base64.urlsafe_decode64 allows padding in the encoded string,
# which if present, must be correct:
# see {Padding}[Base64.html#module-Base64-label-Padding], above:
#
@ -183,11 +183,14 @@
#
module Base64
VERSION = "0.2.0"
VERSION = "0.3.0"
module_function
# Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+.
# :call-seq:
# Base64.encode64(string) -> encoded_string
#
# Returns a string containing the RFC-2045-compliant \Base64-encoding of +string+.
#
# Per RFC 2045, the returned string may contain the URL-unsafe characters
# <tt>+</tt> or <tt>/</tt>;
@ -220,19 +223,22 @@ module Base64
[bin].pack("m")
end
# :call-seq:
# Base64.decode(encoded_string) -> decoded_string
#
# Returns a string containing the decoding of an RFC-2045-compliant
# \Base64-encoded string +str+:
# \Base64-encoded string +encoded_string+:
#
# s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
# Base64.decode64(s) # => "This is line 1\nThis is line 2\n"
#
# Non-\Base64 characters in +str+ are ignored;
# Non-\Base64 characters in +encoded_string+ are ignored;
# see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
# these include newline characters and characters <tt>-</tt> and <tt>/</tt>:
#
# Base64.decode64("\x00\n-_") # => ""
#
# Padding in +str+ (even if incorrect) is ignored:
# Padding in +encoded_string+ (even if incorrect) is ignored:
#
# Base64.decode64("MDEyMzQ1Njc") # => "01234567"
# Base64.decode64("MDEyMzQ1Njc=") # => "01234567"
@ -242,7 +248,10 @@ module Base64
str.unpack1("m")
end
# Returns a string containing the RFC-2045-compliant \Base64-encoding of +bin+.
# :call-seq:
# Base64.strict_encode64(string) -> encoded_string
#
# Returns a string containing the RFC-2045-compliant \Base64-encoding of +string+.
#
# Per RFC 2045, the returned string may contain the URL-unsafe characters
# <tt>+</tt> or <tt>/</tt>;
@ -274,13 +283,16 @@ module Base64
[bin].pack("m0")
end
# :call-seq:
# Base64.strict_decode64(encoded_string) -> decoded_string
#
# Returns a string containing the decoding of an RFC-2045-compliant
# \Base64-encoded string +str+:
# \Base64-encoded string +encoded_string+:
#
# s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK"
# Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n"
#
# Non-\Base64 characters in +str+ not allowed;
# Non-\Base64 characters in +encoded_string+ are not allowed;
# see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
# these include newline characters and characters <tt>-</tt> and <tt>/</tt>:
#
@ -288,7 +300,7 @@ module Base64
# Base64.strict_decode64('-') # Raises ArgumentError
# Base64.strict_decode64('_') # Raises ArgumentError
#
# Padding in +str+, if present, must be correct:
# Padding in +encoded_string+, if present, must be correct:
#
# Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError
# Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
@ -298,7 +310,10 @@ module Base64
str.unpack1("m0")
end
# Returns the RFC-4648-compliant \Base64-encoding of +bin+.
# :call-seq:
# Base64.urlsafe_encode64(string) -> encoded_string
#
# Returns the RFC-4648-compliant \Base64-encoding of +string+.
#
# Per RFC 4648, the returned string will not contain the URL-unsafe characters
# <tt>+</tt> or <tt>/</tt>,
@ -332,16 +347,19 @@ module Base64
str
end
# Returns the decoding of an RFC-4648-compliant \Base64-encoded string +str+:
# :call-seq:
# Base64.urlsafe_decode64(encoded_string) -> decoded_string
#
# +str+ may not contain non-Base64 characters;
# Returns the decoding of an RFC-4648-compliant \Base64-encoded string +encoded_string+:
#
# +encoded_string+ may not contain non-Base64 characters;
# see {Encoding Character Set}[Base64.html#module-Base64-label-Encoding+Character+Sets] above:
#
# Base64.urlsafe_decode64('+') # Raises ArgumentError.
# Base64.urlsafe_decode64('/') # Raises ArgumentError.
# Base64.urlsafe_decode64("\n") # Raises ArgumentError.
#
# Padding in +str+, if present, must be correct:
# Padding in +encoded_string+, if present, must be correct:
# see {Padding}[Base64.html#module-Base64-label-Padding], above:
#
# Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567"

View File

@ -0,0 +1,23 @@
Copyright (c) 2023 Vladimir Dementyev
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,3 @@
# frozen_string_literal: true
require "require-hooks/version"

View File

@ -0,0 +1,132 @@
# frozen_string_literal: true
module RequireHooks
@@around_load = []
@@source_transform = []
@@hijack_load = []
class Context
def initialize(around_load, source_transform, hijack_load)
@around_load = around_load
@source_transform = source_transform
@hijack_load = hijack_load
end
def empty?
@around_load.empty? && @source_transform.empty? && @hijack_load.empty?
end
def source_transform?
@source_transform.any?
end
def hijack?
@hijack_load.any?
end
def run_around_load_callbacks(path)
return yield if @around_load.empty?
chain = @around_load.reverse.inject do |acc_proc, next_proc|
proc { |path, &block| acc_proc.call(path) { next_proc.call(path, &block) } }
end
chain.call(path) { yield }
end
def perform_source_transform(path)
return unless @source_transform.any?
source = nil
@source_transform.each do |transform|
source = transform.call(path, source) || source
end
source
end
def try_hijack_load(path, source)
return unless @hijack_load.any?
@hijack_load.each do |hijack|
result = hijack.call(path, source)
return result if result
end
nil
end
end
class << self
attr_accessor :print_warnings
# Define a block to wrap the code loading.
# The return value MUST be a result of calling the passed block.
# For example, you can use such hooks for instrumentation, debugging purposes.
#
# RequireHooks.around_load do |path, &block|
# puts "Loading #{path}"
# block.call.tap { puts "Loaded #{path}" }
# end
def around_load(patterns: nil, exclude_patterns: nil, &block)
@@around_load << [patterns, exclude_patterns, block]
end
# Define hooks to perform source-to-source transformations.
# The return value MUST be either String (new source code) or nil (indicating that no transformations were performed).
#
# NOTE: The second argument (`source`) MAY be nil, indicating that no transformer tried to transform the source code.
#
# For example, you can prepend each file with `# frozen_string_literal: true` pragma:
#
# RequireHooks.source_transform do |path, source|
# "# frozen_string_literal: true\n#{source}"
# end
def source_transform(patterns: nil, exclude_patterns: nil, &block)
@@source_transform << [patterns, exclude_patterns, block]
end
# This hook should be used to manually compile byte code to be loaded by the VM.
# The arguments are (path, source = nil), where source is only defined if transformations took place.
# Otherwise, you MUST read the source code from the file yourself.
#
# The return value MUST be either nil (continue to the next hook or default behavior) or a platform-specific bytecode object (e.g., RubyVM::InstructionSequence).
#
# RequireHooks.hijack_load do |path, source|
# source ||= File.read(path)
# if defined?(RubyVM::InstructionSequence)
# RubyVM::InstructionSequence.compile(source)
# elsif defined?(JRUBY_VERSION)
# JRuby.compile(source)
# end
# end
def hijack_load(patterns: nil, exclude_patterns: nil, &block)
@@hijack_load << [patterns, exclude_patterns, block]
end
def context_for(path)
around_load = @@around_load.select do |patterns, exclude_patterns, _block|
next unless !patterns || patterns.any? { |pattern| File.fnmatch?(pattern, path) }
next if exclude_patterns&.any? { |pattern| File.fnmatch?(pattern, path) }
true
end.map { |_patterns, _exclude_patterns, block| block }
source_transform = @@source_transform.select do |patterns, exclude_patterns, _block|
next unless !patterns || patterns.any? { |pattern| File.fnmatch?(pattern, path) }
next if exclude_patterns&.any? { |pattern| File.fnmatch?(pattern, path) }
true
end.map { |_patterns, _exclude_patterns, block| block }
hijack_load = @@hijack_load.select do |patterns, exclude_patterns, _block|
next unless !patterns || patterns.any? { |pattern| File.fnmatch?(pattern, path) }
next if exclude_patterns&.any? { |pattern| File.fnmatch?(pattern, path) }
true
end.map { |_patterns, _exclude_patterns, block| block }
Context.new(around_load, source_transform, hijack_load)
end
end
end

View File

@ -0,0 +1,36 @@
# frozen_string_literal: true
module RequireHooks
module Bootsnap
module CompileCacheExt
def input_to_storage(source, path, *)
ctx = RequireHooks.context_for(path)
new_contents = ctx.perform_source_transform(path)
hijacked = ctx.try_hijack_load(path, new_contents)
if hijacked
raise TypeError, "Unsupported bytecode format for #{path}: #{hijack.class}" unless hijacked.is_a?(::RubyVM::InstructionSequence)
return hijacked.to_binary
elsif new_contents
return RubyVM::InstructionSequence.compile(new_contents, path, path, 1).to_binary
end
super
rescue SyntaxError, TypeError
::Bootsnap::CompileCache::UNCOMPILABLE
end
end
module LoadIseqExt
# Around hooks must be performed every time we trigger a file load, even if
# the file is already cached.
def load_iseq(path)
RequireHooks.context_for(path).run_around_load_callbacks(path) { super }
end
end
end
end
Bootsnap::CompileCache::ISeq.singleton_class.prepend(RequireHooks::Bootsnap::CompileCacheExt)
RubyVM::InstructionSequence.singleton_class.prepend(RequireHooks::Bootsnap::LoadIseqExt)

View File

@ -0,0 +1,326 @@
# frozen_string_literal: true
require "mutex_m"
require "pathname"
module RequireHooks
module KernelPatch
class << self
def load(path)
ctx = RequireHooks.context_for(path)
ctx.run_around_load_callbacks(path) do
next load_without_require_hooks(path) unless ctx.source_transform? || ctx.hijack?
new_contents = ctx.perform_source_transform(path)
hijacked = ctx.try_hijack_load(path, new_contents)
return try_evaluate(path, hijacked) if hijacked
if new_contents
evaluate(new_contents, path)
true
else
load_without_require_hooks(path)
end
end
end
private
def try_evaluate(path, bytecode)
if defined?(::RubyVM::InstructionSequence) && bytecode.is_a?(::RubyVM::InstructionSequence)
bytecode.eval
else
raise TypeError, "Unknown bytecode format for #{path}: #{bytecode.inspect}"
end
true
end
if defined?(JRUBY_VERSION) || defined?(TruffleRuby)
def evaluate(code, filepath)
new_toplevel.eval(code, filepath)
end
def new_toplevel
# Create new "toplevel" binding to avoid lexical scope re-use
# (aka "leaking refinements")
eval "proc{binding}.call", TOPLEVEL_BINDING, __FILE__, __LINE__
end
else
def evaluate(code, filepath)
# This is workaround to solve the "leaking refinements" problem in MRI
RubyVM::InstructionSequence.compile(code, filepath).tap do |iseq|
iseq.eval
end
end
end
end
module Features
class Locker
class PathLock
def initialize
@mu = Mutex.new
@resolved = false
end
def owned?
@mu.owned?
end
def locked?
@mu.locked?
end
def lock!
@mu.lock
end
def unlock!
@mu.unlock
end
def resolve!
@resolved = true
end
def resolved?
@resolved
end
end
attr_reader :features, :mu
def initialize
@mu = Mutex.new
@features = {}
end
def lock_feature(fname)
lock = mu.synchronize do
features[fname] ||= PathLock.new
end
# Can this even happen?
return yield(true) if lock.resolved?
# Recursive require
if lock.owned? && lock.locked?
warn "loading in progress, circular require considered harmful: #{fname}" if RequireHooks.print_warnings
return yield(true)
end
lock.lock!
begin
yield(lock.resolved?).tap do
lock.resolve!
end
ensure
lock.unlock!
mu.synchronize do
features.delete(fname)
end
end
end
def locked_feature?(fname)
mu.synchronize { features.key?(fname) }
end
end
LOCK = Locker.new
class << self
def feature_path(path, implitic_ext: true)
path = resolve_feature_path(path, implitic_ext: implitic_ext)
return if path.nil?
return if File.extname(path) != ".rb" && implitic_ext
path
end
# Based on https://github.com/ruby/ruby/blob/b588fd552390c55809719100d803c36bc7430f2f/load.c#L403-L415
def feature_loaded?(feature)
return true if $LOADED_FEATURES.include?(feature) && !LOCK.locked_feature?(feature)
feature = Pathname.new(feature).cleanpath.to_s
efeature = File.expand_path(feature)
# Check absoulute and relative paths
return true if $LOADED_FEATURES.include?(efeature) && !LOCK.locked_feature?(efeature)
candidates = []
$LOADED_FEATURES.each do |lf|
candidates << lf if lf.end_with?("/#{feature}")
end
return false if candidates.empty?
$LOAD_PATH.each do |lp|
lp_feature = File.join(lp, feature)
return true if candidates.include?(lp_feature) && !LOCK.locked_feature?(lp_feature)
end
false
end
private
def lookup_feature_path(path, implitic_ext: true)
path = "#{path}.rb" if File.extname(path).empty? && implitic_ext
# Resolve relative paths only against current directory
if path.match?(/^\.\.?\//)
path = File.expand_path(path)
return path if File.file?(path)
return nil
end
if Pathname.new(path).absolute?
path = File.expand_path(path)
return File.file?(path) ? path : nil
end
# not a relative, not an absolute path — bare path; try looking relative to current dir,
# if it's in the $LOAD_PATH
if $LOAD_PATH.include?(Dir.pwd) && File.file?(path)
return File.expand_path(path)
end
$LOAD_PATH.find do |lp|
lpath = File.join(lp, path)
return File.expand_path(lpath) if File.file?(lpath)
end
end
if $LOAD_PATH.respond_to?(:resolve_feature_path)
def resolve_feature_path(feature, implitic_ext: true)
if implitic_ext
path = $LOAD_PATH.resolve_feature_path(feature)
path.last if path # rubocop:disable Style/SafeNavigation
else
lookup_feature_path(feature, implitic_ext: implitic_ext)
end
rescue LoadError
end
else
def resolve_feature_path(feature, implitic_ext: true)
lookup_feature_path(feature, implitic_ext: implitic_ext)
end
end
end
end
end
end
# Patch Kernel to hijack require/require_relative/load
module Kernel
module_function
alias_method :require_without_require_hooks, :require
# See https://github.com/ruby/ruby/blob/d814722fb8299c4baace3e76447a55a3d5478e3a/load.c#L1181
def require(path)
path = path.to_path if path.respond_to?(:to_path)
raise TypeError unless path.respond_to?(:to_str)
path = path.to_str
raise TypeError unless path.is_a?(::String)
realpath = nil
feature = path
# if extname == ".rb" => lookup feature -> resolve feature -> load
# if extname != ".rb" => append ".rb" - lookup feature -> resolve feature -> lookup orig (no ext) -> resolve orig (no ext) -> load
if File.extname(path) != ".rb"
realpath = RequireHooks::KernelPatch::Features.feature_path(path + ".rb")
if realpath
feature = path + ".rb"
end
end
realpath ||= RequireHooks::KernelPatch::Features.feature_path(path)
return require_without_require_hooks(path) unless realpath
ctx = RequireHooks.context_for(realpath)
return require_without_require_hooks(path) if ctx.empty?
return false if RequireHooks::KernelPatch::Features.feature_loaded?(feature)
RequireHooks::KernelPatch::Features::LOCK.lock_feature(feature) do |loaded|
return false if loaded
$LOADED_FEATURES << realpath
RequireHooks::KernelPatch.load(realpath)
true
end
rescue LoadError => e
$LOADED_FEATURES.delete(realpath) if realpath
warn "RequireHooks failed to require '#{path}': #{e.message}" if RequireHooks.print_warnings
require_without_require_hooks(path)
rescue Errno::ENOENT, Errno::EACCES
raise LoadError, "cannot load such file -- #{path}"
rescue
$LOADED_FEATURES.delete(realpath) if realpath
raise
end
alias_method :require_relative_without_require_hooks, :require_relative
def require_relative(path)
path = path.to_path if path.respond_to?(:to_path)
raise TypeError unless path.respond_to?(:to_str)
path = path.to_str
raise TypeError unless path.is_a?(::String)
return require(path) if Pathname.new(path).absolute?
loc = caller_locations(1..1).first
from = loc.absolute_path || loc.path || File.join(Dir.pwd, "main")
realpath = File.absolute_path(
File.join(
File.dirname(File.absolute_path(from)),
path
)
)
require(realpath)
end
alias_method :load_without_require_hooks, :load
def load(path, wrap = false)
if wrap
warn "RequireHooks does not support `load(smth, wrap: ...)`. Falling back to original `Kernel#load`" if RequireHooks.print_warnings
return load_without_require_hooks(path, wrap)
end
path = path.to_path if path.respond_to?(:to_path)
raise TypeError unless path.respond_to?(:to_str)
path = path.to_str
raise TypeError unless path.is_a?(::String)
realpath =
if path =~ /^\.\.?\//
path
else
RequireHooks::KernelPatch::Features.feature_path(path, implitic_ext: false)
end
return load_without_require_hooks(path, wrap) unless realpath
RequireHooks::KernelPatch.load(realpath)
rescue Errno::ENOENT, Errno::EACCES
raise LoadError, "cannot load such file -- #{path}"
rescue LoadError => e
warn "RuquireHooks failed to load '#{path}': #{e.message}" if RequireHooks.print_warnings
load_without_require_hooks(path)
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
module RequireHooks
module LoadIseq
def load_iseq(path)
ctx = RequireHooks.context_for(path)
ctx.run_around_load_callbacks(path) do
if ctx.source_transform? || ctx.hijack?
new_contents = ctx.perform_source_transform(path)
hijacked = ctx.try_hijack_load(path, new_contents)
if hijacked
raise TypeError, "Unsupported bytecode format for #{path}: #{hijack.class}" unless hijacked.is_a?(::RubyVM::InstructionSequence)
return hijacked
elsif new_contents
return RubyVM::InstructionSequence.compile(new_contents, path, path, 1)
end
end
defined?(super) ? super : RubyVM::InstructionSequence.compile_file(path)
end
end
end
end
if RubyVM::InstructionSequence.respond_to?(:load_iseq)
warn "require-hooks: RubyVM::InstructionSequence.load_iseq is already defined. It won't be used by files processed by require-hooks."
end
RubyVM::InstructionSequence.singleton_class.prepend(RequireHooks::LoadIseq)

View File

@ -0,0 +1,28 @@
# frozen_string_literal: true
require "require-hooks/api"
mode = ENV["REQUIRE_HOOKS_MODE"]
case mode
when "patch"
require "require-hooks/mode/kernel_patch"
when "load_iseq"
require "require-hooks/mode/load_iseq"
when "bootsnap"
require "require-hooks/mode/bootsnap"
else
if defined?(::RubyVM::InstructionSequence)
# Check if Bootsnap has been loaded.
# Based on https://github.com/kddeisz/preval/blob/master/lib/preval.rb
if RubyVM::InstructionSequence.respond_to?(:load_iseq) &&
(load_iseq = RubyVM::InstructionSequence.method(:load_iseq)) &&
load_iseq.source_location[0].include?("/bootsnap/")
require "require-hooks/mode/bootsnap"
else
require "require-hooks/mode/load_iseq"
end
else
require "require-hooks/mode/kernel_patch"
end
end

View File

@ -0,0 +1,5 @@
# frozen_string_literal: true
module RequireHooks
VERSION = "0.2.2"
end

View File

@ -27,7 +27,7 @@ module T
def self.any(type_a, type_b, *types)
type_a = T::Utils.coerce(type_a)
type_b = T::Utils.coerce(type_b)
types = types.map {|t| T::Utils.coerce(t)} if !types.empty?
types = types.map { |t| T::Utils.coerce(t) } if !types.empty?
T::Types::Union::Private::Pool.union_of_types(type_a, type_b, types)
end

View File

@ -4,5 +4,5 @@
module T
# T::Boolean is a type alias helper for the common `T.any(TrueClass, FalseClass)`.
# Defined separately from _types.rb because it has a dependency on T::Types::Union.
Boolean = T.type_alias {T.any(TrueClass, FalseClass)}
Boolean = T.type_alias { T.any(TrueClass, FalseClass) }
end

View File

@ -419,12 +419,12 @@ module T::Configuration
if values.nil?
@scalar_types = values
else
bad_values = values.reject {|v| v.class == String}
bad_values = values.reject { |v| v.class == String }
unless bad_values.empty?
raise ArgumentError.new("Provided values must all be class name strings.")
end
@scalar_types = values.each_with_object({}) {|x, acc| acc[x] = true}.freeze
@scalar_types = values.each_with_object({}) { |x, acc| acc[x] = true }.freeze
end
end
@ -449,9 +449,9 @@ module T::Configuration
private_constant :MODULE_NAME
@default_module_name_mangler = if T::Configuration::AT_LEAST_RUBY_2_7
->(type) {MODULE_NAME.bind_call(type)}
->(type) { MODULE_NAME.bind_call(type) }
else
->(type) {MODULE_NAME.bind(type).call} # rubocop:disable Performance/BindCall
->(type) { MODULE_NAME.bind(type).call } # rubocop:disable Performance/BindCall
end
@module_name_mangler = nil

View File

@ -44,11 +44,11 @@ class T::Enum
extend T::Props::CustomType
# TODO(jez) Might want to restrict this, or make subclasses provide this type
SerializedVal = T.type_alias {T.untyped}
SerializedVal = T.type_alias { T.untyped }
private_constant :SerializedVal
### Enum class methods ###
sig {returns(T::Array[T.attached_class])}
sig { returns(T::Array[T.attached_class]) }
def self.values
if @values.nil?
raise "Attempting to access values of #{self.class} before it has been initialized." \
@ -59,7 +59,7 @@ class T::Enum
# This exists for compatibility with the interface of `Hash` & mostly to support
# the HashEachMethods Rubocop.
sig {params(blk: T.nilable(T.proc.params(arg0: T.attached_class).void)).returns(T.any(T::Enumerator[T.attached_class], T::Array[T.attached_class]))}
sig { params(blk: T.nilable(T.proc.params(arg0: T.attached_class).void)).returns(T.any(T::Enumerator[T.attached_class], T::Array[T.attached_class])) }
def self.each_value(&blk)
if blk
values.each(&blk)
@ -72,7 +72,7 @@ class T::Enum
#
# Note: It would have been nice to make this method final before people started overriding it.
# Note: Failed CriticalMethodsNoRuntimeTypingTest
sig {params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never)}
sig { params(serialized_val: SerializedVal).returns(T.nilable(T.attached_class)).checked(:never) }
def self.try_deserialize(serialized_val)
if @mapping.nil?
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
@ -88,7 +88,7 @@ class T::Enum
#
# @return [self]
# @raise [KeyError] if serialized value does not match any instance.
sig {overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never)}
sig { overridable.params(serialized_val: SerializedVal).returns(T.attached_class).checked(:never) }
def self.from_serialized(serialized_val)
res = try_deserialize(serialized_val)
if res.nil?
@ -99,7 +99,7 @@ class T::Enum
# Note: It would have been nice to make this method final before people started overriding it.
# @return [Boolean] Does the given serialized value correspond with any of this enum's values.
sig {overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never)}
sig { overridable.params(serialized_val: SerializedVal).returns(T::Boolean).checked(:never) }
def self.has_serialized?(serialized_val)
if @mapping.nil?
raise "Attempting to access serialization map of #{self.class} before it has been initialized." \
@ -109,7 +109,7 @@ class T::Enum
end
# Note: Failed CriticalMethodsNoRuntimeTypingTest
sig {override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never)}
sig { override.params(instance: T.nilable(T::Enum)).returns(SerializedVal).checked(:never) }
def self.serialize(instance)
# This is needed otherwise if a Chalk::ODM::Document with a property of the shape
# T::Hash[T.nilable(MyEnum), Integer] and a value that looks like {nil => 0} is
@ -126,7 +126,7 @@ class T::Enum
end
# Note: Failed CriticalMethodsNoRuntimeTypingTest
sig {override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never)}
sig { override.params(mongo_value: SerializedVal).returns(T.attached_class).checked(:never) }
def self.deserialize(mongo_value)
if self == T::Enum
raise "Cannot call T::Enum.deserialize directly. You must call on a specific child class."
@ -136,46 +136,46 @@ class T::Enum
### Enum instance methods ###
sig {returns(T.self_type)}
sig { returns(T.self_type) }
def dup
self
end
sig {returns(T.self_type).checked(:tests)}
sig { returns(T.self_type).checked(:tests) }
def clone
self
end
# Note: Failed CriticalMethodsNoRuntimeTypingTest
sig {returns(SerializedVal).checked(:never)}
sig { returns(SerializedVal).checked(:never) }
def serialize
assert_bound!
@serialized_val
end
sig {params(args: T.untyped).returns(T.untyped)}
sig { params(args: T.untyped).returns(T.untyped) }
def to_json(*args)
serialize.to_json(*args)
end
sig {params(args: T.untyped).returns(T.untyped)}
sig { params(args: T.untyped).returns(T.untyped) }
def as_json(*args)
serialized_val = serialize
return serialized_val unless serialized_val.respond_to?(:as_json)
serialized_val.as_json(*args)
end
sig {returns(String)}
sig { returns(String) }
def to_s
inspect
end
sig {returns(String)}
sig { returns(String) }
def inspect
"#<#{self.class.name}::#{@const_name || '__UNINITIALIZED__'}>"
end
sig {params(other: BasicObject).returns(T.nilable(Integer))}
sig { params(other: BasicObject).returns(T.nilable(Integer)) }
def <=>(other)
case other
when self.class
@ -192,7 +192,7 @@ class T::Enum
# responds to the `to_str` method. It does not actually call `to_str` however.
#
# See https://ruby-doc.org/core-2.4.0/String.html#method-i-3D-3D
T::Sig::WithoutRuntime.sig {returns(String)}
T::Sig::WithoutRuntime.sig { returns(String) }
def to_str
msg = 'Implicit conversion of Enum instances to strings is not allowed. Call #serialize instead.'
if T::Configuration.legacy_t_enum_migration_mode?
@ -200,7 +200,7 @@ class T::Enum
msg,
storytime: {
class: self.class.name,
caller_location: Kernel.caller_locations(1..1)&.[](0)&.then {"#{_1.path}:#{_1.lineno}"},
caller_location: Kernel.caller_locations(1..1)&.[](0)&.then { "#{_1.path}:#{_1.lineno}" },
},
)
serialize.to_s
@ -217,12 +217,12 @@ class T::Enum
if T.unsafe(false)
# Declare to the type system that the `serialize` method for sure exists
# on whatever we mix this into.
T::Sig::WithoutRuntime.sig {abstract.returns(T.untyped)}
T::Sig::WithoutRuntime.sig { abstract.returns(T.untyped) }
def serialize; end
end
# WithoutRuntime so that comparison_assertion_failed can assume a constant stack depth
T::Sig::WithoutRuntime.sig {params(other: BasicObject).returns(T::Boolean)}
T::Sig::WithoutRuntime.sig { params(other: BasicObject).returns(T::Boolean) }
def ==(other)
case other
when String
@ -238,7 +238,7 @@ class T::Enum
end
# WithoutRuntime so that comparison_assertion_failed can assume a constant stack depth
T::Sig::WithoutRuntime.sig {params(other: BasicObject).returns(T::Boolean)}
T::Sig::WithoutRuntime.sig { params(other: BasicObject).returns(T::Boolean) }
def ===(other)
case other
when String
@ -255,7 +255,7 @@ class T::Enum
# WithoutRuntime so that caller_locations can assume a constant stack depth
# (Otherwise, the first call would be the method with the wrapping, which would have a different stack depth.)
T::Sig::WithoutRuntime.sig {params(method: Symbol, other: T.untyped).void}
T::Sig::WithoutRuntime.sig { params(method: Symbol, other: T.untyped).void }
private def comparison_assertion_failed(method, other)
T::Configuration.soft_assert_handler(
'Enum to string comparison not allowed. Compare to the Enum instance directly instead. See go/enum-migration',
@ -265,7 +265,7 @@ class T::Enum
other: other,
other_class: other.class.name,
method: method,
caller_location: Kernel.caller_locations(2..2)&.[](0)&.then {"#{_1.path}:#{_1.lineno}"},
caller_location: Kernel.caller_locations(2..2)&.[](0)&.then { "#{_1.path}:#{_1.lineno}" },
}
)
end
@ -276,7 +276,7 @@ class T::Enum
UNSET = T.let(Module.new.freeze, Module)
private_constant :UNSET
sig {params(serialized_val: SerializedVal).void}
sig { params(serialized_val: SerializedVal).void }
def initialize(serialized_val=UNSET)
raise 'T::Enum is abstract' if self.class == T::Enum
if !self.class.started_initializing?
@ -292,7 +292,7 @@ class T::Enum
self.class._register_instance(self)
end
sig {returns(NilClass).checked(:never)}
sig { returns(NilClass).checked(:never) }
private def assert_bound!
if @const_name.nil?
raise "Attempting to access Enum value on #{self.class} before it has been initialized." \
@ -300,14 +300,14 @@ class T::Enum
end
end
sig {params(const_name: Symbol).void}
sig { params(const_name: Symbol).void }
def _bind_name(const_name)
@const_name = const_name
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.equal?(UNSET)
freeze
end
sig {params(const_name: Symbol).returns(String)}
sig { params(const_name: Symbol).returns(String) }
private def const_to_serialized_val(const_name)
# Historical note: We convert to lowercase names because the majority of existing calls to
# `make_accessible` were arrays of lowercase strings. Doing this conversion allowed for the
@ -315,7 +315,7 @@ class T::Enum
-const_name.to_s.downcase.freeze
end
sig {returns(T::Boolean)}
sig { returns(T::Boolean) }
def self.started_initializing?
unless defined?(@started_initializing)
@started_initializing = T.let(false, T.nilable(T::Boolean))
@ -323,7 +323,7 @@ class T::Enum
T.must(@started_initializing)
end
sig {returns(T::Boolean)}
sig { returns(T::Boolean) }
def self.fully_initialized?
unless defined?(@fully_initialized)
@fully_initialized = T.let(false, T.nilable(T::Boolean))
@ -332,7 +332,7 @@ class T::Enum
end
# Maintains the order in which values are defined
sig {params(instance: T.untyped).void}
sig { params(instance: T.untyped).void }
def self._register_instance(instance)
@values ||= []
@values << T.cast(instance, T.attached_class)
@ -340,7 +340,7 @@ class T::Enum
# Entrypoint for allowing people to register new enum values.
# All enum values must be defined within this block.
sig {params(blk: T.proc.void).void}
sig { params(blk: T.proc.void).void }
def self.enums(&blk)
raise "enums cannot be defined for T::Enum" if self == T::Enum
raise "Enum #{self} was already initialized" if fully_initialized?
@ -375,13 +375,13 @@ class T::Enum
orphaned_instances = T.must(@values) - @mapping.values
if !orphaned_instances.empty?
raise "Enum values must be assigned to constants: #{orphaned_instances.map {|v| v.instance_variable_get('@serialized_val')}}"
raise "Enum values must be assigned to constants: #{orphaned_instances.map { |v| v.instance_variable_get('@serialized_val') }}"
end
@fully_initialized = true
end
sig {params(child_class: T::Class[T.anything]).void}
sig { params(child_class: T::Class[T.anything]).void }
def self.inherited(child_class)
super
@ -394,12 +394,12 @@ class T::Enum
end
# Marshal support
sig {params(_level: Integer).returns(String)}
sig { params(_level: Integer).returns(String) }
def _dump(_level)
Marshal.dump(serialize)
end
sig {params(args: String).returns(T.attached_class)}
sig { params(args: String).returns(T.attached_class) }
def self._load(args)
deserialize(Marshal.load(args)) # rubocop:disable Security/MarshalLoad
end

View File

@ -4,7 +4,7 @@
module T::NonForcingConstants
# NOTE: This method is documented on the RBI in Sorbet's payload, so that it
# shows up in the hover/completion documentation via LSP.
T::Sig::WithoutRuntime.sig {params(val: BasicObject, klass: String).returns(T::Boolean)}
T::Sig::WithoutRuntime.sig { params(val: BasicObject, klass: String).returns(T::Boolean) }
def self.non_forcing_is_a?(val, klass)
method_name = "T::NonForcingConstants.non_forcing_is_a?"
if klass.empty?

View File

@ -25,7 +25,7 @@ module T::Private::Methods
# twice is permitted). we could do this with two tables, but it seems slightly
# cleaner with a single table.
# Effectively T::Hash[Module, T.nilable(Set))]
@modules_with_final = Hash.new {|hash, key| hash[key] = nil}.compare_by_identity
@modules_with_final = Hash.new { |hash, key| hash[key] = nil }.compare_by_identity
# this stores the old [included, extended] hooks for Module and inherited hook for Class that we override when
# enabling final checks for when those hooks are called. the 'hooks' here don't have anything to do with the 'hooks'
# in installed_hooks.
@ -168,7 +168,7 @@ module T::Private::Methods
definition_file, definition_line = T::Private::Methods.signature_for_method(ancestor.instance_method(method_name)).method.source_location
is_redefined = target == ancestor
caller_loc = T::Private::CallerUtils.find_caller {|loc| !loc.path.to_s.start_with?(SORBET_RUNTIME_LIB_PATH)}
caller_loc = T::Private::CallerUtils.find_caller { |loc| !loc.path.to_s.start_with?(SORBET_RUNTIME_LIB_PATH) }
extra_info = "\n"
if caller_loc
extra_info = (is_redefined ? "Redefined" : "Overridden") + " here: #{caller_loc.path}:#{caller_loc.lineno}\n"
@ -471,7 +471,7 @@ module T::Private::Methods
end
def self.all_checked_tests_sigs
@signatures_by_method.values.select {|sig| sig.check_level == :tests}
@signatures_by_method.values.select { |sig| sig.check_level == :tests }
end
# the module target is adding the methods from the module source to itself. we need to check that for all instance
@ -589,6 +589,22 @@ module T::Private::Methods
mod.extend(SingletonMethodHooks)
end
# `name` must be an instance method (for class methods, pass in mod.singleton_class)
def self.visibility_method_name(mod, name)
if mod.public_method_defined?(name)
:public
elsif mod.protected_method_defined?(name)
:protected
elsif mod.private_method_defined?(name)
:private
else
# Raises a NameError formatted like the Ruby VM would (the exact text formatting
# of these errors changed across Ruby VM versions, in ways that would sometimes
# cause tests to fail if they were dependent on hard coding errors).
mod.method(name)
end
end
# use this directly if you don't want/need to box up the method into an object to pass to method_to_key.
private_class_method def self.method_owner_and_name_to_key(owner, name)
"#{owner.object_id}##{name}"

View File

@ -12,7 +12,7 @@ module T::Private::Methods::CallValidation
# @param method_sig [T::Private::Methods::Signature]
# @return [UnboundMethod] the new wrapper method (or the original one if we didn't wrap it)
def self.wrap_method_if_needed(mod, method_sig, original_method)
original_visibility = visibility_method_name(mod, method_sig.method_name)
original_visibility = T::Private::Methods.visibility_method_name(mod, method_sig.method_name)
if method_sig.mode == T::Private::Methods::Modes.abstract
create_abstract_wrapper(mod, method_sig, original_method, original_visibility)
# Do nothing in this case; this method was not wrapped in _on_method_added.
@ -69,11 +69,11 @@ module T::Private::Methods::CallValidation
def self.create_validator_method(mod, original_method, method_sig, original_visibility)
has_fixed_arity = method_sig.kwarg_types.empty? && !method_sig.has_rest && !method_sig.has_keyrest &&
original_method.parameters.all? {|(kind, _name)| kind == :req || kind == :block}
original_method.parameters.all? { |(kind, _name)| kind == :req || kind == :block }
can_skip_block_type = method_sig.block_type.nil? || method_sig.block_type.valid?(nil)
ok_for_fast_path = has_fixed_arity && can_skip_block_type && !method_sig.bind && method_sig.arg_types.length < 5 && is_allowed_to_have_fast_path
all_args_are_simple = ok_for_fast_path && method_sig.arg_types.all? {|_name, type| type.is_a?(T::Types::Simple)}
all_args_are_simple = ok_for_fast_path && method_sig.arg_types.all? { |_name, type| type.is_a?(T::Types::Simple) }
simple_method = all_args_are_simple && method_sig.return_type.is_a?(T::Types::Simple)
simple_procedure = all_args_are_simple && method_sig.return_type.is_a?(T::Private::Types::Void)
@ -330,19 +330,6 @@ module T::Private::Methods::CallValidation
location: caller_loc
)
end
# `name` must be an instance method (for class methods, pass in mod.singleton_class)
private_class_method def self.visibility_method_name(mod, name)
if mod.public_method_defined?(name)
:public
elsif mod.protected_method_defined?(name)
:protected
elsif mod.private_method_defined?(name)
:private
else
mod.method(name) # Raises
end
end
end
if T::Configuration::AT_LEAST_RUBY_2_7

View File

@ -154,7 +154,12 @@ module T::Private::Methods
case decl.mode
when Modes.standard
decl.mode = Modes.override
case allow_incompatible
when true, false, :visibility
decl.override_allow_incompatible = allow_incompatible
else
raise BuilderError.new(".override(allow_incompatible: ...) only accepts `true`, `false`, or `:visibility`, got: #{allow_incompatible.inspect}")
end
when Modes.override, Modes.overridable_override
raise BuilderError.new(".override cannot be repeated in a single signature")
when Modes.overridable

View File

@ -68,14 +68,14 @@ class T::Private::Methods::Signature
writer_method = !(raw_arg_types.size == 1 && raw_arg_types.key?(nil)) && parameters == UNNAMED_REQUIRED_PARAMETERS && method_name[-1] == "="
# For writer methods, map the single parameter to the method name without the "=" at the end
parameters = [[:req, method_name[0...-1].to_sym]] if writer_method
is_name_missing = parameters.any? {|_, name| !raw_arg_types.key?(name)}
is_name_missing = parameters.any? { |_, name| !raw_arg_types.key?(name) }
if is_name_missing
param_names = parameters.map {|_, name| name}
param_names = parameters.map { |_, name| name }
missing_names = param_names - raw_arg_types.keys
raise "The declaration for `#{method.name}` is missing parameter(s): #{missing_names.join(', ')}"
elsif parameters.length != raw_arg_types.size
param_names = parameters.map {|_, name| name}
has_extra_names = parameters.count {|_, name| raw_arg_types.key?(name)} < raw_arg_types.size
param_names = parameters.map { |_, name| name }
has_extra_names = parameters.count { |_, name| raw_arg_types.key?(name) } < raw_arg_types.size
if has_extra_names
extra_names = raw_arg_types.keys - param_names
raise "The declaration for `#{method.name}` has extra parameter(s): #{extra_names.join(', ')}"
@ -95,7 +95,7 @@ class T::Private::Methods::Signature
# always precede optional keyword arguments. We can't tell
# whether the culprit is the Ruby reordering or user error, so
# we error but include a note
if param_kind == :keyreq && parameters.any? {|k, _| k == :key}
if param_kind == :keyreq && parameters.any? { |k, _| k == :key }
hint = "\n\nNote: Any required keyword arguments must precede any optional keyword " \
"arguments. If your method declaration matches your `def`, try reordering any " \
"optional keyword parameters to the end of the method list."
@ -103,7 +103,7 @@ class T::Private::Methods::Signature
raise "Parameter `#{type_name}` is declared out of order (declared as arg number " \
"#{i + 1}, defined in the method as arg number " \
"#{parameters.index {|_, name| name == type_name} + 1}).#{hint}\nMethod: #{method_desc}"
"#{parameters.index { |_, name| name == type_name } + 1}).#{hint}\nMethod: #{method_desc}"
end
type = T::Utils.coerce(raw_type)
@ -245,8 +245,8 @@ class T::Private::Methods::Signature
end
def force_type_init
@arg_types.each {|_, type| type.build_type}
@kwarg_types.each {|_, type| type.build_type}
@arg_types.each { |_, type| type.build_type }
@kwarg_types.each { |_, type| type.build_type }
@block_type&.build_type
@rest_type&.build_type
@keyrest_type&.build_type

View File

@ -72,7 +72,7 @@ module T::Private::Methods::SignatureValidation
# If the super_method has any kwargs we can't build a
# Signature for it, so we'll just skip validation in that case.
if !super_signature && !super_method.parameters.select {|kind, _| kind == :rest || kind == :kwrest}.empty?
if !super_signature && !super_method.parameters.select { |kind, _| kind == :rest || kind == :kwrest }.empty?
nil
else
# super_signature can be nil when we're overriding a method (perhaps a builtin) that didn't use
@ -89,6 +89,7 @@ module T::Private::Methods::SignatureValidation
validate_override_mode(signature, super_signature)
validate_override_shape(signature, super_signature)
validate_override_types(signature, super_signature)
validate_override_visibility(signature, super_signature)
end
else
validate_non_override_mode(signature)
@ -175,7 +176,7 @@ module T::Private::Methods::SignatureValidation
end
def self.validate_override_shape(signature, super_signature)
return if signature.override_allow_incompatible
return if signature.override_allow_incompatible == true
return if super_signature.mode == Modes.untyped
method_name = signature.method_name
@ -231,7 +232,7 @@ module T::Private::Methods::SignatureValidation
end
def self.validate_override_types(signature, super_signature)
return if signature.override_allow_incompatible
return if signature.override_allow_incompatible == true
return if super_signature.mode == Modes.untyped
return unless [signature, super_signature].all? do |sig|
sig.check_level == :always || (sig.check_level == :tests && T::Private::RuntimeLevels.check_tests?)
@ -276,6 +277,38 @@ module T::Private::Methods::SignatureValidation
end
end
def self.validate_override_visibility(signature, super_signature)
return if super_signature.mode == Modes.untyped
# This departs from the behavior of other `validate_override_whatever` functions in that it
# only comes into effect when the child signature explicitly says the word `override`. This was
# done because the primary method for silencing these errors (`allow_incompatible: :visibility`)
# requires an `override` node to attach to. Once we have static override checking for implicitly
# overridden methods, we can remove this.
return unless [Modes.override, Modes.overridable_override].include?(signature.mode)
return if [:visibility, true].include?(signature.override_allow_incompatible)
method = signature.method
super_method = super_signature.method
mode_noun = super_signature.mode == Modes.abstract ? 'implementation' : 'override'
vis = method_visibility(method)
super_vis = method_visibility(super_method)
if visibility_strength(vis) > visibility_strength(super_vis)
raise "Incompatible visibility for #{mode_noun} of method #{method.name}\n" \
"* Base: #{super_vis} (in #{method_loc_str(super_method)})\n" \
"* #{mode_noun.capitalize}: #{vis} (in #{method_loc_str(method)})\n" \
"(The override must be at least as permissive as the supermethod)" \
end
end
private_class_method def self.method_visibility(method)
T::Private::Methods.visibility_method_name(method.owner, method.name)
end
# Higher = more restrictive.
private_class_method def self.visibility_strength(vis)
%i[public protected private].find_index(vis)
end
private_class_method def self.base_override_loc_str(signature, super_signature)
mode_noun = super_signature.mode == Modes.abstract ? 'Implementation' : 'Override'
"\n * Base definition: in #{method_loc_str(super_signature.method)}" \

View File

@ -5,7 +5,7 @@ module T::Private
module MixesInClassMethods
def included(other)
mods = Abstract::Data.get(self, :class_methods_mixins)
mods.each {|mod| other.extend(mod)}
mods.each { |mod| other.extend(mod) }
super
end
end

View File

@ -32,7 +32,7 @@ module T::Private::RuntimeLevels
def self.enable_checking_in_tests
if !@check_tests && @wrapped_tests_with_validation
all_checked_tests_sigs = T::Private::Methods.all_checked_tests_sigs
locations = all_checked_tests_sigs.map {|sig| sig.method.source_location.join(':')}.join("\n- ")
locations = all_checked_tests_sigs.map { |sig| sig.method.source_location.join(':') }.join("\n- ")
raise "Toggle `:tests`-level runtime type checking earlier. " \
"There are already some methods wrapped with `sig.checked(:tests)`:\n" \
"- #{locations}"

View File

@ -5,7 +5,7 @@ module T::Private::Sealed
module NoInherit
def inherited(child)
super
caller_loc = T::Private::CallerUtils.find_caller {|loc| loc.base_label != 'inherited'}
caller_loc = T::Private::CallerUtils.find_caller { |loc| loc.base_label != 'inherited' }
T::Private::Sealed.validate_inheritance(caller_loc, self, child, 'inherited')
@sorbet_sealed_module_all_subclasses << child
end
@ -22,14 +22,14 @@ module T::Private::Sealed
module NoIncludeExtend
def included(child)
super
caller_loc = T::Private::CallerUtils.find_caller {|loc| loc.base_label != 'included'}
caller_loc = T::Private::CallerUtils.find_caller { |loc| loc.base_label != 'included' }
T::Private::Sealed.validate_inheritance(caller_loc, self, child, 'included')
@sorbet_sealed_module_all_subclasses << child
end
def extended(child)
super
caller_loc = T::Private::CallerUtils.find_caller {|loc| loc.base_label != 'extended'}
caller_loc = T::Private::CallerUtils.find_caller { |loc| loc.base_label != 'extended' }
T::Private::Sealed.validate_inheritance(caller_loc, self, child, 'extended')
@sorbet_sealed_module_all_subclasses << child
end
@ -81,7 +81,7 @@ module T::Private::Sealed
if !this_file.start_with?(decl_file)
whitelist = T::Configuration.sealed_violation_whitelist
if !whitelist.nil? && whitelist.any? {|pattern| this_file =~ pattern}
if !whitelist.nil? && whitelist.any? { |pattern| this_file =~ pattern }
return
end

View File

@ -109,7 +109,7 @@ module T::Props
# form.
#
# @return [void]
sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void}
sig { params(name: Symbol, cls: T.untyped, rules: T.untyped).void }
def prop(name, cls, **rules)
cls = T::Utils.coerce(cls) if !cls.is_a?(Module)
decorator.prop_defined(name, cls, rules)
@ -132,7 +132,7 @@ module T::Props
end
# Shorthand helper to define a `prop` with `immutable => true`
sig {params(name: Symbol, cls_or_args: T.untyped, args: T.untyped).void}
sig { params(name: Symbol, cls_or_args: T.untyped, args: T.untyped).void }
def const(name, cls_or_args, **args)
if (cls_or_args.is_a?(Hash) && cls_or_args.key?(:immutable)) || args.key?(:immutable)
Kernel.raise ArgumentError.new("Cannot pass 'immutable' argument when using 'const' keyword to define a prop")

View File

@ -15,7 +15,7 @@ module T::Props::Constructor::DecoratorMethods
# we'll use to check for any unrecognized input.)
#
# checked(:never) - O(runtime object construction)
sig {params(instance: T::Props::Constructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
sig { params(instance: T::Props::Constructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never) }
def construct_props_without_defaults(instance, hash)
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
# and therefore allocates for each entry.

View File

@ -39,7 +39,7 @@ module T::Props
#
# @param [Object] instance
# @return An instance of one of T::Configuration.scalar_types
sig {abstract.params(instance: T.untyped).returns(T.untyped).checked(:never)}
sig { abstract.params(instance: T.untyped).returns(T.untyped).checked(:never) }
def serialize(instance); end
# Given the serialized form of your type, this returns an instance
@ -47,17 +47,17 @@ module T::Props
#
# @param scalar One of T::Configuration.scalar_types
# @return Object
sig {abstract.params(scalar: T.untyped).returns(T.untyped).checked(:never)}
sig { abstract.params(scalar: T.untyped).returns(T.untyped).checked(:never) }
def deserialize(scalar); end
sig {override.params(_base: Module).void}
sig { override.params(_base: Module).void }
def self.included(_base)
super
raise 'Please use "extend", not "include" to attach this module'
end
sig(:final) {params(val: T.untyped).returns(T::Boolean).checked(:never)}
sig(:final) { params(val: T.untyped).returns(T::Boolean).checked(:never) }
def self.scalar_type?(val)
# We don't need to check for val's included modules in
# T::Configuration.scalar_types, because T::Configuration.scalar_types
@ -74,7 +74,7 @@ module T::Props
# implement set-like fields that store a unique-array, but forbid
# hashes; Custom hash types should be implemented via an emebdded
# T::Struct (or a subclass like Chalk::ODM::Document) or via T.
sig(:final) {params(val: Object).returns(T::Boolean).checked(:never)}
sig(:final) { params(val: Object).returns(T::Boolean).checked(:never) }
def self.valid_serialization?(val)
case val
when Array

View File

@ -10,17 +10,17 @@
class T::Props::Decorator
extend T::Sig
Rules = T.type_alias {T::Hash[Symbol, T.untyped]}
DecoratedInstance = T.type_alias {Object} # Would be T::Props, but that produces circular reference errors in some circumstances
PropType = T.type_alias {T::Types::Base}
PropTypeOrClass = T.type_alias {T.any(PropType, Module)}
Rules = T.type_alias { T::Hash[Symbol, T.untyped] }
DecoratedInstance = T.type_alias { Object } # Would be T::Props, but that produces circular reference errors in some circumstances
PropType = T.type_alias { T::Types::Base }
PropTypeOrClass = T.type_alias { T.any(PropType, Module) }
class NoRulesError < StandardError; end
EMPTY_PROPS = T.let({}.freeze, T::Hash[Symbol, Rules], checked: false)
private_constant :EMPTY_PROPS
sig {params(klass: T.untyped).void.checked(:never)}
sig { params(klass: T.untyped).void.checked(:never) }
def initialize(klass)
@class = T.let(klass, T.all(Module, T::Props::ClassMethods))
@class.plugins.each do |mod|
@ -30,22 +30,22 @@ class T::Props::Decorator
end
# checked(:never) - O(prop accesses)
sig {returns(T::Hash[Symbol, Rules]).checked(:never)}
sig { returns(T::Hash[Symbol, Rules]).checked(:never) }
attr_reader :props
sig {returns(T::Array[Symbol])}
sig { returns(T::Array[Symbol]) }
def all_props
props.keys
end
# checked(:never) - O(prop accesses)
sig {params(prop: T.any(Symbol, String)).returns(Rules).checked(:never)}
sig { params(prop: T.any(Symbol, String)).returns(Rules).checked(:never) }
def prop_rules(prop)
props[prop.to_sym] || raise("No such prop: #{prop.inspect}")
end
# checked(:never) - Rules hash is expensive to check
sig {params(prop: Symbol, rules: Rules).void.checked(:never)}
sig { params(prop: Symbol, rules: Rules).void.checked(:never) }
def add_prop_definition(prop, rules)
override = rules.delete(:override)
@ -79,16 +79,16 @@ class T::Props::Decorator
extra
setter_validate
_tnilable
].to_h {|k| [k, true]}.freeze, T::Hash[Symbol, T::Boolean], checked: false)
].to_h { |k| [k, true] }.freeze, T::Hash[Symbol, T::Boolean], checked: false)
private_constant :VALID_RULE_KEYS
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
sig { params(key: Symbol).returns(T::Boolean).checked(:never) }
def valid_rule_key?(key)
!!VALID_RULE_KEYS[key]
end
# checked(:never) - O(prop accesses)
sig {returns(T.all(Module, T::Props::ClassMethods)).checked(:never)}
sig { returns(T.all(Module, T::Props::ClassMethods)).checked(:never) }
def decorated_class
@class
end
@ -98,7 +98,7 @@ class T::Props::Decorator
# Use this to validate that a value will validate for a given prop. Useful for knowing whether a value can be set on a model without setting it.
#
# checked(:never) - potentially O(prop accesses) depending on usage pattern
sig {params(prop: Symbol, val: T.untyped).void.checked(:never)}
sig { params(prop: Symbol, val: T.untyped).void.checked(:never) }
def validate_prop_value(prop, val)
prop_rules(prop).fetch(:value_validate_proc).call(val)
end
@ -202,7 +202,7 @@ class T::Props::Decorator
end
# TODO: we should really be checking all the methods on `cls`, not just Object
BANNED_METHOD_NAMES = T.let(Object.instance_methods.each_with_object({}) {|x, acc| acc[x] = true}.freeze, T::Hash[Symbol, TrueClass], checked: false)
BANNED_METHOD_NAMES = T.let(Object.instance_methods.each_with_object({}) { |x, acc| acc[x] = true }.freeze, T::Hash[Symbol, TrueClass], checked: false)
# checked(:never) - Rules hash is expensive to check
sig do
@ -223,7 +223,7 @@ class T::Props::Decorator
"to 'sensitivity:' (in prop #{@class.name}.#{name})")
end
if rules.keys.any? {|k| !valid_rule_key?(k)}
if rules.keys.any? { |k| !valid_rule_key?(k) }
raise ArgumentError.new("At least one invalid prop arg supplied in #{self}: #{rules.keys.inspect}")
end
@ -247,7 +247,7 @@ class T::Props::Decorator
SAFE_NAME = T.let(/\A[A-Za-z_][A-Za-z0-9_-]*\z/.freeze, Regexp, checked: false)
# Used to validate both prop names and serialized forms
sig {params(name: T.any(Symbol, String)).void.checked(:never)}
sig { params(name: T.any(Symbol, String)).void.checked(:never) }
private def validate_prop_name(name)
if !name.match?(SAFE_NAME)
raise ArgumentError.new("Invalid prop name in #{@class.name}: #{name}")
@ -255,7 +255,7 @@ class T::Props::Decorator
end
# This converts the type from a T::Type to a regular old ruby class.
sig {params(type: T::Types::Base).returns(Module).checked(:never)}
sig { params(type: T::Types::Base).returns(Module).checked(:never) }
private def convert_type_to_class(type)
case type
when T::Types::TypedArray, T::Types::FixedArray
@ -392,7 +392,7 @@ class T::Props::Decorator
end
# checked(:never) - Rules hash is expensive to check
sig {params(name: Symbol, rules: Rules).void.checked(:never)}
sig { params(name: Symbol, rules: Rules).void.checked(:never) }
private def define_getter_and_setter(name, rules)
T::Configuration.without_ruby_warnings do
if !rules[:immutable]
@ -440,7 +440,7 @@ class T::Props::Decorator
end
# checked(:never) - Rules hash is expensive to check
sig {params(prop_name: Symbol, rules: Rules).void.checked(:never)}
sig { params(prop_name: Symbol, rules: Rules).void.checked(:never) }
private def validate_not_missing_sensitivity(prop_name, rules)
if rules[:sensitivity].nil?
if rules[:redaction]
@ -612,7 +612,7 @@ class T::Props::Decorator
#
# This gets called when a module or class that extends T::Props gets included, extended,
# prepended, or inherited.
sig {params(child: Module).void.checked(:never)}
sig { params(child: Module).void.checked(:never) }
def model_inherited(child)
child.extend(T::Props::ClassMethods)
child = T.cast(child, T.all(Module, T::Props::ClassMethods))
@ -656,19 +656,19 @@ class T::Props::Decorator
end
end
sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)}
sig { params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never) }
private def clobber_getter?(child, prop)
!!(child.decorator.method(:prop_get).owner != method(:prop_get).owner &&
child.instance_method(prop).source_location&.first == __FILE__)
end
sig {params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never)}
sig { params(child: T.all(Module, T::Props::ClassMethods), prop: Symbol).returns(T::Boolean).checked(:never) }
private def clobber_setter?(child, prop)
!!(child.decorator.method(:prop_set).owner != method(:prop_set).owner &&
child.instance_method("#{prop}=").source_location&.first == __FILE__)
end
sig {params(mod: Module).void.checked(:never)}
sig { params(mod: Module).void.checked(:never) }
def plugin(mod)
decorated_class.plugins << mod
T::Props::Plugin::Private.apply_class_methods(mod, decorated_class)

View File

@ -159,7 +159,7 @@ module T::Props
assert_equal(:resbody, rescue_body.type)
exceptions, assignment, handler = rescue_body.children
assert_equal(:array, exceptions.type)
exceptions.children.each {|c| assert_equal(:const, c.type)}
exceptions.children.each { |c| assert_equal(:const, c.type) }
assert_equal(:lvasgn, assignment.type)
assert_equal([:e], assignment.children)
@ -169,7 +169,7 @@ module T::Props
receiver, method, *args = deserialization_error.children
assert_equal(nil, receiver)
assert_equal(:raise_deserialization_error, method)
args.each {|a| validate_lack_of_side_effects(a, whitelisted_methods_for_deserialize)}
args.each { |a| validate_lack_of_side_effects(a, whitelisted_methods_for_deserialize) }
validate_lack_of_side_effects(val_return, whitelisted_methods_for_deserialize)
else
@ -222,12 +222,12 @@ module T::Props
# Primitives & self are ok
when :lvar, :arg, :ivar
# Reading local & instance variables & arguments is ok
unless node.children.all? {|c| c.is_a?(Symbol)}
unless node.children.all? { |c| c.is_a?(Symbol) }
raise ValidationError.new("Unexpected child for #{node.type}: #{node.inspect}")
end
when :args, :mlhs, :block, :begin, :if
# Blocks etc are read-only if their contents are read-only
node.children.each {|c| validate_lack_of_side_effects(c, whitelisted_methods_by_receiver_type) if c}
node.children.each { |c| validate_lack_of_side_effects(c, whitelisted_methods_by_receiver_type) if c }
when :send
# Sends are riskier so check a whitelist
receiver, method, *args = node.children

View File

@ -30,12 +30,12 @@ module T::Props
#
# Note it does _not_ prevent explicit calls to `eagerly_define_lazy_methods!`
# from working.
sig {void}
sig { void }
def self.disable_lazy_evaluation!
@lazy_evaluation_disabled ||= true
end
sig {returns(T::Boolean)}
sig { returns(T::Boolean) }
def self.lazy_evaluation_enabled?
!defined?(@lazy_evaluation_disabled) || !@lazy_evaluation_disabled
end
@ -43,17 +43,17 @@ module T::Props
module DecoratorMethods
extend T::Sig
sig {returns(T::Hash[Symbol, T.proc.returns(String)]).checked(:never)}
sig { returns(T::Hash[Symbol, T.proc.returns(String)]).checked(:never) }
private def lazily_defined_methods
@lazily_defined_methods ||= {}
end
sig {returns(T::Hash[Symbol, T.untyped]).checked(:never)}
sig { returns(T::Hash[Symbol, T.untyped]).checked(:never) }
private def lazily_defined_vm_methods
@lazily_defined_vm_methods ||= {}
end
sig {params(name: Symbol).void}
sig { params(name: Symbol).void }
private def eval_lazily_defined_method!(name)
if !HasLazilySpecializedMethods.lazy_evaluation_enabled?
raise SourceEvaluationDisabled.new
@ -68,7 +68,7 @@ module T::Props
cls.send(:private, name)
end
sig {params(name: Symbol).void}
sig { params(name: Symbol).void }
private def eval_lazily_defined_vm_method!(name)
if !HasLazilySpecializedMethods.lazy_evaluation_enabled?
raise SourceEvaluationDisabled.new
@ -80,7 +80,7 @@ module T::Props
cls.send(:private, name)
end
sig {params(name: Symbol, blk: T.proc.returns(String)).void}
sig { params(name: Symbol, blk: T.proc.returns(String)).void }
private def enqueue_lazy_method_definition!(name, &blk)
lazily_defined_methods[name] = blk
@ -100,7 +100,7 @@ module T::Props
cls.send(:private, name)
end
sig {params(name: Symbol, blk: T.untyped).void}
sig { params(name: Symbol, blk: T.untyped).void }
private def enqueue_lazy_vm_method_definition!(name, &blk)
lazily_defined_vm_methods[name] = blk
@ -115,7 +115,7 @@ module T::Props
cls.send(:private, name)
end
sig {void}
sig { void }
def eagerly_define_lazy_methods!
return if lazily_defined_methods.empty?
@ -125,18 +125,18 @@ module T::Props
cls = decorated_class
cls.class_eval(source)
lazily_defined_methods.each_key {|name| cls.send(:private, name)}
lazily_defined_methods.each_key { |name| cls.send(:private, name) }
lazily_defined_methods.clear
end
sig {void}
sig { void }
def eagerly_define_lazy_vm_methods!
return if lazily_defined_vm_methods.empty?
lazily_defined_vm_methods.values.map(&:call)
cls = decorated_class
lazily_defined_vm_methods.each_key {|name| cls.send(:private, name)}
lazily_defined_vm_methods.each_key { |name| cls.send(:private, name) }
lazily_defined_vm_methods.clear
end
end

View File

@ -43,11 +43,11 @@ module T::Props::Optional::DecoratorMethods
end
# checked(:never) - O(runtime object construction)
sig {returns(T::Hash[Symbol, T::Props::Private::ApplyDefault]).checked(:never)}
sig { returns(T::Hash[Symbol, T::Props::Private::ApplyDefault]).checked(:never) }
attr_reader :props_with_defaults
# checked(:never) - O(runtime object construction)
sig {returns(T::Hash[Symbol, T::Props::Private::SetterFactory::SetterProc]).checked(:never)}
sig { returns(T::Hash[Symbol, T::Props::Private::SetterFactory::SetterProc]).checked(:never) }
attr_reader :props_without_defaults
def add_prop_definition(prop, rules)

View File

@ -49,21 +49,21 @@ module T::Props::PrettyPrintable
module DecoratorMethods
extend T::Sig
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
sig { params(key: Symbol).returns(T::Boolean).checked(:never) }
def valid_rule_key?(key)
super || key == :inspect
end
# Overridable method to specify how the first part of a `pretty_print`d object's class should look like
# NOTE: This is just to support Stripe's `PrettyPrintableModel` case, and not recommended to be overridden
sig {params(instance: T::Props::PrettyPrintable).returns(String)}
sig { params(instance: T::Props::PrettyPrintable).returns(String) }
def inspect_class_with_decoration(instance)
T.unsafe(instance).class.to_s
end
# Overridable method to add anything that is not a prop
# NOTE: This is to support cases like Serializable's `@_extra_props`, and Stripe's `PrettyPrintableModel#@_deleted`
sig {params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void}
sig { params(instance: T::Props::PrettyPrintable, pp: T.any(PrettyPrint, PP::SingleLine)).void }
def pretty_print_extra(instance, pp); end
end
end

View File

@ -9,28 +9,28 @@ module T::Props
abstract!
# checked(:never) - O(object construction x prop count)
sig {returns(SetterFactory::SetterProc).checked(:never)}
sig { returns(SetterFactory::SetterProc).checked(:never) }
attr_reader :setter_proc
# checked(:never) - We do this with `T.let` instead
sig {params(accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never)}
sig { params(accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never) }
def initialize(accessor_key, setter_proc)
@accessor_key = T.let(accessor_key, Symbol)
@setter_proc = T.let(setter_proc, SetterFactory::SetterProc)
end
# checked(:never) - O(object construction x prop count)
sig {abstract.returns(T.untyped).checked(:never)}
sig { abstract.returns(T.untyped).checked(:never) }
def default; end
# checked(:never) - O(object construction x prop count)
sig {abstract.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)}
sig { abstract.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
def set_default(instance); end
NO_CLONE_TYPES = T.let([TrueClass, FalseClass, NilClass, Symbol, Numeric, T::Enum].freeze, T::Array[Module])
# checked(:never) - Rules hash is expensive to check
sig {params(cls: Module, rules: T::Hash[Symbol, T.untyped]).returns(T.nilable(ApplyDefault)).checked(:never)}
sig { params(cls: Module, rules: T::Hash[Symbol, T.untyped]).returns(T.nilable(ApplyDefault)).checked(:never) }
def self.for(cls, rules)
accessor_key = rules.fetch(:accessor_key)
setter = rules.fetch(:setter_proc)
@ -67,7 +67,7 @@ module T::Props
abstract!
# checked(:never) - We do this with `T.let` instead
sig {params(default: BasicObject, accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never)}
sig { params(default: BasicObject, accessor_key: Symbol, setter_proc: SetterFactory::SetterProc).void.checked(:never) }
def initialize(default, accessor_key, setter_proc)
# FIXME: Ideally we'd check here that the default is actually a valid
# value for this field, but existing code relies on the fact that we don't.
@ -80,7 +80,7 @@ module T::Props
end
# checked(:never) - O(object construction x prop count)
sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)}
sig { override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
def set_default(instance)
instance.instance_variable_set(@accessor_key, default)
end
@ -88,13 +88,13 @@ module T::Props
class ApplyPrimitiveDefault < ApplyFixedDefault
# checked(:never) - O(object construction x prop count)
sig {override.returns(T.untyped).checked(:never)}
sig { override.returns(T.untyped).checked(:never) }
attr_reader :default
end
class ApplyComplexDefault < ApplyFixedDefault
# checked(:never) - O(object construction x prop count)
sig {override.returns(T.untyped).checked(:never)}
sig { override.returns(T.untyped).checked(:never) }
def default
T::Props::Utils.deep_clone_object(@default)
end
@ -105,13 +105,13 @@ module T::Props
# `some_empty_array.dup`
class ApplyEmptyArrayDefault < ApplyDefault
# checked(:never) - O(object construction x prop count)
sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)}
sig { override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
def set_default(instance)
instance.instance_variable_set(@accessor_key, [])
end
# checked(:never) - O(object construction x prop count)
sig {override.returns(T::Array[T.untyped]).checked(:never)}
sig { override.returns(T::Array[T.untyped]).checked(:never) }
def default
[]
end
@ -122,13 +122,13 @@ module T::Props
# `some_empty_hash.dup`
class ApplyEmptyHashDefault < ApplyDefault
# checked(:never) - O(object construction x prop count)
sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)}
sig { override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
def set_default(instance)
instance.instance_variable_set(@accessor_key, {})
end
# checked(:never) - O(object construction x prop count)
sig {override.returns(T::Hash[T.untyped, T.untyped]).checked(:never)}
sig { override.returns(T::Hash[T.untyped, T.untyped]).checked(:never) }
def default
{}
end
@ -153,7 +153,7 @@ module T::Props
end
# checked(:never) - O(object construction x prop count)
sig {override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never)}
sig { override.params(instance: T.all(T::Props::Optional, Object)).void.checked(:never) }
def set_default(instance)
# Use the actual setter to validate the factory returns a legitimate
# value every time
@ -161,7 +161,7 @@ module T::Props
end
# checked(:never) - O(object construction x prop count)
sig {override.returns(T.untyped).checked(:never)}
sig { override.returns(T.untyped).checked(:never) }
def default
@class.class_exec(&@factory)
end

View File

@ -29,7 +29,7 @@ module T::Props
.checked(:never)
end
def self.generate(props, defaults)
stored_props = props.reject {|_, rules| rules[:dont_store]}
stored_props = props.reject { |_, rules| rules[:dont_store] }
parts = stored_props.map do |prop, rules|
# All of these strings should already be validated (directly or
# indirectly) in `validate_prop_name`, so we don't bother with a nice

View File

@ -10,7 +10,7 @@ module T::Props
private_constant :Serialize
class Deserialize; end
private_constant :Deserialize
ModeType = T.type_alias {T.any(Serialize, Deserialize)}
ModeType = T.type_alias { T.any(Serialize, Deserialize) }
private_constant :ModeType
module Mode
@ -63,7 +63,7 @@ module T::Props
end
when T::Types::Simple
raw = type.raw_type
if NO_TRANSFORM_TYPES.any? {|cls| raw <= cls}
if NO_TRANSFORM_TYPES.any? { |cls| raw <= cls }
nil
elsif raw <= Float
case mode
@ -99,7 +99,7 @@ module T::Props
else
"#{varname}.nil? ? nil : #{inner}"
end
elsif type.types.all? {|t| generate(t, mode, varname).nil?}
elsif type.types.all? { |t| generate(t, mode, varname).nil? }
# Handle, e.g., T::Boolean
nil
else
@ -122,8 +122,8 @@ module T::Props
# NB: This deliberately does include `nil`, which means we know we
# don't need to do any transforming.
inner_known = type.types
.map {|t| generate(t, mode, varname)}
.reject {|t| t == dynamic_fallback}
.map { |t| generate(t, mode, varname) }
.reject { |t| t == dynamic_fallback }
.uniq
if inner_known.size != 1
@ -151,7 +151,7 @@ module T::Props
end
end
sig {params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never)}
sig { params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never) }
private_class_method def self.handle_serializable_subtype(varname, type, mode)
case mode
when Serialize
@ -164,7 +164,7 @@ module T::Props
end
end
sig {params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never)}
sig { params(varname: String, type: Module, mode: ModeType).returns(String).checked(:never) }
private_class_method def self.handle_custom_type(varname, type, mode)
case mode
when Serialize
@ -177,7 +177,7 @@ module T::Props
end
end
sig {params(type: Module).returns(T.nilable(String)).checked(:never)}
sig { params(type: Module).returns(T.nilable(String)).checked(:never) }
private_class_method def self.module_name(type)
T::Configuration.module_name_mangler.call(type)
end

View File

@ -24,7 +24,7 @@ module T::Props
.checked(:never)
end
def self.generate(props)
stored_props = props.reject {|_, rules| rules[:dont_store]}
stored_props = props.reject { |_, rules| rules[:dont_store] }
parts = stored_props.map do |prop, rules|
# All of these strings should already be validated (directly or
# indirectly) in `validate_prop_name`, so we don't bother with a nice

View File

@ -6,9 +6,9 @@ module T::Props
module SetterFactory
extend T::Sig
SetterProc = T.type_alias {T.proc.params(val: T.untyped).void}
ValueValidationProc = T.type_alias {T.proc.params(val: T.untyped).void}
ValidateProc = T.type_alias {T.proc.params(prop: Symbol, value: T.untyped).void}
SetterProc = T.type_alias { T.proc.params(val: T.untyped).void }
ValueValidationProc = T.type_alias { T.proc.params(val: T.untyped).void }
ValidateProc = T.type_alias { T.proc.params(prop: Symbol, value: T.untyped).void }
sig do
params(
@ -236,7 +236,7 @@ module T::Props
base_message = "Can't set #{klass.name}.#{prop} to #{val.inspect} (instance of #{val.class}) - need a #{type}"
pretty_message = "Parameter '#{prop}': #{base_message}\n"
caller_loc = caller_locations.find {|l| !l.to_s.include?('sorbet-runtime/lib/types/props')}
caller_loc = caller_locations.find { |l| !l.to_s.include?('sorbet-runtime/lib/types/props') }
if caller_loc
pretty_message += "Caller: #{caller_loc.path}:#{caller_loc.lineno}\n"
end

View File

@ -78,7 +78,7 @@ module T::Props::Serializable
if hash.size > hash_keys_matching_props
serialized_forms = self.class.decorator.prop_by_serialized_forms
extra = hash.reject {|k, _| serialized_forms.key?(k)}
extra = hash.reject { |k, _| serialized_forms.key?(k) }
# `extra` could still be empty here if the input matches a `dont_store` prop;
# historically, we just ignore those
@ -111,7 +111,7 @@ module T::Props::Serializable
new_obj[k.to_s] = recursive_stringify_keys(v)
end
elsif obj.is_a?(Array)
new_obj = obj.map {|v| recursive_stringify_keys(v)}
new_obj = obj.map { |v| recursive_stringify_keys(v) }
else
new_obj = obj
end
@ -126,7 +126,7 @@ module T::Props::Serializable
if old_extra != new_extra
difference =
if old_extra
new_extra.reject {|k, v| old_extra[k] == v}
new_extra.reject { |k, v| old_extra[k] == v }
else
new_extra
end
@ -195,7 +195,7 @@ module T::Props::Serializable::DecoratorMethods
end
def required_props
@class.props.select {|_, v| T::Props::Utils.required_prop?(v)}.keys
@class.props.select { |_, v| T::Props::Utils.required_prop?(v) }.keys
end
def prop_dont_store?(prop)
@ -228,11 +228,11 @@ module T::Props::Serializable::DecoratorMethods
res = super
prop_by_serialized_forms[serialized_form] = prop
if T::Configuration.use_vm_prop_serde?
enqueue_lazy_vm_method_definition!(:__t_props_generated_serialize) {generate_serialize2}
enqueue_lazy_vm_method_definition!(:__t_props_generated_deserialize) {generate_deserialize2}
enqueue_lazy_vm_method_definition!(:__t_props_generated_serialize) { generate_serialize2 }
enqueue_lazy_vm_method_definition!(:__t_props_generated_deserialize) { generate_deserialize2 }
else
enqueue_lazy_method_definition!(:__t_props_generated_serialize) {generate_serialize_source}
enqueue_lazy_method_definition!(:__t_props_generated_deserialize) {generate_deserialize_source}
enqueue_lazy_method_definition!(:__t_props_generated_serialize) { generate_serialize_source }
enqueue_lazy_method_definition!(:__t_props_generated_deserialize) { generate_deserialize_source }
end
res
end
@ -263,7 +263,7 @@ module T::Props::Serializable::DecoratorMethods
def message_with_generated_source_context(error, generated_method, generate_source_method)
generated_method = generated_method.to_s
if error.backtrace_locations
line_loc = error.backtrace_locations.find {|l| l.base_label == generated_method}
line_loc = error.backtrace_locations.find { |l| l.base_label == generated_method }
return unless line_loc
line_num = line_loc.lineno
@ -275,7 +275,7 @@ module T::Props::Serializable::DecoratorMethods
# in `__t_props_generated_serialize'"
"in `#{generated_method}'"
end
line_label = error.backtrace.find {|l| l.end_with?(label)}
line_label = error.backtrace.find { |l| l.end_with?(label) }
return unless line_label
line_num = if line_label.start_with?("(eval)")

View File

@ -11,7 +11,7 @@ module T::Props::TypeValidation
module DecoratorMethods
extend T::Sig
sig {params(key: Symbol).returns(T::Boolean).checked(:never)}
sig { params(key: Symbol).returns(T::Boolean).checked(:never) }
def valid_rule_key?(key)
super || key == :DEPRECATED_underspecified_type
end
@ -58,19 +58,19 @@ module T::Props::TypeValidation
# If the type is fully valid, returns nil.
#
# checked(:never) - called potentially many times recursively
sig {params(type: T::Types::Base).returns(T.nilable(T::Types::Base)).checked(:never)}
sig { params(type: T::Types::Base).returns(T.nilable(T::Types::Base)).checked(:never) }
private def find_invalid_subtype(type)
case type
when T::Types::TypedEnumerable
find_invalid_subtype(type.type)
when T::Types::FixedHash
type.types.values.map {|subtype| find_invalid_subtype(subtype)}.compact.first
type.types.values.map { |subtype| find_invalid_subtype(subtype) }.compact.first
when T::Types::Union, T::Types::FixedArray
# `T.any` is valid if all of the members are valid
type.types.map {|subtype| find_invalid_subtype(subtype)}.compact.first
type.types.map { |subtype| find_invalid_subtype(subtype) }.compact.first
when T::Types::Intersection
# `T.all` is valid if at least one of the members is valid
invalid = type.types.map {|subtype| find_invalid_subtype(subtype)}.compact
invalid = type.types.map { |subtype| find_invalid_subtype(subtype) }.compact
if invalid.length == type.types.length
invalid.first
else

View File

@ -13,7 +13,7 @@ module T::Props::Utils
when Symbol, NilClass, Numeric
what
when Array
what.map {|v| deep_clone_object(v, freeze: freeze)}
what.map { |v| deep_clone_object(v, freeze: freeze) }
when Hash
h = what.class.new
what.each do |k, v|

View File

@ -6,7 +6,7 @@ module T::Props::WeakConstructor
extend T::Sig
# checked(:never) - O(runtime object construction)
sig {params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never)}
sig { params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never) }
def initialize(hash={})
decorator = self.class.decorator
@ -28,7 +28,7 @@ module T::Props::WeakConstructor::DecoratorMethods
# we'll use to check for any unrecognized input.)
#
# checked(:never) - O(runtime object construction)
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
sig { params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never) }
def construct_props_without_defaults(instance, hash)
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
# and therefore allocates for each entry.
@ -49,7 +49,7 @@ module T::Props::WeakConstructor::DecoratorMethods
# we'll use to check for any unrecognized input.)
#
# checked(:never) - O(runtime object construction)
sig {params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never)}
sig { params(instance: T::Props::WeakConstructor, hash: T::Hash[Symbol, T.untyped]).returns(Integer).checked(:never) }
def construct_props_with_defaults(instance, hash)
# Use `each_pair` rather than `count` because, as of Ruby 2.6, the latter delegates to Enumerator
# and therefore allocates for each entry.

View File

@ -14,7 +14,7 @@ module T::Sig
# At runtime, does nothing, but statically it is treated exactly the same
# as T::Sig#sig. Only use it in cases where you can't use T::Sig#sig.
T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void}
T::Sig::WithoutRuntime.sig { params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void }
def self.sig(arg0=nil, &blk); end # rubocop:disable Lint/DuplicateMethods
$VERBOSE = original_verbose
@ -23,7 +23,7 @@ module T::Sig
# Declares a method with type signatures and/or
# abstract/override/... helpers. See the documentation URL on
# {T::Helpers}
T::Sig::WithoutRuntime.sig {params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void}
T::Sig::WithoutRuntime.sig { params(arg0: T.nilable(Symbol), blk: T.proc.bind(T::Private::Methods::DeclBuilder).void).void }
def sig(arg0=nil, &blk)
T::Private::Methods.declare_sig(self, Kernel.caller_locations(1, 1)&.first, arg0, &blk)
end

View File

@ -30,7 +30,7 @@ class T::ImmutableStruct < T::InexactStruct
end
# Matches the one in WeakConstructor, but freezes the object
sig {params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never)}
sig { params(hash: T::Hash[Symbol, T.untyped]).void.checked(:never) }
def initialize(hash={})
super
@ -38,7 +38,7 @@ class T::ImmutableStruct < T::InexactStruct
end
# Matches the signature in Props, but raises since this is an immutable struct and only const is allowed
sig {params(name: Symbol, cls: T.untyped, rules: T.untyped).void}
sig { params(name: Symbol, cls: T.untyped, rules: T.untyped).void }
def self.prop(name, cls, **rules)
return super if (cls.is_a?(Hash) && cls[:immutable]) || rules[:immutable]

View File

@ -83,27 +83,27 @@ module T::Types
# Note: order of cases here matters!
if t1.is_a?(T::Types::Union) # 7, 8, 9
# this will be incorrect if/when we have Type members
return t1.types.all? {|t1_member| t1_member.subtype_of?(t2)}
return t1.types.all? { |t1_member| t1_member.subtype_of?(t2) }
end
if t2.is_a?(T::Types::Intersection) # 2, 5
# this will be incorrect if/when we have Type members
return t2.types.all? {|t2_member| t1.subtype_of?(t2_member)}
return t2.types.all? { |t2_member| t1.subtype_of?(t2_member) }
end
if t2.is_a?(T::Types::Union)
if t1.is_a?(T::Types::Intersection) # 6
# dropping either of parts eagerly make subtype test be too strict.
# we have to try both cases, when we normally try only one
return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} ||
t1.types.any? {|t1_member| t1_member.subtype_of?(t2)}
return t2.types.any? { |t2_member| t1.subtype_of?(t2_member) } ||
t1.types.any? { |t1_member| t1_member.subtype_of?(t2) }
end
return t2.types.any? {|t2_member| t1.subtype_of?(t2_member)} # 3
return t2.types.any? { |t2_member| t1.subtype_of?(t2_member) } # 3
end
if t1.is_a?(T::Types::Intersection) # 4
# this will be incorrect if/when we have Type members
return t1.types.any? {|t1_member| t1_member.subtype_of?(t2)}
return t1.types.any? { |t1_member| t1_member.subtype_of?(t2) }
end
# 1; Start with some special cases

View File

@ -11,7 +11,7 @@ module T::Types
end
def types
@types ||= @inner_types.map {|type| T::Utils.coerce(type)}
@types ||= @inner_types.map { |type| T::Utils.coerce(type) }
end
def build_type

View File

@ -10,7 +10,7 @@ module T::Types
end
def types
@types ||= @inner_types.transform_values {|v| T::Utils.coerce(v)}
@types ||= @inner_types.transform_values { |v| T::Utils.coerce(v) }
end
def build_type
@ -26,16 +26,16 @@ module T::Types
# overrides Base
def recursively_valid?(obj)
return false unless obj.is_a?(Hash)
return false if types.any? {|key, type| !type.recursively_valid?(obj[key])}
return false if obj.any? {|key, _| !types[key]}
return false if types.any? { |key, type| !type.recursively_valid?(obj[key]) }
return false if obj.any? { |key, _| !types[key] }
true
end
# overrides Base
def valid?(obj)
return false unless obj.is_a?(Hash)
return false if types.any? {|key, type| !type.valid?(obj[key])}
return false if obj.any? {|key, _| !types[key]}
return false if types.any? { |key, type| !type.valid?(obj[key]) }
return false if obj.any? { |key, _| !types[key] }
true
end
@ -48,7 +48,7 @@ module T::Types
when TypedHash
# warning: covariant hashes
key1, key2, *keys_rest = types.keys.map {|key| T::Utils.coerce(key.class)}
key1, key2, *keys_rest = types.keys.map { |key| T::Utils.coerce(key.class) }
key_type = if !key2.nil?
T::Types::Union::Private::Pool.union_of_types(key1, key2, keys_rest)
elsif key1.nil?

View File

@ -32,12 +32,12 @@ module T::Types
# overrides Base
def recursively_valid?(obj)
types.all? {|type| type.recursively_valid?(obj)}
types.all? { |type| type.recursively_valid?(obj) }
end
# overrides Base
def valid?(obj)
types.all? {|type| type.valid?(obj)}
types.all? { |type| type.valid?(obj) }
end
# overrides Base

View File

@ -44,11 +44,11 @@ module T::Types
nilable = T::Utils.coerce(NilClass)
trueclass = T::Utils.coerce(TrueClass)
falseclass = T::Utils.coerce(FalseClass)
if types.any? {|t| t == nilable}
remaining_types = types.reject {|t| t == nilable}
if types.any? { |t| t == nilable }
remaining_types = types.reject { |t| t == nilable }
"T.nilable(#{type_shortcuts(remaining_types)})"
elsif types.any? {|t| t == trueclass} && types.any? {|t| t == falseclass}
remaining_types = types.reject {|t| t == trueclass || t == falseclass}
elsif types.any? { |t| t == trueclass } && types.any? { |t| t == falseclass }
remaining_types = types.reject { |t| t == trueclass || t == falseclass }
type_shortcuts([T::Private::Types::StringHolder.new("T::Boolean")] + remaining_types)
else
names = types.map(&:name).compact.sort
@ -58,12 +58,12 @@ module T::Types
# overrides Base
def recursively_valid?(obj)
types.any? {|type| type.recursively_valid?(obj)}
types.any? { |type| type.recursively_valid?(obj) }
end
# overrides Base
def valid?(obj)
types.any? {|type| type.valid?(obj)}
types.any? { |type| type.valid?(obj) }
end
# overrides Base
@ -72,7 +72,7 @@ module T::Types
end
def unwrap_nilable
non_nil_types = types.reject {|t| t == T::Utils::Nilable::NIL_TYPE}
non_nil_types = types.reject { |t| t == T::Utils::Nilable::NIL_TYPE }
return nil if types.length == non_nil_types.length
case non_nil_types.length
when 0 then nil