use_case_pattern 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -1
- data/CHANGELOG.md +7 -0
- data/README.md +42 -12
- data/examples/harvest.rb +3 -0
- data/examples/thing_speak_reporter.rb +10 -0
- data/lib/use_case_pattern/base.rb +11 -5
- data/lib/use_case_pattern/version.rb +1 -1
- data/use_case_pattern.gemspec +3 -3
- metadata +5 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0197a45aa4b6b6aa27b43d0887d884950636bcb6
|
4
|
+
data.tar.gz: 5441894af403f3c87f1c63127d647528ca84e1c7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7646d2e26a134e69f196366eaa34440bc10bbfc3c0ddf23045156463482fcd01c34ec635671a3fd448e02960f5128524ff566105e966815dab5d988640ed6f0b
|
7
|
+
data.tar.gz: 074c32d9931fb4df34311a999a50acb845aca8b89f964ae901155de40c038d74b4af1b7faea99f857621351a9eabf0a4016dada3ae3f3ccd961580fb4c5bf88a
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
data/README.md
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# UseCasePattern
|
2
2
|
|
3
|
+
[![Build Status](https://travis-ci.org/AbleTech/use_case_pattern.svg?branch=master)](https://travis-ci.org/AbleTech/use_case_pattern)
|
4
|
+
|
3
5
|
A module that helps you to implement the Use Case design pattern.
|
4
6
|
|
5
|
-
This pattern is widely used by the teams at Abletech. We were first introduced to this pattern by Shevaun Coker at RubyConf AU 2015 in Melbourne, Australia. You can read more about this pattern in her blog post A [Case for Use Cases](http://webuild.envato.com/blog/a-case-for-use-cases/), and also in the [video of the presentation](https://rubyconf.eventer.com/rubyconf-australia-2015-1223/a-case-for-use-cases-by-shevaun-coker-1734) that she gave.
|
7
|
+
This pattern is widely used by the teams at Abletech. We were first introduced to this pattern by Shevaun Coker at RubyConf AU 2015 in Melbourne, Australia. You can read more about this pattern in her blog post A [Case for Use Cases](http://webuild.envato.com/blog/a-case-for-use-cases/), and also in the [video of the presentation](https://rubyconf.eventer.com/rubyconf-australia-2015-1223/a-case-for-use-cases-by-shevaun-coker-1734) that she gave.
|
6
8
|
|
7
9
|
## Installation
|
8
10
|
|
@@ -24,28 +26,22 @@ Or install it yourself as:
|
|
24
26
|
|
25
27
|
When you follow the use case design pattern, you normally define a class with a constructor, and a perform method. You should include the `UseCasePattern` module. Here is a simple example:
|
26
28
|
|
27
|
-
```ruby
|
29
|
+
```ruby
|
28
30
|
class NumberMultiplier
|
29
31
|
include UseCasePattern
|
30
32
|
|
31
33
|
attr_reader :product
|
32
|
-
|
34
|
+
|
33
35
|
validates :number1, :number2, presence: true
|
34
36
|
|
35
37
|
def initialize(number1, number2)
|
36
38
|
@number1 = number1
|
37
39
|
@number2 = number2
|
38
40
|
end
|
39
|
-
|
41
|
+
|
40
42
|
def perform
|
41
|
-
|
42
|
-
@product = number1 * number2
|
43
|
-
end
|
43
|
+
@product = @number1 * @number2
|
44
44
|
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
attr_reader :number1, :number2
|
49
45
|
end
|
50
46
|
```
|
51
47
|
|
@@ -54,7 +50,7 @@ You could call this simple example from a Rails Controller, or anywhere else rea
|
|
54
50
|
```ruby
|
55
51
|
def multiply
|
56
52
|
multiplier = NumberMultiplier.perform(params[:number1], params[:number2])
|
57
|
-
|
53
|
+
|
58
54
|
if multiplier.success?
|
59
55
|
@result = multiplier.result
|
60
56
|
else
|
@@ -63,6 +59,40 @@ You could call this simple example from a Rails Controller, or anywhere else rea
|
|
63
59
|
end
|
64
60
|
```
|
65
61
|
|
62
|
+
## Normal workflow
|
63
|
+
|
64
|
+
This section defines the expected approach to implementing a class which uses the use case pattern.
|
65
|
+
|
66
|
+
### Initialisation
|
67
|
+
|
68
|
+
You would normally define a constructor for your use case. The constructor should store any supplied parameters as instance variables. You shouldn't perform any processing or business logic in the constructor.
|
69
|
+
|
70
|
+
The constructor is called with the parameters that are passed to the `perform` class method. For example, using the NumberMultiplier defined above, making a call to `NumberMultiplier.perform(1, 2)` will result in the initialiser being called as `initialize(1, 2)`.
|
71
|
+
|
72
|
+
### Validation
|
73
|
+
|
74
|
+
You should use ActiveModel validators to check that supplied parameters and any other dependencies are correct. You can also write custom validation methods using the [validate method](http://api.rubyonrails.org/classes/ActiveModel/Validations/ClassMethods.html#method-i-validate). Following the standard validation approach, you should add to the `errors` collection if validation fails.
|
75
|
+
|
76
|
+
### Execution
|
77
|
+
|
78
|
+
The `perform` method is where the execution of the use case should happen. In this method, you should perform all of the processing and business logic of your use case. Results of the execution should be stored as instance variables.
|
79
|
+
|
80
|
+
Sometimes during the execution of the `perform` method, an error may occur. You could choose to add to the errors collection or alternatively raise an exception. You should only add to the errors collection if you expect the caller to handle the error.
|
81
|
+
|
82
|
+
You should note that the value returned from the perform method is discarded. This encourages the caller to make use of the public accessor methods to access the results of the operation.
|
83
|
+
|
84
|
+
#### The alternative `perform!` method
|
85
|
+
|
86
|
+
The `perform!` method works in a similar manner to the ActiveRecord `save!` method. Should a validation or other error occur, an exception is raised. This method should be used in scenarios where the caller does not expect any errors to occur. One example of this is when the parameters have been pre-checked by a controller class or similar.
|
87
|
+
|
88
|
+
### Post-execution
|
89
|
+
|
90
|
+
During the `perform` method, you should have stored the results as instance variables. You would normally make these publicly accessible using a `attr_reader` method declaration. You should avoid declaring public methods that further process the output of the `perform` method.
|
91
|
+
|
92
|
+
#### Checking for errors
|
93
|
+
|
94
|
+
The caller can check the success or failure of the use case by calling the `success?` and `failure?` helper methods. If the use case has had a failure, the errors will be available on the standard `errors` collection.
|
95
|
+
|
66
96
|
## Development
|
67
97
|
|
68
98
|
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.
|
data/examples/harvest.rb
CHANGED
@@ -30,3 +30,13 @@ class ThingSpeakReporter
|
|
30
30
|
params.merge(api_key: api_key)
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
# example usage
|
35
|
+
|
36
|
+
reporter = ThingSpeakReporter.perform(api_key: 'XZY123', params: {indoor_temperature: 22, outdoor_temperature: 15})
|
37
|
+
|
38
|
+
if reporter.success?
|
39
|
+
puts "Temperature saved"
|
40
|
+
else
|
41
|
+
puts "Oh dear, there is a problem: #{reporter.errors.full_messages.join('; ')}"
|
42
|
+
end
|
@@ -9,10 +9,14 @@ module UseCasePattern
|
|
9
9
|
module ClassMethods
|
10
10
|
# The perform method of a UseCase should always return itself
|
11
11
|
def perform(*args)
|
12
|
-
new(*args).tap
|
12
|
+
new(*args).tap do |use_case|
|
13
|
+
if use_case.valid?
|
14
|
+
use_case.perform
|
15
|
+
end
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
|
-
# Raise
|
19
|
+
# Raise a validation error if perform has created any errors
|
16
20
|
def perform!(*args)
|
17
21
|
new(*args).tap { |use_case| use_case.perform! }
|
18
22
|
end
|
@@ -24,19 +28,21 @@ module UseCasePattern
|
|
24
28
|
end
|
25
29
|
|
26
30
|
def perform!
|
27
|
-
|
31
|
+
if valid?
|
32
|
+
perform
|
33
|
+
end
|
28
34
|
|
29
35
|
if failure?
|
30
36
|
raise_validation_error
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
34
|
-
#
|
40
|
+
# Did the use case performed its task without errors?
|
35
41
|
def success?
|
36
42
|
errors.none?
|
37
43
|
end
|
38
44
|
|
39
|
-
# Did
|
45
|
+
# Did the use case have any errors?
|
40
46
|
def failure?
|
41
47
|
errors.any?
|
42
48
|
end
|
data/use_case_pattern.gemspec
CHANGED
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.required_ruby_version = '~> 2.
|
23
|
+
spec.required_ruby_version = '~> 2.2'
|
24
24
|
|
25
|
-
spec.add_runtime_dependency "activemodel", [">= 4.0.0"
|
26
|
-
spec.add_runtime_dependency "activesupport", [">= 4.0.0"
|
25
|
+
spec.add_runtime_dependency "activemodel", [">= 4.0.0"]
|
26
|
+
spec.add_runtime_dependency "activesupport", [">= 4.0.0"]
|
27
27
|
|
28
28
|
spec.add_development_dependency "bundler", "~> 1.13"
|
29
29
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: use_case_pattern
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nigel Ramsay
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -17,9 +17,6 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 4.0.0
|
20
|
-
- - "~>"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: 5.0.0
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,9 +24,6 @@ dependencies:
|
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: 4.0.0
|
30
|
-
- - "~>"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: 5.0.0
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: activesupport
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,9 +31,6 @@ dependencies:
|
|
37
31
|
- - ">="
|
38
32
|
- !ruby/object:Gem::Version
|
39
33
|
version: 4.0.0
|
40
|
-
- - "~>"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: 5.0.0
|
43
34
|
type: :runtime
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -47,9 +38,6 @@ dependencies:
|
|
47
38
|
- - ">="
|
48
39
|
- !ruby/object:Gem::Version
|
49
40
|
version: 4.0.0
|
50
|
-
- - "~>"
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: 5.0.0
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
42
|
name: bundler
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +90,7 @@ files:
|
|
102
90
|
- ".gitignore"
|
103
91
|
- ".rspec"
|
104
92
|
- ".travis.yml"
|
93
|
+
- CHANGELOG.md
|
105
94
|
- Gemfile
|
106
95
|
- README.md
|
107
96
|
- Rakefile
|
@@ -125,7 +114,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
114
|
requirements:
|
126
115
|
- - "~>"
|
127
116
|
- !ruby/object:Gem::Version
|
128
|
-
version: '2.
|
117
|
+
version: '2.2'
|
129
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
130
119
|
requirements:
|
131
120
|
- - ">="
|
@@ -133,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
122
|
version: '0'
|
134
123
|
requirements: []
|
135
124
|
rubyforge_project:
|
136
|
-
rubygems_version: 2.
|
125
|
+
rubygems_version: 2.5.1
|
137
126
|
signing_key:
|
138
127
|
specification_version: 4
|
139
128
|
summary: A module that helps you to implement the Use Case design pattern
|