Splittable

Gem Version Ruby Ruby Version License

🎯 Problem Solved

When dividing monetary values, you often get results with many decimal places that need to be rounded to cents (2 decimal places). This creates a common problem: the sum of rounded installments doesn't equal the original total.

Example of the problem:

# Dividing $100.00 into 3 equal parts
100.00 / 3 = 33.333333...

# If we round each installment to 2 decimal places:
[33.33, 33.33, 33.33].sum = 99.99  # ❌ Missing $0.01!

Splittable solves this by:

  • Truncating values to the specified precision
  • Adding the difference to the first installment
  • Ensuring the sum always equals the original value

🚀 Installation

Add this line to your application's Gemfile:

gem 'splittable'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install splittable

📖 Usage

Division Method

Split a total value into equal installments:

# Basic usage - split $0.12 into 3 equal parts
Splittable.division(value: 0.12, quantity: 3)
# => [0.04, 0.04, 0.04]  # Sum: 0.12

# Custom precision - 3 decimal places
Splittable.division(value: 10, quantity: 3, precision: 3)
# => [3.334, 3.333, 3.333]  # Sum: 10.000

Normalize Method

Normalize existing installments to match a total value:

# Normalize installments to sum exactly $100.00
Splittable.normalize(value: 100.00, installments: [33.33, 33.33, 33.33])
# => [33.34, 33.33, 33.33]  # Sum: 100.00

# With custom precision
Splittable.normalize(value: 100, installments: [33.333, 33.333, 33.333], precision: 3)
# => [33.334, 33.333, 33.333]  # Sum: 100.000

💡 Real-World Examples

E-commerce Payment Splitting

# Split a $99.99 order into 3 monthly payments
payments = Splittable.division(value: 99.99, quantity: 3)
# => [33.33, 33.33, 33.33]
# Total: $99.99 ✅

Invoice Distribution

# Distribute a $1,000.00 invoice across departments
departments = ['Sales', 'Marketing', 'Support']
amounts = [400.00, 350.00, 250.00]

normalized = Splittable.normalize(value: 1000.01, installments: amounts)
# => [400.01, 350.00, 250.00]
# Total: $1,000.01 ✅

Subscription Billing

# Annual subscription split into monthly payments
monthly_payment = Splittable.division(value: 120.01, quantity: 12)
# => [10.01, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00, 10.00]
# Total: $120.01 ✅

⚠️ Error Handling

# Invalid quantity (must be positive)
Splittable.division(value: 100, quantity: 0)
# => ArgumentError: quantity should be positive

# Empty installments array
Splittable.normalize(value: 100, installments: [])
# => ArgumentError: installments should be a non-empty array

# Nil installments
Splittable.normalize(value: 100, installments: nil)
# => ArgumentError: installments should be a non-empty array

🛠️ Development

Setup

git clone https://github.com/m4rcelotoledo/splittable.git
cd splittable
bundle install

Running Tests

# Run all tests
bundle exec rspec

# Run with coverage
bundle exec rspec --format documentation

# Run specific test file
bundle exec rspec spec/splittable_spec.rb

Code Quality

# Run RuboCop
bundle exec rubocop

# Auto-fix RuboCop issues
bundle exec rubocop -a

Interactive Console

bundle exec bin/console

Project Structure

lib/

📦 Release Process

Automatic Release

  1. Update version in lib/splittable/version.rb
  2. Update CHANGELOG.md with relevant changes
  3. Merge to master branch
  4. GitHub Actions will automatically publish to RubyGems

Manual Release

# Update version and changelog first
bundle exec rake release

🤝 Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

Bug reports and pull requests are welcome on GitHub at https://github.com/m4rcelotoledo/splittable/blob/master/CONTRIBUTING.md.

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

📚 Code of Conduct

This project follows the Contributor Covenant code of conduct.