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
================================================
#  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
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
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": "#  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.