light-services 2.0.0.rc6 → 2.0.0.rc8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +6 -6
- data/Gemfile.lock +48 -51
- data/README.md +327 -3
- data/lib/light/services/base.rb +7 -8
- data/lib/light/services/collection/base.rb +5 -1
- data/lib/light/services/messages.rb +5 -5
- data/lib/light/services/settings/argument.rb +6 -5
- data/lib/light/services/version.rb +1 -1
- data/light-services.gemspec +1 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 033745e056484b3cb06dd7047bde7aa8f57d3e7a831f5f9eb2495aec0f9f96e9
|
4
|
+
data.tar.gz: 6927b650f82197c0ee0403487f18f71015096d244785ae947d0b8ea4dd56373f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c87c5af17cccc1cce0514a65dd8f87b84d21599fcafec91ea92fa9f5d068842bfb01f0055b98c62340809a47e4eb3721a974b5958c7cd6b6410249251cf4cdca
|
7
|
+
data.tar.gz: a48e79125c81939dd5967ea08e6fcafcb6474f9a13edbc07f1e1d4ec69fc83b23e2bc43a660bf978d999d4b97a57c4f543f5f14b65219c555f2266ce3d06b51f
|
data/Gemfile
CHANGED
@@ -9,12 +9,12 @@ group :test do
|
|
9
9
|
gem "database_cleaner-active_record", "~> 1.8"
|
10
10
|
gem "sqlite3", "~> 1.4"
|
11
11
|
|
12
|
-
gem "codecov", "~> 0.
|
12
|
+
gem "codecov", "~> 0.6.0"
|
13
13
|
gem "rake", "~> 13.0"
|
14
|
-
gem "rspec", "~> 3.
|
15
|
-
gem "simplecov", "~> 0.
|
14
|
+
gem "rspec", "~> 3.11"
|
15
|
+
gem "simplecov", "~> 0.21"
|
16
16
|
|
17
|
-
gem "rubocop", "~>
|
18
|
-
gem "rubocop-performance", "~> 1.
|
19
|
-
gem "rubocop-rspec", "~>
|
17
|
+
gem "rubocop", "~> 1.27", require: false
|
18
|
+
gem "rubocop-performance", "~> 1.13", require: false
|
19
|
+
gem "rubocop-rspec", "~> 2.9", require: false
|
20
20
|
end
|
data/Gemfile.lock
CHANGED
@@ -1,101 +1,98 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
light-services (2.0.0.
|
4
|
+
light-services (2.0.0.rc8)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
activemodel (6.1.
|
10
|
-
activesupport (= 6.1.
|
11
|
-
activerecord (6.1.
|
12
|
-
activemodel (= 6.1.
|
13
|
-
activesupport (= 6.1.
|
14
|
-
activesupport (6.1.
|
9
|
+
activemodel (6.1.5)
|
10
|
+
activesupport (= 6.1.5)
|
11
|
+
activerecord (6.1.5)
|
12
|
+
activemodel (= 6.1.5)
|
13
|
+
activesupport (= 6.1.5)
|
14
|
+
activesupport (6.1.5)
|
15
15
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
16
|
i18n (>= 1.6, < 2)
|
17
17
|
minitest (>= 5.1)
|
18
18
|
tzinfo (~> 2.0)
|
19
19
|
zeitwerk (~> 2.3)
|
20
20
|
ast (2.4.2)
|
21
|
-
codecov (0.
|
22
|
-
|
23
|
-
|
24
|
-
concurrent-ruby (1.1.9)
|
21
|
+
codecov (0.6.0)
|
22
|
+
simplecov (>= 0.15, < 0.22)
|
23
|
+
concurrent-ruby (1.1.10)
|
25
24
|
database_cleaner (1.99.0)
|
26
25
|
database_cleaner-active_record (1.99.0)
|
27
26
|
activerecord
|
28
27
|
database_cleaner (~> 1.99.0)
|
29
|
-
diff-lcs (1.
|
28
|
+
diff-lcs (1.5.0)
|
30
29
|
docile (1.4.0)
|
31
|
-
i18n (1.
|
30
|
+
i18n (1.10.0)
|
32
31
|
concurrent-ruby (~> 1.0)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
parser (3.0.2.0)
|
32
|
+
minitest (5.15.0)
|
33
|
+
parallel (1.22.1)
|
34
|
+
parser (3.1.2.0)
|
37
35
|
ast (~> 2.4.1)
|
38
|
-
rainbow (3.
|
36
|
+
rainbow (3.1.1)
|
39
37
|
rake (13.0.6)
|
40
|
-
regexp_parser (2.
|
38
|
+
regexp_parser (2.3.0)
|
41
39
|
rexml (3.2.5)
|
42
|
-
rspec (3.
|
43
|
-
rspec-core (~> 3.
|
44
|
-
rspec-expectations (~> 3.
|
45
|
-
rspec-mocks (~> 3.
|
46
|
-
rspec-core (3.
|
47
|
-
rspec-support (~> 3.
|
48
|
-
rspec-expectations (3.
|
40
|
+
rspec (3.11.0)
|
41
|
+
rspec-core (~> 3.11.0)
|
42
|
+
rspec-expectations (~> 3.11.0)
|
43
|
+
rspec-mocks (~> 3.11.0)
|
44
|
+
rspec-core (3.11.0)
|
45
|
+
rspec-support (~> 3.11.0)
|
46
|
+
rspec-expectations (3.11.0)
|
49
47
|
diff-lcs (>= 1.2.0, < 2.0)
|
50
|
-
rspec-support (~> 3.
|
51
|
-
rspec-mocks (3.
|
48
|
+
rspec-support (~> 3.11.0)
|
49
|
+
rspec-mocks (3.11.1)
|
52
50
|
diff-lcs (>= 1.2.0, < 2.0)
|
53
|
-
rspec-support (~> 3.
|
54
|
-
rspec-support (3.
|
55
|
-
rubocop (
|
51
|
+
rspec-support (~> 3.11.0)
|
52
|
+
rspec-support (3.11.0)
|
53
|
+
rubocop (1.27.0)
|
56
54
|
parallel (~> 1.10)
|
57
|
-
parser (>=
|
55
|
+
parser (>= 3.1.0.0)
|
58
56
|
rainbow (>= 2.2.2, < 4.0)
|
59
|
-
regexp_parser (>= 1.8)
|
57
|
+
regexp_parser (>= 1.8, < 3.0)
|
60
58
|
rexml
|
61
|
-
rubocop-ast (>=
|
59
|
+
rubocop-ast (>= 1.16.0, < 2.0)
|
62
60
|
ruby-progressbar (~> 1.7)
|
63
|
-
unicode-display_width (>= 1.4.0, <
|
64
|
-
rubocop-ast (1.
|
65
|
-
parser (>= 3.
|
66
|
-
rubocop-performance (1.
|
67
|
-
rubocop (>=
|
61
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
62
|
+
rubocop-ast (1.17.0)
|
63
|
+
parser (>= 3.1.1.0)
|
64
|
+
rubocop-performance (1.13.3)
|
65
|
+
rubocop (>= 1.7.0, < 2.0)
|
68
66
|
rubocop-ast (>= 0.4.0)
|
69
|
-
rubocop-rspec (
|
70
|
-
rubocop (~>
|
71
|
-
rubocop-ast (>= 0.7.1)
|
67
|
+
rubocop-rspec (2.9.0)
|
68
|
+
rubocop (~> 1.19)
|
72
69
|
ruby-progressbar (1.11.0)
|
73
70
|
simplecov (0.21.2)
|
74
71
|
docile (~> 1.1)
|
75
72
|
simplecov-html (~> 0.11)
|
76
73
|
simplecov_json_formatter (~> 0.1)
|
77
74
|
simplecov-html (0.12.3)
|
78
|
-
simplecov_json_formatter (0.1.
|
75
|
+
simplecov_json_formatter (0.1.4)
|
79
76
|
sqlite3 (1.4.2)
|
80
77
|
tzinfo (2.0.4)
|
81
78
|
concurrent-ruby (~> 1.0)
|
82
|
-
unicode-display_width (1.
|
83
|
-
zeitwerk (2.4
|
79
|
+
unicode-display_width (2.1.0)
|
80
|
+
zeitwerk (2.5.4)
|
84
81
|
|
85
82
|
PLATFORMS
|
86
83
|
ruby
|
87
84
|
|
88
85
|
DEPENDENCIES
|
89
86
|
activerecord (~> 6.0)
|
90
|
-
codecov (~> 0.
|
87
|
+
codecov (~> 0.6.0)
|
91
88
|
database_cleaner-active_record (~> 1.8)
|
92
89
|
light-services!
|
93
90
|
rake (~> 13.0)
|
94
|
-
rspec (~> 3.
|
95
|
-
rubocop (~>
|
96
|
-
rubocop-performance (~> 1.
|
97
|
-
rubocop-rspec (~>
|
98
|
-
simplecov (~> 0.
|
91
|
+
rspec (~> 3.11)
|
92
|
+
rubocop (~> 1.27)
|
93
|
+
rubocop-performance (~> 1.13)
|
94
|
+
rubocop-rspec (~> 2.9)
|
95
|
+
simplecov (~> 0.21)
|
99
96
|
sqlite3 (~> 1.4)
|
100
97
|
|
101
98
|
BUNDLED WITH
|
data/README.md
CHANGED
@@ -1,4 +1,328 @@
|
|
1
|
-
# Light Services
|
2
|
-
![CI](https://github.com/light-ruby/light-services/workflows/CI/badge.svg)
|
3
|
-
[![Codecov](https://codecov.io/gh/light-ruby/light-services/branch/master/graph/badge.svg)](https://codecov.io/gh/light-ruby/light-services)
|
1
|
+
# 🚀 Light Services <sup>BETA</sup>
|
4
2
|
|
3
|
+
Implementation of Service Object pattern for Ruby/Rails applications.
|
4
|
+
|
5
|
+
## 👀 Table of Contents
|
6
|
+
1. [Simple Example](#simple-example)
|
7
|
+
2. [Usage](#usage)
|
8
|
+
1. [Arguments](#arguments)
|
9
|
+
2. [Steps](#steps)
|
10
|
+
3. [Outputs](#outputs)
|
11
|
+
4. [Context](#context)
|
12
|
+
3. [Complex Example](#complex-example)
|
13
|
+
4. [More Examples](#more-examples)
|
14
|
+
|
15
|
+
## 💪 Features
|
16
|
+
|
17
|
+
1. Ability to define `arguments`, `steps` and `outputs`
|
18
|
+
2. Isolated behaviour of each service object
|
19
|
+
3. Raising of errors to stop processing next steps
|
20
|
+
4. Wrapping actions into database transactions
|
21
|
+
5. Ability to pass context to child service object
|
22
|
+
6. Framework agnostic
|
23
|
+
7. 100% test coverage
|
24
|
+
|
25
|
+
## ❌ Problems
|
26
|
+
|
27
|
+
As this gem was just for internal usage, it has some problems:
|
28
|
+
|
29
|
+
1. Gem isn't documented well
|
30
|
+
2. Code doesn't have any comments
|
31
|
+
3. Repo doesn't have any CI/CD
|
32
|
+
|
33
|
+
## Installation
|
34
|
+
|
35
|
+
Add this line to your application's Gemfile:
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
gem 'light-services', '~> 2.0.0.rc7'
|
39
|
+
```
|
40
|
+
|
41
|
+
## Simple Example
|
42
|
+
|
43
|
+
### Send notification
|
44
|
+
|
45
|
+
Let's create an elementary service object that sends a notification to the user.
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
class User::SendNotification < ApplicationService
|
49
|
+
# Arguments
|
50
|
+
arg :user, type: User
|
51
|
+
arg :text, type: :string
|
52
|
+
|
53
|
+
# Steps
|
54
|
+
step :validate_user
|
55
|
+
step :validate_text
|
56
|
+
step :send_notification
|
57
|
+
|
58
|
+
# Outputs
|
59
|
+
output :response
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def validate_user
|
64
|
+
return if user.active?
|
65
|
+
|
66
|
+
errors.add(:user, "isn't active")
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_text
|
70
|
+
return if text.present?
|
71
|
+
|
72
|
+
errors.add(:text, "must be present")
|
73
|
+
end
|
74
|
+
|
75
|
+
def send_notification
|
76
|
+
self.response = ExternalAPI.send_message(...)
|
77
|
+
rescue ExternalAPI::Error
|
78
|
+
errors.add(:base, "External API doesn't work")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
```
|
82
|
+
|
83
|
+
## Usage
|
84
|
+
|
85
|
+
### Arguments
|
86
|
+
|
87
|
+
You may send some arguments into the service object.
|
88
|
+
|
89
|
+
**How to define arguments:**
|
90
|
+
```ruby
|
91
|
+
class User::SendNotification < ApplicationService
|
92
|
+
# Required argument
|
93
|
+
arg :user, type: User
|
94
|
+
|
95
|
+
# Optional argument
|
96
|
+
arg :device, type: Device, optional: true
|
97
|
+
|
98
|
+
# Argument with default value
|
99
|
+
arg :text, type: :string, default: "Hello, how are you?"
|
100
|
+
|
101
|
+
# Argument with multiple allowed types
|
102
|
+
arg :retry, type: [TrueClass, FalseClass], default: false
|
103
|
+
|
104
|
+
# Argument which will be automatically passed into child components
|
105
|
+
arg :provider, type: Provider, context: true
|
106
|
+
end
|
107
|
+
```
|
108
|
+
|
109
|
+
**How to pass arguments in controller:**
|
110
|
+
```ruby
|
111
|
+
class UsersController
|
112
|
+
def send_notification
|
113
|
+
service = User::SendNotification.run(user: User.first, provider: Provider.first)
|
114
|
+
# ...
|
115
|
+
end
|
116
|
+
end
|
117
|
+
```
|
118
|
+
|
119
|
+
**How to pass arguments and context from parent to child service object:**
|
120
|
+
```ruby
|
121
|
+
class User::Update
|
122
|
+
# Arguments
|
123
|
+
arg :user, type: User, context: true
|
124
|
+
|
125
|
+
# Steps
|
126
|
+
# ...
|
127
|
+
step :send_notification
|
128
|
+
|
129
|
+
private
|
130
|
+
|
131
|
+
# ...
|
132
|
+
|
133
|
+
def send_notification
|
134
|
+
User::SendNotification
|
135
|
+
.with(self) # This line specifies the current service object as a parent and passes all context arguments into a child service object
|
136
|
+
.run(text: "Your profile was updated") # We don't need to pass `user` here as it's a context argument
|
137
|
+
end
|
138
|
+
end
|
139
|
+
```
|
140
|
+
|
141
|
+
### Steps
|
142
|
+
|
143
|
+
Steps are a bit more powerful than you think.
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
class User::Charge
|
147
|
+
# Run step only when condition meets
|
148
|
+
step :create_payment_account, unless: :payment_account?
|
149
|
+
|
150
|
+
# Run step only when condition meets
|
151
|
+
step :charge_credit_card, if: :pay_with_credit_card?
|
152
|
+
|
153
|
+
# Run step after other step
|
154
|
+
step :update_payment_account, after: :create_payment_account
|
155
|
+
|
156
|
+
# Or before
|
157
|
+
step :save_information, before: :log_action
|
158
|
+
end
|
159
|
+
```
|
160
|
+
|
161
|
+
### Outputs
|
162
|
+
|
163
|
+
Outputs are pretty straightforward.
|
164
|
+
|
165
|
+
```ruby
|
166
|
+
class User::Charge
|
167
|
+
# Simple output
|
168
|
+
output :payment
|
169
|
+
|
170
|
+
# Output with initial value
|
171
|
+
output :items, default: []
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
### Context
|
176
|
+
|
177
|
+
The context specifies the relationship between parent and child service objects.
|
178
|
+
|
179
|
+
What context does:
|
180
|
+
1. It tells the parent service object to pass context arguments into a child service object
|
181
|
+
2. When the child service object fails, it tells the parent service object to fail too (customizable)
|
182
|
+
|
183
|
+
```ruby
|
184
|
+
class User::Charge
|
185
|
+
# Arguments
|
186
|
+
arg :user, type: User, context: true
|
187
|
+
arg :cents, type: Integer
|
188
|
+
|
189
|
+
# ...
|
190
|
+
|
191
|
+
private
|
192
|
+
|
193
|
+
# ...
|
194
|
+
|
195
|
+
def send_notification
|
196
|
+
# Run service object w/o any context
|
197
|
+
User::SendNotification
|
198
|
+
.run(user: user, text: "...")
|
199
|
+
|
200
|
+
# Run service object and specify current one as a parent
|
201
|
+
User::SendNotification
|
202
|
+
.with(self)
|
203
|
+
.run(text: "...")
|
204
|
+
|
205
|
+
# Run service object with context but don't load errors from the child service object
|
206
|
+
service = User::SendNotification
|
207
|
+
.with(self, load_errors: false)
|
208
|
+
.run(text: "...")
|
209
|
+
|
210
|
+
if service.failed?
|
211
|
+
# That's ok. Process it somehow...
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
```
|
216
|
+
|
217
|
+
## Complex Example
|
218
|
+
|
219
|
+
### Creation of records
|
220
|
+
|
221
|
+
Let's investigate a more exciting example where we create a wrapper to create database records.
|
222
|
+
|
223
|
+
**Here is an example of controller (pretty thin, yeah? but we can make it even thinner):**
|
224
|
+
```ruby
|
225
|
+
class ContactsController < ApplicationController
|
226
|
+
# ...
|
227
|
+
|
228
|
+
def create
|
229
|
+
service = Contact::Create.run(service_args)
|
230
|
+
|
231
|
+
if service.success?
|
232
|
+
render locals: { contact: service.contact }, status: :ok
|
233
|
+
else
|
234
|
+
render "shared/errors", locals: { service: service }, status: :bad_request
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# ...
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
**Then, let's create a service object (no way, it couldn't be so simple):**
|
243
|
+
```ruby
|
244
|
+
class Contact::Create < CreateService
|
245
|
+
# We create alias just for a better readability
|
246
|
+
# so that we can call `service.contact` instead of `service.record`
|
247
|
+
alias contact record
|
248
|
+
|
249
|
+
private
|
250
|
+
|
251
|
+
def filtered_params
|
252
|
+
params.require(:contact).permit(:name, :phone)
|
253
|
+
end
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
**Let's check what logic we put into `CreateService`:**
|
258
|
+
```ruby
|
259
|
+
class CreateService < ApplicationService
|
260
|
+
# Arguments
|
261
|
+
arg :attributes, type: Hash, optional: true
|
262
|
+
|
263
|
+
# Outputs
|
264
|
+
output :record
|
265
|
+
|
266
|
+
# Steps
|
267
|
+
step :initialize_record
|
268
|
+
step :assign_attributes
|
269
|
+
step :authorize
|
270
|
+
step :validate
|
271
|
+
step :save_record
|
272
|
+
|
273
|
+
private
|
274
|
+
|
275
|
+
def initialize_record
|
276
|
+
self.record = self.class.module_parent.new
|
277
|
+
end
|
278
|
+
|
279
|
+
def assign_attributes
|
280
|
+
record.assign_attributes(filtered_params)
|
281
|
+
end
|
282
|
+
|
283
|
+
def authorize
|
284
|
+
return if force || attributes
|
285
|
+
|
286
|
+
# Here is some Pundit logic 👇
|
287
|
+
authorize!(record, with_action: :create?)
|
288
|
+
end
|
289
|
+
|
290
|
+
def validate
|
291
|
+
return if record.valid?
|
292
|
+
|
293
|
+
errors.copy_from(record)
|
294
|
+
end
|
295
|
+
|
296
|
+
def save_record
|
297
|
+
record.save_with!(self)
|
298
|
+
end
|
299
|
+
|
300
|
+
def filtered_params
|
301
|
+
raise NotImplementedError
|
302
|
+
end
|
303
|
+
end
|
304
|
+
```
|
305
|
+
|
306
|
+
**Now we can easily reuse all this code and create as many services as we want:**
|
307
|
+
```ruby
|
308
|
+
class Team::Create < CreateService
|
309
|
+
alias team record
|
310
|
+
|
311
|
+
private
|
312
|
+
|
313
|
+
def filtered_params
|
314
|
+
params.require(:team).permit(:name)
|
315
|
+
end
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
## More examples
|
320
|
+
|
321
|
+
You can find more examples here:
|
322
|
+
[https://github.com/light-ruby/light-services/tree/v2/spec/data/services](https://github.com/light-ruby/light-services/tree/v2/spec/data/services)
|
323
|
+
|
324
|
+
# Happy coding!
|
325
|
+
|
326
|
+
## License
|
327
|
+
|
328
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/lib/light/services/base.rb
CHANGED
@@ -28,14 +28,10 @@ module Light
|
|
28
28
|
mount_class_based_collection :arguments, item_class: Settings::Argument, shortcut: :arg, allow_redefine: true
|
29
29
|
|
30
30
|
# Arguments
|
31
|
-
|
31
|
+
arg :verbose, default: false
|
32
32
|
arg :benchmark, default: false
|
33
33
|
arg :deepness, default: 0, context: true
|
34
34
|
|
35
|
-
# Steps
|
36
|
-
step :load_defaults_and_validate
|
37
|
-
step :log_header, if: :benchmark?
|
38
|
-
|
39
35
|
# Getters
|
40
36
|
attr_reader :outputs, :arguments, :errors, :warnings
|
41
37
|
|
@@ -78,6 +74,9 @@ module Light
|
|
78
74
|
end
|
79
75
|
|
80
76
|
def call
|
77
|
+
load_defaults_and_validate
|
78
|
+
log_header if benchmark? || verbose?
|
79
|
+
|
81
80
|
time = Benchmark.ms do
|
82
81
|
run_steps
|
83
82
|
run_steps_with_always
|
@@ -103,7 +102,7 @@ module Light
|
|
103
102
|
|
104
103
|
def with(service_or_config = {}, config = {})
|
105
104
|
service = service_or_config.is_a?(Hash) ? nil : service_or_config
|
106
|
-
config =
|
105
|
+
config = service_or_config unless service
|
107
106
|
|
108
107
|
BaseWithContext.new(self, service, config)
|
109
108
|
end
|
@@ -181,9 +180,9 @@ module Light
|
|
181
180
|
log "🏎 Run service #{self.class}"
|
182
181
|
end
|
183
182
|
|
184
|
-
def within_transaction
|
183
|
+
def within_transaction(&block)
|
185
184
|
if @config[:use_transactions] && defined?(ActiveRecord::Base)
|
186
|
-
ActiveRecord::Base.transaction(requires_new: true)
|
185
|
+
ActiveRecord::Base.transaction(requires_new: true, &block)
|
187
186
|
else
|
188
187
|
yield
|
189
188
|
end
|
@@ -40,7 +40,11 @@ module Light
|
|
40
40
|
settings_collection.each do |name, settings|
|
41
41
|
next if !settings.default_exists || key?(name)
|
42
42
|
|
43
|
-
|
43
|
+
if settings.default.is_a?(Proc)
|
44
|
+
set(name, settings.default.call)
|
45
|
+
else
|
46
|
+
set(name, deep_dup(settings.default))
|
47
|
+
end
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
@@ -10,12 +10,12 @@ module Light
|
|
10
10
|
@messages = {}
|
11
11
|
end
|
12
12
|
|
13
|
-
def add(key,
|
14
|
-
raise Light::Services::Error, "Error text can't be blank" if !
|
13
|
+
def add(key, texts, opts = {})
|
14
|
+
raise Light::Services::Error, "Error text can't be blank" if !texts || texts.blank?
|
15
15
|
|
16
16
|
message = nil
|
17
17
|
|
18
|
-
[*
|
18
|
+
[*texts].each do |text|
|
19
19
|
message = text.is_a?(Message) ? text : Message.new(key, text, opts)
|
20
20
|
|
21
21
|
@messages[key] ||= []
|
@@ -48,7 +48,7 @@ module Light
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def copy_to(entity)
|
51
|
-
if defined?(ActiveRecord::Base) && entity.is_a?(ActiveRecord::Base) || entity.is_a?(Light::Services::Base)
|
51
|
+
if (defined?(ActiveRecord::Base) && entity.is_a?(ActiveRecord::Base)) || entity.is_a?(Light::Services::Base)
|
52
52
|
each do |key, messages|
|
53
53
|
messages.each do |message|
|
54
54
|
entity.errors.add(key, message.to_s)
|
@@ -67,7 +67,7 @@ module Light
|
|
67
67
|
end
|
68
68
|
|
69
69
|
def to_h
|
70
|
-
@messages.to_h.
|
70
|
+
@messages.to_h.transform_values { |value| value.map(&:to_s) }
|
71
71
|
end
|
72
72
|
|
73
73
|
def method_missing(method, *args, &block)
|
@@ -25,9 +25,10 @@ module Light
|
|
25
25
|
|
26
26
|
def valid_type?(value)
|
27
27
|
return if !@type || [*@type].any? do |type|
|
28
|
-
|
28
|
+
case type
|
29
|
+
when :boolean
|
29
30
|
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
30
|
-
|
31
|
+
when Symbol
|
31
32
|
arg_type(value) == type
|
32
33
|
else
|
33
34
|
value.is_a?(type)
|
@@ -45,9 +46,9 @@ module Light
|
|
45
46
|
|
46
47
|
@arg_types_cache[klass] ||= klass
|
47
48
|
.name
|
48
|
-
.gsub(/::/,
|
49
|
-
.gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
50
|
-
.gsub(/([a-z\d])([A-Z])/,'\1_\2')
|
49
|
+
.gsub(/::/, "/")
|
50
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
51
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
51
52
|
.tr("-", "_")
|
52
53
|
.downcase
|
53
54
|
.to_sym
|
data/light-services.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light-services
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.rc8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Emelianenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Powerful implementation of Service Object pattern for Ruby and Rails
|
14
14
|
email:
|
@@ -56,6 +56,7 @@ metadata:
|
|
56
56
|
homepage_uri: https://github.com/light-ruby/light-services
|
57
57
|
source_code_uri: https://github.com/light-ruby/light-services
|
58
58
|
changelog_uri: https://github.com/light-ruby/light-services/blob/master/CHANGELOG.md
|
59
|
+
rubygems_mfa_required: 'true'
|
59
60
|
post_install_message:
|
60
61
|
rdoc_options: []
|
61
62
|
require_paths:
|
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
72
|
- !ruby/object:Gem::Version
|
72
73
|
version: 1.3.1
|
73
74
|
requirements: []
|
74
|
-
rubygems_version: 3.1.
|
75
|
+
rubygems_version: 3.1.6
|
75
76
|
signing_key:
|
76
77
|
specification_version: 4
|
77
78
|
summary: Powerful implementation of Service Object pattern for Ruby and Rails
|