solid_use_case 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +109 -0
- data/Rakefile +1 -0
- data/lib/solid_use_case.rb +16 -0
- data/lib/solid_use_case/command.rb +19 -0
- data/lib/solid_use_case/command/error_struct.rb +7 -0
- data/lib/solid_use_case/command/util.rb +21 -0
- data/lib/solid_use_case/rspec_matchers.rb +24 -0
- data/lib/solid_use_case/version.rb +3 -0
- data/solid_use_case.gemspec +28 -0
- data/spec/command_spec.rb +30 -0
- data/spec/spec_helper.rb +18 -0
- metadata +119 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cb8bb82fa087ffe6fba31b8f8e8753537a3d32c8
|
4
|
+
data.tar.gz: 0dc0ea23f89441e88959892a6e0ae8c201023cae
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b841281bb8558dc27c46c905c22cdb651752f6e8ac60861fcd04696633bb89f666c3985bab1a9fb6adebeb190a818a47843b23feb0be8e7d6af466320ba9437a
|
7
|
+
data.tar.gz: 8f48815ec737c7d537c3af38f8de2f193df4629929e5aefbb5238e35ddc63d603b110cc5594265c08887f83698092d671fdaba4cb2741ad588c050f010e46c8e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Gilbert
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
# Solid Use Case
|
2
|
+
|
3
|
+
**Solid Use Case** is a gem to help you implement well-tested and flexible use cases. Solid Use Case is not a framework - it's a **design pattern library**. This means it works *with* your app's workflow, not against it.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'solid_use_case'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install solid_use_case
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
At its core, this library is a light wrapper around [Deterministic](https://github.com/pzol/deterministic), a practical abstraction over the Either monad. Don't let that scare you - you don't have to understand monad theory to reap its benefits.
|
22
|
+
|
23
|
+
The only required method is the `#run` method.
|
24
|
+
|
25
|
+
### Rails Example
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
class UserSignup < SolidUseCase::Command
|
29
|
+
def run(params)
|
30
|
+
attempt_all do
|
31
|
+
step { validate(params) }
|
32
|
+
step {|params| save_user(params) }
|
33
|
+
try {|params| email_user(params) }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def validate(params)
|
38
|
+
user = User.new(params[:user])
|
39
|
+
if user.valid?
|
40
|
+
fail :invalid_user, :user => user
|
41
|
+
else
|
42
|
+
params[:user] = user
|
43
|
+
Success(params)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def save_user(params)
|
48
|
+
user = params[:user]
|
49
|
+
if user.save
|
50
|
+
fail :user_save_failed, :user => user
|
51
|
+
else
|
52
|
+
Success(params)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def email_user(params)
|
57
|
+
UserMailer.async.deliver(:welcome, params[:user].id)
|
58
|
+
Success(params[:user])
|
59
|
+
end
|
60
|
+
end
|
61
|
+
```
|
62
|
+
|
63
|
+
Now you can run your use case in your controller and easily respond to the different outcomes (with **pattern matching**!):
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
class UsersController < ApplicationController
|
67
|
+
def create
|
68
|
+
UserSignup.run(params).match do
|
69
|
+
success do |user|
|
70
|
+
flash[:success] = "Thanks for signing up!"
|
71
|
+
redirect_to profile_path(user)
|
72
|
+
end
|
73
|
+
|
74
|
+
failure(:invalid_user) do |error_data|
|
75
|
+
render_new(error_data, "Oops, fix your mistakes and try again")
|
76
|
+
end
|
77
|
+
|
78
|
+
failure(:user_save_failed) do |error_data|
|
79
|
+
render_new(error_data, "Sorry, something went wrong on our side.")
|
80
|
+
end
|
81
|
+
|
82
|
+
failure do |exception|
|
83
|
+
flash[:error] = "Something went terribly wrong"
|
84
|
+
render 'new'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def render_new(user, error_message)
|
92
|
+
@user = user
|
93
|
+
@error_message = error_message
|
94
|
+
render 'new'
|
95
|
+
end
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
## Testing
|
100
|
+
|
101
|
+
$ bundle exec rspec
|
102
|
+
|
103
|
+
## Contributing
|
104
|
+
|
105
|
+
1. Fork it
|
106
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
107
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
108
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
109
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require "deterministic"
|
2
|
+
require "deterministic/core_ext/either"
|
3
|
+
|
4
|
+
require "solid_use_case/version"
|
5
|
+
require 'solid_use_case/command/util.rb'
|
6
|
+
require 'solid_use_case/command/error_struct.rb'
|
7
|
+
require 'solid_use_case/command.rb'
|
8
|
+
|
9
|
+
module SolidUseCase
|
10
|
+
end
|
11
|
+
|
12
|
+
class Deterministic::Either
|
13
|
+
class AttemptAll
|
14
|
+
alias :step :let
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SolidUseCase
|
2
|
+
class Command
|
3
|
+
include Deterministic::CoreExt::Either
|
4
|
+
include CommandUtil
|
5
|
+
|
6
|
+
def self.run(input_hash={})
|
7
|
+
self.new.run(input_hash)
|
8
|
+
end
|
9
|
+
|
10
|
+
# # # # # # # # #
|
11
|
+
# Monad-related #
|
12
|
+
# # # # # # # # #
|
13
|
+
|
14
|
+
def fail(type, data={})
|
15
|
+
data[:type] = type
|
16
|
+
Failure(ErrorStruct.new(data))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SolidUseCase
|
2
|
+
module CommandUtil
|
3
|
+
|
4
|
+
def symbolize_names(object)
|
5
|
+
case object
|
6
|
+
when Hash
|
7
|
+
new = {}
|
8
|
+
object.each do |key, value|
|
9
|
+
key = (key.to_sym rescue key) || key
|
10
|
+
new[key] = symbolize_names(value)
|
11
|
+
end
|
12
|
+
new
|
13
|
+
when Array
|
14
|
+
object.map { |value| symbolize_names(value) }
|
15
|
+
else
|
16
|
+
object
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SolidUseCase
|
2
|
+
module RSpecMatchers
|
3
|
+
|
4
|
+
def be_a_success
|
5
|
+
ValidateSuccess.new
|
6
|
+
end
|
7
|
+
|
8
|
+
class ValidateSuccess
|
9
|
+
def matches?(result)
|
10
|
+
@result = result
|
11
|
+
@result.is_a? Deterministic::Success
|
12
|
+
end
|
13
|
+
|
14
|
+
def failure_message_for_should
|
15
|
+
"expected result to be a success\nError & Data:\n #{@result.value.type} - #{@result.value.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def failure_message_for_should_not
|
19
|
+
"expected result to not be a success"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'solid_use_case/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "solid_use_case"
|
8
|
+
spec.version = SolidUseCase::VERSION
|
9
|
+
spec.authors = ["Gilbert"]
|
10
|
+
spec.email = ["gilbertbgarza@gmail.com"]
|
11
|
+
spec.description = %q{Create use cases the way they were meant to be. Easily verify inputs at each step and seamlessly fail with custom error data and convenient pattern matching.}
|
12
|
+
spec.summary = %q{A flexible UseCase pattern that works *with* your workflow, not against it.}
|
13
|
+
spec.homepage = "https://github.com/mindeavor/solid_use_case"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '~> 2.0'
|
22
|
+
|
23
|
+
spec.add_dependency "deterministic", '~> 0.2.0'
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec", "~> 2.14.1"
|
28
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SolidUseCase::Command do
|
4
|
+
|
5
|
+
describe 'Stepping' do
|
6
|
+
class TestA < SolidUseCase::Command
|
7
|
+
def run(inputs)
|
8
|
+
attempt_all do
|
9
|
+
step { step_1(inputs) }
|
10
|
+
step {|inputs| step_2(inputs) }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def step_1(inputs)
|
15
|
+
inputs[:number] += 10
|
16
|
+
Success(inputs)
|
17
|
+
end
|
18
|
+
|
19
|
+
def step_2(inputs)
|
20
|
+
inputs[:number] *= 2
|
21
|
+
Success(inputs)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "pipes one step result to the next step" do
|
26
|
+
result = TestA.run(:number => 10)
|
27
|
+
expect(result).to be_a_success
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'solid_use_case'
|
2
|
+
require 'solid_use_case/rspec_matchers'
|
3
|
+
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.include(SolidUseCase::RSpecMatchers)
|
6
|
+
end
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
10
|
+
config.run_all_when_everything_filtered = true
|
11
|
+
config.filter_run :focus
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: solid_use_case
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gilbert
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-03-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: deterministic
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.2.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.2.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.14.1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.14.1
|
69
|
+
description: Create use cases the way they were meant to be. Easily verify inputs
|
70
|
+
at each step and seamlessly fail with custom error data and convenient pattern matching.
|
71
|
+
email:
|
72
|
+
- gilbertbgarza@gmail.com
|
73
|
+
executables: []
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .rspec
|
79
|
+
- Gemfile
|
80
|
+
- LICENSE.txt
|
81
|
+
- README.md
|
82
|
+
- Rakefile
|
83
|
+
- lib/solid_use_case.rb
|
84
|
+
- lib/solid_use_case/command.rb
|
85
|
+
- lib/solid_use_case/command/error_struct.rb
|
86
|
+
- lib/solid_use_case/command/util.rb
|
87
|
+
- lib/solid_use_case/rspec_matchers.rb
|
88
|
+
- lib/solid_use_case/version.rb
|
89
|
+
- solid_use_case.gemspec
|
90
|
+
- spec/command_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
homepage: https://github.com/mindeavor/solid_use_case
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ~>
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '2.0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.2.2
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: A flexible UseCase pattern that works *with* your workflow, not against it.
|
116
|
+
test_files:
|
117
|
+
- spec/command_spec.rb
|
118
|
+
- spec/spec_helper.rb
|
119
|
+
has_rdoc:
|