The hati-command gem is designed to simplify command execution, emphasizing effective handling of success and failure outcomes. It can be employed as a service object or interactor, fostering clean and organized code for managing complex operations.
-
hati-command provides a simple and flexible way to handle command execution and result handling.
-
hati-command offers a
SuccessandFailureresult classes to handle command execution results. -
hati-command It provides a
Resultobject to access the result value, success, and failure, along with options to attach custom messages and metadata for better context.
- Command Execution: Execute commands seamlessly, allowing for optional parameters.
- Success Handling: Provides success responses with transformed messages and additional metadata.
- Failure Handling: Handles failures gracefully, returning informative messages and context.
- Introduction
- Features
- Installation
- Basic Usage
- Advanced Usage
- Development
- Contributing
- License
- Code of Conduct
Install the gem and add to the application's Gemfile by executing:
bundle add hati-commandIf bundler is not being used to manage dependencies, install the gem by executing:
gem install hati-commandTo use the hati-command gem, you can create a command class that includes the HatiCommand::Cmd module. Here’s a simple example:
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 endresult = 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::Successresult = 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::Failureclass 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# 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"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"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!"]Configurations and customization allow users to tailor the command to meet their specific needs and preferences
Here are some advanced examples of result customization. Available options are
meta- Hash to attach custom metadataerr- Message or Error access viaerrormethodtrace- By designFailure!andunexpected_errerror's stack top entry
class GreetingCommand include HatiCommand::Cmd # ... def process_message(message) Success(message.upcase, meta: { lang: :eng, length: message.length }) end # ... endresult = 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}class GreetingCommand include HatiCommand::Cmd # ... def process_message(message) Failure(message, err: "No message provided") end endresult = GreetingCommand.call puts result.value # Outputs: nil puts result.error # Outputs: "No message provided" puts result.trace # Outputs:1| class DoomedCommand 2| include HatiCommand::Cmd 3| 4| def call 5| Failure! 6| end 7| # ... 8| endresult = GreetingCommand.call puts result.failure? # Outputs: true puts result.trace # Outputs: path/to/cmds/doomed_command.rb:5:in `call'Provides options for default failure message or errors. Available configs are:
failure- Message or Errorfail_fast- Message or Errorunexpected_err- Bool(true) or Message or Error
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| endresult = DoomedCommand.call(fail_fast: true) # NOTE: not configured fail fast uses default error 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"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| endresult = 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'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| endresult = 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'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| endresult = GreetingCommand.call # NOTE: Original error becomes value (failure) 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'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.
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.
The gem is available as open source under the terms of the MIT License.
Everyone interacting in the HatCommand project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.