Add bin and edit workflow
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 9s

This commit is contained in:
2026-09-16 13:11:16 -06:00
parent c8ac4fcae5
commit 4cee170d66
17576 changed files with 895740 additions and 2 deletions
@@ -0,0 +1,151 @@
# frozen_string_literal: true
require 'stringio'
require_relative 'placeholder'
module TTFunk
# Risen when the final encoded string was requested but there were some
# unresolved placeholders in it.
class UnresolvedPlaceholderError < StandardError
end
# Risen when a placeholder is added to an Encoded String but it already
# contains a placeholder with the same name.
class DuplicatePlaceholderError < StandardError
end
# Encoded string takes care of placeholders in binary strings. Placeholders
# are used when bytes need to be placed in the stream before their value is
# known.
#
# @api private
class EncodedString
# @yieldparam [self]
def initialize
yield(self) if block_given?
end
# Append to string.
#
# @param obj [String, Placeholder, EncodedString]
# @return [self]
def <<(obj)
case obj
when String
io << obj
when Placeholder
add_placeholder(obj)
io << ("\0" * obj.length)
when self.class
# adjust placeholders to be relative to the entire encoded string
obj.placeholders.each_pair do |_, placeholder|
add_placeholder(placeholder.dup, placeholder.position + io.length)
end
io << obj.unresolved_string
end
self
end
# Append multiple objects.
#
# @param objs [Array<String, Placeholder, EncodedString>]
# @return [self]
def concat(*objs)
objs.each do |obj|
self << obj
end
self
end
# Append padding to align string to the specified word width.
#
# @param width [Integer]
# @return [self]
def align!(width = 4)
if (length % width).positive?
self << ("\0" * (width - (length % width)))
end
self
end
# Length of this string.
#
# @return [Integer]
def length
io.length
end
# Raw string.
#
# @return [String]
# @raise [UnresolvedPlaceholderError] if there are any unresolved
# placeholders left.
def string
unless placeholders.empty?
raise UnresolvedPlaceholderError,
"string contains #{placeholders.size} unresolved placeholder(s)"
end
io.string
end
# Raw bytes.
#
# @return [Array<Integer>]
# @raise [UnresolvedPlaceholderError] if there are any unresolved
# placeholders left.
def bytes
string.bytes
end
# Unresolved raw string.
#
# @return [String]
def unresolved_string
io.string
end
# Resolve placeholder.
#
# @param name [Symbol]
# @param value [String]
# @return [void]
def resolve_placeholder(name, value)
last_pos = io.pos
if (placeholder = placeholders[name])
io.seek(placeholder.position)
io.write(value[0..placeholder.length])
placeholders.delete(name)
end
ensure
io.seek(last_pos)
end
# Plaholders
#
# @return [Hash{Symbol => Plaholder}]
def placeholders
@placeholders ||= {}
end
private
def add_placeholder(new_placeholder, pos = io.pos)
if placeholders.include?(new_placeholder.name)
raise DuplicatePlaceholderError,
"placeholder #{new_placeholder.name} already exists"
end
new_placeholder.position = pos
placeholders[new_placeholder.name] = new_placeholder
end
def io
@io ||= StringIO.new(''.b).binmode
end
end
end