solid_use_case 2.0.1 → 2.0.2
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 +4 -4
- data/README.md +42 -1
- data/lib/solid_use_case/composable.rb +15 -0
- data/lib/solid_use_case/version.rb +1 -1
- data/spec/control_flow_spec.rb +69 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ddf3a778dbf1eb61bc2f63319813267790aa806
|
4
|
+
data.tar.gz: 11b3e39668ca2ca7502255f90999eb2b8181753e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c6177ff65b30961fce7808ecce96401259926075f8d55340767efc6ff104180728e00365fce5044a24dbf4413b8ae08a8df65229e604e61366f98930c57d589
|
7
|
+
data.tar.gz: 77ff94dd60cb46f013ae170e92863c1c60f027d8dd74817676b644f6385863ac71039f7353c1e7c7cc799691b1bc273ad6838089823acea803a46b04d67def49
|
data/README.md
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
Add this line to your application's Gemfile:
|
8
8
|
|
9
|
-
gem 'solid_use_case', '~> 2.0.
|
9
|
+
gem 'solid_use_case', '~> 2.0.2'
|
10
10
|
|
11
11
|
And then execute:
|
12
12
|
|
@@ -93,6 +93,47 @@ class UsersController < ApplicationController
|
|
93
93
|
end
|
94
94
|
```
|
95
95
|
|
96
|
+
## Control Flow Helpers
|
97
|
+
|
98
|
+
`check_exists` (alias `maybe_continue`) allows you to implicitly return a failure when a value is nil:
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
# NOTE: The following assumes that #post_comment returns a Success or Failure
|
102
|
+
video = Video.find_by_id(params[:video_id])
|
103
|
+
check_exists(video).and_then { post_comment(params) }
|
104
|
+
|
105
|
+
# NOTE: The following assumes that #find_tag and #create_tag both return a Success or Failure
|
106
|
+
check_exists(Tag.find_by(name: tag)).or_else { create_tag(tag) }.and_then { ... }
|
107
|
+
|
108
|
+
# If you wanted, you could refactor the above to use a method:
|
109
|
+
def find_tag(name)
|
110
|
+
maybe_continue(Tag.find_by(name: name))
|
111
|
+
end
|
112
|
+
|
113
|
+
# Then, elsewhere...
|
114
|
+
find_tag(tag)
|
115
|
+
.or_else { create_tag(tag) }
|
116
|
+
.and_then do |active_record_tag|
|
117
|
+
# At this point you can safely assume you have a tag :)
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
`attempt` allows you to catch an exception. It's useful when you want to attempt something that might fail, but don't want to write all that exception-handling boilerplate.
|
122
|
+
|
123
|
+
`attempt` also **auto-wraps your values**; in other words, the inner code does **not** have to return a success or failure.
|
124
|
+
|
125
|
+
For example, a Stripe API call:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
# Goal: Only charge customer if he/she exists
|
129
|
+
attempt {
|
130
|
+
Stripe::Customer.retrieve(some_id)
|
131
|
+
}
|
132
|
+
.and_then do |stripe_customer|
|
133
|
+
stripe_customer.charge(...)
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
96
137
|
## RSpec Matchers
|
97
138
|
|
98
139
|
If you're using RSpec, Solid Use Case provides some helpful matchers for testing.
|
@@ -32,11 +32,26 @@ module SolidUseCase
|
|
32
32
|
# Helpers #
|
33
33
|
# # # # # #
|
34
34
|
|
35
|
+
def check_exists(val, error=:not_found)
|
36
|
+
if val.nil?
|
37
|
+
fail(error)
|
38
|
+
else
|
39
|
+
continue(val)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def attempt
|
44
|
+
attempt_all do
|
45
|
+
try { yield }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
35
49
|
def fail(type, data={})
|
36
50
|
data[:type] = type
|
37
51
|
Failure(ErrorStruct.new(data))
|
38
52
|
end
|
39
53
|
|
54
|
+
alias :maybe_continue :check_exists
|
40
55
|
alias :continue :Success
|
41
56
|
end
|
42
57
|
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "Control Flow Helpers" do
|
4
|
+
|
5
|
+
describe '#check_exists' do
|
6
|
+
class FloodGate
|
7
|
+
include SolidUseCase::Composable
|
8
|
+
|
9
|
+
def basic(input)
|
10
|
+
check_exists(input).and_then {|x| Success(x * 2) }
|
11
|
+
end
|
12
|
+
|
13
|
+
def alias(input)
|
14
|
+
maybe_continue(input)
|
15
|
+
end
|
16
|
+
|
17
|
+
def custom_error(input, err)
|
18
|
+
check_exists(input, err)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "stops when the value is nil" do
|
23
|
+
result = FloodGate.new.basic(nil)
|
24
|
+
expect(result).to fail_with(:not_found)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "continues when the value is not nil" do
|
28
|
+
result = FloodGate.new.basic(17)
|
29
|
+
expect(result).to be_a_success
|
30
|
+
expect(result.value).to eq 34
|
31
|
+
end
|
32
|
+
|
33
|
+
it "has an alias" do
|
34
|
+
result = FloodGate.new.basic(17)
|
35
|
+
expect(result).to be_a_success
|
36
|
+
expect(result.value).to eq 34
|
37
|
+
end
|
38
|
+
|
39
|
+
it "allows a custom error" do
|
40
|
+
result = FloodGate.new.custom_error(nil, :my_error)
|
41
|
+
expect(result).to fail_with(:my_error)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#attempt' do
|
46
|
+
class Bubble
|
47
|
+
include SolidUseCase::Composable
|
48
|
+
|
49
|
+
def pop1
|
50
|
+
attempt { "pop!" }
|
51
|
+
end
|
52
|
+
|
53
|
+
def pop2
|
54
|
+
attempt { raise NoMethodError.new("oops") }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "succeeds when no exceptions happen" do
|
59
|
+
expect(Bubble.new.pop1).to be_a_success
|
60
|
+
end
|
61
|
+
|
62
|
+
it "catches exceptions" do
|
63
|
+
result = Bubble.new.pop2
|
64
|
+
expect(result).to_not be_a_success
|
65
|
+
expect(result.value).to be_a NoMethodError
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: solid_use_case
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gilbert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-08-
|
11
|
+
date: 2014-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: deterministic
|
@@ -89,6 +89,7 @@ files:
|
|
89
89
|
- lib/solid_use_case/version.rb
|
90
90
|
- solid_use_case.gemspec
|
91
91
|
- spec/composable_spec.rb
|
92
|
+
- spec/control_flow_spec.rb
|
92
93
|
- spec/rspec_matchers_spec.rb
|
93
94
|
- spec/spec_helper.rb
|
94
95
|
homepage: https://github.com/mindeavor/solid_use_case
|
@@ -117,6 +118,7 @@ specification_version: 4
|
|
117
118
|
summary: A flexible UseCase pattern that works *with* your workflow, not against it.
|
118
119
|
test_files:
|
119
120
|
- spec/composable_spec.rb
|
121
|
+
- spec/control_flow_spec.rb
|
120
122
|
- spec/rspec_matchers_spec.rb
|
121
123
|
- spec/spec_helper.rb
|
122
124
|
has_rdoc:
|