{"id":17472464,"url":"https://github.com/sleeplessbyte/command","last_synced_at":"2025-08-20T23:10:35.034Z","repository":{"id":65609450,"uuid":"136022745","full_name":"SleeplessByte/command","owner":"SleeplessByte","description":" :arrow_forward: Command adds the Command Design Pattern to any Class.","archived":false,"fork":false,"pushed_at":"2023-01-09T18:53:58.000Z","size":33,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-08-12T16:53:31.604Z","etag":null,"topics":["command","pattern"],"latest_commit_sha":null,"homepage":"https://rubygems.org/gems/commande","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SleeplessByte.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-06-04T12:36:21.000Z","updated_at":"2023-01-07T16:07:58.000Z","dependencies_parsed_at":"2023-02-08T13:31:22.040Z","dependency_job_id":null,"html_url":"https://github.com/SleeplessByte/command","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/SleeplessByte/command","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SleeplessByte%2Fcommand","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SleeplessByte%2Fcommand/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SleeplessByte%2Fcommand/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SleeplessByte%2Fcommand/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SleeplessByte","download_url":"https://codeload.github.com/SleeplessByte/command/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SleeplessByte%2Fcommand/sbom","scorecard":{"id":131024,"data":{"date":"2025-08-11","repo":{"name":"github.com/SleeplessByte/command","commit":"9ea7af6231d5b646a576182978623d43e4699f98"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Code-Review","score":0,"reason":"Found 0/24 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 6 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-16T05:15:32.229Z","repository_id":65609450,"created_at":"2025-08-16T05:15:32.229Z","updated_at":"2025-08-16T05:15:32.229Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271400259,"owners_count":24752830,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-20T02:00:09.606Z","response_time":69,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command","pattern"],"created_at":"2024-10-18T17:18:11.791Z","updated_at":"2025-08-20T23:10:35.001Z","avatar_url":"https://github.com/SleeplessByte.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Command\n[![Build Status: master](https://travis-ci.com/SleeplessByte/command.svg?branch=master)](https://travis-ci.com/SleeplessByte/command)\n[![Gem Version](https://badge.fury.io/rb/commande.svg)](https://badge.fury.io/rb/commande)\n[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)\n[![Maintainability](https://api.codeclimate.com/v1/badges/070b90f32c99865db49f/maintainability)](https://codeclimate.com/github/SleeplessByte/command/maintainability)\n\nCommand adds the [Command Design Pattern](https://sourcemaking.com/design_patterns/command) to any `Class`. \n\nThis was based on `Hanami::Interactor`, and started off as adding a direct `call` on the singleton class, before that\nwas added to Hanami's. After working with different interactors and command-style gems, including ways to organize\nunits for execution and without depending on other utility classes, `command` was born.\n\nBecause [`command`](https://rubygems.org/gems/command) has been taken on rubygems (but not updated since 2013), and\n[`commando`](https://rubygems.org/gems/commando) has been taken (but not updated since 2009) and the Dutch `opdracht` is\nprobably not pronounceable by most people using this, I've decided to register this on the French \n[`commande`](https://rubygems.org/gems/commande).\n\nHowever, if you are using this directly from GitHub, you can continue using it as is, without renaming, as long as you\nchange the Gemfile line to `require: 'command'`.\n\n```Ruby\n# Gemfile\ngem 'commande', require: 'command'\n```\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```Ruby\ngem 'commande'\n```\n\nor alternatively if you would like to refer to commande as `Command`:\n\n```Ruby\ngem 'commande', require: 'command'\n```\n\nAnd then execute:\n\n    $ bundle\n\nOr install it yourself as:\n\n    $ gem install commande\n\n## Usage\n\nThere are examples in the code and the tests. Here is a crude and basic example:\n\n```Ruby\nclass FetchSecondInput\n  include Commande\n  \n  output :fetched\n  \n  def call(*args)\n    # always define call\n    self.fetched = args.second \n  end\n  \n  def valid?(*args)\n    args.length == 2\n  end\n  \n  private\n  \n  attr_accessor :fetched\nend\n\nresult = FetchSecondInput.call(42, 'gem')\nresult.successful? # =\u003e true\nresult.fetched # =\u003e 'gem'\n\nresult = FetchSecondInput.call(42, 'gem', 'three is a crowd')\nresult.successful? # =\u003e false\nresult.fetched # =\u003e nil\n```\n\n### Chaining\n\nIf you opt-in to chaining `require 'commande/chain'`, you can create a call chain that chains multiple `Commande`. The\nonly limitation is that you can _only_ use named arguments. This is to ensure breakage on unexpected output, name\nmismatches and collisions.\n\n```ruby\nrequire 'command'\nrequire 'command/chain'\n\nclass StartCommand\n  include Commande\n\n  output :foo, :baz\n\n  def valid?(test:)\n    error! 'test must at least be 3' if test \u003c 3\n\n    true\n  end\n\n  def call(test:)\n    self.foo = 'foo' * test\n    self.not_an_output = 'not_an_output'\n  end\n\n  private\n\n  attr_accessor :foo, :baz, :not_an_output\nend\n\nclass SecondCommand\n  include Commande\n\n  output :result\n\n  def call(foo:, **_opts)\n    self.result = foo\n  end\n\n  private\n\n  attr_accessor :result\nend\n\nchained = Chain.new(StartCommand, SecondCommand).call(test: 3)\n# =\u003e result is successful, and output matches `SecondCommand`\nchained.chain_result.result\n# =\u003e 'foofoofoo'\n\nboomed = Chain.new(StartCommand, SecondCommand).call(test: 2) \n# =\u003e boomed has failed, and output matches nil\nboomed.error\n# =\u003e 'test must at least be 3'\n```\n## Testing\n\nThere are some `Minitest` assertions included in this library.\n\n```Ruby\nrequire 'commande/minitest'\n```\n| Assert | Refute | |\n|:---:|:---:|:---:|\n| `assert_successful(command_result)` | `refute_successful` | passes if the command is successful?\n| `assert_valid(command, *args_for_valid)` | `refute_valid` | passes if the command is valid\n| `assert_with_error(expected, actual)` | `refute_with_error` | passes if the command has a certain error message\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. \nYou can also run `bin/console` for an interactive prompt that will allow you to experiment.\n\nTo install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the \nversion number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, \npush git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).\n\n## Contributing\n\nBug reports and pull requests are welcome on GitHub at [SleeplessByte/commmand](https://github.com/SleeplessByte/command).\nThis project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to\nthe [Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).\n\n## Code of Conduct\n\nEveryone interacting in the Shrine::ConfigurableStorage project’s codebases, issue trackers, chat rooms and mailing\nlists is expected to follow the [code of conduct](https://github.com/SleeplessByte/command/blob/master/CODE_OF_CONDUCT.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsleeplessbyte%2Fcommand","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsleeplessbyte%2Fcommand","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsleeplessbyte%2Fcommand/lists"}