{"id":20349521,"url":"https://github.com/datacrafts-io/stepped","last_synced_at":"2025-10-26T05:10:01.112Z","repository":{"id":76184247,"uuid":"283179298","full_name":"datacrafts-io/stepped","owner":"datacrafts-io","description":"Make your services running step-by-step with error handling, logging and easy testing.","archived":false,"fork":false,"pushed_at":"2022-04-25T19:12:10.000Z","size":11,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-04-19T08:04:12.125Z","etag":null,"topics":["gem","ruby","stepped","tools"],"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/datacrafts-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"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":"2020-07-28T10:29:38.000Z","updated_at":"2022-04-25T19:12:13.000Z","dependencies_parsed_at":null,"dependency_job_id":"21ecc984-78f1-4413-bd24-f15cb2e33735","html_url":"https://github.com/datacrafts-io/stepped","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/datacrafts-io/stepped","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacrafts-io%2Fstepped","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacrafts-io%2Fstepped/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacrafts-io%2Fstepped/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacrafts-io%2Fstepped/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datacrafts-io","download_url":"https://codeload.github.com/datacrafts-io/stepped/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datacrafts-io%2Fstepped/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281059632,"owners_count":26437061,"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-10-26T02:00:06.575Z","response_time":61,"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":["gem","ruby","stepped","tools"],"created_at":"2024-11-14T22:26:15.603Z","updated_at":"2025-10-26T05:10:01.080Z","avatar_url":"https://github.com/datacrafts-io.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"![Ruby](https://github.com/datacrafts-io/stepped/workflows/Ruby/badge.svg?branch=master)\n\n# Make your services Stepped\n\n## Installation\n\nadd to your Gemfile:\n```ruby\ngem \"stepped\", github: \"datacrafts-io/stepped\"\n```\n\n## Usage\n\n#### 1. `include Stepped` into your service\n```ruby\nclass ClassName\n  include Stepped\n\n  ...\nend\n```\n\n#### 2. Use `param` and `option` keywords to define initial arguments:\n```ruby\n  class ClassName\n    ...\n\n    param :argument_name,               # reader name\n          -\u003e(value) { value.to_s },     # optional proc for type coercing\n          default: -\u003e { \"some string\" } # optional proc with default value\n\n    ...\n  end\n```\n`param` is used to define arguments, `option` is for keyword arguments\n\n#### 3. Define the Steps:\n- passed params and options are accessed in step blocks\n- by default steps are passing result to next step\n- set optional `pass: false` to cancel passing result of current step to next\n- set optional `cache: true` to save result of current step and access it in another steps later via `step_result(:step_name)`\n- set optional `from: :step_name` to receive arguments from `:step_name` instead of previous step (must be combined with `cache: true` for `from` step)\n- set optional error handler on step `on_failure: [handler]`, `[handler]` is `Proc` or `:method_name` receiving 2 arguments: `:step_name` and `error` instance\n```ruby\n  class ClassName\n    ...\n\n    step :step_one, cache: true do\n      puts \"I'm the step one\"\n      \"Result of Step One\"\n    end\n\n    step :step_two, on_failure: -\u003e(_, err) { ... } do |result_of_prev_step|\n      puts result_of_prev_step # =\u003e Result of Step One\n    end\n\n    step :step_three, from: :step_one do |result_of_step_one|\n      puts result_of_prev_step # =\u003e Result of Step One\n    end\n\n    ...\n  end\n```\n\n\n#### 4. Set optional `on_failure` options (default: `on_failure stop: false, reraise: true`):\n\nFirst optional argument can be `:method_name` or `Proc`:\n```ruby\n  class ClassName\n    ...\n\n    on_failure :error_handler, stop: true,   # stop process on error\n                               reraise: true # reraise error after error handling\n\n    def error_handler(step_name, error)\n      Notifier.call(step_name, error.message)\n    end\n\n    ...\n  end\n```\n\n#### 5. Use optional logger settings for debug or logging:\n```ruby\n  class ClassName\n    ...\n\n    logger on_start: true,    # =\u003e [Stepped] Started ClassName with arguments: (arguments below)\n           before_step: true, # =\u003e [Stepped] Step [step_name] received: (arguments below)\n           after_step: true,  # =\u003e [Stepped] Step [step_name] passed: (arguments below)\n           on_end: true,      # =\u003e [Stepped] ClassName finished and returned: (arguments below)\n           method: Rails.logger.method(:info) # method, proc, service, etc which has method :call with one arg\n\n    ...\n  end\n```\n\n#### 6. Add optional wrapper:\nWrap all steps in block provided by passed arg\n\n```ruby\nclass ClassName\n  ...\n\n  wrap ActiveRecord::Base.method(:transaction) # pass something which has method :call and can receive block\n\n  ...\nend\n```\n\n## Example usage:\n\n```ruby\n  # define class\n  class CreateUser\n    include Stepped\n\n    param :attributes\n    option :available_points, proc(\u0026:to_i), default: -\u003e { 0 }\n\n    on_failure :notify\n\n    step :create_user, cache: true do\n      User.create!(attributes)\n    end\n\n    step :send_email do |user|\n      UserMailer.send_welcome_email(user)\n    end\n\n    step :assign_points, from: :create_user do |user|\n      user.add_points(available_points)\n      user\n    end\n\n    step :notify do |user|\n      SlackNotifier.user_created(user)\n    end\n\n    private\n\n    def notify(step_name, error)\n      SlackNotifier.user_create_error(error)\n    end\n  end\n\n  # use\n  attributes = { name: \"John\", email: \"john@example.com\" }\n\n  service = CreateUser.new(attributes, available_points: 5)\n  service.call\n\n  # or shortly\n\n  CreateUser.call(attributes, available_points: 5)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatacrafts-io%2Fstepped","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatacrafts-io%2Fstepped","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatacrafts-io%2Fstepped/lists"}