Full Code of hackico-ai/ruby-hati-command for AI

main 5fcdbb040eca cached
37 files
66.7 KB
17.5k tokens
86 symbols
1 requests
Download .txt
Repository: hackico-ai/ruby-hati-command
Branch: main
Commit: 5fcdbb040eca
Files: 37
Total size: 66.7 KB

Directory structure:
gitextract_ucqxjbxu/

├── .gitignore
├── .rubocop.yml
├── CODE_OF_CONDUCT.md
├── Gemfile
├── LICENSE
├── README.md
├── hati-command.gemspec
├── lib/
│   ├── hati/
│   │   └── command.rb
│   ├── hati_command/
│   │   ├── befehl.rb
│   │   ├── callee.rb
│   │   ├── cmd.rb
│   │   ├── errors/
│   │   │   ├── base_error.rb
│   │   │   ├── configuration_error.rb
│   │   │   ├── fail_fast_error.rb
│   │   │   └── transaction_error.rb
│   │   ├── failure.rb
│   │   ├── result.rb
│   │   ├── success.rb
│   │   └── version.rb
│   └── hati_command.rb
└── spec/
    ├── integration/
    │   └── hati_command/
    │       ├── befehl_ar_transaction_spec.rb
    │       ├── befehl_spec.rb
    │       ├── callee_spec.rb
    │       └── cmd_spec.rb
    ├── spec_helper.rb
    ├── support/
    │   ├── active_record.rb
    │   └── dummy.rb
    └── unit/
        └── hati_command/
            ├── befehl_config_spec.rb
            ├── callee_spec.rb
            ├── cmd_spec.rb
            ├── errors/
            │   ├── base_error_spec.rb
            │   ├── configuration_error_spec.rb
            │   ├── fail_fast_error_spec.rb
            │   └── transaction_error_spec.rb
            ├── failure_spec.rb
            ├── result_spec.rb
            └── success_spec.rb

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
*.gem
*.rbc
/.config
/coverage/
/InstalledFiles
/pkg/
/spec/reports/
/spec/examples.txt
/test/tmp/
/test/version_tmp/
/tmp/

# Used by dotenv library to load environment variables.
# .env

# Ignore Byebug command history file.
.byebug_history

## Specific to RubyMotion:
.dat*
.repl_history
build/
*.bridgesupport
build-iPhoneOS/
build-iPhoneSimulator/

## Specific to RubyMotion (use of CocoaPods):
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# vendor/Pods/

## Documentation cache and generated files:
/.yardoc/
/_yardoc/
/doc/
/rdoc/

## Environment normalization:
/.bundle/
/vendor/bundle
/lib/bundler/man/

# for a library or gem, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# Gemfile.lock
# .ruby-version
# .ruby-gemset

# unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
.rvmrc

# Used by RuboCop. Remote config files pulled in from inherit_from directive.
# .rubocop-https?--*

# Specs
.rspec_status

# Dev env
Gemfile.lock

# macOS
.DS_Store


================================================
FILE: .rubocop.yml
================================================
require:
  - rubocop-rspec
  - rubocop-rake

AllCops:
  NewCops: enable
  TargetRubyVersion: 3.0

Style/StringLiteralsInInterpolation:
  EnforcedStyle: double_quotes


================================================
FILE: CODE_OF_CONDUCT.md
================================================
# [hackico-ai] Code of Conduct

## Our Pledge

We, as members, contributors, and leaders of [Your Community Name], pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.

We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment for our community include:

- Demonstrating empathy and kindness toward others.
- Being respectful of differing opinions, viewpoints, and experiences.
- Giving and gracefully accepting constructive feedback.
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience.
- Focusing on what is best not just for us as individuals, but for the overall community.

Examples of unacceptable behavior include:

- The use of sexualized language or imagery, and sexual attention or advances of any kind.
- Trolling, insulting or derogatory comments, and personal or political attacks.
- Public or private harassment.
- Publishing others' private information, such as a physical or email address, without their explicit permission.
- Other conduct which could reasonably be considered inappropriate in a professional setting.

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.

Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event.

## Enforcement

Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at [Yuri Gi](https://github.com/yurigitsu), [Marie Giy](https://github.com/yurigitsu). All complaints will be reviewed and investigated promptly and fairly.

All community leaders are obligated to respect the privacy and security of the reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of actions.

**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.

**Consequence**: A permanent ban from any sort of public interaction within the community.

## Attribution

This Code of Conduct is adapted from the version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].

For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations].

[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations


================================================
FILE: Gemfile
================================================
# frozen_string_literal: true

source 'https://rubygems.org'

gemspec

gem 'rake'

# Spec
gem 'activerecord'
gem 'rspec', '~> 3.0'
gem 'sqlite3'

# Linter & Static
gem 'fasterer', '~> 0.11.0'
gem 'rubocop', '~> 1.21'
gem 'rubocop-rake'
gem 'rubocop-rspec', require: false


================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2025 hackico.ai

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# ![Ruby](icon.svg) hati-command

The `hati-command` gem provides a lightweight framework for structuring logic as discrete, callable actions — ideal for agentic AI systems that require modular execution and explicit outcome handling.

## What it provides:

- **hati-command** lets you define commands as service objects or interactors, ready for orchestration by AI agents.
- **hati-command** returns standardized `Success` and `Failure` results, making it easy to reason about next steps in autonomous workflows.
- **hati-command** provides built-in error tracing and metadata propagation, enabling reliable debugging, observability, and auditability across execution chains.
- **hati-command** supports integrated transaction handling, allowing commands to execute safely within database or domain-level transactional boundaries.

## Features

- **Command Execution**: Encapsulate atomic operations with clear inputs and outputs.
- **Structured Results**: Return `Result` objects with status, value, and metadata.
- **Deterministic Execution**: Enforce explicit execution → outcome flow.
- **Failure as Data**: Represent errors as explicit results.
- **Framework-Agnostic Service Objects**: Works with plain `Ruby` or `Rails`.
- **Execution Transparency**: Make decision points and failure paths visible.
- **Automation & AI-Ready**: Suitable for orchestration and agent-driven w

## Table of Contents

- [Introduction](#introduction)
- [Features](#features)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
  - [Handling Success](#handling-success)
  - [Handling Failure](#handling-failure)
  - [Transactional Behavior](#transactional-behavior-fail-fast-with-failure)
- [Advanced Usage](#advanced-usage)

  - [Result Customization](#result-customization)
    - [meta](#meta)
    - [error](#error)
    - [trace](#trace)
  - [Native DB Transaction](#native-db-active-record-transaction)
  - [Command Configurations](#command-configurations)
    - [result_inference](#result_inference)
    - [call_as](#call_as)
    - [failure](#failure)
    - [fail_fast](#fail_fast)
    - [unexpected_err](#unexpected_err)
    - [ar_transaction](#ar_transaction)

- [Development](#development)
- [Contributing](#contributing)
- [License](#license)
- [Code of Conduct](#code-of-conduct)

## Installation

Install the gem and add to the application's Gemfile by executing:

```bash
bundle add hati-command
```

If bundler is not being used to manage dependencies, install the gem by executing:

```bash
gem install hati-command
```

## Basic Usage

To use the `hati-command` gem, you can create a command class that includes the `HatiCommand::Cmd` module.

Note: No need to nest object APIs under `private` as popular template for `Servie Object` designs

    only main caller method is public by design

#### Example

```ruby
require 'hati_command'

class GreetingCommand
  include HatiCommand::Cmd

  def call(greeting = nil)
    message = build_greeting(greeting)
    return message if message.failure?

    process_message(message)
  end

  def build_greeting(greeting)
    greeting ? Success(greeting) : Failure("No greeting provided")
  end

  def process_message(message)
    message.success? ? Success(message.upcase) : Failure("No message provided")
  end
end
```

### Command `API`

```ruby
result = GreetingCommand.call("Hello, World!") # Outputs: Result
result = GreetingCommand.new                   # Outputs: private method `new' called
```

### Handling `Success`

```ruby
result = GreetingCommand.call("Hello, World!")

puts result.success? # Outputs: true
puts result.failure? # Outputs: false

puts result.success  # Outputs: "HELLO, WORLD!"
puts result.failure  # Outputs: nil

puts result.value    # Outputs: "HELLO, WORLD!"
puts result.result   # Outputs: HatiCommand::Success
```

### Handling `Failure`

```ruby
result = GreetingCommand.call

puts result.failure? # Outputs: true
puts result.success? # Outputs: false

puts result.failure  # Outputs: "No message provided"
puts result.success  # Outputs: nil

puts result.value    # Outputs: "No message provided"
puts result.result   # Outputs: HatiCommand::Failure
```

### Transactional Behavior: Fail Fast with `Failure!`

```ruby
class GreetingCommand
  include HatiCommand::Cmd

  # NOTE: Will catch unexpected and wrap to HatiCommand::Failure object
  #       Requires true || ErrorObject
  command do
    unexpected_err true
  end

  def call(params)
    message = process_message(params[:message])
    msg = normalize_message(message, params[:recipients])

    Success(msg)
  end

  # NOTE: No message passed - auto break an execution
  def process_message(message)
    message ? message.upcase : Failure!("No message provided")
  end

  def normalize_message(message, recipients)
    Failure!("No recipients provided") if recipients.empty?

    recipients.map { |recipient| "#{recipient}: #{message}" }
  end
end
```

```ruby
# NOTE: No message passed - command exited
#       Returns Result (Failure) object
result = GreetingCommand.call

puts result.failure? # Outputs: true
puts result.failure  # Outputs: "No message provided"
puts result.value    # Outputs: "No message provided"
```

```ruby

result = GreetingCommand.call(params.merge(message: "Hello!"))

puts result.failure? # Outputs: true
puts result.failure  # Outputs: "No recipients provided"
puts result.value    # Outputs: "No recipients provided"
```

```ruby
result = GreetingCommand.call(params.merge(recipients: ["Alice", "Bob"]))

puts result.failure? # Outputs: false
puts result.success  # Outputs: true
puts result.value    # Outputs: ["Alice: Hello!", "Bob: Hello!"]
```

## Advanced Usage

Configurations and customization allow users to tailor the command to meet their specific needs and preferences

### `Result` Customization

Here are some advanced examples of result customization. Available options are

- `meta` - Hash to attach custom metadata
- `err` - Message or Error access via `error` method
- `trace` - By design `Failure!` and `unexpected_err` error's stack top entry

### .meta

```ruby
class GreetingCommand
  include HatiCommand::Cmd
  # ...
  def process_message(message)
    Success(message.upcase, meta: { lang: :eng, length: message.length })
  end
  # ...
end
```

```ruby
result = GreetingCommand.("Hello, Advanced World!")
puts result.value         # Outputs: "HELLO, ADVANCED WORLD!"

puts result.meta[:lang]   # Outputs: :eng
puts result.meta[:length] # Outputs: 22
puts result.meta          # Outputs: {:lang=>:eng, :length=>22}
```

### .error

##### set via `err` access via `error` method. Availiable as param for `#Success` as well (ex. partial success)

```ruby
class GreetingCommand
  include HatiCommand::Cmd
  # ...
  def process_message(message)
    Failure(message, err: "No message provided")
  end
end
```

```ruby
result = GreetingCommand.call
puts result.value   # Outputs: nil
puts result.error   # Outputs: "No message provided"
puts result.trace   # Outputs:
```

### .trace

##### Available as accessor on `Result` object

```ruby
1| class DoomedCommand
2|   include HatiCommand::Cmd
3|
4|   def call
5|     Failure!
6|   end
7|   # ...
8| end
```

```ruby
result = GreetingCommand.call
puts result.failure? # Outputs: true
puts result.trace    # Outputs: path/to/cmds/doomed_command.rb:5:in `call'
```

### Command `Configurations`

Provides options for default failure message or errors. Available configs are:

- `result_inference`(Bool(true)) => implicit Result wrapper
- `call_as`(Symbol[:call]) => Main call method name
- `failure`(String | ErrorClass) => Message or Error
- `fail_fast`(String || ErrorClass) => Message or Error
- `unexpected_err`(Bool[true]) => Message or Error

#### Native DB Active Record Transaction:

- `ar_transaction`(Array[Symbol], returnable: Bool[true]) => methods to wrap in Transaction, requires 'activerecord'

```ruby
class AppService
  include HatiCommand::Cmd

  command do
    result_inference true
    call_as :perform
    failure "Default Error"
    fail_fast "Default Fail Fast Error"
    unexpected_err BaseServiceError
  end

  # ...
end

class PaymentService < AppService
  command do
    ar_transaction :perform
    unexpected_err PaymentServiceTechnicalError
  end

  def perform(params)
    account = Account.lock.find(user_id)
    Failure("User account is inactive") unless user.active?

    CreditTransaction.create!(user_id: user.id, amount: amount)
    AuditLog.create!(action: 'add_funds', account: account)

    Success('Funds has been add to account')
  end

  # ...
end

```

### result_inference

```ruby
class GreetingCommand
  include HatiCommand::Cmd

  command do
    result_inference true # Implicitly wraps non-Result as Success
  end

  def call
    42
  end
  # ...
end
```

```ruby
result = GreetingCommand.call
puts result.success  # Outputs: 42
puts result.failure? # Outputs: false
```

### call_as

```ruby
class GreetingCommand
  include HatiCommand::Cmd

  command do
    call_as :execute # E.q. :perform, :run, etc.
  end

  def execute
    Success(42)
  end
  # ...
end
```

```ruby
result = GreetingCommand.execute
puts result.success  # Outputs: 42
puts result.failure? # Outputs: false
```

### failure

```ruby
1 | class DoomedCommand
2 |   include HatiCommand::Cmd
3 |
4 |   command do
5 |     failure "Default Error"
6 |   end
7 |
8 |   def call(error = nil, fail_fast: false)
9 |     Failure! if fail_fast
10|
11|     return Failure("Foo") unless option
12|
13|     Failure(error, err: "Insufficient funds")
14|   end
15|   # ...
16| end
```

NOTE: not configured fail fast uses default error

```ruby
result = DoomedCommand.call(fail_fast: true)

puts result.failure # Outputs: nil
puts result.error   # Outputs: "Default Error"
puts result.trace   # Outputs: path/to/cmds/doomed_command.rb:5:in `call'


result = DoomedCommand.call
puts result.failure # Outputs: "Foo"
puts result.error   # Outputs: "Default Error"

result = DoomedCommand.call('Buzz')
puts result.failure # Outputs: "Buzz"
puts result.error   # Outputs: "Insufficient funds"
```

### fail_fast

```ruby
1 | class DoomedCommand
2 |   include HatiCommand::Cmd
3 |
4 |   command do
5 |     fail_fast "Default Fail Fast Error"
6 |   end
7 |
8 |   def call
9 |     Failure!
10|   end
11|   # ...
12| end
```

```ruby
result = DoomedCommand.call
puts result.failure # Outputs: nil
puts result.error   # Outputs: "Default Fail Fast Error"
puts result.trace   # Outputs: path/to/cmds/doomed_command.rb:9:in `call'
```

### unexpected_err

```ruby
1 | class GreetingCommand
2 |   include HatiCommand::Cmd
3 |
4 |   command do
5 |     unexpected_err true
5 |   end
6 |
7 |   def call
8 |     1 + "2"
9 |   end
10|   # ...
11| end
```

```ruby
result = GreetingCommand.call
puts result.failure # Outputs: nil
puts result.error   # Outputs: TypeError: no implicit conversion of Integer into String
puts result.trace   # Outputs: path/to/cmds/greeting_command.rb:9:in `call'
```

### unexpected_err (wrapped)

```ruby
1 | class GreetingCommand
2 |   include HatiCommand::Cmd
3 |
4 |   class GreetingError < StandardError; end
5 |
6 |   command do
7 |     unexpected_err GreetingError
8 |   end
9 |
10|   def call
11|     1 + "2"
12|   end
13|   # ...
14| end
```

NOTE: Original error becomes value (failure)

```ruby
result = GreetingCommand.call

puts result.failure # Outputs: TypeError: no implicit conversion of Integer into String
puts result.error   # Outputs: GreetingError
puts result.trace   # Outputs: path/to/cmds/greeting_command.rb:12:in `call'
```

### ar_transaction

Wraps listed methods in Transaction with blocking non-Result returns.
At this dev stage relies on 'activerecord'

- NOTE: considering extensicve expirience of usage, we recomend to use some naming convention
  across codebase for such methods, to keep healthy Elegance-to-Explicitness ratio

  #### E.g. suffixes: \_flow, \_transaction, \_task, etc.

- NOTE: `Failure()` works as transaction break, returns only from called method's as Result (Failure) object

- NOTE: `Failure!()` works on Service level same fail_fast immediately halts execution, return from

- NOTE: Unlike `ActiveRecord::Transaction` Implicit non-Result returns will trigger `TransactionError`,
  blocking partial commit state unless:

```ruby
  ar_transaction :transactional_method_name, returnable: false # Defaults to true
```

### Pseudo-Example:

```ruby
  class PaymentService < AppService
    command do
      ar_transaction :add_funds_transaction
      unexpected_err PaymentServiceTechnicalError
    end

    def call(params)
      amount = currency_exchange(params[:amount])
      debit_transaction = add_funds_transaction(amount)

      return debit_transaction if debit_transaction.success?

      Failure(debit_transaction, err: 'Unable to add funds')
    end

    def currency_exchange
      # ...
    end

    # Whole method evaluates in ActiveRecord::Transaction block
    def add_funds_transaction(amount)
      account = Account.lock.find(user_id)
      Failure("User account is inactive") unless user.active?

      # Fires TransactionError, unless :returnable configuration is disabled
      return 'I am an Error'

      user.balance += amount
      user.save
      Failure('Account debit issue') if user.errors

      CreditTransaction.create!(user_id: user.id, amount: amount)
      AuditLog.create!(action: 'add_funds', account: account)

      # NOTE: result inference won't work, use only Result objects
      Success('Great Succeess')
    end

  # ...
  end
```

## Authors
- [Marie Giy](https://github.com/mariegiy)

## Contributors
- [yurigitsu](https://github.com/yurigitsu) 

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/hackico-ai/hati-command. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/hackico-ai/hati-command/blob/main/CODE_OF_CONDUCT.md).

## License

The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).

## Code of Conduct

Everyone interacting in the HatCommand project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hackico-ai/hati-command/blob/main/CODE_OF_CONDUCT.md).


================================================
FILE: hati-command.gemspec
================================================
# frozen_string_literal: true

lib = File.expand_path('lib', __dir__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)

require 'hati_command/version'

Gem::Specification.new do |spec|
  spec.name    = 'hati-command'
  spec.version = HatiCommand::VERSION
  spec.authors = ['Mariya Giy', 'Yuri Gi']
  spec.email   = %w[yurigi.pro@gmail.com giy.mariya@gmail.com]
  spec.license = 'MIT'

  spec.summary = 'A Ruby gem for creating modular, agent-ready service objects and command-pattern interactors, following Railway-oriented design principles with structured, explicit result handling.'
  spec.description = 'hati-command offers a clear, minimal abstraction for implementing composable service objects and command-pattern interactors. By enforcing explicit Success and Failure result pathways, it aligns well with autonomous system pipelines, decision-chain architectures, and AI-driven orchestration flows.'
  spec.homepage    = "https://github.com/hackico-ai/#{spec.name}"

  spec.required_ruby_version = '>= 3.0.0'

  spec.files  = Dir['CHANGELOG.md', 'LICENSE', 'README.md', 'hati-command.gemspec', 'lib/**/*']
  spec.bindir = 'bin'
  spec.executables   = []
  spec.require_paths = ['lib']

  spec.metadata['repo_homepage']     = spec.homepage
  spec.metadata['allowed_push_host'] = 'https://rubygems.org'

  spec.metadata['homepage_uri']    = spec.homepage
  spec.metadata['changelog_uri']   = "#{spec.homepage}/blob/main/CHANGELOG.md"
  spec.metadata['source_code_uri'] = spec.homepage
  spec.metadata['bug_tracker_uri'] = "#{spec.homepage}/issues"

  spec.metadata['rubygems_mfa_required'] = 'true'
end


================================================
FILE: lib/hati/command.rb
================================================
# frozen_string_literal: true

# Compatibility shim for Bundler auto-require
require_relative '../hati_command'


================================================
FILE: lib/hati_command/befehl.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities for creating and managing commands.
# This module serves as the main namespace for all command-related operations.
module HatiCommand
  # @module Befehl
  # Core module for command handling that provides the base functionality for creating commands.
  # This module is designed to be extended by classes that need command handling capabilities.
  module Befehl
    # Extends the base class with command handling functionality
    # @param base [Class] the class that is extending this module
    # @return [void]
    def self.extended(base)
      base.extend(BefehlClassMethods)
      def base.inherited(subclass)
        super
        subclass.instance_variable_set(:@__command_config, @__command_config.dup)
      end
    end

    # @module BefehlClassMethods
    # Provides class methods for command configuration and execution.
    # These methods are automatically added to any class that extends Befehl.
    module BefehlClassMethods
      # @module namespace as alias
      ERR = HatiCommand::Errors

      # Configures a command block with specific settings
      # @yield [void] The configuration block
      # @return [Hash] The command configuration
      # @example
      #   command do
      #     failure :my_failure_handler
      #     fail_fast true
      #   end
      def command(&block)
        instance_eval(&block) if block_given?
      end

      # @return [Hash] The current command configuration settings
      def command_config
        __command_config
      end

      # Sets the result inference behavior for the command.
      # @param value [Boolean] Indicates whether to enable result inference.
      # @return [void]
      def result_inference(value)
        command_config[:result_inference] = value
      end

      # Sets the failure handler for the command
      # @param value [Symbol, Proc] The failure handler to be used
      # @return [void]
      def failure(value)
        command_config[:failure] = value
      end

      # Sets the fail-fast behavior for the command
      # @param value [Boolean] Whether to enable fail-fast behavior
      # @return [void]
      def fail_fast(value)
        command_config[:fail_fast] = value
      end

      # Sets the unexpected error handler for the command
      # @param value [Symbol, Proc, Boolean] The error handler to be used
      # @return [void]
      def unexpected_err(value)
        command_config[:unexpected_err] = value
      end

      # This method checks if a caller method has been set; if not, it defaults to `:call`.
      # @return [Symbol] The name of the method to call.
      def call_as(value = :call)
        command_config[:call_as] = value

        singleton_class.send(:alias_method, value, :call)
      end

      # WIP: experimental
      # TODO: set of methods
      def ar_transaction(*cmd_methods, returnable: true)
        has_ar_defined = defined?(ActiveRecord::Base) && ActiveRecord::Base.respond_to?(:transaction)
        raise ERR::ConfigurationError, 'No ActiveRecord defined' unless has_ar_defined

        has_valid_mthds = cmd_methods.any? { |value| value.is_a?(Symbol) }
        raise ERR::ConfigurationError, 'Invalid types. Accepts Array[Symbol]' unless has_valid_mthds

        command_config[:ar_transaction] = {
          methods: cmd_methods,
          returnable: returnable
        }

        dynamic_module = Module.new do
          cmd_methods.each do |method_name|
            define_method(method_name) do |*args, **kwargs, &block|
              rez = ActiveRecord::Base.transaction do
                result = super(*args, **kwargs, &block)

                # Rollbacks to prevent partial transaction state
                if returnable && !result.is_a?(HatiCommand::Result)
                  raise ERR::ConfigurationError,
                        'This command configuration requires explicit Result-return from transaction'
                end

                # Allows explicit partial commit
                if result.failure?
                  raise ERR::TransactionError.new('Transaction brake has been triggered', failure_obj: result.value)
                end

                result
              end

              rez
            rescue ERR::TransactionError => e
              # TODO: process trace corectly (line of code)
              HatiCommand::Failure.new(e.failure_obj, err: e.message, trace: e.backtrace&.first)
            # Every other error including FailFast goes to main caller method
            rescue ActiveRecord::ActiveRecordError => e
              # TODO: process trace
              HatiCommand::Failure.new(e, err: e.message, trace: e.backtrace&.first)
            end
          end
        end

        prepend dynamic_module
      end

      # Executes the command with the given arguments.
      #
      # This method creates a new instance of the command class, yields it to an optional block,
      # and then calls the instance method with the provided arguments. It handles the result
      # of the command execution, returning a success or failure result based on the outcome.
      #
      # @param args [Array] Arguments to be passed to the instance method.
      # @yield [Object] Optional block that yields the new instance for additional configuration.
      # @return [HatiCommand::Result, Object] The result of the command, wrapped in a Result object if applicable.
      # @raise [HatiCommand::Errors::FailFastError] If a fail-fast condition is triggered.
      # @raise [StandardError] If an unexpected error occurs and no handler is configured.
      def call(*args, __command_reciever: nil, **kwargs, &block)
        result = caller_result(*args, __command_reciever: __command_reciever, **kwargs, &block)

        return result unless command_config[:result_inference]
        return result if result.is_a?(HatiCommand::Result)

        HatiCommand::Success.new(result)
      rescue ERR::FailFastError => e
        handle_fail_fast_error(e)
      rescue StandardError => e
        handle_standard_error(e)
      end

      # TODO: think on opts to hide reciever
      def caller_result(*args, __command_reciever: nil, **kwargs, &block)
        # expecting pre-configured reciever if given
        if __command_reciever
          obj = __command_reciever
        else
          obj = new
          yield(obj) if !obj && block_given?
        end

        # TODO: add error if no instance method to call
        obj.send(command_config[:call_as] || :call, *args, **kwargs, &block)
      end

      module_function

      # @return [Hash] The current command configuration settings
      # @api private
      def __command_config
        @__command_config ||= {}
      end

      # Handles fail-fast errors during command execution
      # @param error [HatiCommand::Errors::FailFastError] The fail-fast error to handle
      # @return [HatiCommand::Failure] A failure object containing error details
      # @api private
      def handle_fail_fast_error(error)
        failure_obj = error.failure_obj
        return HatiCommand::Failure.new(error, trace: error.backtrace.first) unless failure_obj

        failure_obj.tap { |err| err.trace = error.backtrace[1] }
      end

      # Handles standard errors during command execution
      # @param error [StandardError] The error to handle
      # @return [HatiCommand::Failure] A failure object containing error details
      # @raise [StandardError] If no unexpected error handler is configured
      # @api private
      def handle_standard_error(error)
        internal_err = command_config[:unexpected_err]
        raise error unless internal_err

        err = internal_err.is_a?(TrueClass) ? error : internal_err
        HatiCommand::Failure.new(error, err: err, trace: error.backtrace.first)
      end

      def execute_with_transaction_handling?
        has_ar_defined = defined?(ActiveRecord::Base) && ActiveRecord::Base.respond_to?(:transaction)

        !!(command_config.dig(:ar_transaction, :methods) && has_ar_defined)
      end
    end
  end
end


================================================
FILE: lib/hati_command/callee.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities and callable patterns.
module HatiCommand
  # @module Callee
  # Module for adding callable functionality to a class.
  # This module implements the callable pattern, allowing classes to be called like functions
  # while maintaining object-oriented principles.
  #
  # @example
  #   class MyCallable
  #     include HatiCommand::Callee
  #
  #     def call(input)
  #       # Process input
  #       input.upcase
  #     end
  #   end
  #
  #   # Can be used as:
  #   result = MyCallable.call("hello")  # => "HELLO"
  #
  #   # Or with a block:
  #   MyCallable.call("hello") do |instance|
  #     instance.configure(some: :option)
  #   end
  module Callee
    # Extends the including class with callable functionality
    # @param base [Class] The class including this module
    # @return [void]
    # @api private
    def self.included(base)
      base.extend(CalleeClassMethods)
    end

    # Returns the identity of the module
    # @note This is a work in progress method
    # @return [String] The module's identity string
    # @api public
    def self.whoami
      'My Name is Callee'
    end

    # @module CalleeClassMethods
    # Class methods that are extended to classes including Callee.
    # Provides the callable interface at the class level.
    module CalleeClassMethods
      # This method checks if a caller method has been set; if not, it defaults to `:call`.
      #
      # @return [Symbol] The name of the method to call.
      def __caller_method
        @__caller_method || :call
      end

      # Creates a new instance and calls its `call` method with the given arguments.
      # This method implements the callable pattern, allowing the class to be used
      # like a function while maintaining object-oriented principles.
      #
      # @param args [Array] Arguments to be passed to the instance's call method
      # @yield [Object] Optional block that yields the new instance before calling
      # @yieldparam instance [Object] The newly created instance
      # @return [Object] The result of the instance method call
      #
      # @example Without block
      #   MyCallable.call(arg1, arg2)
      # @example With configuration block
      #   MyCallable.call(input) do |instance|
      #     instance.configure(option: value)
      #   end
      def call(...)
        obj = new

        yield(obj) if block_given?

        obj.send(__caller_method, ...)
      end

      # This method allows you to configure command call method name such as: :execute, :perform, etc.
      # Note: method call_as and command main instance method should much
      # @param method_name [Symbol] The name of the alias to create for the `call` method.
      # @return [void]
      #
      #  @example
      #   class MyCallable
      #     include HatiCommand::Callee
      #
      #     call_as :execute # :run, :perform, etc.
      #
      #     def execute(input) # :run, :perform, etc.
      #       input.upcase
      #     end
      #
      #   end
      #   MyCallable.execute("hello")  # => "HELLO"
      #   MyCallable.perform("hello")  # => "HELLO"
      #   MyCallable.run("hello")  # => "HELLO"
      def call_as(method_name)
        @__caller_method = method_name

        singleton_class.send(:alias_method, method_name, :call)
      end
    end
  end
end


================================================
FILE: lib/hati_command/cmd.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities with a focus on Railway-oriented programming.
# This module implements the Railway pattern for better error handling and command flow control.
module HatiCommand
  # @module Cmd
  # Dev-friendly extension of the Befehl core module with Railway track API.
  # This module provides a Railway-oriented programming interface for handling success and failure states
  # in a functional way, making it easier to chain operations and handle errors gracefully.
  #
  # @example
  #   class MyCommand
  #     include HatiCommand::Cmd
  #
  #     def call(input)
  #       if valid?(input)
  #         Success(input)
  #       else
  #         Failure("Invalid input")
  #       end
  #     end
  #   end
  module Cmd
    # Includes the module in the base class and sets up necessary configurations
    # @param base [Class] The class including this module
    # @return [void]
    def self.included(base)
      base.extend(HatiCommand::Befehl)
      base.private_class_method :new
    end

    # Returns the identity of the module
    # @note This is a work in progress method
    # @return [String] The module's identity string
    # @api public
    def self.whoami
      'My Name is Cmd'
    end

    # Creates a Success monad representing a successful operation
    # @param value [Object, nil] The value to wrap in the Success monad
    # @param err [Object, nil] Optional error object
    # @param meta [Hash] Additional metadata for the success state
    # @return [HatiCommand::Success] A Success monad containing the result
    # @example
    #   Success("Operation completed", meta: { time: Time.now })
    def Success(value = nil, err: nil, meta: {}) # rubocop:disable Naming/MethodName
      HatiCommand::Success.new(value, err: err, meta: meta)
    end

    # Creates a Failure monad representing a failed operation
    # @param value [Object, nil] The value to wrap in the Failure monad
    # @param err [Object, nil] Optional error object (falls back to configured default)
    # @param meta [Hash] Additional metadata for the failure state
    # @return [HatiCommand::Failure] A Failure monad containing the error details
    # @example
    #   Failure("Operation failed", err: StandardError.new, meta: { reason: "invalid_input" })
    def Failure(value = nil, err: nil, meta: {}) # rubocop:disable Naming/MethodName
      default_err = self.class.command_config[:failure]
      HatiCommand::Failure.new(value, err: err || default_err, meta: meta)
    end

    # Creates a Failure monad and immediately raises a FailFastError
    # @param value [Object, nil] The value to wrap in the Failure monad
    # @param err [Object, nil] Optional error object (falls back to configured defaults)
    # @param meta [Hash] Additional metadata for the failure state
    # @param _opts [Hash] Additional options (currently unused)
    # @raise [HatiCommand::Errors::FailFastError] Always raises with the created Failure monad
    # @example
    #   Failure!("Critical error", err: FatalError.new)
    def Failure!(value = nil, err: nil, meta: {}, **_opts) # rubocop:disable Naming/MethodName
      default_error = self.class.command_config[:fail_fast] || self.class.command_config[:failure]
      error = err || default_error

      failure_obj = HatiCommand::Failure.new(value, err: error, meta: meta)
      raise HatiCommand::Errors::FailFastError.new('Fail Fast Triggered', failure_obj: failure_obj)
    end
  end
end


================================================
FILE: lib/hati_command/errors/base_error.rb
================================================
# frozen_string_literal: true

module HatiCommand
  module Errors
    # Custom BaseError class for command issues scenarios in HatiCommand
    #
    # @example Raising a BaseError with a message
    #   raise HatiCommand::Error::BaseError, "Operation failed"
    class BaseError < StandardError
      DEFAULT_MSG = 'Default message: Oooops! Something went wrong. Please check the logs.'

      attr_reader :failure_obj

      # @param message [String] The error message
      # @param failure_obj [Object] An optional Error || Failure DTO
      def initialize(message = nil, failure_obj: nil)
        msg = build_msg + (message || default_message)
        super(msg)
        @failure_obj = failure_obj
      end

      def error_klass
        self.class.name
      end

      def build_msg
        "[#{error_klass}] "
      end

      def default_message
        DEFAULT_MSG
      end
    end
  end
end


================================================
FILE: lib/hati_command/errors/configuration_error.rb
================================================
# frozen_string_literal: true

module HatiCommand
  module Errors
    # Custom error class for configuration issues scenarios in HatiCommand
    class ConfigurationError < BaseError
      def default_message
        'Invalid configurations'
      end
    end
  end
end


================================================
FILE: lib/hati_command/errors/fail_fast_error.rb
================================================
# frozen_string_literal: true

module HatiCommand
  module Errors
    # Custom error class for FailFast scenario in HatiCommand
    class FailFastError < BaseError
      def default_message
        'Halt Execution'
      end
    end
  end
end


================================================
FILE: lib/hati_command/errors/transaction_error.rb
================================================
# frozen_string_literal: true

module HatiCommand
  module Errors
    # Custom error class for Transaction issue scenarios in HatiCommand
    class TransactionError < BaseError
      def default_message
        'Transaction Error has been triggerd'
      end
    end
  end
end


================================================
FILE: lib/hati_command/failure.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities and result objects.
module HatiCommand
  # @class Failure
  # Represents a failure result in the Result pattern.
  # This class is used to wrap failure values and provide a consistent interface
  # for handling both successful and failed operations.
  #
  # The Failure class is part of the Result pattern implementation, working alongside
  # the Success class to provide a type-safe way to handle operation outcomes.
  #
  # @example Basic usage
  #   failure = HatiCommand::Failure.new("Operation failed")
  #   failure.failure?  # => true
  #   failure.success?  # => false
  #
  # @example With error and metadata
  #   error = StandardError.new("Database connection failed")
  #   failure = HatiCommand::Failure.new(
  #     "Could not save record",
  #     err: error,
  #     meta: { attempted_at: Time.now }
  #   )
  #
  # @example Pattern matching
  #   case result
  #   when HatiCommand::Failure
  #     handle_error(result.failure)
  #   end
  #
  # @see HatiCommand::Success
  # @see HatiCommand::Result
  class Failure < Result
    # Returns the failure value wrapped by this Failure instance.
    # This method provides access to the actual error value or message
    # that describes why the operation failed.
    #
    # @return [Object] The wrapped failure value
    # @example
    #   failure = Failure.new("Database error")
    #   failure.failure  # => "Database error"
    def failure
      value
    end

    # Indicates that this is a failure result.
    # This method is part of the Result pattern interface and always
    # returns true for Failure instances.
    #
    # @return [Boolean] Always returns true
    # @example
    #   failure = Failure.new("Error")
    #   failure.failure?  # => true
    def failure?
      true
    end

    # Returns nil since a Failure has no success value.
    # This method is part of the Result pattern interface and always
    # returns nil for Failure instances.
    #
    # @return [nil] Always returns nil
    # @example
    #   failure = Failure.new("Error")
    #   failure.success  # => nil
    def success
      nil
    end

    # Indicates that this is not a success result.
    # This method is part of the Result pattern interface and always
    # returns false for Failure instances.
    #
    # @return [Boolean] Always returns false
    # @example
    #   failure = Failure.new("Error")
    #   failure.success?  # => false
    def success?
      false
    end

    # Returns the symbolic representation of this result type.
    # Useful for pattern matching and result type checking.
    #
    # @return [Symbol] Always returns :failure
    # @api public
    # @example
    #   failure = Failure.new("Error")
    #   failure.to_sym  # => :failure
    def to_sym
      :failure
    end
  end
end


================================================
FILE: lib/hati_command/result.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities and result objects.
module HatiCommand
  # @class Result
  # Base class for the Result pattern implementation.
  # This class serves as the foundation for Success and Failure result types,
  # providing common functionality and a consistent interface for handling
  # operation outcomes.
  #
  # The Result pattern helps in handling operation outcomes in a type-safe way,
  # making it explicit whether an operation succeeded or failed, and carrying
  # additional context like error messages and metadata.
  #
  # @abstract Subclass and override {#to_sym} to implement a concrete result type
  #
  # @example Basic usage
  #   result = HatiCommand::Result.new("Operation output")
  #   result.value  # => "Operation output"
  #
  # @example With error and metadata
  #   result = HatiCommand::Result.new(
  #     "Operation output",
  #     err: "Warning: partial completion",
  #     meta: { duration_ms: 150 }
  #   )
  #
  # @example Using trace information
  #   result = HatiCommand::Result.new("Output", trace: caller(1..1))
  #   result.trace  # => ["path/to/file.rb:42:in `method_name'"]
  #
  # @see HatiCommand::Success
  # @see HatiCommand::Failure
  #
  # @!attribute [r] value
  #   @return [Object] The wrapped value representing the operation's output
  #
  # @!attribute [r] meta
  #   @return [Hash] Additional metadata associated with the result
  #
  # @!attribute [rw] trace
  #   @return [Array<String>, nil] Execution trace information for debugging
  class Result
    attr_reader :value, :meta
    attr_accessor :trace, :err

    # Initializes a new Result instance with a value and optional context.
    #
    # @param value [Object] The value to be wrapped in the result
    # @param err [String, nil] Optional error message or error object
    # @param meta [Hash] Optional metadata for additional context
    # @param trace [Array<String>, nil] Optional execution trace for debugging
    #
    # @example Basic initialization
    #   result = Result.new("Success")
    #
    # @example With full context
    #   result = Result.new(
    #     "Partial success",
    #     err: "Some records failed",
    #     meta: { processed: 10, failed: 2 },
    #     trace: caller
    #   )
    def initialize(value, err: nil, meta: {}, trace: nil)
      @value = value
      @err = err
      @meta = meta
      @trace = trace
    end

    # Returns self to provide a consistent interface across result types.
    # This method ensures that all result objects can be treated uniformly
    # when chaining operations.
    #
    # @return [HatiCommand::Result] The result instance itself
    # @api public
    def result
      self
    end

    # Returns the error associated with this result.
    # This can be used to check for warnings or errors even in successful results.
    #
    # @return [String, nil] The error message or object, if any
    # @raise [StandardError] If accessing the error triggers an error condition
    # @api public
    # @example
    #   result = Result.new("Value", err: "Warning message")
    #   result.error  # => "Warning message"
    def error
      @err
    end

    # Returns the symbolic representation of this result type.
    # This is an abstract method that should be overridden by concrete result types.
    #
    # @return [Symbol] Returns :undefined for the base class
    # @abstract Subclasses must override this method
    # @api public
    # @example
    #   Result.new("value").to_sym  # => :undefined
    def to_sym
      :undefined
    end
  end
end


================================================
FILE: lib/hati_command/success.rb
================================================
# frozen_string_literal: true

# @module HatiCommand
# Provides command handling functionalities and result objects.
module HatiCommand
  # @class Success
  # Represents a successful result in the Result pattern.
  # This class is used to wrap successful operation values and provide a consistent interface
  # for handling both successful and failed operations.
  #
  # The Success class is part of the Result pattern implementation, working alongside
  # the Failure class to provide a type-safe way to handle operation outcomes.
  #
  # @example Basic usage
  #   success = HatiCommand::Success.new("Operation completed")
  #   success.success?  # => true
  #   success.failure?  # => false
  #
  # @example With metadata
  #   success = HatiCommand::Success.new(
  #     { id: 123, name: "Example" },
  #     meta: { duration_ms: 50 }
  #   )
  #   success.success  # => { id: 123, name: "Example" }
  #
  # @example Pattern matching
  #   case result
  #   when HatiCommand::Success
  #     process_data(result.success)
  #   end
  #
  # @see HatiCommand::Failure
  # @see HatiCommand::Result
  class Success < Result
    # Returns the success value wrapped by this Success instance.
    # This method provides access to the actual value or result
    # that was produced by the successful operation.
    #
    # @return [Object] The wrapped success value
    # @example
    #   success = Success.new("Operation output")
    #   success.success  # => "Operation output"
    def success
      value
    end

    # Indicates that this is a success result.
    # This method is part of the Result pattern interface and always
    # returns true for Success instances.
    #
    # @return [Boolean] Always returns true
    # @example
    #   success = Success.new("Result")
    #   success.success?  # => true
    def success?
      true
    end

    # Returns nil since a Success has no failure value.
    # This method is part of the Result pattern interface and always
    # returns nil for Success instances.
    #
    # @return [nil] Always returns nil
    # @example
    #   success = Success.new("Result")
    #   success.failure  # => nil
    def failure
      nil
    end

    # Indicates that this is not a failure result.
    # This method is part of the Result pattern interface and always
    # returns false for Success instances.
    #
    # @return [Boolean] Always returns false
    # @example
    #   success = Success.new("Result")
    #   success.failure?  # => false
    def failure?
      false
    end

    # Returns the symbolic representation of this result type.
    # Useful for pattern matching and result type checking.
    #
    # @return [Symbol] Always returns :success
    # @api public
    # @example
    #   success = Success.new("Result")
    #   success.to_sym  # => :success
    def to_sym
      :success
    end
  end
end


================================================
FILE: lib/hati_command/version.rb
================================================
# frozen_string_literal: true

module HatiCommand
  VERSION = '0.1.2'
end


================================================
FILE: lib/hati_command.rb
================================================
# frozen_string_literal: true

require 'hati_command/version'
# errors
require 'hati_command/errors/base_error'
require 'hati_command/errors/configuration_error'
require 'hati_command/errors/fail_fast_error'
require 'hati_command/errors/transaction_error'
# result
require 'hati_command/result'
require 'hati_command/success'
require 'hati_command/failure'
# core
require 'hati_command/callee'
require 'hati_command/befehl'
# cmd
require 'hati_command/cmd'


================================================
FILE: spec/integration/hati_command/befehl_ar_transaction_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'
require 'support/active_record'

RSpec.describe HatiCommand::Befehl do
  let(:ar_model) { 'Widget' }
  let(:befehl_klass) { support_dummy_befehl('DummyBefehl') }
  let(:ar_command) { 'MyDummyExecBefehl' }

  describe 'ActiveRecord transaction wrapping' do
    before do
      stub_const(ar_model, Class.new(ActiveRecord::Base))

      stub_const(
        ar_command,
        Class.new(befehl_klass) do
          command { ar_transaction :call }

          def call(message)
            Widget.create!(name: message)
            raise ActiveRecord::Rollback if message == :fail

            HatiCommand::Success.new(message)
          end
        end
      )
    end

    it 'commits the transaction on success' do
      expect { MyDummyExecBefehl.call('Widget1') }.to change(Widget, :count).by(1)
    end

    it 'rolls back the transaction on failure' do
      expect do
        MyDummyExecBefehl.call(:fail)
      rescue StandardError
        nil
      end.not_to change(Widget, :count)
    end
  end
end


================================================
FILE: spec/integration/hati_command/befehl_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Befehl do
  let(:befehl_klass) { support_dummy_befehl('DummyBefehl') }

  before do
    stub_const(
      'MyDummyBefehl',
      Class.new(befehl_klass) do
        command do
          fail_fast 'Default Fail Fast message provided'
          unexpected_err true
          result_inference true
        end

        def call(message, fail_fast: false, unexpected_err: false, result_inference: false)
          raise HatiCommand::Errors::FailFastError.new('Fail Fast Triggered') if fail_fast # rubocop:disable Style/RaiseArgs
          raise StandardError if unexpected_err

          result_inference ? message : HatiCommand::Success.new(message)
        end
      end
    )
  end

  describe '.call' do
    let(:result) { MyDummyBefehl.call('Success!') }

    it 'returns success' do
      aggregate_failures 'result' do
        expect(result).to be_a(HatiCommand::Success)
        expect(result.value).to eq('Success!')
        expect(result.error).to be_nil
      end
    end

    context 'when fail_fast is true' do
      let(:result) { MyDummyBefehl.call('This is a fail fast message', fail_fast: true) }

      it 'returns failure' do
        aggregate_failures 'result' do
          expect(result).to be_a(HatiCommand::Failure)
          expect(result.value).to be_a(HatiCommand::Errors::FailFastError)
        end
      end
    end

    context 'when unexpected_err is true' do
      let(:result) { MyDummyBefehl.call('This is a unexpected error message', unexpected_err: true) }

      it 'returns failure' do
        aggregate_failures 'result' do
          expect(result).to be_a(HatiCommand::Failure)
          expect(result.error).to be_a(StandardError)
        end
      end
    end

    context 'when result_inference is true' do
      let(:result) { MyDummyBefehl.call('This is a result inference message', result_inference: true) }

      it 'returns success' do
        expect(result).to be_a(HatiCommand::Success)
      end
    end
  end

  describe 'call configuration' do
    before do
      stub_const(
        'MyDummyExecBefehl',
        Class.new(befehl_klass) do
          command do
            call_as :execute
          end

          def execute(message)
            HatiCommand::Success.new(message)
          end
        end
      )
    end

    describe '.execute' do
      let(:rez_msg) { 'This is a result inference message' }
      let(:result) { MyDummyExecBefehl.execute(rez_msg) }

      it 'returns success' do
        aggregate_failures do
          expect(result).to be_a(HatiCommand::Success)
          expect(result.value).to eq(rez_msg)
        end
      end
    end
  end
end


================================================
FILE: spec/integration/hati_command/callee_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Callee do
  context 'when run command' do
    before do
      stub_const('DummyCallee', Class.new do
        include HatiCommand::Callee

        def call(rez)
          HatiCommand::Success.new(rez)
        end
      end)
    end

    let(:callee_klass) { DummyCallee }

    describe '.call' do
      let(:result) { callee_klass.call('Success!') }

      it 'returns success' do
        expect(result.value).to eq('Success!')
      end
    end
  end

  context 'when call is configured' do
    before do
      stub_const('DummyExecutee', Class.new do
        include HatiCommand::Callee

        call_as :execute

        def execute(rez)
          HatiCommand::Success.new(rez)
        end
      end)
    end

    let(:callee_klass) { DummyExecutee }

    describe '.execute' do
      let(:result) { DummyExecutee.execute('Success!') }

      it 'returns success' do
        expect(result.value).to eq('Success!')
      end
    end
  end
end


================================================
FILE: spec/integration/hati_command/cmd_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Cmd do
  before do
    support_dummy_cmd('BaseDummyCommand')
    support_dummy_error('DummyFailFastError')
    support_dummy_error('DummyInternalError')

    stub_const(
      'DummyCommand',
      Class.new(BaseDummyCommand) do
        command do
          fail_fast 'Default Fail Fast message provided'
          unexpected_err DummyInternalError
        end
      end
    )

    stub_const(
      'MyDummyCommand',
      Class.new(DummyCommand) do
        command do
          fail_fast DummyFailFastError
        end

        def call(greeting = nil, fail_fast: false, unexpected_err: false)
          raise 'Oooooooops' if unexpected_err

          salute = build_greeting(greeting)
          howdy = normalize_salute(salute, fail_fast)

          process_howdy(howdy.value)
        end

        def build_greeting(greeting)
          greeting ? Success(greeting) : Failure(greeting)
        end

        def normalize_salute(salute, fail_fast)
          Failure!(salute) if fail_fast

          salute.success ? Success("#{salute.success}!") : Failure(salute.failure)
        end

        def process_howdy(howdy)
          if howdy
            Success(howdy.upcase, meta: { lang: :eng, length: howdy.length })
          else
            Failure(howdy, err: 'No message provided')
          end
        end
      end
    )
  end

  let(:message) { 'Hello, World' }

  describe '.call' do
    context 'when pipeline success' do
      let(:raw_message) { 'Hello, World' }
      let(:message) { 'Hello, World!' }
      let(:result) { MyDummyCommand.call(raw_message) }

      it 'runs the success command' do
        aggregate_failures 'result' do
          expect(result.value).to eq(message.upcase)
          expect(result.success).to eq(message.upcase)
        end
      end

      it 'returns meta' do
        meta = { lang: :eng, length: message.length }

        expect(result.meta).to eq(meta)
      end
    end

    context 'when pipeline failure' do
      let(:result) { MyDummyCommand.call }

      it 'runs the failure command' do
        aggregate_failures 'result' do
          expect(result).to be_failure
          expect(result.value).to be_nil
        end
      end

      it 'returns message' do
        message = 'No message provided'

        expect(result.error).to eq(message)
      end
    end

    context 'when fail-fast' do
      let(:result) { MyDummyCommand.call(fail_fast: true) }

      it 'returns failure' do
        expect(result.error).to eq(DummyFailFastError)
      end
    end

    context 'when unexpected error' do
      let(:result) { MyDummyCommand.call(unexpected_err: true) }

      it 'returns failure' do
        expect(result.error).to eq(DummyInternalError)
      end
    end
  end
end


================================================
FILE: spec/spec_helper.rb
================================================
# frozen_string_literal: true

require 'bundler/setup'
require 'hati_command'

RSpec.configure do |config|
  config.example_status_persistence_file_path = '.rspec_status'
  config.disable_monkey_patching!
  config.expect_with :rspec do |c|
    c.syntax = :expect
  end

  # performance
  exclude_support_files = ['active_record']

  Dir[File.join('./spec/support/**/*.rb')].each do |support_file|
    next if exclude_support_files.include?(support_file)

    require support_file
  end

  config.include Dummy
end


================================================
FILE: spec/support/active_record.rb
================================================
# frozen_string_literal: true

require 'active_record'

ActiveRecord::Base.establish_connection(
  adapter: 'sqlite3',
  database: ':memory:'
)

ActiveRecord::Schema.define do
  create_table :widgets, force: true do |t|
    t.string :name
    t.timestamps
  end
end


================================================
FILE: spec/support/dummy.rb
================================================
# frozen_string_literal: true

# NOTE: helper names follow convention 'support_<module_name>_<helper_name>'

module Dummy
  def support_dummy_befehl(name)
    stub_const(name, Class.new do
      extend HatiCommand::Befehl
    end)
  end

  def support_dummy_cmd(name)
    stub_const(name, Class.new do
      include HatiCommand::Cmd

      command do
        fail_fast 'Base Fail Fast Message'
      end
    end)
  end

  def support_dummy_error(name)
    stub_const(name, Class.new(StandardError))
  end
end


================================================
FILE: spec/unit/hati_command/befehl_config_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Befehl do
  describe 'command configurations' do
    let(:command_klass) { 'BefehlClass' }
    let(:befehl_klass) { command_klass.constantize }
    let(:command_klass_attr) { 'BefehlClassAttr' }
    let(:befehl_klass_attr) { command_klass_attr.constantize }

    before do
      stub_const(command_klass, Class.new do
        extend HatiCommand::Befehl::BefehlClassMethods

        command do
          call_as :execute
          fail_fast 'Befehl Fail Fast Message'
          failure 'Befehl Failure Message'
          unexpected_err 'Befehl Unexpected Error'
          result_inference true
        end
      end)

      # no block configs
      stub_const(command_klass_attr, Class.new do
        extend HatiCommand::Befehl::BefehlClassMethods

        call_as :execute
        fail_fast 'Befehl Fail Fast Message'
        failure 'Befehl Failure Message'
        unexpected_err 'Befehl Unexpected Error'
        result_inference true
      end)
    end

    describe '.fail_fast' do
      it 'sets the fail_fast config' do
        expect(befehl_klass.command_config[:fail_fast]).to eq('Befehl Fail Fast Message')
      end
    end

    describe '.unexpected_err' do
      it 'sets the unexpected_err config' do
        expect(befehl_klass.command_config[:unexpected_err]).to eq('Befehl Unexpected Error')
      end
    end

    describe '.failure' do
      it 'sets the failure config' do
        expect(befehl_klass.command_config[:failure]).to eq('Befehl Failure Message')
      end
    end

    describe '.result_inference' do
      it 'sets the result_inference config' do
        expect(befehl_klass.command_config[:result_inference]).to be(true)
      end
    end

    describe '.command_config' do
      let(:configs) { befehl_klass.command_config }
      let(:configs_attr) { befehl_klass_attr.command_config }

      it 'returns the configurations' do
        aggregate_failures 'of command options' do
          expect(configs[:fail_fast]).to eq('Befehl Fail Fast Message')
          expect(configs[:failure]).to eq('Befehl Failure Message')
          expect(configs[:unexpected_err]).to eq('Befehl Unexpected Error')
          expect(configs[:result_inference]).to be(true)
          expect(configs[:call_as]).to be(:execute)
        end
      end

      it 'has identical no-block and block configurations' do
        aggregate_failures 'of block and no-block command options' do
          expect(configs[:fail_fast]).to eq(configs_attr[:fail_fast])
          expect(configs[:failure]).to eq(configs_attr[:failure])
          expect(configs[:unexpected_err]).to eq(configs_attr[:unexpected_err])
          expect(configs[:result_inference]).to be(configs_attr[:result_inference])
          expect(configs[:call_as]).to be(configs_attr[:call_as])
        end
      end
    end
  end
end


================================================
FILE: spec/unit/hati_command/callee_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

# WIP: performance extensions
RSpec.describe HatiCommand::Callee do
  subject(:callee_klass) { described_class }

  let(:whoami) { 'My Name is Callee' }

  describe '.whoami' do
    it 'returns the class name' do
      expect(callee_klass.whoami).to eq(whoami)
    end
  end
end


================================================
FILE: spec/unit/hati_command/cmd_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

# WIP: performance extensions
RSpec.describe HatiCommand::Cmd do
  subject(:cmd_klass) { described_class }

  let(:whoami) { 'My Name is Cmd' }

  describe '.whoami' do
    it 'returns the class name' do
      expect(cmd_klass.whoami).to eq(whoami)
    end
  end
end


================================================
FILE: spec/unit/hati_command/errors/base_error_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Errors::BaseError do
  subject(:error_klass) { described_class }

  describe '#initialize' do
    it 'initializes with a message' do
      error = error_klass.new('Operation failed')

      expect(error.message).to eq("[#{error_klass}] Operation failed")
    end

    it 'initializes with a failure object' do
      failure_obj = StandardError.new('Booom!')
      error = error_klass.new('Operation failed', failure_obj: failure_obj)

      expect(error.instance_variable_get(:@failure_obj)).to eq(failure_obj)
    end

    it 'uses the default message if no message is provided' do
      error = error_klass.new

      expect(error.message).to eq("[#{error_klass}] #{error_klass::DEFAULT_MSG}")
    end
  end

  describe '#error_klass' do
    it 'returns the class name' do
      error = error_klass.new

      expect(error.error_klass).to eq(error_klass.name)
    end
  end

  describe '#build_msg' do
    it 'builds the message correctly' do
      error = error_klass.new('Test message')

      expect(error.build_msg).to eq("[#{error_klass}] ")
    end
  end
end


================================================
FILE: spec/unit/hati_command/errors/configuration_error_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Errors::ConfigurationError do
  subject(:error_klass) { described_class }

  it 'inherits from BaseError' do
    expect(error_klass).to be < HatiCommand::Errors::BaseError
  end

  it 'has the correct default message' do
    error = error_klass.new

    expect(error.message).to eq("[#{error_klass}] #{error.default_message}")
  end
end


================================================
FILE: spec/unit/hati_command/errors/fail_fast_error_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Errors::FailFastError do
  subject(:error_klass) { described_class }

  it 'inherits from BaseError' do
    expect(error_klass).to be < HatiCommand::Errors::BaseError
  end

  it 'has the correct default message' do
    error = error_klass.new

    expect(error.message).to eq("[#{error_klass}] #{error.default_message}")
  end
end


================================================
FILE: spec/unit/hati_command/errors/transaction_error_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Errors::TransactionError do
  subject(:error_klass) { described_class }

  it 'inherits from BaseError' do
    expect(error_klass).to be < HatiCommand::Errors::BaseError
  end

  it 'has the correct default message' do
    error = error_klass.new

    expect(error.message).to eq("[#{error_klass}] #{error.default_message}")
  end
end


================================================
FILE: spec/unit/hati_command/failure_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Failure do
  subject(:failure_instance) { described_class.new(value) }

  let(:value) { 'error_value' }

  describe '#initialize' do
    it { is_expected.to have_attributes(value: value) }
  end

  describe '#failure' do
    it { expect(failure_instance.failure).to eq(value) }
  end

  describe '#failure?' do
    it { is_expected.to be_failure }
  end

  describe '#success' do
    it { expect(failure_instance.success).to be_nil }
  end

  describe '#success?' do
    it { expect(failure_instance.success?).to be false }
  end
end


================================================
FILE: spec/unit/hati_command/result_spec.rb
================================================
# frozen_string_literal: true

require 'rspec'

RSpec.describe HatiCommand::Result do
  let(:value) { 'test_value' }

  describe '#initialize' do
    it { expect(described_class.new(value).value).to eq(value) }
  end

  describe '#result' do
    it 'returns result object' do
      result = described_class.new(value)

      expect(result.result).to eq(result)
    end
  end

  describe '#error' do
    it 'returns error' do
      result = described_class.new(value, err: 'test_message')

      expect(result.error).to eq('test_message')
    end
  end

  describe '#meta' do
    it 'returns meta' do
      result = described_class.new(value, meta: { 'test_meta' => 'test_value' })

      expect(result.meta).to eq({ 'test_meta' => 'test_value' })
    end
  end
end


================================================
FILE: spec/unit/hati_command/success_spec.rb
================================================
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe HatiCommand::Success do
  subject(:success_instance) { described_class.new(value) }

  let(:value) { 'success_value' }

  describe '#initialize' do
    it { is_expected.to have_attributes(value: value) }
  end

  describe '#result' do
    it { expect(success_instance.result).to eq(success_instance) }
  end

  describe '#success' do
    it { expect(success_instance.success).to eq(value) }
  end

  describe '#success?' do
    it { expect(success_instance.success?).to be true }
  end

  describe '#failure' do
    it { expect(success_instance.failure).to be_nil }
  end

  describe '#failure?' do
    it { expect(success_instance.failure?).to be false }
  end
end
Download .txt
gitextract_ucqxjbxu/

├── .gitignore
├── .rubocop.yml
├── CODE_OF_CONDUCT.md
├── Gemfile
├── LICENSE
├── README.md
├── hati-command.gemspec
├── lib/
│   ├── hati/
│   │   └── command.rb
│   ├── hati_command/
│   │   ├── befehl.rb
│   │   ├── callee.rb
│   │   ├── cmd.rb
│   │   ├── errors/
│   │   │   ├── base_error.rb
│   │   │   ├── configuration_error.rb
│   │   │   ├── fail_fast_error.rb
│   │   │   └── transaction_error.rb
│   │   ├── failure.rb
│   │   ├── result.rb
│   │   ├── success.rb
│   │   └── version.rb
│   └── hati_command.rb
└── spec/
    ├── integration/
    │   └── hati_command/
    │       ├── befehl_ar_transaction_spec.rb
    │       ├── befehl_spec.rb
    │       ├── callee_spec.rb
    │       └── cmd_spec.rb
    ├── spec_helper.rb
    ├── support/
    │   ├── active_record.rb
    │   └── dummy.rb
    └── unit/
        └── hati_command/
            ├── befehl_config_spec.rb
            ├── callee_spec.rb
            ├── cmd_spec.rb
            ├── errors/
            │   ├── base_error_spec.rb
            │   ├── configuration_error_spec.rb
            │   ├── fail_fast_error_spec.rb
            │   └── transaction_error_spec.rb
            ├── failure_spec.rb
            ├── result_spec.rb
            └── success_spec.rb
Download .txt
SYMBOL INDEX (86 symbols across 16 files)

FILE: lib/hati_command/befehl.rb
  type HatiCommand (line 6) | module HatiCommand
    type Befehl (line 10) | module Befehl
      function extended (line 14) | def self.extended(base)
      type BefehlClassMethods (line 25) | module BefehlClassMethods
        function command (line 37) | def command(&block)
        function command_config (line 42) | def command_config
        function result_inference (line 49) | def result_inference(value)
        function failure (line 56) | def failure(value)
        function fail_fast (line 63) | def fail_fast(value)
        function unexpected_err (line 70) | def unexpected_err(value)
        function call_as (line 76) | def call_as(value = :call)
        function ar_transaction (line 84) | def ar_transaction(*cmd_methods, returnable: true)
        function call (line 142) | def call(*args, __command_reciever: nil, **kwargs, &block)
        function caller_result (line 156) | def caller_result(*args, __command_reciever: nil, **kwargs, &block)
        function __command_config (line 173) | def __command_config
        function handle_fail_fast_error (line 181) | def handle_fail_fast_error(error)
        function handle_standard_error (line 193) | def handle_standard_error(error)
        function execute_with_transaction_handling? (line 201) | def execute_with_transaction_handling?

FILE: lib/hati_command/callee.rb
  type HatiCommand (line 5) | module HatiCommand
    type Callee (line 28) | module Callee
      function included (line 33) | def self.included(base)
      function whoami (line 41) | def self.whoami
      type CalleeClassMethods (line 48) | module CalleeClassMethods
        function __caller_method (line 52) | def __caller_method
        function call (line 71) | def call(...)
        function call_as (line 98) | def call_as(method_name)

FILE: lib/hati_command/cmd.rb
  type HatiCommand (line 6) | module HatiCommand
    type Cmd (line 24) | module Cmd
      function included (line 28) | def self.included(base)
      function whoami (line 37) | def self.whoami
      function Success (line 48) | def Success(value = nil, err: nil, meta: {}) # rubocop:disable Namin...
      function Failure (line 59) | def Failure(value = nil, err: nil, meta: {}) # rubocop:disable Namin...
      function Failure! (line 72) | def Failure!(value = nil, err: nil, meta: {}, **_opts) # rubocop:dis...

FILE: lib/hati_command/errors/base_error.rb
  type HatiCommand (line 3) | module HatiCommand
    type Errors (line 4) | module Errors
      class BaseError (line 9) | class BaseError < StandardError
        method initialize (line 16) | def initialize(message = nil, failure_obj: nil)
        method error_klass (line 22) | def error_klass
        method build_msg (line 26) | def build_msg
        method default_message (line 30) | def default_message

FILE: lib/hati_command/errors/configuration_error.rb
  type HatiCommand (line 3) | module HatiCommand
    type Errors (line 4) | module Errors
      class ConfigurationError (line 6) | class ConfigurationError < BaseError
        method default_message (line 7) | def default_message

FILE: lib/hati_command/errors/fail_fast_error.rb
  type HatiCommand (line 3) | module HatiCommand
    type Errors (line 4) | module Errors
      class FailFastError (line 6) | class FailFastError < BaseError
        method default_message (line 7) | def default_message

FILE: lib/hati_command/errors/transaction_error.rb
  type HatiCommand (line 3) | module HatiCommand
    type Errors (line 4) | module Errors
      class TransactionError (line 6) | class TransactionError < BaseError
        method default_message (line 7) | def default_message

FILE: lib/hati_command/failure.rb
  type HatiCommand (line 5) | module HatiCommand
    class Failure (line 35) | class Failure < Result
      method failure (line 44) | def failure
      method failure? (line 56) | def failure?
      method success (line 68) | def success
      method success? (line 80) | def success?
      method to_sym (line 92) | def to_sym

FILE: lib/hati_command/result.rb
  type HatiCommand (line 5) | module HatiCommand
    class Result (line 44) | class Result
      method initialize (line 65) | def initialize(value, err: nil, meta: {}, trace: nil)
      method result (line 78) | def result
      method error (line 91) | def error
      method to_sym (line 103) | def to_sym

FILE: lib/hati_command/success.rb
  type HatiCommand (line 5) | module HatiCommand
    class Success (line 34) | class Success < Result
      method success (line 43) | def success
      method success? (line 55) | def success?
      method failure (line 67) | def failure
      method failure? (line 79) | def failure?
      method to_sym (line 91) | def to_sym

FILE: lib/hati_command/version.rb
  type HatiCommand (line 3) | module HatiCommand

FILE: spec/integration/hati_command/befehl_ar_transaction_spec.rb
  function call (line 20) | def call(message)

FILE: spec/integration/hati_command/befehl_spec.rb
  function call (line 18) | def call(message, fail_fast: false, unexpected_err: false, result_infere...
  function execute (line 79) | def execute(message)

FILE: spec/integration/hati_command/callee_spec.rb
  function call (line 11) | def call(rez)
  function execute (line 35) | def execute(rez)

FILE: spec/integration/hati_command/cmd_spec.rb
  function call (line 28) | def call(greeting = nil, fail_fast: false, unexpected_err: false)
  function build_greeting (line 37) | def build_greeting(greeting)
  function normalize_salute (line 41) | def normalize_salute(salute, fail_fast)
  function process_howdy (line 47) | def process_howdy(howdy)

FILE: spec/support/dummy.rb
  type Dummy (line 5) | module Dummy
    function support_dummy_befehl (line 6) | def support_dummy_befehl(name)
    function support_dummy_cmd (line 12) | def support_dummy_cmd(name)
    function support_dummy_error (line 22) | def support_dummy_error(name)
Condensed preview — 37 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (73K chars).
[
  {
    "path": ".gitignore",
    "chars": 1271,
    "preview": "*.gem\n*.rbc\n/.config\n/coverage/\n/InstalledFiles\n/pkg/\n/spec/reports/\n/spec/examples.txt\n/test/tmp/\n/test/version_tmp/\n/t"
  },
  {
    "path": ".rubocop.yml",
    "chars": 166,
    "preview": "require:\n  - rubocop-rspec\n  - rubocop-rake\n\nAllCops:\n  NewCops: enable\n  TargetRubyVersion: 3.0\n\nStyle/StringLiteralsIn"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "chars": 5367,
    "preview": "# [hackico-ai] Code of Conduct\n\n## Our Pledge\n\nWe, as members, contributors, and leaders of [Your Community Name], pledg"
  },
  {
    "path": "Gemfile",
    "chars": 272,
    "preview": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\ngemspec\n\ngem 'rake'\n\n# Spec\ngem 'activerecord'\ngem 'rspec'"
  },
  {
    "path": "LICENSE",
    "chars": 1067,
    "preview": "MIT License\n\nCopyright (c) 2025 hackico.ai\n\nPermission is hereby granted, free of charge, to any person obtaining a copy"
  },
  {
    "path": "README.md",
    "chars": 14859,
    "preview": "# ![Ruby](icon.svg) hati-command\n\nThe `hati-command` gem provides a lightweight framework for structuring logic as discr"
  },
  {
    "path": "hati-command.gemspec",
    "chars": 1616,
    "preview": "# frozen_string_literal: true\n\nlib = File.expand_path('lib', __dir__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?"
  },
  {
    "path": "lib/hati/command.rb",
    "chars": 112,
    "preview": "# frozen_string_literal: true\n\n# Compatibility shim for Bundler auto-require\nrequire_relative '../hati_command'\n"
  },
  {
    "path": "lib/hati_command/befehl.rb",
    "chars": 8102,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities for creating and managi"
  },
  {
    "path": "lib/hati_command/callee.rb",
    "chars": 3397,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities and callable patterns.\n"
  },
  {
    "path": "lib/hati_command/cmd.rb",
    "chars": 3511,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities with a focus on Railway"
  },
  {
    "path": "lib/hati_command/errors/base_error.rb",
    "chars": 903,
    "preview": "# frozen_string_literal: true\n\nmodule HatiCommand\n  module Errors\n    # Custom BaseError class for command issues scenar"
  },
  {
    "path": "lib/hati_command/errors/configuration_error.rb",
    "chars": 269,
    "preview": "# frozen_string_literal: true\n\nmodule HatiCommand\n  module Errors\n    # Custom error class for configuration issues scen"
  },
  {
    "path": "lib/hati_command/errors/fail_fast_error.rb",
    "chars": 243,
    "preview": "# frozen_string_literal: true\n\nmodule HatiCommand\n  module Errors\n    # Custom error class for FailFast scenario in Hati"
  },
  {
    "path": "lib/hati_command/errors/transaction_error.rb",
    "chars": 277,
    "preview": "# frozen_string_literal: true\n\nmodule HatiCommand\n  module Errors\n    # Custom error class for Transaction issue scenari"
  },
  {
    "path": "lib/hati_command/failure.rb",
    "chars": 2873,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities and result objects.\nmod"
  },
  {
    "path": "lib/hati_command/result.rb",
    "chars": 3615,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities and result objects.\nmod"
  },
  {
    "path": "lib/hati_command/success.rb",
    "chars": 2862,
    "preview": "# frozen_string_literal: true\n\n# @module HatiCommand\n# Provides command handling functionalities and result objects.\nmod"
  },
  {
    "path": "lib/hati_command/version.rb",
    "chars": 74,
    "preview": "# frozen_string_literal: true\n\nmodule HatiCommand\n  VERSION = '0.1.2'\nend\n"
  },
  {
    "path": "lib/hati_command.rb",
    "chars": 457,
    "preview": "# frozen_string_literal: true\n\nrequire 'hati_command/version'\n# errors\nrequire 'hati_command/errors/base_error'\nrequire "
  },
  {
    "path": "spec/integration/hati_command/befehl_ar_transaction_spec.rb",
    "chars": 1060,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\nrequire 'support/active_record'\n\nRSpec.describe HatiCommand::Befehl"
  },
  {
    "path": "spec/integration/hati_command/befehl_spec.rb",
    "chars": 2703,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Befehl do\n  let(:befehl_klass) { suppo"
  },
  {
    "path": "spec/integration/hati_command/callee_spec.rb",
    "chars": 1026,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Callee do\n  context 'when run command'"
  },
  {
    "path": "spec/integration/hati_command/cmd_spec.rb",
    "chars": 2818,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Cmd do\n  before do\n    support_dummy_c"
  },
  {
    "path": "spec/spec_helper.rb",
    "chars": 514,
    "preview": "# frozen_string_literal: true\n\nrequire 'bundler/setup'\nrequire 'hati_command'\n\nRSpec.configure do |config|\n  config.exam"
  },
  {
    "path": "spec/support/active_record.rb",
    "chars": 266,
    "preview": "# frozen_string_literal: true\n\nrequire 'active_record'\n\nActiveRecord::Base.establish_connection(\n  adapter: 'sqlite3',\n "
  },
  {
    "path": "spec/support/dummy.rb",
    "chars": 509,
    "preview": "# frozen_string_literal: true\n\n# NOTE: helper names follow convention 'support_<module_name>_<helper_name>'\n\nmodule Dumm"
  },
  {
    "path": "spec/unit/hati_command/befehl_config_spec.rb",
    "chars": 2884,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Befehl do\n  describe 'command configur"
  },
  {
    "path": "spec/unit/hati_command/callee_spec.rb",
    "chars": 333,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\n# WIP: performance extensions\nRSpec.describe HatiCommand::Callee d"
  },
  {
    "path": "spec/unit/hati_command/cmd_spec.rb",
    "chars": 321,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\n# WIP: performance extensions\nRSpec.describe HatiCommand::Cmd do\n "
  },
  {
    "path": "spec/unit/hati_command/errors/base_error_spec.rb",
    "chars": 1149,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Errors::BaseError do\n  subject(:error_"
  },
  {
    "path": "spec/unit/hati_command/errors/configuration_error_spec.rb",
    "chars": 419,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Errors::ConfigurationError do\n  subjec"
  },
  {
    "path": "spec/unit/hati_command/errors/fail_fast_error_spec.rb",
    "chars": 414,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Errors::FailFastError do\n  subject(:er"
  },
  {
    "path": "spec/unit/hati_command/errors/transaction_error_spec.rb",
    "chars": 417,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Errors::TransactionError do\n  subject("
  },
  {
    "path": "spec/unit/hati_command/failure_spec.rb",
    "chars": 616,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Failure do\n  subject(:failure_instance"
  },
  {
    "path": "spec/unit/hati_command/result_spec.rb",
    "chars": 765,
    "preview": "# frozen_string_literal: true\n\nrequire 'rspec'\n\nRSpec.describe HatiCommand::Result do\n  let(:value) { 'test_value' }\n\n  "
  },
  {
    "path": "spec/unit/hati_command/success_spec.rb",
    "chars": 735,
    "preview": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nRSpec.describe HatiCommand::Success do\n  subject(:success_instance"
  }
]

About this extraction

This page contains the full source code of the hackico-ai/ruby-hati-command GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 37 files (66.7 KB), approximately 17.5k tokens, and a symbol index with 86 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!