active_call 0.2.0 → 0.3.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/.rubocop.yml +7 -0
- data/CHANGELOG.md +8 -2
- data/README.md +35 -18
- data/lib/active_call/base.rb +72 -7
- data/lib/active_call/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 31e782b9a67b967ad37abe80818b43aa445517aa99a4830e2ec158c67404922e
|
4
|
+
data.tar.gz: 587d98f44af3c0a36198ffb76367bf30f0b8eb22b342d0d3d361c452452faf7a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4354d1137d8dfc1dae8570ccc6fb1324f2999d9b099c3f2a0e1da1fe4b93aa99b39692029d6169263736772e8eadce59376f0cd25d9812da38080f7309d06502
|
7
|
+
data.tar.gz: a2875e4fd4b26027584f4c830befb94ea9dc799fbc70aacbe791d44a39fa679ff56817a22c25fa5816bb715a1d6555f9717332026410a6e1af3c66f7ae1282da
|
data/.rubocop.yml
CHANGED
@@ -18,10 +18,17 @@ AllCops:
|
|
18
18
|
Layout/LineEndStringConcatenationIndentation:
|
19
19
|
EnforcedStyle: indented
|
20
20
|
|
21
|
+
Layout/LineLength:
|
22
|
+
AllowedPatterns:
|
23
|
+
- '#'
|
24
|
+
|
21
25
|
Lint/MissingSuper:
|
22
26
|
AllowedParentClasses:
|
23
27
|
- ActiveCall::Base
|
24
28
|
|
29
|
+
Metrics/AbcSize:
|
30
|
+
Enabled: false
|
31
|
+
|
25
32
|
Metrics/BlockLength:
|
26
33
|
Exclude:
|
27
34
|
- spec/*/**.rb
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
-
## [
|
1
|
+
## [0.3.0] - 2025-03-31
|
2
|
+
|
3
|
+
- Added `validate on: :request` which runs after `before_call` and before invoking `call`'.
|
4
|
+
|
5
|
+
## [0.2.1] - 2025-03-25
|
6
|
+
|
7
|
+
- Gemspec `changelog_uri` fixed.
|
2
8
|
|
3
9
|
## [0.2.0] - 2025-03-20
|
4
10
|
|
5
|
-
- Added method `.call!` with a bang, which will raise an `ActiveCall::ValidationError` exception when validation fails and an `ActiveCall::RequestError` exception when errors were added to the service object in the `
|
11
|
+
- Added method `.call!` with a bang, which will raise an `ActiveCall::ValidationError` exception when validation fails and an `ActiveCall::RequestError` exception when errors were added to the service object in the `validate on: :response` block.
|
6
12
|
- Use new method `success?` instead of `valid?`.
|
7
13
|
- Method `valid?` will return `true` if the service object passed validation and was able to make the `call` method.
|
8
14
|
- Use `validate, on: :response` to validate the response object.
|
data/README.md
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# Active Call
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/active_call)
|
4
|
+
|
3
5
|
Active Call provides a standardized way to create service objects.
|
4
6
|
|
5
7
|
## Installation
|
@@ -28,17 +30,19 @@ Each service object must define only one public method named `call`.
|
|
28
30
|
|
29
31
|
1. **Before** invoking `call`.
|
30
32
|
|
31
|
-
- Validate the
|
33
|
+
- Validate the service with `validates`.
|
32
34
|
|
33
35
|
- Use the `before_call` hook to set up anything **after validation** passes.
|
34
36
|
|
37
|
+
- Validate the request with `validate on: :request`.
|
38
|
+
|
35
39
|
2. **During** `call` invocation.
|
36
40
|
|
37
41
|
- A `response` attribute gets set with the result of the `call` method.
|
38
42
|
|
39
43
|
3. **After** invoking `call`.
|
40
44
|
|
41
|
-
- Validate the response with `validate
|
45
|
+
- Validate the response with `validate on: :response`.
|
42
46
|
|
43
47
|
- Use the `after_call` hook to set up anything **after response validation** passes.
|
44
48
|
|
@@ -49,16 +53,20 @@ Define a service object with optional validations and callbacks.
|
|
49
53
|
```ruby
|
50
54
|
require 'active_call'
|
51
55
|
|
52
|
-
class
|
53
|
-
attr_reader :message
|
56
|
+
class YourGem::SomeResource::CreateService < ActiveCall::Base
|
57
|
+
attr_reader :message, :another_service
|
54
58
|
|
55
59
|
validates :message, presence: true
|
56
60
|
|
61
|
+
validate on: :request do
|
62
|
+
errors.merge!(another_service.errors) unless another_service.success?
|
63
|
+
end
|
64
|
+
|
57
65
|
validate on: :response do
|
58
66
|
errors.add(:message, :invalid, message: 'cannot be baz') if response[:foo] == 'baz'
|
59
67
|
end
|
60
68
|
|
61
|
-
before_call :strip_message
|
69
|
+
before_call :call_another_service, :strip_message
|
62
70
|
|
63
71
|
after_call :log_response
|
64
72
|
|
@@ -72,6 +80,10 @@ class YourGemName::SomeResource::CreateService < ActiveCall::Base
|
|
72
80
|
|
73
81
|
private
|
74
82
|
|
83
|
+
def call_another_service
|
84
|
+
@another_service = YourGem::SomeResource::GetService.call(id: '1')
|
85
|
+
end
|
86
|
+
|
75
87
|
def strip_message
|
76
88
|
@message.strip!
|
77
89
|
end
|
@@ -82,12 +94,12 @@ class YourGemName::SomeResource::CreateService < ActiveCall::Base
|
|
82
94
|
end
|
83
95
|
```
|
84
96
|
|
85
|
-
### Using
|
97
|
+
### Using `call`
|
86
98
|
|
87
99
|
You will get an **errors** object when validation fails.
|
88
100
|
|
89
101
|
```ruby
|
90
|
-
service =
|
102
|
+
service = YourGem::SomeResource::CreateService.call(message: '')
|
91
103
|
service.success? # => false
|
92
104
|
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=blank, options={}>]>
|
93
105
|
service.errors.full_messages # => ["Message can't be blank"]
|
@@ -97,7 +109,7 @@ service.response # => nil
|
|
97
109
|
A **response** object on a successful `call` invocation.
|
98
110
|
|
99
111
|
```ruby
|
100
|
-
service =
|
112
|
+
service = YourGem::SomeResource::CreateService.call(message: ' bar ')
|
101
113
|
service.success? # => true
|
102
114
|
service.response # => {:foo=>"bar"}
|
103
115
|
```
|
@@ -105,20 +117,20 @@ service.response # => {:foo=>"bar"}
|
|
105
117
|
And an **errors** object if you added errors during the `validate, on: :response` validation.
|
106
118
|
|
107
119
|
```ruby
|
108
|
-
service =
|
120
|
+
service = YourGem::SomeResource::CreateService.call(message: 'baz')
|
109
121
|
service.success? # => false
|
110
122
|
service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=invalid, options={:message=>"cannot be baz"}>]>
|
111
123
|
service.errors.full_messages # => ["Message cannot be baz"]
|
112
124
|
service.response # => {:foo=>"baz"}
|
113
125
|
```
|
114
126
|
|
115
|
-
### Using
|
127
|
+
### Using `call!`
|
116
128
|
|
117
129
|
An `ActiveCall::ValidationError` **exception** gets raised when validation fails.
|
118
130
|
|
119
131
|
```ruby
|
120
132
|
begin
|
121
|
-
service =
|
133
|
+
service = YourGem::SomeResource::CreateService.call!(message: '')
|
122
134
|
rescue ActiveCall::ValidationError => exception
|
123
135
|
exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=blank, options={}>]>
|
124
136
|
exception.errors.full_messages # => ["Message can't be blank"]
|
@@ -128,7 +140,7 @@ end
|
|
128
140
|
A **response** object on a successful `call` invocation.
|
129
141
|
|
130
142
|
```ruby
|
131
|
-
service =
|
143
|
+
service = YourGem::SomeResource::CreateService.call!(message: ' bar ')
|
132
144
|
service.success? # => true
|
133
145
|
service.response # => {:foo=>"bar"}
|
134
146
|
```
|
@@ -137,7 +149,7 @@ And an `ActiveCall::RequestError` **exception** gets raised if you added errors
|
|
137
149
|
|
138
150
|
```ruby
|
139
151
|
begin
|
140
|
-
service =
|
152
|
+
service = YourGem::SomeResource::CreateService.call!(message: 'baz')
|
141
153
|
rescue ActiveCall::RequestError => exception
|
142
154
|
exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=invalid, options={:message=>"cannot be baz"}>]>
|
143
155
|
exception.errors.full_messages # => ["Message cannot be baz"]
|
@@ -150,17 +162,17 @@ end
|
|
150
162
|
If you have secrets, use a **configuration** block.
|
151
163
|
|
152
164
|
```ruby
|
153
|
-
class
|
165
|
+
class YourGem::BaseService < ActiveCall::Base
|
154
166
|
self.abstract_class = true
|
155
167
|
|
156
168
|
config_accessor :api_key, default: ENV['API_KEY'], instance_writer: false
|
157
169
|
end
|
158
170
|
```
|
159
171
|
|
160
|
-
Then in your application code you can
|
172
|
+
Then in your application code you can override the configuration defaults.
|
161
173
|
|
162
174
|
```ruby
|
163
|
-
|
175
|
+
YourGem::BaseService.configure do |config|
|
164
176
|
config.api_key = Rails.application.credentials.api_key || ENV['API_KEY']
|
165
177
|
end
|
166
178
|
```
|
@@ -170,7 +182,7 @@ And implement a service object like so.
|
|
170
182
|
```ruby
|
171
183
|
require 'net/http'
|
172
184
|
|
173
|
-
class
|
185
|
+
class YourGem::SomeResource::CreateService < YourGem::BaseService
|
174
186
|
def call
|
175
187
|
Net::HTTP.get_response(URI("http://example.com/api?#{URI.encode_www_form(api_key: api_key)}"))
|
176
188
|
end
|
@@ -199,9 +211,14 @@ spec.add_dependency 'active_call'
|
|
199
211
|
|
200
212
|
Now start adding your service objects in the `lib` directory and make sure they inherit from `ActiveCall::Base`.
|
201
213
|
|
214
|
+
## Active Call Extensions
|
215
|
+
|
216
|
+
- [Active Call - API](https://rubygems.org/gems/active_call-api)
|
217
|
+
|
202
218
|
## Gems Using Active Call
|
203
219
|
|
204
|
-
- [
|
220
|
+
- [Active Call - nCino KYC DocFox](https://rubygems.org/gems/active_call-doc_fox)
|
221
|
+
- [Active Call - Zoho Sign](https://rubygems.org/gems/active_call-zoho_sign)
|
205
222
|
|
206
223
|
## Development
|
207
224
|
|
data/lib/active_call/base.rb
CHANGED
@@ -14,13 +14,13 @@ class ActiveCall::Base
|
|
14
14
|
# Abstract classes are not meant to be instantiated directly, but rather inherited from.
|
15
15
|
# The `call` method doesn't need to be implemented in abstract classes.
|
16
16
|
#
|
17
|
-
#
|
17
|
+
# ==== Examples
|
18
18
|
#
|
19
|
-
# class
|
19
|
+
# class YourGem::BaseService < ActiveCall::Base
|
20
20
|
# self.abstract_class = true
|
21
21
|
# end
|
22
22
|
#
|
23
|
-
# class
|
23
|
+
# class YourGem::SomeResource::CreateService < YourGem::BaseService
|
24
24
|
# def call
|
25
25
|
# # Implementation specific to this service.
|
26
26
|
# end
|
@@ -32,32 +32,97 @@ class ActiveCall::Base
|
|
32
32
|
@abstract_class == true
|
33
33
|
end
|
34
34
|
|
35
|
-
# TODO: Refactor `call` and `call!`. The only differences are the
|
35
|
+
# TODO: Refactor `call` and `call!`. The only differences are the lines raising exceptions.
|
36
|
+
|
37
|
+
# Using `call`
|
38
|
+
#
|
39
|
+
# ==== Examples
|
40
|
+
#
|
41
|
+
# You will get an `errors` object when validation fails.
|
42
|
+
#
|
43
|
+
# service = YourGem::SomeResource::CreateService.call(message: '')
|
44
|
+
# service.success? # => false
|
45
|
+
# service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=blank, options={}>]>
|
46
|
+
# service.errors.full_messages # => ["Message can't be blank"]
|
47
|
+
# service.response # => nil
|
48
|
+
#
|
49
|
+
# A `response` object on a successful `call` invocation.
|
50
|
+
#
|
51
|
+
# service = YourGem::SomeResource::CreateService.call(message: ' bar ')
|
52
|
+
# service.success? # => true
|
53
|
+
# service.response # => {:foo=>"bar"}
|
54
|
+
#
|
55
|
+
# And an `errors` object if you added errors during the `validate, on: :response` validation.
|
56
|
+
#
|
57
|
+
# service = YourGem::SomeResource::CreateService.call(message: 'baz')
|
58
|
+
# service.success? # => false
|
59
|
+
# service.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=invalid, options={:message=>"cannot be baz"}>]>
|
60
|
+
# service.errors.full_messages # => ["Message cannot be baz"]
|
61
|
+
# service.response # => {:foo=>"baz"}
|
62
|
+
#
|
36
63
|
def call(...)
|
37
64
|
service_object = new(...)
|
38
65
|
service_object.instance_variable_set(:@bang, false)
|
39
|
-
return service_object if service_object.invalid?(except_on: :response)
|
66
|
+
return service_object if service_object.invalid?(except_on: [:request, :response])
|
40
67
|
|
41
68
|
service_object.run_callbacks(:call) do
|
42
69
|
next if service_object.is_a?(Enumerable)
|
43
70
|
|
71
|
+
service_object.validate(:request)
|
72
|
+
return service_object unless service_object.success?
|
73
|
+
|
44
74
|
service_object.instance_variable_set(:@response, service_object.call)
|
45
75
|
service_object.validate(:response)
|
46
|
-
|
47
76
|
return service_object unless service_object.success?
|
48
77
|
end
|
49
78
|
|
50
79
|
service_object
|
51
80
|
end
|
52
81
|
|
82
|
+
# Using `call!`
|
83
|
+
#
|
84
|
+
# ==== Examples
|
85
|
+
#
|
86
|
+
# An `ActiveCall::ValidationError` exception gets raised when validation fails.
|
87
|
+
#
|
88
|
+
# begin
|
89
|
+
# service = YourGem::SomeResource::CreateService.call!(message: '')
|
90
|
+
# rescue ActiveCall::ValidationError => exception
|
91
|
+
# exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=blank, options={}>]>
|
92
|
+
# exception.errors.full_messages # => ["Message can't be blank"]
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# A `response` object on a successful `call` invocation.
|
96
|
+
#
|
97
|
+
# service = YourGem::SomeResource::CreateService.call!(message: ' bar ')
|
98
|
+
# service.success? # => true
|
99
|
+
# service.response # => {:foo=>"bar"}
|
100
|
+
#
|
101
|
+
# And an `ActiveCall::RequestError` exception gets raised if you added errors during the `validate, on: :response`
|
102
|
+
# validation.
|
103
|
+
#
|
104
|
+
# begin
|
105
|
+
# service = YourGem::SomeResource::CreateService.call!(message: 'baz')
|
106
|
+
# rescue ActiveCall::RequestError => exception
|
107
|
+
# exception.errors # => #<ActiveModel::Errors [#<ActiveModel::Error attribute=message, type=invalid, options={:message=>"cannot be baz"}>]>
|
108
|
+
# exception.errors.full_messages # => ["Message cannot be baz"]
|
109
|
+
# exception.response # => {:foo=>"baz"}
|
110
|
+
# end
|
111
|
+
#
|
53
112
|
def call!(...)
|
54
113
|
service_object = new(...)
|
55
114
|
service_object.instance_variable_set(:@bang, true)
|
56
|
-
|
115
|
+
|
116
|
+
if service_object.invalid?(except_on: [:request, :response])
|
117
|
+
raise ActiveCall::ValidationError, service_object.errors
|
118
|
+
end
|
57
119
|
|
58
120
|
service_object.run_callbacks(:call) do
|
59
121
|
next if service_object.is_a?(Enumerable)
|
60
122
|
|
123
|
+
service_object.validate(:request)
|
124
|
+
raise ActiveCall::RequestError.new(nil, service_object.errors) unless service_object.success?
|
125
|
+
|
61
126
|
service_object.instance_variable_set(:@response, service_object.call)
|
62
127
|
service_object.validate(:response)
|
63
128
|
|
data/lib/active_call/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_call
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kobus Joubert
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-03-
|
11
|
+
date: 2025-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -66,7 +66,7 @@ metadata:
|
|
66
66
|
rubygems_mfa_required: 'true'
|
67
67
|
homepage_uri: https://github.com/kobusjoubert/active_call
|
68
68
|
source_code_uri: https://github.com/kobusjoubert/active_call
|
69
|
-
changelog_uri: https://github.com/kobusjoubert/active_call/CHANGELOG.md
|
69
|
+
changelog_uri: https://github.com/kobusjoubert/active_call/blob/main/CHANGELOG.md
|
70
70
|
post_install_message:
|
71
71
|
rdoc_options: []
|
72
72
|
require_paths:
|