Data Unit Converter — Ruby source
Convert between digital data units - B, KB/KiB, MB/MiB, GB/GiB, TB/TiB. Switch between decimal (1000) and binary (1024) bases, runs entirely in your browser.
This is the Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# =============================================================================
# data-unit-converter.rb — CosmoDev polyglot showcase port of the
# `data-unit-converter` tool
# -----------------------------------------------------------------------------
# Language : Ruby (3.2, standard library only)
# Source: ported from src/lib/dataUnits.ts (the canonical, live TypeScript
# lib); mirrors src/tool-sources/data-unit-converter/{python.py,rust.rs}
# License : display source — part of CosmoDev's polyglot tool pages
# (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
# Python ports and the other language ports.
# -----------------------------------------------------------------------------
# Pure digital-data unit conversion. Convert between B, KB/KiB, MB/MiB,
# GB/GiB, TB/TiB: the decimal base 1000 pairs with KB/MB/GB/TB (SI) and the
# binary base 1024 with KiB/MiB/GiB/TiB (IEC). Deterministic and
# side-effect free; convert_data returns Float::NAN for non-finite input,
# unknown unit symbols, or an invalid base — never raises.
# =============================================================================
# Pure digital-data unit conversion for the Data Unit Converter tool on
# CosmoDev (dev.cosmolabs.org).
module DataUnits
# Units available under each base, ordered smallest (B) to largest. The UI
# uses this to populate the per-base unit pickers. Frozen — nothing in this
# module is mutable.
UNITS = {
1000 => %w[B KB MB GB TB].freeze,
1024 => %w[B KiB MiB GiB TiB].freeze,
}.freeze
# Power-of-base rank for each unit symbol: "B" is rank 0 and each prefix
# step adds 1. KB and KiB are both rank 1 — the unit picks the rank, the
# base decides whether a rank means ×1000 or ×1024.
EXPONENTS = {
'B' => 0,
'KB' => 1, 'MB' => 2, 'GB' => 3, 'TB' => 4,
'KiB' => 1, 'MiB' => 2, 'GiB' => 3, 'TiB' => 4,
}.freeze
module_function
# Convert a value between two digital-data units under the given base.
#
# Strategy: reduce to bytes via value × base**from_exp, then divide by
# base**to_exp. Returns Float::NAN for non-finite input (NaN or Infinity),
# unknown unit symbols, or a base other than 1000/1024 — never raises
# (mirrors the TypeScript contract).
#
# value - the Float magnitude to convert, expressed in from_unit
# from_unit - source unit symbol, e.g. "MB"
# to_unit - target unit symbol, e.g. "GiB"
# base - conversion radix: 1000 (decimal/SI) or 1024 (binary/IEC)
#
# Returns a Float, or Float::NAN on invalid input.
def convert_data(value, from_unit, to_unit, base)
# Reject Inf/NaN early so they don't propagate through the multiplication.
# Float#finite? is false for both, which keeps the check to one call.
return Float::NAN unless value.finite?
# Only the two canonical bases are valid; anything else is a caller bug.
return Float::NAN unless base == 1000 || base == 1024
# Unknown unit symbols miss the hash (nil) — treat as invalid.
from_exp = EXPONENTS[from_unit]
to_exp = EXPONENTS[to_unit]
return Float::NAN if from_exp.nil? || to_exp.nil?
(value * base**from_exp) / base**to_exp
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 →