cpf-dv for Ruby
Gem Version Downloads Count Ruby Version Test Status Last Update Date Project License
A Ruby utility to calculate check digits on CPF (Brazilian Individual's Taxpayer ID).
Ruby Support
| Ruby 3.2 | Ruby 3.3 | Ruby 3.4 |
|---|---|---|
| Passing β | Passing β | Passing β |
Features
- β
Flexible input: Accepts
StringorArrayof strings - β Format agnostic: Strips non-numeric characters from string input
- β Auto-expansion: Multi-character strings in arrays are joined and parsed like a single string
- β Input validation: Rejects ineligible CPFs (9 identical digits in the base β repeated-digit pattern)
- β Lazy evaluation: Check digits are calculated only when accessed (via methods)
- β Caching: Calculated values are cached for subsequent access
- β
Minimal dependencies: Only
lacus-utils - β
Error handling: API misuse vs domain errors with a
CpfDV::Errormarker for library-wide rescue
Installation
Install the gem directly:
gem install cpf-dv
Or add it to your Gemfile and run bundle install:
gem 'cpf-dv'
Require
require 'cpf-dv'
Quick Start
require 'cpf-dv'
check_digits = CpfDV::CpfCheckDigits.new('054496519')
check_digits.first # => '1'
check_digits.second # => '0'
check_digits.both # => '10'
check_digits.cpf # => '05449651910'
Usage
The main resource of this package is the class CpfDV::CpfCheckDigits. Through an instance, you access CPF check-digit information:
initialize:CpfDV::CpfCheckDigits.new(cpf_input)βcpf_inputmust be aStringor anArrayof strings. After sanitization, the value must have 9β11 digits (formatting stripped from strings). Only the first 9 digits are used as the base; if you pass 10 or 11 digits (e.g. a full CPF including prior check digits), digits 10β11 are ignored and the check digits are recalculated. There are no options, keyword arguments, or configuration objects β the constructor takes only the CPF input.first: First check digit (10th digit of the full CPF). Lazy, cached.second: Second check digit (11th digit of the full CPF). Lazy, cached.both: Both check digits concatenated as a string.cpf: The complete CPF as a string of 11 digits (9 base digits + 2 check digits).
Input formats
The CpfCheckDigits class accepts multiple input formats:
String input: plain digits or formatted CPF (e.g. 054.496.519-10, 123.456.789). Non-numeric characters are removed. Leading zeros are preserved.
Array of strings: each element must be a string; values are concatenated and then parsed like a single string (e.g. ['0','5','4',β¦], ['054','496','519'], ['054496519']). Non-string elements are not allowed.
require 'cpf-dv'
# String β plain, formatted, or with existing check digits (only first 9 digits used)
CpfDV::CpfCheckDigits.new('054496519')
CpfDV::CpfCheckDigits.new('054.496.519-10')
CpfDV::CpfCheckDigits.new('05449651910')
# Array of strings β single- or multi-character elements
CpfDV::CpfCheckDigits.new(%w[0 5 4 4 9 6 5 1 9])
CpfDV::CpfCheckDigits.new(%w[054 496 519])
CpfDV::CpfCheckDigits.new(%w[054496519])
Error handling
Errors fall into two categories:
| Category | Meaning |
|---|---|
| API misuse | The caller invoked the library incorrectly (wrong type). Detectable from the call shape. |
| Domain error | The call was structurally correct, but a value violates a business rule (length, eligibility). |
Every custom error includes the CpfDV::Error marker module. Domain failures (InvalidLengthError, ValidationError) inherit from CpfDV::DomainError (RangeError).
Summary
| Class | Inherits from | Category | Trigger condition |
|---|---|---|---|
CpfDV::TypeMismatchError |
TypeError (+ include Error) |
API misuse | Argument has the wrong data type |
CpfDV::InvalidLengthError |
CpfDV::DomainError |
Domain error | Sanitized length is not 9β11 |
CpfDV::ValidationError |
CpfDV::DomainError |
Domain error | First 9 digits are all identical (repeated-digit pattern) |
CpfDV::Error (marker module)
- Inheritance: module marker mixed into every library error via
include(not a class). - Category: N/A (rescue target only) β not a failure mode by itself.
- When it is raised: Never raised directly; included by every custom error the library raises.
- Example: N/A
- How to rescue it:
rescue CpfDV::Error
# everything this library raises
CpfDV::DomainError
- Inheritance:
CpfDV::DomainError < RangeError(includesCpfDV::Error) - Category: Domain error β ancestor for numeric/length domain failures.
- When it is raised: Not raised directly; prefer raising a leaf subclass.
- Example: Prefer
raise CpfDV::InvalidLengthErrorover raisingDomainErrordirectly. - How to rescue it:
rescue CpfDV::DomainError
# InvalidLengthError, ValidationError, and any other DomainError subclass
CpfDV::TypeMismatchError
- Inheritance:
CpfDV::TypeMismatchError < TypeError(includesCpfDV::Error) - Category: API misuse β the caller passed a value of the wrong type.
- When it is raised: Raised when the CPF input is not a
Stringor anArrayof strings (or an array contains a non-string element). - Example:
CpfDV::CpfCheckDigits.new(12_345_678_901) # raises CpfDV::TypeMismatchError
- How to rescue it:
rescue CpfDV::TypeMismatchError
# this library's type-contract violation
rescue TypeError
# native type errors, including this library's TypeMismatchError
CpfDV::InvalidLengthError
- Inheritance:
CpfDV::InvalidLengthError < CpfDV::DomainError < RangeError(includesCpfDV::Error) - Category: Domain error β a collection or string length violates a business rule.
- When it is raised: Raised when the sanitized CPF input does not contain 9 to 11 digits.
- Example:
CpfDV::CpfCheckDigits.new('12345678') # raises CpfDV::InvalidLengthError
- How to rescue it:
rescue CpfDV::InvalidLengthError
# this exact length violation
rescue CpfDV::DomainError
# RangeError-rooted domain failures from this library
CpfDV::ValidationError
- Inheritance:
CpfDV::ValidationError < CpfDV::DomainError < RangeError(includesCpfDV::Error) - Category: Domain error β a value fails a non-numeric, non-length domain rule.
- When it is raised: Raised when the first 9 digits are all the same digit (repeated-digit pattern).
- Example:
CpfDV::CpfCheckDigits.new('111111111') # raises CpfDV::ValidationError
- How to rescue it:
rescue CpfDV::ValidationError
# this exact domain validation failure
rescue CpfDV::DomainError
# RangeError-rooted domain failures from this library
Rescue granularity
# 1) Single native class β catches type misuse from this library (and other TypeErrors).
rescue TypeError
# CpfDV::TypeMismatchError and any other TypeError (library or not)
# 2) CpfDV::DomainError β catches business-rule violations under DomainError.
rescue CpfDV::DomainError
# CpfDV::InvalidLengthError, CpfDV::ValidationError, and other DomainError subclasses
# 3) CpfDV::Error β catches everything the library raises.
rescue CpfDV::Error
# every custom error that includes CpfDV::Error
# 4) Specific leaf class β catches only that exact failure mode.
rescue CpfDV::InvalidLengthError
# only CpfDV::InvalidLengthError
Notable attributes on raised errors:
TypeMismatchError:actual_input,actual_type,expected_typeInvalidLengthError:actual_input,evaluated_input,min_expected_length,max_expected_lengthValidationError:actual_input,reason
Other available resources
After require 'cpf-dv':
CpfDV::CPF_MIN_LENGTH:9CpfDV::CPF_MAX_LENGTH:11- Errors: see above (
CpfDV::Error,DomainError, and raised leaves)
Calculation algorithm
The package calculates CPF check digits using the official Brazilian modulo-11 algorithm:
- First check digit (10th position): apply to the first 9 base digits; weights 10, 9, 8, 7, 6, 5, 4, 3, 2 (left to right); let
remainder = 11 - (sum(digit Γ weight) % 11). The digit is0ifremainder > 9, otherwiseremainder. - Second check digit (11th position): apply to the first 9 base digits plus the first check digit; weights 11, 10, 9, 8, 7, 6, 5, 4, 3, 2 (left to right); same formula for
remainder.
Contribution & Support
We welcome contributions! Please see our Contributing Guidelines for details. If you find this project helpful, please consider:
- β Starring the repository
- π€ Contributing to the codebase
- π‘ Suggesting new features
- π Reporting bugs
License
This project is licensed under the MIT License β see the LICENSE file for details.
Changelog
See CHANGELOG for a list of changes and version history.
Made with β€οΈ by Lacus Solutions