light_operations 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +2 -1
- data/README.md +95 -25
- data/lib/light_operations/core.rb +12 -15
- data/lib/light_operations/version.rb +1 -1
- data/spec/lib/core_spec.rb +43 -11
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b1cafc172727a76d2b73b15c1eaf8c16726dd4e
|
4
|
+
data.tar.gz: 5cbaaa590c2c85b73a440c2366f67960a789d02a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd91a0435ba27b38faa56e17b0ea1ed94bc2b2a645858e9b7c1324a8b171447cf983a3e8b0de37af3b1795efc76feb4a45c0bc197f893497a888c40b034ad6b9
|
7
|
+
data.tar.gz: 9e29c25d4ccbd1da90da0ad9e8ad6b85ccda391663d1b280e27c7e9eb7c8258198c61ad523fbe1bdac899091620c3894836f37abfbd162df2468dedfa758e640
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -39,6 +39,71 @@ There is many possible usecases where and how you could use operations.
|
|
39
39
|
You can build csacade of opreations, use them one after the other,
|
40
40
|
use them recursively and a lot more.
|
41
41
|
|
42
|
+
|
43
|
+
Examples:
|
44
|
+
|
45
|
+
#### Simple
|
46
|
+
```ruby
|
47
|
+
require 'light_operations'
|
48
|
+
|
49
|
+
class CorrectNumber < LightOperations::Core
|
50
|
+
def execute(params)
|
51
|
+
params[:number] > 0 || fail!(:wrong_number)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
op = CorrectNumber.new
|
56
|
+
|
57
|
+
p op.run(number: 0).success? # return false
|
58
|
+
p op.run(number: 0).false? # return true
|
59
|
+
p op.run(number: 1).success? # return true
|
60
|
+
p op.run(number: 1).false? # return false
|
61
|
+
```
|
62
|
+
|
63
|
+
#### With active_model
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'light_operations'
|
67
|
+
require 'active_model'
|
68
|
+
|
69
|
+
class Person
|
70
|
+
include ActiveModel::Model
|
71
|
+
|
72
|
+
attr_accessor :name, :age
|
73
|
+
validates_presence_of :name
|
74
|
+
end
|
75
|
+
|
76
|
+
class CreatePerson < LightOperations::Core
|
77
|
+
subject_name :person
|
78
|
+
def execute(params = {})
|
79
|
+
dependency(:repository).new(params).tap do |person|
|
80
|
+
person.valid?
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class FakeController
|
86
|
+
def create(params = {})
|
87
|
+
create_operation.run(params)
|
88
|
+
end
|
89
|
+
|
90
|
+
def create_operation
|
91
|
+
@create_operation ||= CreatePerson.new(repository: Person).bind_with(self).on(success: :render_success, fail: :render_fail)
|
92
|
+
end
|
93
|
+
|
94
|
+
def render_success(operation)
|
95
|
+
person = operation.person
|
96
|
+
puts "name: #{person.name}"
|
97
|
+
end
|
98
|
+
|
99
|
+
def render_fail(operation)
|
100
|
+
person, errors = operation.subject, operation.errors
|
101
|
+
puts errors.as_json
|
102
|
+
puts "name: #{person.name}"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
```
|
42
107
|
Class
|
43
108
|
|
44
109
|
```ruby
|
@@ -60,9 +125,9 @@ You can add deferred actions for success and fail
|
|
60
125
|
|
61
126
|
```ruby
|
62
127
|
# 1
|
63
|
-
MyOperation.new.on_success { |
|
128
|
+
MyOperation.new.on_success { |operation| render :done, locals: { model: operation.subject } }
|
64
129
|
# 2
|
65
|
-
MyOperation.new.on(success: -> () { |
|
130
|
+
MyOperation.new.on(success: -> () { |operation| render :done, locals: { model: operation.subject } )
|
66
131
|
```
|
67
132
|
|
68
133
|
When you bind operation with other object you could delegate actions to binded object methods
|
@@ -104,24 +169,26 @@ operation.new(dependencies).tap do |op|
|
|
104
169
|
end
|
105
170
|
```
|
106
171
|
|
107
|
-
#### success block or method receive
|
108
|
-
|
172
|
+
#### success block or method receive operation as argument
|
173
|
+
##### operation.subject hold success object. You can use subject_name to create alias_method for subject
|
174
|
+
`(operation) -> { }`
|
109
175
|
|
110
176
|
or
|
111
177
|
|
112
178
|
```ruby
|
113
|
-
def success_method(
|
179
|
+
def success_method(operation)
|
114
180
|
...
|
115
181
|
end
|
116
182
|
|
117
183
|
```
|
118
|
-
#### fail block or method receive
|
119
|
-
|
184
|
+
#### fail block or method receive operation as argument
|
185
|
+
##### operation.subject, operation.errors hold failure object and errors. You can use subject_name to create alias_method for subject
|
186
|
+
`(operation) -> { }`
|
120
187
|
|
121
188
|
or
|
122
189
|
|
123
190
|
```ruby
|
124
|
-
def fail_method(
|
191
|
+
def fail_method(operation)
|
125
192
|
...
|
126
193
|
end
|
127
194
|
|
@@ -182,6 +249,7 @@ Operation
|
|
182
249
|
```ruby
|
183
250
|
class CollectFeedsOperation < LightOperations::Core
|
184
251
|
rescue_from Timeout::Error, with: :on_timeout
|
252
|
+
subject_name :news
|
185
253
|
|
186
254
|
def execute(params = {})
|
187
255
|
dependency(:http_client).get(params.fetch(:url)).body
|
@@ -208,14 +276,14 @@ class NewsFeedsController < ApplicationController
|
|
208
276
|
|
209
277
|
private
|
210
278
|
|
211
|
-
def second_attempt(
|
212
|
-
|
279
|
+
def second_attempt(operation)
|
280
|
+
operation
|
213
281
|
.on_fail(:display_old_news)
|
214
282
|
.run(url: BACKUP_NEWS_URL)
|
215
283
|
end
|
216
284
|
|
217
|
-
def display_news(
|
218
|
-
render :display_news, locals: { news: news }
|
285
|
+
def display_news(operation)
|
286
|
+
render :display_news, locals: { news: operation.news }
|
219
287
|
end
|
220
288
|
|
221
289
|
def display_old_news
|
@@ -237,6 +305,7 @@ Operation
|
|
237
305
|
|
238
306
|
```ruby
|
239
307
|
class AddBookOperation < LightOperations::Core
|
308
|
+
subject_name :book
|
240
309
|
def execute(params = {})
|
241
310
|
dependency(:book_model).new(params).tap do |model|
|
242
311
|
model.valid? # this method automatically provide errors from model.errors
|
@@ -266,11 +335,12 @@ class BooksController < ApplicationController
|
|
266
335
|
|
267
336
|
private
|
268
337
|
|
269
|
-
def book_created(
|
270
|
-
redirect_to :index, notice: "book #{book.name} created"
|
338
|
+
def book_created(operation)
|
339
|
+
redirect_to :index, notice: "book #{operation.book.name} created"
|
271
340
|
end
|
272
341
|
|
273
|
-
def render_book_form(
|
342
|
+
def render_book_form(operation=nil)
|
343
|
+
book = operation ? operation.book : Book.new
|
274
344
|
render :new, locals: { book: book }
|
275
345
|
end
|
276
346
|
|
@@ -291,7 +361,7 @@ Operation
|
|
291
361
|
```ruby
|
292
362
|
class AuthOperation < LightOperations::Core
|
293
363
|
rescue_from AuthFail, with: :on_auth_error
|
294
|
-
|
364
|
+
subject_name :account
|
295
365
|
def execute(params = {})
|
296
366
|
dependency(:auth_service).login(login: login(params), password: password(params))
|
297
367
|
end
|
@@ -328,13 +398,13 @@ class AuthController < ApplicationController
|
|
328
398
|
|
329
399
|
private
|
330
400
|
|
331
|
-
def create_session_with_dashbord_redirection(
|
332
|
-
session_create_for(account)
|
401
|
+
def create_session_with_dashbord_redirection(operation)
|
402
|
+
session_create_for(operation.account)
|
333
403
|
redirect_to :dashboard
|
334
404
|
end
|
335
405
|
|
336
|
-
def render_account_with_errors(
|
337
|
-
render :new, locals: { account: account }
|
406
|
+
def render_account_with_errors(operation)
|
407
|
+
render :new, locals: { account: operation.account }
|
338
408
|
end
|
339
409
|
|
340
410
|
def auth_op
|
@@ -357,8 +427,8 @@ class AuthController < ApplicationController
|
|
357
427
|
|
358
428
|
def create
|
359
429
|
auth_op
|
360
|
-
.on_success{ |
|
361
|
-
.on_fail { |
|
430
|
+
.on_success{ |op| create_session_with_dashbord_redirection(op.account) }
|
431
|
+
.on_fail { |op| render :new, locals: { account: op.account } }
|
362
432
|
.run(params)
|
363
433
|
end
|
364
434
|
|
@@ -394,14 +464,14 @@ class AuthController < ApplicationController
|
|
394
464
|
private
|
395
465
|
|
396
466
|
def go_to_dashboard
|
397
|
-
-> (
|
398
|
-
session_create_for(account)
|
467
|
+
-> (op) do
|
468
|
+
session_create_for(op.account)
|
399
469
|
redirect_to :dashboard
|
400
470
|
end
|
401
471
|
end
|
402
472
|
|
403
473
|
def go_to_login
|
404
|
-
-> (
|
474
|
+
-> (op) { render :new, locals: { account: op.account } }
|
405
475
|
end
|
406
476
|
|
407
477
|
def auth_op
|
@@ -5,7 +5,11 @@ module LightOperations
|
|
5
5
|
include ::ActiveSupport::Rescuable
|
6
6
|
MissingDependency = Class.new(StandardError)
|
7
7
|
|
8
|
-
attr_reader :
|
8
|
+
attr_reader :subject
|
9
|
+
|
10
|
+
def self.subject_name(method_name)
|
11
|
+
send(:define_method, method_name, proc { self.subject })
|
12
|
+
end
|
9
13
|
|
10
14
|
def initialize(dependencies = {})
|
11
15
|
@dependencies = dependencies
|
@@ -78,28 +82,21 @@ module LightOperations
|
|
78
82
|
|
79
83
|
protected
|
80
84
|
|
81
|
-
attr_reader :fail_errors
|
85
|
+
attr_reader :dependencies, :bind_object, :fail_errors
|
82
86
|
|
83
87
|
def actions_assign(hash, *keys)
|
84
88
|
keys.each { |key| actions[key] = hash[key] if hash.key?(key) }
|
85
89
|
end
|
86
90
|
|
87
91
|
def execute_actions
|
88
|
-
success? ?
|
89
|
-
end
|
90
|
-
|
91
|
-
def execute_success_action
|
92
|
-
return unless actions.key?(:success)
|
93
|
-
action = actions[:success]
|
94
|
-
bind_object.send(action, subject) if action.is_a?(Symbol) && bind_object
|
95
|
-
action.call(subject) if action.is_a?(Proc)
|
92
|
+
success? ? execute_action_kind(:success) : execute_action_kind(:fail)
|
96
93
|
end
|
97
94
|
|
98
|
-
def
|
99
|
-
return unless actions.key?(
|
100
|
-
action = actions[
|
101
|
-
bind_object.send(action,
|
102
|
-
action.call(
|
95
|
+
def execute_action_kind(kind)
|
96
|
+
return unless actions.key?(kind)
|
97
|
+
action = actions[kind]
|
98
|
+
bind_object.send(action, self) if action.is_a?(Symbol) && bind_object
|
99
|
+
action.call(self) if action.is_a?(Proc)
|
103
100
|
end
|
104
101
|
|
105
102
|
def fail!(fail_obj = true)
|
data/spec/lib/core_spec.rb
CHANGED
@@ -8,9 +8,9 @@ describe LightOperations::Core do
|
|
8
8
|
let(:binding_object) do
|
9
9
|
Class.new(Object).tap do |klass|
|
10
10
|
klass.class_eval do
|
11
|
-
def success_action(
|
11
|
+
def success_action(_operation); end
|
12
12
|
|
13
|
-
def error_action(
|
13
|
+
def error_action(_operaation); end
|
14
14
|
end
|
15
15
|
end.new
|
16
16
|
end
|
@@ -27,6 +27,17 @@ describe LightOperations::Core do
|
|
27
27
|
expect { subject.on(success: :do_nothing).run }.to raise_error('Not implemented yet')
|
28
28
|
end
|
29
29
|
|
30
|
+
it '.subject_name' do
|
31
|
+
test_obj = subject_factory do
|
32
|
+
subject_name :order
|
33
|
+
def execute(params)
|
34
|
+
params[:done] || fail!(:error)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
test_obj.run(done: :success)
|
38
|
+
expect(test_obj.order).to eq(:success)
|
39
|
+
end
|
40
|
+
|
30
41
|
context 'use cases' do
|
31
42
|
# dependency using
|
32
43
|
|
@@ -112,12 +123,12 @@ describe LightOperations::Core do
|
|
112
123
|
|
113
124
|
context '#on_success' do
|
114
125
|
it 'when bind_with and send_method is used' do
|
115
|
-
expect(binding_object).to receive(:success_action).with(
|
126
|
+
expect(binding_object).to receive(:success_action).with(subject)
|
116
127
|
subject.on_success(:success_action).bind_with(binding_object).run
|
117
128
|
end
|
118
129
|
|
119
130
|
it 'when block is used' do
|
120
|
-
subject.on_success { |
|
131
|
+
subject.on_success { |operation| expect(operation.subject).to eq(:success) }.run
|
121
132
|
end
|
122
133
|
end
|
123
134
|
|
@@ -172,14 +183,14 @@ describe LightOperations::Core do
|
|
172
183
|
|
173
184
|
context '#on_fail' do
|
174
185
|
it 'when bind_with and send_method is used' do
|
175
|
-
expect(binding_object).to receive(:error_action).with(
|
186
|
+
expect(binding_object).to receive(:error_action).with(subject)
|
176
187
|
subject.bind_with(binding_object).on_fail(:error_action).run
|
177
188
|
end
|
178
189
|
|
179
190
|
it 'when block is used' do
|
180
|
-
subject.on_fail do |
|
181
|
-
expect(
|
182
|
-
expect(errors).to eq([email: :unknown])
|
191
|
+
subject.on_fail do |operation|
|
192
|
+
expect(operation.subject).to eq(:fail)
|
193
|
+
expect(operation.errors).to eq([email: :unknown])
|
183
194
|
end
|
184
195
|
subject.run
|
185
196
|
end
|
@@ -202,7 +213,7 @@ describe LightOperations::Core do
|
|
202
213
|
context 'prepare operation to reuse or simply clear' do
|
203
214
|
it '#unbind!' do
|
204
215
|
subject.bind_with(:some_object)
|
205
|
-
expect { subject.unbind! }.to change { subject.bind_object }
|
216
|
+
expect { subject.unbind! }.to change { subject.send(:bind_object) }
|
206
217
|
.from(:some_object)
|
207
218
|
.to(nil)
|
208
219
|
end
|
@@ -235,6 +246,27 @@ describe LightOperations::Core do
|
|
235
246
|
end
|
236
247
|
end
|
237
248
|
|
249
|
+
context '#fail! in execute when is without arguments' do
|
250
|
+
subject do
|
251
|
+
subject_factory do
|
252
|
+
def execute(params = {})
|
253
|
+
fail! unless params.key?(:result)
|
254
|
+
params[:result]
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
it 'setup operation in fail state' do
|
260
|
+
expect(subject.run.success?).to eq(false)
|
261
|
+
expect(subject.run.fail?).to eq(true)
|
262
|
+
end
|
263
|
+
|
264
|
+
it 'setup operation in fail state' do
|
265
|
+
expect(subject.run(result: 'ok').success?).to eq(true)
|
266
|
+
expect(subject.run(result: 'ok').fail?).to eq(false)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
238
270
|
context 'Operation executed several times' do
|
239
271
|
subject do
|
240
272
|
subject_factory do
|
@@ -250,9 +282,9 @@ describe LightOperations::Core do
|
|
250
282
|
.bind_with(binding_object)
|
251
283
|
.on(success: :success_action, fail: :error_action)
|
252
284
|
|
253
|
-
expect(binding_object).to receive(:error_action).with(
|
285
|
+
expect(binding_object).to receive(:error_action).with(subject)
|
254
286
|
subject.run
|
255
|
-
expect(binding_object).to receive(:success_action).with(
|
287
|
+
expect(binding_object).to receive(:success_action).with(subject)
|
256
288
|
subject.run(result: :success)
|
257
289
|
end
|
258
290
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: light_operations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Pawel Niemczyk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-03-
|
11
|
+
date: 2015-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|