Project

cmdx

0.0
A long-lived project that still receives updates
CMDx is a framework for building maintainable business processes.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies
 Project Readme
CMDx Logo CMDx Logo

Build business logic that’s powerful, predictable, and maintainable.

Documentation · Changelog · Report Bug · Request Feature · LLM.md

Version Build License

CMDx

Say goodbye to messy service objects. CMDx helps you design business logic with clarity and consistency—build faster, debug easier, and ship with confidence.

Note

Documentation reflects the latest code on main. For version-specific documentation, please refer to the docs/ directory within that version's tag.

Requirements

  • Ruby: MRI 3.1+ or JRuby 9.4+.

CMDx works with any Ruby framework. Rails support is built-in, but it's framework-agnostic at its core.

Installation

gem install cmdx
# - or -
bundle add cmdx

Quick Example

Build powerful business logic in four simple steps:

1. Compose

# Full-featured task example
# See docs for minimum viable task examples

class AnalyzeMetrics < CMDx::Task
  register :middleware, CMDx::Middlewares::Correlate, id: -> { Current.request_id }

  on_success :track_analysis_completion!

  required :dataset_id, type: :integer, numeric: { min: 1 }
  optional :analysis_type, default: "standard"

  def work
    if dataset.nil?
      fail!("Dataset not found", code: 404)
    elsif dataset.unprocessed?
      skip!("Dataset not ready for analysis")
    else
      context.result = PValueAnalyzer.execute(dataset:, analysis_type:)
      context.analyzed_at = Time.now

      SendAnalyzedEmail.execute(user_id: Current.account.manager_id)
    end
  end

  private

  def dataset
    @dataset ||= Dataset.find_by(id: dataset_id)
  end

  def track_analysis_completion!
    dataset.update!(analysis_result_id: context.result.id)
  end
end

2. Execute

result = AnalyzeMetrics.execute(
  dataset_id: 123,
  "analysis_type" => "advanced"
)

3. React

if result.success?
  puts "Metrics analyzed at #{result.context.analyzed_at}"
elsif result.skipped?
  puts "Skipping analyzation due to: #{result.reason}"
elsif result.failed?
  puts "Analyzation failed due to: #{result.reason} with code #{result.metadata[:code]}"
end

4. Observe

I, [2022-07-17T18:42:37.000000 #3784] INFO -- CMDx:
index=1 chain_id="018c2b95-23j4-2kj3-32kj-3n4jk3n4jknf" type="Task" class="SendAnalyzedEmail" state="complete" status="success" metadata={runtime: 347}

I, [2022-07-17T18:43:15.000000 #3784] INFO -- CMDx:
index=0 chain_id="018c2b95-b764-7615-a924-cc5b910ed1e5" type="Task" class="AnalyzeMetrics" state="complete" status="success" metadata={runtime: 187}

Ready to dive in? Check out the Getting Started guide to learn more.

Ecosystem

For backwards compatibility of certain functionality:

Contributing

Bug reports and pull requests are welcome at https://github.com/drexed/cmdx. We're committed to fostering a welcoming, collaborative community. Please follow our code of conduct.

License

The gem is available as open source under the terms of the MIT License.