diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0cb6eeb --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..8c18f1a --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--format documentation +--color diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..2a6fef7 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,5 @@ +sudo: false +language: ruby +rvm: + - 2.2.2 +before_install: gem install bundler -v 1.13.1 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..88c49ef --- /dev/null +++ b/Gemfile @@ -0,0 +1,4 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in use_case_pattern.gemspec +gemspec diff --git a/README.md b/README.md new file mode 100644 index 0000000..e9417c1 --- /dev/null +++ b/README.md @@ -0,0 +1,33 @@ +# UseCasePattern + +A module that helps you to implement the Use Case design pattern. + +## Installation + +Add this line to your application's Gemfile: + +```ruby +gem 'use_case_pattern' +``` + +And then execute: + + $ bundle + +Or install it yourself as: + + $ gem install use_case_pattern + +## Usage + +TODO: Write usage instructions here + +## Development + +After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. + +To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). + +## Contributing + +Bug reports and pull requests are welcome on GitHub at https://github.com/abletech/use_case_pattern. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..b7e9ed5 --- /dev/null +++ b/Rakefile @@ -0,0 +1,6 @@ +require "bundler/gem_tasks" +require "rspec/core/rake_task" + +RSpec::Core::RakeTask.new(:spec) + +task :default => :spec diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..3cf10e8 --- /dev/null +++ b/bin/console @@ -0,0 +1,14 @@ +#!/usr/bin/env ruby + +require "bundler/setup" +require "use_case_pattern" + +# You can add fixtures and/or initialization code here to make experimenting +# with your gem easier. You can also use a different console, if you like. + +# (If you use this, don't forget to add pry to your Gemfile!) +# require "pry" +# Pry.start + +require "irb" +IRB.start diff --git a/bin/setup b/bin/setup new file mode 100755 index 0000000..dce67d8 --- /dev/null +++ b/bin/setup @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +IFS=$'\n\t' +set -vx + +bundle install + +# Do any other automated setup that you need to do here diff --git a/lib/use_case_pattern.rb b/lib/use_case_pattern.rb new file mode 100644 index 0000000..bfab65f --- /dev/null +++ b/lib/use_case_pattern.rb @@ -0,0 +1,8 @@ +require "use_case_pattern/version" +require "use_case_pattern/base" + +module UseCasePattern + def self.included(receiver) + receiver.send :include, UseCasePattern::Base + end +end diff --git a/lib/use_case_pattern/base.rb b/lib/use_case_pattern/base.rb new file mode 100644 index 0000000..3e7c0fc --- /dev/null +++ b/lib/use_case_pattern/base.rb @@ -0,0 +1,43 @@ +require "active_support" +require "active_model" + +module UseCasePattern + module Base + extend ActiveSupport::Concern + include ActiveModel::Validations + + module ClassMethods + # The perform method of a UseCase should always return itself + def perform(*args) + new(*args).tap { |use_case| use_case.perform } + end + + # raise an exception if perform generates any errors + def perform!(*args) + new(*args).tap { |use_case| use_case.perform! } + end + end + + # implement all the steps required to complete this use case + def perform + raise NotImplementedError + end + + def perform! + perform + + if failure? + raise "Unexpected error #{errors.full_messages.join(', ')}" + end + end + + # inside of perform, add errors if the use case did not succeed + def success? + errors.none? + end + + def failure? + errors.any? + end + end +end diff --git a/lib/use_case_pattern/version.rb b/lib/use_case_pattern/version.rb new file mode 100644 index 0000000..e0ae424 --- /dev/null +++ b/lib/use_case_pattern/version.rb @@ -0,0 +1,3 @@ +module UseCasePattern + VERSION = "1.0.0" +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..711025d --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,2 @@ +$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__) +require "use_case_pattern" diff --git a/spec/use_case_pattern/base_spec.rb b/spec/use_case_pattern/base_spec.rb new file mode 100644 index 0000000..7201b99 --- /dev/null +++ b/spec/use_case_pattern/base_spec.rb @@ -0,0 +1,43 @@ +require "spec_helper" + +describe UseCasePattern::Base do + describe "#perform" do + context "when the including class has defined a perform method" do + it "should call the perform method" do + expect(SimpleUseCase).to receive(:perform) + SimpleUseCase.perform + end + end + + context "when the including class has defined a perform method and initializer" do + subject(:use_case){ UseCaseWithConstructor.perform(10) } + + it "should call the initializer" do + expect(UseCaseWithConstructor).to receive(:new).with(10).and_call_original + use_case + end + + it "should have no errors" do + expect(use_case.errors.full_messages).to eq([]) + end + end + end +end + +class SimpleUseCase + include UseCasePattern + + def perform + end +end + +class UseCaseWithConstructor + include UseCasePattern + + def initialize(args) + @args = args + end + + def perform + end +end diff --git a/spec/use_case_pattern_spec.rb b/spec/use_case_pattern_spec.rb new file mode 100644 index 0000000..aceb31c --- /dev/null +++ b/spec/use_case_pattern_spec.rb @@ -0,0 +1,7 @@ +require "spec_helper" + +describe UseCasePattern do + it "has a version number" do + expect(UseCasePattern::VERSION).not_to be nil + end +end diff --git a/use_case_pattern.gemspec b/use_case_pattern.gemspec new file mode 100644 index 0000000..9c79222 --- /dev/null +++ b/use_case_pattern.gemspec @@ -0,0 +1,31 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'use_case_pattern/version' + +Gem::Specification.new do |spec| + spec.name = "use_case_pattern" + spec.version = UseCasePattern::VERSION + spec.authors = ["Nigel Ramsay"] + spec.email = ["nigel@abletech.nz"] + + spec.summary = "A module that helps you to implement the Use Case design pattern" + spec.description = "A module that helps you to implement the Use Case design pattern" + spec.homepage = "https://github.com/abletech/use_case_pattern" + + spec.files = `git ls-files -z`.split("\x0").reject do |f| + f.match(%r{^(test|spec|features)/}) + end + + spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } + spec.require_paths = ["lib"] + + spec.required_ruby_version = '~> 2.0' + + spec.add_runtime_dependency "activemodel", [">= 4.0.0", "~> 5.0.0"] + spec.add_runtime_dependency "activesupport", [">= 4.0.0", "~> 5.0.0"] + + spec.add_development_dependency "bundler", "~> 1.13" + spec.add_development_dependency "rake", "~> 10.0" + spec.add_development_dependency "rspec", "~> 3.0" +end