0.0
No commit activity in last 3 years
No release in over 3 years
Use-case driven design for ruby projects. Keeps your business logic in the right place!
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

ActionCase

Implementation of use-case driven design for ruby projects. Keep your business logic in the right place!

Supports: Ruby 1.9.3 +

Build Status

Installation

Add this line to your application's Gemfile:

gem 'action_case'

And then execute:

$ bundle

Or install it yourself as:

$ gem install action_case

Usage

There are a variety of classes available to implement use-case driven design principles and patterns in your project.

Creating use-case class

# /app/use_cases/survey_exporter.rb
require "csv"

module UseCases
  module Surveys
    class SurveyExporter < ActionCase::Base

      def export_csv survey_id
        begin
          survey = resource.find(survey_id)

          return respond CSV.generate({}) { |csv|
            csv << [:id, :title, :created_at]
            survey.entries.each do |entry|
              csv << [entry.id, entry.title, entry.created_at]
            end
          }
        rescue Exception => exception
          log :error, exception.message
        end

        respond "Unable to export the survey due to errors", false
      end

      def resource
        Survey
      end

    end
  end
end

Items of note:

  1. Injection of concrete implementation via 'resource'
  2. Use of #resource in #export_csv method, not concrete implementation
  3. Use of inherited respond method to handle both successful and error responses
  4. While it isn't required, it is recommended to namespace your use-cases with a matching folder structure.

Leveraging Use-case (perhaps in a Rails controller)

Generic Handler Syntax

In many cases, you'll only have one operation in a given use case. When that is the case, you can cut down on verbosity by using the generic handler syntax. Format: [use_case_class_name_snake_cased]_[success_or_error]

# /app/controllers/surveys_controller.rb

class SurveyController < ActionController::Base

  # POST /surveys/:id/export
  def export
    UseCases::Surveys::SurveyExporter.new(self).export_csv params[:id]
  end

  def survey_exporter_success csv_output
    flash[:notice] = "Survey successfully exported!"
    send_data csv_output, type: "text/plain", filename: "survey-export.csv", disposition: "attachment"
  end

  def survey_exporter_error error_output
    flash[:alert] = "There were issues exporting the survey - #{error_output}"
  end

end

Items of note:

  1. We set the controller as the listener for the use-case, via 'self'
  2. SurveyController#export stays short, sweet and to the point.
  3. We avoid coupling by using a very event-like callback (tell don't ask) communication pattern.

Explicit Handler Syntax

As your application scales and business rules change, you may have related but slightly different method signatures on a given use-case with each requiring different responses. In those cases the more verbose explicit handler syntax is necessary. Format: [class_name_snake_cased]_[method_name_snake_cased]_[success_or_error]

# /app/controllers/surveys_controller.rb

class SurveyController < ActionController::Base

  # POST /surveys/:id/export
  def export
    UseCases::Surveys::SurveyExporter.new(self).export_csv params[:id]
  end

  def survey_exporter_export_csv_success csv_output
    flash[:notice] = "Survey successfully exported!"
    send_data csv_output, type: "text/plain", filename: "survey-export.csv", disposition: "attachment"
  end

  def survey_exporter_export_csv_error error_output
    flash[:alert] = "There were issues exporting the survey - #{error_output}"
  end

end

Items of note:

  1. The expanded method signatures including the _export_csv component

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request