single_action_service 0.3.0 → 0.4.0
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/Gemfile.lock +5 -5
- data/README.md +106 -37
- data/lib/single_action_service.rb +6 -4
- data/lib/single_action_service/base.rb +94 -7
- data/lib/single_action_service/exceptions.rb +1 -0
- data/lib/single_action_service/module_helper.rb +21 -0
- data/lib/single_action_service/result.rb +16 -18
- data/lib/single_action_service/service_error.rb +8 -0
- data/lib/single_action_service/version.rb +1 -1
- data/single_action_service.gemspec +20 -18
- metadata +10 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6457094da633a11d6323fc370acdb124e0af8a74fd873a3b21b97e77a36ba7ac
|
4
|
+
data.tar.gz: 466715ec68f4508c7fd67c353b862965379a14ae4dd7ce718b6de8addd5b855f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cf3e5df350aa221819badc9064c14467bc9d35dc6fa124306ebdf33ab461b2c769a59a4b0859eaf9f4bcf0a5105c21db931dd41f25556691f148c55f5378e8f
|
7
|
+
data.tar.gz: 7faebeb6bce78ff1e2d6aa601da89df2cfcfaf30d6b1251ec3ae878440bb7c694f624f34e43cfc53ab5f2e6583fb08bdebf1c7879e3e4e09fe7ed21d732a02bf
|
data/Gemfile.lock
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
single_action_service (0.
|
4
|
+
single_action_service (0.4.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
diff-lcs (1.3)
|
10
|
-
rake (
|
10
|
+
rake (13.0.3)
|
11
11
|
rspec (3.9.0)
|
12
12
|
rspec-core (~> 3.9.0)
|
13
13
|
rspec-expectations (~> 3.9.0)
|
@@ -26,10 +26,10 @@ PLATFORMS
|
|
26
26
|
ruby
|
27
27
|
|
28
28
|
DEPENDENCIES
|
29
|
-
bundler (~> 1
|
30
|
-
rake (~>
|
29
|
+
bundler (~> 2.1)
|
30
|
+
rake (~> 13.0)
|
31
31
|
rspec (~> 3.0)
|
32
32
|
single_action_service!
|
33
33
|
|
34
34
|
BUNDLED WITH
|
35
|
-
|
35
|
+
2.2.9
|
data/README.md
CHANGED
@@ -22,70 +22,139 @@ Or install it yourself as:
|
|
22
22
|
|
23
23
|
## Usage
|
24
24
|
|
25
|
-
|
25
|
+
Create an inheritor from a `SingleActionService::Base` with a single method named `call`
|
26
|
+
|
26
27
|
```ruby
|
27
|
-
class
|
28
|
+
class Summator < SingleActionService::Base
|
29
|
+
def call
|
30
|
+
end
|
28
31
|
end
|
29
32
|
```
|
30
|
-
|
33
|
+
|
34
|
+
Create a constructor with parameters
|
35
|
+
|
31
36
|
```ruby
|
32
|
-
|
33
|
-
def initialize(x, y)
|
34
|
-
|
35
|
-
|
37
|
+
class Summator < SingleActionService::Base
|
38
|
+
def initialize(x, y)
|
39
|
+
@x = x
|
40
|
+
@y = y
|
41
|
+
end
|
36
42
|
end
|
37
43
|
```
|
38
|
-
|
44
|
+
|
45
|
+
or pass them to the call method
|
46
|
+
|
39
47
|
```ruby
|
40
|
-
|
48
|
+
class Summator < SingleActionService::Base
|
49
|
+
def call(x, y)
|
50
|
+
end
|
41
51
|
end
|
42
52
|
```
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
```
|
47
|
-
4. Return the result:
|
48
|
-
```ruby
|
49
|
-
success(sum)
|
50
|
-
```
|
51
|
-
or without data
|
53
|
+
|
54
|
+
Perform the action and return the result by calling `success(data = nil)`
|
55
|
+
|
52
56
|
```ruby
|
53
|
-
|
57
|
+
class Summator < SingleActionService::Base
|
58
|
+
def call(x, y)
|
59
|
+
sum = x + y
|
60
|
+
success(sum)
|
61
|
+
end
|
62
|
+
end
|
54
63
|
```
|
55
|
-
|
64
|
+
|
65
|
+
or return the error based on the validations by calling `error(data: nil, code: nil)`
|
66
|
+
|
56
67
|
```ruby
|
57
|
-
|
68
|
+
class Summator < SingleActionService::Base
|
69
|
+
NIL_NUMBERS_ERROR = :nil_numbers_error
|
70
|
+
|
71
|
+
def call(x, y)
|
72
|
+
if x.nil? || y.nil?
|
73
|
+
return error(code: NIL_NUMBERS_ERROR)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
58
77
|
```
|
59
|
-
The 'data' parameter is any data (optional).
|
60
78
|
|
61
|
-
|
79
|
+
Call the service and process a result
|
62
80
|
|
63
|
-
6. You can process the result received from the service as follows:
|
64
81
|
```ruby
|
65
|
-
|
66
|
-
result =
|
67
|
-
|
82
|
+
summator = Summator.new
|
83
|
+
result = summator.call(1, 2)
|
84
|
+
|
68
85
|
if result.success?
|
69
86
|
result.data
|
70
87
|
else
|
71
|
-
|
72
|
-
error_code: result.error_code,
|
73
|
-
data: result.data
|
74
|
-
}
|
88
|
+
result.error_code
|
75
89
|
end
|
76
90
|
```
|
77
|
-
|
91
|
+
|
92
|
+
Or you can use a `data!` method if you want to throw an exception when an error has occurred:
|
93
|
+
|
78
94
|
```ruby
|
79
95
|
begin
|
80
|
-
result =
|
96
|
+
result = Summator.new.call(1, 2).data!
|
81
97
|
rescue SingleActionService::InvalidResult => e
|
82
|
-
|
83
|
-
error_code: e.result.error_code,
|
84
|
-
data: e.result.data
|
85
|
-
}
|
98
|
+
e.result.error_code
|
86
99
|
end
|
87
100
|
```
|
88
101
|
|
102
|
+
You can define a list of errors of a service by calling a `self.errors(errors_data)` method.<br/>For each error, a method `#{error_name}_error(data = nil)` will be generated to instantiate the result with the appropriate code and optional data:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Summator < SingleActionService::Base
|
106
|
+
errors [
|
107
|
+
{ name: :nil_numbers, code: 1 }
|
108
|
+
]
|
109
|
+
|
110
|
+
def call(x, y)
|
111
|
+
if x.nil? || y.nil?
|
112
|
+
return nil_numbers_error
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
You can check for the specific error calling an autogenerated checking method of the result:
|
119
|
+
|
120
|
+
```ruby
|
121
|
+
result = Summator.new.call(nil, nil)
|
122
|
+
result.nil_numbers_error? # true
|
123
|
+
```
|
124
|
+
|
125
|
+
## API Reference
|
126
|
+
|
127
|
+
### SingleActionService::Base
|
128
|
+
|
129
|
+
A base class for services. Create an inheritor from him to use it. Methods:
|
130
|
+
|
131
|
+
Name |Description
|
132
|
+
---------------------------------|-----------
|
133
|
+
`success(data = nil)` |Returns a successful `SingleActionService::Result` with<br/>data passed in arguments.
|
134
|
+
`error(data: nil, code: nil)` |Returns an error `SingleActionService::Result` with<br/> data and the error code passed in arguments.
|
135
|
+
`#{error_name}_error(data = nil)`|Autogenerated method to create an error result <br/>with the specific error code<br/>without having to pass it in arguments.<br/>Generated for each error passed to the `self.errors` method.<br/>Returns an error `SingleActionService::Result` with<br/> data passed to arguments.
|
136
|
+
`self.errors(errors_data)` |Call this method to identify possible service errors.<br/>Accepts an array of objects:<br/>`{ name: :error_name, code: :error_code }`
|
137
|
+
|
138
|
+
### SingleActionService::Result
|
139
|
+
|
140
|
+
A base class for the result that the service returns. Instantiated by service methods such as `success`, `error` and autogenerated error methods. Methods:
|
141
|
+
|
142
|
+
Name |Description
|
143
|
+
----------------------|-----------
|
144
|
+
`success?` |Call this method to check the result for success.<br/>Returns `true` for successful results created by the<br/>`success` method of a service.
|
145
|
+
`error?` |Call this method to check the result for error.<br/>Returns `false` for error results created by the<br/>`error` method of a service or by autogenerated<br/> error methods.
|
146
|
+
`#{error_name}_error?`|Call this method to check the result for the specific error.<br/>Autogenerated for each error passed to the `self.errors`<br/> of a service.
|
147
|
+
`data` |Returns data passed to the result instantiation method
|
148
|
+
`data!` |Returns data passed to the result instantiation method.<br/>Throws a `SingleActionService::InvalidResult`<br/>exception if the result contains an error.
|
149
|
+
|
150
|
+
### SingleActionService::InvalidResult
|
151
|
+
|
152
|
+
An exception thrown by the `data!` method of a result. Methods:
|
153
|
+
|
154
|
+
Name |Description
|
155
|
+
------------|-----------
|
156
|
+
`result` |Returns a `SingleActionService::Result`
|
157
|
+
|
89
158
|
## Contributing
|
90
159
|
|
91
160
|
Bug reports and pull requests are welcome on GitHub at https://github.com/sequenia/single_action_service. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
@@ -1,7 +1,9 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
1
|
+
require 'single_action_service/exceptions'
|
2
|
+
require 'single_action_service/module_helper'
|
3
|
+
require 'single_action_service/base'
|
4
|
+
require 'single_action_service/result'
|
5
|
+
require 'single_action_service/service_error'
|
6
|
+
require 'single_action_service/version'
|
5
7
|
|
6
8
|
module SingleActionService
|
7
9
|
end
|
@@ -1,13 +1,100 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
# Parent class for services.
|
2
|
+
# A service is an object that implements part of the business logic.
|
3
|
+
# Create an inheritor to use it
|
4
|
+
# and call 'success' or 'error' methods to return a result object.
|
5
|
+
class SingleActionService::Base
|
6
|
+
protected
|
4
7
|
|
5
|
-
|
6
|
-
|
8
|
+
# Helper methods to setup the service
|
9
|
+
class << self
|
10
|
+
# Some usefull methods that exists in Rails
|
11
|
+
# but does not exists in the pure ruby
|
12
|
+
unless respond_to?(:module_parent)
|
13
|
+
include SingleActionService::ModuleHelper
|
7
14
|
end
|
8
15
|
|
9
|
-
|
10
|
-
|
16
|
+
# Call this method to generate methods in the service to return
|
17
|
+
# specific errors.
|
18
|
+
#
|
19
|
+
# @param errors_data is an array of hashes with information about errors.
|
20
|
+
# Each hash can contain keys:
|
21
|
+
# :name => A symbol representing a name of the error.
|
22
|
+
# :code => A symbol representing an error code of the error.
|
23
|
+
#
|
24
|
+
# For each name, a method "#{name}_error" will be generated
|
25
|
+
# to return a result with the corresponding error code.
|
26
|
+
# The returned result will have "#{name}_error?" methods
|
27
|
+
# for checking for a specific error.
|
28
|
+
#
|
29
|
+
# For example, if you pass an array:
|
30
|
+
# [{ name: :already_exists, code: :'errors.already_exists' }],
|
31
|
+
# the 'already_exists_error' method will be generated to return the
|
32
|
+
# result with a :'errors.already_exists' code.
|
33
|
+
# You can check for the error by calling 'already_exists_error?'
|
34
|
+
# method on the result object.
|
35
|
+
def errors(errors_data = nil)
|
36
|
+
return @errors if errors_data.nil?
|
37
|
+
|
38
|
+
parse_errors(errors_data)
|
39
|
+
create_result_class
|
40
|
+
define_methods_to_create_error_results
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_errors(errors_data)
|
44
|
+
@errors = errors_data.map do |error_data|
|
45
|
+
SingleActionService::ServiceError.new(**error_data)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_result_class
|
50
|
+
demodulized_name = name.split('::').last
|
51
|
+
result_class_name = "#{demodulized_name}Result"
|
52
|
+
return if module_parent.const_defined?(result_class_name)
|
53
|
+
|
54
|
+
# Programmatically create the inheritor for the service result object
|
55
|
+
# with autogenerated methods for checking for errors.
|
56
|
+
errors = @errors
|
57
|
+
@result_class = Class.new(SingleActionService::Result) do
|
58
|
+
def self.define_error_checking_method(error)
|
59
|
+
method_name = "#{error.name}_error?"
|
60
|
+
|
61
|
+
define_method(method_name) do
|
62
|
+
error_code == error.code
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
errors.each do |error|
|
67
|
+
define_error_checking_method(error)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
module_parent.const_set(result_class_name, @result_class)
|
11
72
|
end
|
73
|
+
|
74
|
+
def define_methods_to_create_error_results
|
75
|
+
@errors.each do |error_object|
|
76
|
+
result_method_name = "#{error_object.name}_error"
|
77
|
+
define_method(result_method_name) do |data = nil|
|
78
|
+
error(code: error_object.code, data: data)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def result_class
|
84
|
+
@result_class ||= SingleActionService::Result
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# @return a result with a success indicator and passed data.
|
89
|
+
# @param data is any data to return from service.
|
90
|
+
def success(data = nil)
|
91
|
+
self.class.result_class.new(true, data: data)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return a result with an error indicator, passed data and error code.
|
95
|
+
# @param data is any data to return from the service.
|
96
|
+
# @param code is an error code of the occurred error.
|
97
|
+
def error(data: nil, code: nil)
|
98
|
+
self.class.result_class.new(false, data: data, error_code: code)
|
12
99
|
end
|
13
100
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module SingleActionService::ModuleHelper
|
2
|
+
def module_parent
|
3
|
+
module_parent_name ? constantize(module_parent_name) : Object
|
4
|
+
end
|
5
|
+
|
6
|
+
def constantize(string)
|
7
|
+
string.split('::').inject(Object) do |module_object, class_name|
|
8
|
+
module_object.const_get(class_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def module_parent_name
|
13
|
+
if defined?(@parent_name)
|
14
|
+
@parent_name
|
15
|
+
else
|
16
|
+
parent_name = name =~ /::[^:]+\z/ ? -$` : nil
|
17
|
+
@parent_name = parent_name unless frozen?
|
18
|
+
parent_name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -1,25 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
attr_accessor :status, :data, :error_code
|
1
|
+
class SingleActionService::Result
|
2
|
+
attr_accessor :status, :data, :error_code
|
4
3
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
def initialize(status, data: nil, error_code: nil)
|
5
|
+
@status = status
|
6
|
+
@data = data
|
7
|
+
@error_code = error_code
|
8
|
+
end
|
10
9
|
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
def success?
|
11
|
+
status
|
12
|
+
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
def error?
|
15
|
+
!success?
|
16
|
+
end
|
18
17
|
|
19
|
-
|
20
|
-
|
18
|
+
def data!
|
19
|
+
return data if success?
|
21
20
|
|
22
|
-
|
23
|
-
end
|
21
|
+
raise SingleActionService::InvalidResult, self
|
24
22
|
end
|
25
23
|
end
|
@@ -1,29 +1,31 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
3
|
+
require 'single_action_service/version'
|
5
4
|
|
6
5
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
6
|
+
spec.name = 'single_action_service'
|
8
7
|
spec.version = SingleActionService::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
8
|
+
spec.authors = ['Bazov Peter']
|
9
|
+
spec.email = ['petr@sequenia.com']
|
11
10
|
|
12
|
-
spec.summary =
|
13
|
-
spec.description =
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
11
|
+
spec.summary = 'Single Action Service'
|
12
|
+
spec.description = 'A Ruby library to organize the code'
|
13
|
+
spec.homepage = 'https://github.com/sequenia/SingleActionService'
|
14
|
+
spec.license = 'MIT'
|
16
15
|
|
17
16
|
# Specify which files should be added to the gem when it is released.
|
18
|
-
# The `git ls-files -z` loads the files in the RubyGem
|
19
|
-
|
20
|
-
|
17
|
+
# The `git ls-files -z` loads the files in the RubyGem
|
18
|
+
# that have been added into git.
|
19
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
20
|
+
`git ls-files -z`
|
21
|
+
.split("\x0")
|
22
|
+
.reject { |f| f.match(%r{^(test|spec|features)/}) }
|
21
23
|
end
|
22
|
-
spec.bindir =
|
24
|
+
spec.bindir = 'exe'
|
23
25
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
24
|
-
spec.require_paths = [
|
26
|
+
spec.require_paths = ['lib']
|
25
27
|
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
28
|
-
spec.add_development_dependency
|
28
|
+
spec.add_development_dependency 'bundler', '~> 2.1'
|
29
|
+
spec.add_development_dependency 'rake', '~> 13.0'
|
30
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
29
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: single_action_service
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bazov Peter
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1
|
19
|
+
version: '2.1'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1
|
26
|
+
version: '2.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '13.0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '13.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -73,10 +73,12 @@ files:
|
|
73
73
|
- lib/single_action_service.rb
|
74
74
|
- lib/single_action_service/base.rb
|
75
75
|
- lib/single_action_service/exceptions.rb
|
76
|
+
- lib/single_action_service/module_helper.rb
|
76
77
|
- lib/single_action_service/result.rb
|
78
|
+
- lib/single_action_service/service_error.rb
|
77
79
|
- lib/single_action_service/version.rb
|
78
80
|
- single_action_service.gemspec
|
79
|
-
homepage:
|
81
|
+
homepage: https://github.com/sequenia/SingleActionService
|
80
82
|
licenses:
|
81
83
|
- MIT
|
82
84
|
metadata: {}
|
@@ -95,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
97
|
- !ruby/object:Gem::Version
|
96
98
|
version: '0'
|
97
99
|
requirements: []
|
98
|
-
rubygems_version: 3.
|
100
|
+
rubygems_version: 3.2.3
|
99
101
|
signing_key:
|
100
102
|
specification_version: 4
|
101
103
|
summary: Single Action Service
|