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

@ -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.
@ -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

@ -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)}" \