igmarin/ruby-core-skills

implement-calculator-pattern

Use when building variant-based calculators with SERVICE_MAP routing via `Factory.for(entity)` (ONLY permitted entry point — direct instantiation FORBIDDEN), BaseService defines `calculate`→`compute_result` if `should_calculate?`, NullService has `should_calculate?`=false+`compute_result`=nil, Concrete services override both methods and MUST call `super` in `should_calculate?` — and each component is tested in order (write spec → run → verify Red → implement → run → verify Green before next com…

First seen Jul 28, 2026

Installation

$ npx skills add igmarin/ruby-core-skills --skill implement-calculator-pattern

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from igmarin/ruby-core-skills · top by installs.

npx skills add igmarin/ruby-core-skills

Browse all from igmarin/ruby-core-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 2
License LICENSE
Default branch main
Open issues 0
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

Version1.0.0
LicenseMIT
More metadata
version
1.0.0
user-invocable
true
origin
Extracted from igmarin/rails-agent-skills v5.1.17

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 6,027 B
  • docs SUMMARY.md 878 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 19 installs

SKILL.md

Implement Calculator Pattern

One API for the client: Calculator::Factory.for(entity).calculate. The factory picks the strategy; NullService handles unknown variants safely.

Quick Reference

Component Responsibility
Factory Dispatch to correct service class via SERVICE_MAP; fall back to NullService
BaseService Guard with shouldcalculate?; delegate to computeresult
NullService Always returns nil safely — never raises
Concrete Override shouldcalculate? (add variant check on top of super) and computeresult

HARD-GATE

Tests Gate Implementation

For each component (Factory → BaseService → NullService → Concrete):
1. Write the spec/test — contexts per variant, plus the NullService path
2. Run it — verify it fails because the component does not exist yet
3. Implement the component — minimum code to make the test pass
4. Run again — confirm green, then proceed to the next component
Each component gets its own RED command/output and GREEN command/output before
the next component starts. Do not collapse NullService and concrete services
into a single verification step.

Output requirements per component:

  • Test coverage: Factory, NullService, and every concrete service must cover named variants, inactive plan, nil plan, and unknown variant contexts (or explicitly explain why a context does not apply).
  • End with the calculator test directory command and the broader test suite command when available.
  • Language — English unless explicitly requested otherwise.

Core Process

  1. Create the Factory. No qualifying context or unknown variant → NullService.
  2. Create the BaseService. Define calculate that delegates to computeresult if shouldcalculate? is true.
  3. Create the NullService. Always return false for shouldcalculate? and nil for computeresult.
  4. Create Concrete services. Override shouldcalculate? and computeresult. Always call super in should_calculate?.
  5. Run the full test suite.
  6. Verify the Single entry point rule: Factory.for(entity) is the only permitted access path.

File Structure

services/<calculator_name>/
├── factory.rb
├── base_service.rb
├── null_service.rb
├── standard_service.rb
├── premium_service.rb

Minimal Inline Implementation

# factory.rb
module PricingCalculator
  class Factory
    SERVICE_MAP = {
      "standard" => StandardService,
      "premium"  => PremiumService
    }.freeze

    def self.for(entity)
      SERVICE_MAP.fetch(entity.plan_variant, NullService).new(entity)
    end
  end
end
# null_service.rb
module PricingCalculator
  class NullService < BaseService
    def should_calculate? = false
    def compute_result    = nil
  end
end
# base_service.rb
module PricingCalculator
  class BaseService
    def initialize(entity)
      @entity = entity
    end

    def calculate
      return nil unless should_calculate?
      compute_result
    end

    private

    def should_calculate?
      @entity.present?
    end

    def compute_result
      raise NotImplementedError
    end
  end
end

Minimal Usage Example

# Single public entry point — never instantiate service classes directly
price = PricingCalculator::Factory.for(order).calculate

Full implementations for all components including multi-variant expansion are in [IMPLEMENTATION.md](IMPLEMENTATION.md). Full test examples are in [TESTING.md](TESTING.md).

Pitfalls

Pitfall Fix
SERVICE_MAP key mismatch Keys must match exactly what is stored in the database — typos cause silent NullService fallbacks
Missing NullService spec/test Always add a context for unknown/nil variants or fallback regressions go undetected
Direct service instantiation Route through Factory.for(entity) — direct instantiation bypasses the NullService safety net
Forgetting super in concrete should_calculate? Always call super — skipping it removes the base nil/presence guard

Further Reading

  • [assets/examples.md](assets/examples.md) — Additional worked examples showing alternative domain contexts (e.g., discount calculators, shipping calculators) using the same pattern.
  • [IMPLEMENTATION.md](IMPLEMENTATION.md) — Full Ruby implementations for every component (Factory, BaseService, NullService, Concrete Service), module naming conventions, and multi-variant expansion guidance.
  • [TESTING.md](TESTING.md) — Full RSpec/Minitest examples covering all variant contexts (named variants, inactive plan, nil plan, unknown variant) for Factory, NullService, and concrete services.

Integration

Skill When to chain
write-tests For writing spec files
create-service-object For naming conventions, YARD docs, and frozenstringliteral baseline