Skip to content

Latest commit

 

History

History
139 lines (103 loc) · 4.02 KB

File metadata and controls

139 lines (103 loc) · 4.02 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

About Operandi

Operandi is a Ruby gem providing a service architecture pattern for organizing business logic. Services are defined as classes with arguments, steps, and outputs, featuring transactions, inheritance, error handling, and context sharing.

Development Commands

Testing

# Run all tests
bundle exec rspec

# Run specific test file
bundle exec rspec spec/path/to/file_spec.rb

# Run with coverage (uses SimpleCov)
bundle exec rspec

Linting

# Run RuboCop linter
bundle exec rubocop

# Auto-fix RuboCop issues
bundle exec rubocop -a

Build and Release

# Build gem
bundle exec rake build

# Default task (runs tests)
bundle exec rake

Architecture

Core Components

  1. Base Service (lib/operandi/base.rb:15)

    • Main service class that all services inherit from
    • Handles service lifecycle: initialization, execution, callbacks, error management
    • Provides DSL for defining arguments, steps, and outputs
    • Manages transactions and error propagation to parent services
  2. Callbacks System (lib/operandi/callbacks.rb:5)

    • Supports service and step-level callbacks
    • Events: before_service_run, after_service_run, around_service_run, on_service_success, on_service_failure
    • Step events: before_step_run, after_step_run, around_step_run, on_step_success, on_step_failure
  3. Settings

    • Step (lib/operandi/settings/step.rb:7): Handles step execution with conditional logic (if, unless, always)
    • Field (lib/operandi/settings/field.rb): Manages argument and output validation and type checking
  4. Messages System (lib/operandi/messages.rb)

    • Collects errors and warnings with options for breaking, raising, or rolling back
    • Supports copying messages between parent and child services
  5. Collection (lib/operandi/collection.rb)

    • Manages arguments and outputs as collections with validation and defaults
    • Supports Sorbet runtime types for type validation

Service DSL

Services use a declarative DSL:

class ExampleService < Operandi::Base
  # Define input arguments
  arg :name, type: String
  arg :age, type: Integer, optional: true, default: 25

  # Define execution steps
  step :validate_input
  step :process_data, if: :should_process?
  step :cleanup, always: true

  # Define outputs
  output :result, type: Hash

  private

  def validate_input
    errors.add(:name, "required") if name.nil? || name.strip.empty?
  end

  def process_data
    self.result = { name: name, age: age }
  end

  def cleanup
    # Runs regardless of errors/warnings, unless stop! was called
  end

  def should_process?
    !(name.nil? || name.strip.empty?)
  end
end

Service Execution

  • Services can be run with .run(args) or .run!(args) (raises on error)
  • Use .with(service_or_context) to chain services with shared context
  • Transactions automatically rollback on errors when use_transactions: true
  • Steps run sequentially, stopping on errors unless always: true

Error Handling

  • Errors collected in @errors message collection
  • Supports break_on_error, raise_on_error, rollback_on_error configuration
  • Warnings work similarly with @warnings collection
  • Parent services can inherit child errors/warnings based on configuration

Testing Patterns

  • Services are tested using RSpec with database transactions
  • Use DatabaseCleaner for test isolation
  • Mock database models and external dependencies
  • Test both success and failure scenarios
  • Validate arguments, outputs, and error conditions

Configuration

RuboCop Rules

  • Target Ruby version: 2.7+
  • Method length max: 20 lines
  • Uses double quotes for strings
  • Enables trailing commas for multiline structures
  • Disables documentation requirements and guard clauses

Database Support

  • Optional ActiveRecord integration for transactions
  • Uses SQLite3 for testing
  • Database cleaner ensures test isolation