CtrlK
BlogDocsLog inGet started
Tessl Logo

igmarin/ruby-core-skills

Curated library of 16 public Ruby AI agent skills: 10 atomic skills (YARD docs, service objects, calculator pattern, API clients, DDD, bug triage, code review, skill routing), 5 process-discipline skills (TDD, refactoring, review, security, test planning), and 1 planning skill (TDD task generation). Zero agents — this is a foundational library consumed by framework-specific tiles like rails-agent-skills and hanakai-yaku.

95

1.05x
Quality

96%

Does it follow best practices?

Impact

95%

1.05x

Average score across 16 eval scenarios

SecuritybySnyk

Passed

No known issues

Overview
Quality
Evals
Security
Files

SKILL.mdskills/patterns/implement-calculator-pattern/

name:
implement-calculator-pattern
license:
MIT
description:
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 component, without collapsing NullService and concrete into one step). Test coverage includes: named variants, inactive plan, nil plan, and unknown variant contexts. Scaffolds tests per variant. Trigger words: strategy pattern, factory pattern, null object pattern, variant calculator, dispatch table, SERVICE_MAP, no-op fallback.
metadata:
{"version":"1.0.0","user-invocable":"true","origin":"Extracted from igmarin/rails-agent-skills v5.1.17"}

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

ComponentResponsibility
FactoryDispatch to correct service class via SERVICE_MAP; fall back to NullService
BaseServiceGuard with should_calculate?; delegate to compute_result
NullServiceAlways returns nil safely — never raises
ConcreteOverride should_calculate? (add variant check on top of super) and compute_result

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 compute_result if should_calculate? is true.
  3. Create the NullService. Always return false for should_calculate? and nil for compute_result.
  4. Create Concrete services. Override should_calculate? and compute_result. 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. Full test examples are in TESTING.md.

Pitfalls

PitfallFix
SERVICE_MAP key mismatchVerify keys match exactly what is stored in the database — typos cause silent NullService fallbacks
Missing NullService spec/testAlways add a test context for unknown/nil variants or tests will never catch the fallback regression
Direct service instantiation (ServiceClass.new(entity))Route through Factory.for(entity) — it is the sole public entry point; direct instantiation bypasses the NullService safety net
Forgetting super in concrete should_calculate?Always call super — skipping it removes the base nil/presence guard
  • assets/examples.md — Additional worked examples showing alternative domain contexts (e.g., discount calculators, shipping calculators) using the same pattern.
  • IMPLEMENTATION.md — Full Ruby implementations for every component (Factory, BaseService, NullService, Concrete Service), module naming conventions, and multi-variant expansion guidance.
  • 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

SkillWhen to chain
write-testsFor writing spec files
create-service-objectFor naming conventions, YARD docs, and frozen_string_literal baseline

skills

README.md

tile.json