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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: daff2324f298c8c3565ac162ad4f898b46a67444
4
- data.tar.gz: c29a35d3bb49d0f939dd0ceda12d7199bf818af4
3
+ metadata.gz: 6b1cafc172727a76d2b73b15c1eaf8c16726dd4e
4
+ data.tar.gz: 5cbaaa590c2c85b73a440c2366f67960a789d02a
5
5
  SHA512:
6
- metadata.gz: e49fc15fc00e7a754d7cbcf9d1b42543b01ab1233916e57af9238453de7f222e55d7d515d49b6bebaa15f00856a773fb46f2fe728f4d203ee86e460d0ecfa377
7
- data.tar.gz: 75f5551894d511923473fd6644c836510586b1a74f0bfdcb0b04e22da3b8127493146102deb57b7d7d7714d1c3e6dd4751b47b843d62b040ee40e919be9a7ea7
6
+ metadata.gz: bd91a0435ba27b38faa56e17b0ea1ed94bc2b2a645858e9b7c1324a8b171447cf983a3e8b0de37af3b1795efc76feb4a45c0bc197f893497a888c40b034ad6b9
7
+ data.tar.gz: 9e29c25d4ccbd1da90da0ad9e8ad6b85ccda391663d1b280e27c7e9eb7c8258198c61ad523fbe1bdac899091620c3894836f37abfbd162df2468dedfa758e640
data/.rubocop.yml CHANGED
@@ -45,4 +45,5 @@ Metrics/LineLength:
45
45
  AllCops:
46
46
  Exclude:
47
47
  - '**/Guardfile'
48
- - '**/light_operations.gemspec'
48
+ - '**/model_operations.gemspec'
49
+ - '**/spec/support/factory_helper.rb'
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 { |model| render :done, locals: { model: model } }
128
+ MyOperation.new.on_success { |operation| render :done, locals: { model: operation.subject } }
64
129
  # 2
65
- MyOperation.new.on(success: -> () { |model| render :done, locals: { model: model } )
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 subject as argument
108
- `(subject) -> { }`
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(subject)
179
+ def success_method(operation)
114
180
  ...
115
181
  end
116
182
 
117
183
  ```
118
- #### fail block or method receive subject and errors as argument
119
- `(subject, errors) -> { }`
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(subject, errors)
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(_news, _errors)
212
- collect_feeds_op
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(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(book)
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(book = Book.new, _errors = nil)
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(account)
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(account, _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{ |account| create_session_with_dashbord_redirection(account) }
361
- .on_fail { |account, _errors| render :new, locals: { account: account } }
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
- -> (account) do
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
- -> (account, _errors) { render :new, locals: { account: account } }
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 :dependencies, :bind_object, :subject
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? ? execute_success_action : execute_fail_action
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 execute_fail_action
99
- return unless actions.key?(:fail)
100
- action = actions[:fail]
101
- bind_object.send(action, subject, errors) if action.is_a?(Symbol) && bind_object
102
- action.call(subject, errors) if action.is_a?(Proc)
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)
@@ -1,3 +1,3 @@
1
1
  module LightOperations
2
- VERSION = '0.0.9'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -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(_subject); end
11
+ def success_action(_operation); end
12
12
 
13
- def error_action(_subject, _errors); end
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(:success)
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 { |result| expect(result).to eq(:success) }.run
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(:fail, [email: :unknown])
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 |result, errors|
181
- expect(result).to eq(:fail)
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(nil, :missing_result)
285
+ expect(binding_object).to receive(:error_action).with(subject)
254
286
  subject.run
255
- expect(binding_object).to receive(:success_action).with(:success)
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.9
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-15 00:00:00.000000000 Z
11
+ date: 2015-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport