{"id":17981383,"url":"https://github.com/javierav/haku","last_synced_at":"2025-10-08T17:15:08.574Z","repository":{"id":41831081,"uuid":"478189741","full_name":"javierav/haku","owner":"javierav","description":"A library for build simple service objects","archived":false,"fork":false,"pushed_at":"2023-10-06T07:12:35.000Z","size":94,"stargazers_count":2,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"development","last_synced_at":"2025-07-06T10:13:58.450Z","etag":null,"topics":["actions","poro","rails","ruby","service-object"],"latest_commit_sha":null,"homepage":"","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/javierav.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-04-05T15:27:04.000Z","updated_at":"2023-07-18T09:11:40.000Z","dependencies_parsed_at":"2024-10-29T18:48:19.746Z","dependency_job_id":null,"html_url":"https://github.com/javierav/haku","commit_stats":{"total_commits":38,"total_committers":2,"mean_commits":19.0,"dds":"0.21052631578947367","last_synced_commit":"defd0ef5aeb7c22b54fb50c8405e41900ff507e5"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/javierav/haku","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javierav%2Fhaku","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javierav%2Fhaku/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javierav%2Fhaku/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javierav%2Fhaku/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/javierav","download_url":"https://codeload.github.com/javierav/haku/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/javierav%2Fhaku/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264010949,"owners_count":23543716,"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","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":["actions","poro","rails","ruby","service-object"],"created_at":"2024-10-29T18:09:43.303Z","updated_at":"2025-10-08T17:15:03.528Z","avatar_url":"https://github.com/javierav.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Haku\n\n![CI](https://github.com/javierav/haku/workflows/CI/badge.svg)\n\nA simple library for build simple service objects.\n\n\n## Status\n\n\u003e :warning: **This project is still experimental, use with caution!**\n\n\n## Installation\n\nAdd this line to your application's Gemfile:\n\n```ruby\ngem 'haku'\n```\n\nAnd then execute:\n\n```shell\nbundle install\n```\n\n\n## Usage\n\n**Haku** is made up of four modules that add functionality to our service objects:\n\n* [Haku::Core](#hakucore)\n* [Haku::Delayable](#hakudelayable)\n* [Haku::Eventable](#hakueventable)\n* [Haku::Resourceable](#hakuresourceable)\n\nAdditionally, it's available the [Haku::Controller](#hakucontroller) module for use in ours Rails controllers.\n\n\n### Haku::Core\n\n```ruby\nclass Users::Update\n  include Haku::Core\n\n  input :user, :attributes\n  on_success :send_email\n\n  def call\n    if user.update(attributes)\n      success! resource: user\n    else\n      failure! resource: user, errors: user.errors\n    end\n  end\n\n  private\n\n  def send_email\n    UserMailer.with(user: user).update.deliver_later\n  end\nend\n\nresponse = Users::Update.call(user: User.first, attributes: { name: \"Javier\" })\n\nresponse.success? # =\u003e true\nresponse.result # =\u003e { resource: \u003cUser id=\"1\" ...\u003e }\nresponse.resource # =\u003e \u003cUser id=\"1\" ...\u003e\n```\n\nAs you can see, if the payload passed to `success!` or `failure!` is a hash, each key of the hash can be accessed\ndirectly in response object.\n\n\n### Haku::Delayable\n\n```ruby\nclass Users::ComputeHours\n  include Haku::Core\n  include Haku::Delayable\n\n  input :user\n\n  def call\n    # compute expensive data for user\n  end\nend\n\nUsers::ComputeHours.delayed.call(user: User.first)\n```\n\nUse `delayed.call` instead of `call` for execute service object in background using `ActiveJob` job.\n\n#### Customize job\n\n```ruby\nUsers::ComputeHours.delayed(job: OtherJob).call(user: User.first)\n```\n\n#### Customize job options\n\n```ruby\nUsers::ComputeHours.delayed(job: OtherJob, queue: :low, priority: 2).call(user: User.first)\n```\n\nYou can pass the same options allowed by ActiveJob\n[set](https://api.rubyonrails.org/v7.0.4/classes/ActiveJob/Core/ClassMethods.html#method-i-set) method:\n\n#### Config options\n\n```ruby\n# config/initializers/haku.rb\n\nHaku.configure do |config|\n  config.job_queue = \"low_priority\"\nend\n```\n\n| Config      | Description                      | Default value |\n|:------------|:---------------------------------|:--------------|\n| `job_queue` | String or Symbol with queue name | `default`     |\n\n\n### Haku::Eventable\n\n```ruby\nclass Users::Update\n  include Haku::Core\n  include Haku::Eventable\n\n  input :user, :attributes\n  event resource: :user\n\n  def call\n    success! resource: user\n  end\nend\n\nUsers::Update.call(user: User.first, attributes: { name: \"Javier\" })\n\n# =\u003e call Event.create(name: \"user:update\", resource: User.first)\n```\n\nThe `name` attribute are calculated using the custom proc from `event_name` config option. You can change it with\n\n```ruby\nevent name: \"custom:name\", resource: :user\n```\n\n#### Properties passed to event model\n\nFor each property passed as payload of `event` class method, it will try to:\n\n1. If is a block, it is called to get the value of property.\n2. If is a symbol, a method is used to get the value of property:\n3. In other case, uses the raw value.\n\n#### Config options\n\n```ruby\n# config/initializers/haku.rb\n\nHaku.configure do |config|\n  config.event_model = \"EventLog\"\nend\n```\n\n| Config                    | Description                                           | Default value                                          |\n|:--------------------------|:------------------------------------------------------|:-------------------------------------------------------|\n| `event_model`             | Name of the model used for create events              | `Event`                                                |\n| `event_property_for_name` | Property used for name in event model                 | `:name`                                                |\n| `event_name`              | String or Proc to determine the event name            | Custom Proc. Returns `user:create` for `Users::Create` |\n\n\n### Haku::Resourceable\n\nThis module include helpers to works with *ActiveRecord* compatible model resources, invoking `success!` or `failure!`\nbased in the result of the performed operation.\n\n```ruby\nclass Users::Update\n  include Haku::Core\n  include Haku::Resourceable\n\n  input :user, :attributes\n  on_success :send_email\n\n  def call\n    update_resource(user, attributes)\n  end\n\n  private\n\n  def send_email\n    UserMailer.with(user: user).update.deliver_later\n  end\nend\n```\n\n#### create_resource\n\nCall to `create` or `\u003csingleton\u003e_create` method of the `parent` object passing the `attributes` and storing\nthe result object in the `ivar` instance variable. Invoke `success!` if the model is persisted or `failure!` in other\ncase.\n\n| parameter    | type     | description                                                      |\n|--------------|----------|------------------------------------------------------------------|\n| `parent`     | `Object` | Parent object where new resource will be created                 |\n| `attributes` | `Hash`   | Attributes for create                                            |\n| `ivar`       | `Symbol` | Name of the instance variable used to access to the new resource |\n| `options`    | `Hash`   | Options hash                                                     |\n\n##### options\n\n| parameter   | type     | description                                                          |\n|-------------|----------|----------------------------------------------------------------------|\n| `singleton` | `Symbol` | If the resource should be created using `\u003csingleton\u003e_create` suffix. |\n\n#### update_resource\n\nCall to `update` method of the `resource` object passing `attributes`to it. Invoke `success!` if the model is updated or\n`failure!` in other case.\n\n| parameter    | type     | description            |\n|--------------|----------|------------------------|\n| `resource`   | `Object` | Resource to be updated |\n| `attributes` | `Hash`   | Attributes to update   |\n\n#### destroy_resource\n\nCall to `destroy` method of the `resource`. Invoke `success!` if the model is destroyed or `failure!` in other case.\n\n| parameter    | type     | description              |\n|--------------|----------|--------------------------|\n| `resource`   | `Object` | Resource to be destroyed |\n\n#### persist_resource\n\n| parameter      | type     | description                                 |\n|----------------|----------|---------------------------------------------|\n| `resource`     | `Object` | Resource to be destroyed                    |\n| `save_options` | `Hash`   | Options passed to `save` method of resource |\n\nFor more info please view the [source code](lib/haku/resourceable.rb) of the module.\n\n\n### Haku::Controller\n\n```ruby\nclass UsersController \u003c ApplicationController\n  include Haku::Controller\n\n  before_action :find_user\n\n  def update\n    execute Users::Update, user: @user, attributes: update_params\n\n    if execution.success?\n      redirect_to user_path(execution.resource)\n    else\n      render :edit, errors: execution.errors\n    end\n  end\n\n  private\n\n  def find_user\n    @user = User.find(params[:id])\n  end\n\n  def update_params\n    params.require(:user).permit(:first_name, :last_name)\n  end\nend\n```\n\n\n### Using parent class\n\n```ruby\nclass ApplicationAction\n  include Haku::Core\n  include Haku::Resourceable\n  include Haku::Eventable\nend\n\nclass Users::Update \u003c ApplicationAction\nend\n```\n\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`.\n\nTo release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`,\nwhich will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to\n[rubygems.org](https://rubygems.org).\n\n\n## Contributing\n\nBug reports and pull requests are welcome, please follow\n[Github Flow](https://docs.github.com/en/get-started/quickstart/github-flow).\n\n\n## Code of Conduct\n\nEveryone interacting in the Haku project's codebases, issue trackers, chat rooms and mailing lists is expected to\nfollow the [code of conduct](https://github.com/javierav/haku/blob/development/CODE_OF_CONDUCT.md).\n\n\n## License\n\nCopyright © 2022-2023 Javier Aranda. Released under the terms of the [MIT license](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavierav%2Fhaku","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjavierav%2Fhaku","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjavierav%2Fhaku/lists"}