Skip to content

Base64 Encode / Decode — Ruby source

Encode text to Base64 or decode it back. UTF-8 safe, runs entirely in your browser, with a shareable link to your exact input.

This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.

# base64 — UTF-8 safe Base64 encode/decode.
#
# Language: Ruby (3.2, standard library only — the base64 default gem)
# Source:   CosmoDev polyglot showcase port of the `base64` tool, ported
#           from src/lib/base64.ts (the canonical TypeScript implementation).
# License:  display source — part of CosmoDev's polyglot tool pages.
#
# Ruby strings are byte containers with an attached encoding, so a String
# tagged UTF-8 is already the byte sequence Base64 operates on — there is no
# separate "encode to UTF-8" step, unlike the TypeScript port's TextEncoder.
# strict_encode64 / strict_decode64 are the RFC 4648 pair (encode64 wraps
# output every 60 characters, which this tool does not want). Decoded bytes
# are validated as UTF-8 before being returned — the TextDecoder step — via
# force_encoding + valid_encoding?, because String(bytes, encoding:) never
# fails and would silently carry invalid bytes.

# frozen_string_literal: true

require "base64"

##
# Encode a Unicode string to standard (padded) Base64. The string's own
# bytes are used, so characters outside Latin-1 (emoji, accents, CJK, ...)
# survive the round trip.
def b64encode(text)
  Base64.strict_encode64(text)
end

##
# Decode a standard Base64 string back to the original Unicode text.
#
# Whitespace inside the input is stripped first (the TS port's /\s+/ regex),
# so line-wrapped Base64 decodes cleanly. Any malformed input — illegal
# characters, bad padding, or decoded bytes that are not valid UTF-8 —
# raises ArgumentError, matching the TS port's "throw on invalid input"
# contract.
def b64decode(b64)
  cleaned = b64.gsub(/\s+/, "")

  raw = begin
    Base64.strict_decode64(cleaned)
  rescue ArgumentError => e
    raise ArgumentError, "invalid Base64 input: #{e.message}"
  end

  text = raw.dup.force_encoding("UTF-8")
  unless text.valid_encoding?
    raise ArgumentError, "decoded bytes are not valid UTF-8"
  end
  text
end

if $PROGRAM_NAME == __FILE__
  puts b64encode("Hello, world!")                 # SGVsbG8sIHdvcmxkIQ==
  puts b64decode("aGVs\nbG8g d29ybGQ=")          # hello world
  puts b64decode(b64encode("héllo 🌍"))           # multi-byte UTF-8 survives

  begin
    b64decode("SGVsbG8*")
  rescue ArgumentError => e
    puts e.message
  end

  # "/w==" decodes to the single byte 0xFF, which is not valid UTF-8.
  begin
    b64decode("/w==")
  rescue ArgumentError => e
    puts e.message
  end
end

Also available in 13 other languages

Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →