RubyMoney/money
A Ruby Library for dealing with money and currency conversion.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 6w ago
- ✓15 active contributors
- ✓Distributed ownership (top contributor 49% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/rubymoney/money)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/rubymoney/money on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: RubyMoney/money
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/RubyMoney/money shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 6w ago
- 15 active contributors
- Distributed ownership (top contributor 49% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live RubyMoney/money
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/RubyMoney/money.
What it runs against: a local clone of RubyMoney/money — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in RubyMoney/money | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | Last commit ≤ 71 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of RubyMoney/money. If you don't
# have one yet, run these first:
#
# git clone https://github.com/RubyMoney/money.git
# cd money
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of RubyMoney/money and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "RubyMoney/money(\\.git)?\\b" \\
&& ok "origin remote is RubyMoney/money" \\
|| miss "origin remote is not RubyMoney/money (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 71 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~41d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/RubyMoney/money"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
RubyMoney/money is a Ruby gem that encapsulates monetary values as immutable objects with integer-based cent storage to avoid floating-point rounding errors. It provides the Money class (with value + currency), Money::Currency for currency metadata, and pluggable exchange rate engines (Memory, Variable, SingleCurrency banks) for multi-currency operations. Modular monolith: lib/money/money.rb is the core Money class with composition files (arithmetic.rb, allocation.rb, formatter.rb); lib/money/bank/ contains exchange rate strategies (base.rb, variable_exchange.rb, single_currency.rb); lib/money/currency/ handles currency metadata and i18n; lib/money/rates_store/ abstracts exchange rate persistence. Config files (config/currency_iso.json, currency_backwards_compatible.json) centralize currency definitions.
👥Who it's for
Ruby developers building financial, e-commerce, or accounting applications who need to safely represent and convert between currencies without floating-point precision loss. Used by payment systems, billing platforms, and any app handling multi-currency transactions.
🌱Maturity & risk
Production-ready and actively maintained. The repo shows mature practices: comprehensive RSpec test suite, strict RuboCop linting, GitHub Actions CI/CD (ruby.yml, lint.yml), TypeScript RBS type signatures in sig/, and clear upgrade guides (UPGRADING-6.0.md, UPGRADING-7.0.md) indicating multi-year stability. High-quality foundational library with broad ecosystem adoption.
Standard open source risks apply.
Active areas of work
Active maintenance on RBS type signatures (sig/ directory present), continued RuboCop/linting enforcement, and Dependabot integration for dependency updates. Major version work appears complete (v7 upgrade guide exists); current work likely focuses on type safety, locale backend improvements (lib/money/locale_backend/i18n.rb), and stability.
🚀Get running
git clone https://github.com/RubyMoney/money.git && cd money && gem install bundler && bundle install && rake install
Daily commands:
This is a library, not an app. To develop: bundle exec rspec runs the test suite; bundle exec rubocop lints code; rake (from Rakefile) likely builds/installs. No web server or daemon—import as require 'money' in your Ruby project.
🗺️Map of the codebase
- lib/money/money.rb: Primary Money class definition; encapsulates all core behavior for monetary value representation
- lib/money/currency.rb: Currency class that holds ISO codes, symbols, and precision metadata for all supported currencies
- lib/money/bank/variable_exchange.rb: Main exchange rate engine for multi-currency conversion; implements rate lookup and arithmetic
- lib/money/money/arithmetic.rb: Implements +, -, *, / operators and allocation logic for safe monetary arithmetic
- lib/money/money/formatter.rb: Handles money-to-string conversion with locale-aware symbols and formatting rules
- config/currency_iso.json: Authoritative list of ISO 4217 currency codes, symbols, and precision; loaded at runtime
- lib/money/bank/base.rb: Abstract base class and interface for all exchange rate strategies; defines the bank extension point
- lib/money/locale_backend/i18n.rb: I18n integration for translating currency symbols and formatting rules based on locale
🛠️How to make changes
Core money logic: edit lib/money/money.rb and submods (arithmetic.rb, constructors.rb, formatter.rb). New exchange rate strategy? Subclass lib/money/bank/base.rb. Currency metadata: update config/currency_iso.json or lib/money/currency/loader.rb. Locale formatting: lib/money/locale_backend/ (add new backends or extend i18n.rb). Tests go in spec/ with RSpec (see .rspec config).
🪤Traps & gotchas
UTF-8 required: the gem relies on UTF-8 encoding for non-ASCII currency symbols (stated in README). Precision varies by currency: JPY uses 0 decimals while USD uses 2—always check Money::Currency#exponent. Allocation returns arrays that must sum to original (rounding mode matters in lib/money/money/allocation.rb). Bank instance is global by default—test isolation requires managing Money.default_bank carefully. I18n backend is pluggable (Money.locale_backend assignment in lib/money/money/locale_backend.rb) and must be configured before use.
💡Concepts to learn
- Cent-based integer representation — This repo's core design: storing monetary values as integer cents instead of floats eliminates rounding errors that plague financial software; you must understand this invariant when working with Money#cents vs #amount
- Strategy pattern for exchange rates — lib/money/bank/base.rb defines an extensible interface; implementations (VariableExchange, SingleCurrency, Memory store) let users swap exchange rate sources without changing Money core logic
- Immutability and value semantics — Money objects should be treated as immutable values (like integers); arithmetic operations return new Money instances rather than modifying in-place, essential for thread safety in financial apps
- Locale-aware formatting backend — lib/money/locale_backend/ abstracts currency symbol and number formatting rules; I18n backend plugs in translation data per-locale, allowing '¥100' (JPY) vs '$100' (USD) rendering without hardcoded rules
- ISO 4217 currency codes and precision — Currencies have metadata (JPY=0 decimals, BTC=8 decimals via non_iso.json) stored in Money::Currency; precision is critical for arithmetic and formatting—this is loaded from config/ JSON
- Money allocation (fair division) — lib/money/money/allocation.rb solves the problem of dividing an amount among recipients so remainders sum correctly (e.g., $1.00 / 3 = [$0.34, $0.33, $0.33]); critical for invoicing and distribution
- RBS type signatures — sig/ directory contains Ruby type hints (RBS format) that enable static type checking without changing source; ensures Money + Currency classes have declared types for better IDE support and bug prevention
🔗Related repos
RubyMoney/monetize— Companion gem that parses Money strings (e.g., '100 USD') into Money objects; the money gem handles representation and math, monetize handles parsingRubyMoney/eu_central_bank— Exchange rate provider for money gem; implements a bank that fetches live rates from ECB XML feedsthoughtbot/money-rails— Rails integration layer for the money gem; ActiveRecord model support, form helpers, and migration generators for money columnsstripe/stripe-ruby— Real-world consumer of money gem concepts; Stripe's Ruby SDK uses similar cent-based amount representation for safe payment processingspree/spree— E-commerce framework that depends on money gem for all product pricing, tax, and shipping cost calculations
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive RBS type signatures for lib/money/bank/single_currency.rb
The repo has RBS type signature files (sig/) for most core modules, but sig/lib/money/bank/single_currency.rbs is missing. This is a key bank implementation that users rely on. Adding proper type signatures will improve IDE autocomplete, enable type checking with Steep, and match the repo's investment in type safety.
- [ ] Review lib/money/bank/single_currency.rb to understand all public methods and their signatures
- [ ] Create sig/lib/money/bank/single_currency.rbs with complete type definitions
- [ ] Cross-reference lib/money/bank/base.rbs to ensure consistency with the base class interface
- [ ] Run type checker (if configured) to verify signatures match implementation
- [ ] Add tests in spec/money/bank/ to validate the type signatures are correct
Implement comprehensive test suite for lib/money/rates_store/memory.rb
The rates_store module exists with an RBS signature (sig/lib/money/rates_store/memory.rbs), but there's no corresponding test file visible in the spec directory. This core functionality for exchange rate storage needs thorough test coverage for edge cases, thread safety, and data persistence across operations.
- [ ] Create spec/money/rates_store/memory_spec.rb
- [ ] Add tests for basic storage operations (add, get, remove exchange rates)
- [ ] Add tests for concurrent access if the class supports it
- [ ] Add tests for edge cases (nil rates, invalid currency pairs, overwriting rates)
- [ ] Add integration tests showing how VariableExchangeBank uses the rates store
Add missing RBS signatures for lib/money/locale_backend/ implementations
The locale_backend module has a base class and multiple implementations (currency.rb, i18n.rb), but only sig/lib/money/locale_backend/i18n.rbs exists. The base class and currency implementation lack type signatures, creating gaps in type coverage for this feature used by Money#format and related methods.
- [ ] Create sig/lib/money/locale_backend/base.rbs defining the interface all backends must implement
- [ ] Create sig/lib/money/locale_backend/currency.rbs with complete type definitions for the CurrencyBackend
- [ ] Review lib/money/locale_backend/errors.rb and add sig/lib/money/locale_backend/errors.rbs for custom exception types
- [ ] Ensure all backend implementations properly match the base interface signatures
- [ ] Verify existing i18n.rbs signatures are compatible with the new base interface
🌿Good first issues
- Add RBS type stubs for lib/money/rates_store/memory.rb—the rates_store directory exists but sig/lib/money/rates_store/ is likely incomplete or missing, blocking full type safety for exchange rate caching
- Document the allocation algorithm in lib/money/money/allocation.rb with a code example in the API docs—the method distributes money across recipients but the rounding behavior and guarantee that totals match original is under-explained
- Expand currency_non_iso.json coverage: audit config/currency_non_iso.json against real-world non-ISO currencies (crypto, historical) and add missing entries with tests in spec/money/currency_spec.rb
⭐Top contributors
Click to expand
Top contributors
- @sunny — 49 commits
- @yukideluxe — 33 commits
- @wwahammy — 2 commits
- @juliamoneybird — 2 commits
- @dideler — 2 commits
📝Recent commits
Click to expand
Recent commits
a7c8360— Add 'head' to ruby-version matrix in workflow and turn off fail-fast (#1214) (yukideluxe)6c56245— Merge branch 'main' into patch-1 (wwahammy)e55aa5a— Pin rubocop gems to prevent surprise CI failures (#1215) (yukideluxe)4bbac76— Pin rubocop gems to prevent surprise CI failures (yukideluxe)73a17a2— Add 'head' to ruby-version matrix in workflow and turn off fail-fast (wwahammy)48f0591— Fix XPF currency symbol from 'Fr' to '₣' (#1205) (yukideluxe)a8fb064— Fix XPF currency symbol from 'Fr' to '₣' (AmineAffifSkello)f4f7ceb— Add ruby 4.0 to test matrix (#1212) (yukideluxe)fb1039b— add ruby 4.0 to test matrix (yukideluxe)9fe122c— Lint: Fix performance cops (#1211) (sunny)
🔒Security observations
The RubyMoney/money library demonstrates generally good security practices with CI/CD workflows, linting, and Dependabot integration already in place. However, there are areas for improvement: (1) Currency configuration files lack integrity validation mechanisms; (2) Input validation for currency data loading should be strengthened; (3) A formal security policy is missing; (4) Dependency management should be continuously monitored. The codebase is a well-maintained library without obvious injection vulnerabilities, hardcoded secrets, or critical misconfigurations. Recommendations focus on hardening data integrity and establishing clear security processes.
- Medium · Hardcoded Currency Configuration Files —
config/currency_*.json. Currency data is stored in JSON configuration files (currency_iso.json, currency_non_iso.json, currency_backwards_compatible.json) without apparent integrity validation. While not secrets, these files could be modified to inject malicious currency data affecting financial calculations. Fix: Implement checksum validation or digital signatures for currency configuration files. Consider loading currency data from a trusted, signed source and validating integrity at runtime. - Medium · Potential Input Validation Risk in Currency Loader —
lib/money/currency/loader.rb. The Currency::Loader module loads external JSON configuration files. Without visible input sanitization or schema validation, there's a risk of malformed data causing unexpected behavior or denial of service. Fix: Implement strict JSON schema validation for all loaded configuration files. Use a library like 'json-schema' to validate currency data structure and constraints before processing. - Medium · Missing Security Policy Documentation —
Repository root. No SECURITY.md or security policy file is visible in the repository structure, making it unclear how security vulnerabilities should be reported. Fix: Create a SECURITY.md file following GitHub's recommended format (https://docs.github.com/en/code-security/getting-started/adding-a-security-policy-to-your-repository) to define responsible disclosure procedures. - Low · Lack of Visible Dependency Lock File Security —
Gemfile, Gemfile.lock (not provided). While the repository appears to use Bundler (Gemfile present), no detailed dependency analysis was provided. Ruby dependency vulnerabilities should be regularly audited. Fix: Use 'bundler-audit' or 'bundle outdated' regularly to scan for known vulnerabilities. Integrate dependency checking into CI/CD pipeline via GitHub's Dependabot (already configured in .github/dependabot.yml - good practice observed). - Low · Test Configuration Exposure Risk —
spec/support/. Support files in spec/support/ (e.g., default_currency.rb) could potentially contain test credentials or hardcoded values that might be accidentally committed. Fix: Ensure test fixtures use factory patterns or environment variables. Never commit actual API keys or credentials in test files. Consider adding spec/support/ directories to .gitignore patterns if they might contain sensitive test data.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.