light_operations 0.0.3 → 0.0.4

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: c894c1e7f9c3a1a15692c6875f4ded5b88d458d9
4
- data.tar.gz: 9d841c8af28c066013159703d302ef42cb354991
3
+ metadata.gz: f01d43765f156039ef8227aa36ef7fc853bbc722
4
+ data.tar.gz: 6a28e10184931953b04722b98ad505e100636307
5
5
  SHA512:
6
- metadata.gz: 2c3dcbef05689a60f891fc292b4fb96079406e6703d5ce7df0ca56ca2fee36ccc6808bb4987bbbfe4f095ec03f2dee656ff1aaa90dc5155a6982ddd4a522f3fb
7
- data.tar.gz: a1b15f8668462cf6409450825a6a9f23d2e20040b44e53a8b39a42f17a73499a23bf28ab70ead3a583911e3453836bbc13e15bcbfe69163c2aae3df8f8a68952
6
+ metadata.gz: 0709083f10d462b9421924e4313323b38dd077a3908827fef106eb8cfee646a6128cde566399fff48cc431c72cc18d5e1c86a8bfa3044d9f61a59a4ba9219527
7
+ data.tar.gz: 80297934730c17e80022a7ecb2c843a3882ae14cd6041fab3a8fa08941e446c47aa6dca8c507005dfc2014dd0777fbe884d8793d6354065193282d61087ce6d5
data/README.md CHANGED
@@ -19,6 +19,109 @@ Or install it yourself as:
19
19
 
20
20
  $ gem install light_operations
21
21
 
22
+ ## How it works
23
+
24
+ Basicly this is a Container for buissnes logic.
25
+
26
+ You can define dependencies during initialization and run with custom parameters.
27
+ When you define deferred actions on `success` and `fail` before operation execution is finished,
28
+ after execution one of those action depend for execution result will be executed.
29
+ Actions could be a block (Proc) or you could delgate execution to method other object,
30
+ by binding operation with specific object with those methods.
31
+ You also could use operation as simple execution and check status by `success?` or `fail?` method
32
+ and then by using `subject` and `errors` method build your own logic to finish your result.
33
+ There is many possible usecases where and how you could use operations.
34
+ You can build csacade of opreations, use them one after the other,
35
+ use them recursively and a lot more.
36
+
37
+ Class
38
+
39
+ ```ruby
40
+ class MyOperation < LightOperations::Core
41
+ def execute(_params = nil)
42
+ dependency(:my_service) # when missing MissingDependency error will be raised
43
+ end
44
+ end
45
+
46
+ ```
47
+
48
+ Initialization
49
+
50
+ ```ruby
51
+ MyOperation.new(my_service: MyService.new)
52
+ ```
53
+
54
+ You can add deferred actions for success and fail
55
+
56
+ ```ruby
57
+ # 1
58
+ MyOperation.new.on_success { |model| render :done, locals: { model: model } }
59
+ # 2
60
+ MyOperation.new.on(success: -> () { |model| render :done, locals: { model: model } )
61
+ ```
62
+
63
+ When you bind operation with other object you could delegate actions to binded object methods
64
+
65
+ ```ruby
66
+ # 1
67
+ MyOperation.new.bind_with(self).on_success(:done)
68
+ # 2
69
+ MyOperation.new.bind_with(self).on(success: :done)
70
+ ```
71
+
72
+ Execution method `#run` finalize actions execution
73
+
74
+ ```ruby
75
+ MyOperation.new.bind_with(self).on(success: :done).run(params)
76
+ ```
77
+
78
+ After execution operation hold execution state you could get back all info you need
79
+
80
+ - `#success?` => `true/false`
81
+ - `#fail?` => `true/false`
82
+ - `#subject?` => `success or fail object`
83
+ - `#errors` => `errors by default array but you can return any objec tou want`
84
+
85
+ Default usage
86
+
87
+ ```ruby
88
+ operation.new(dependencies)
89
+ .on(success: :done, fail: :show_error)
90
+ .bind_with(self)
91
+ .run(params)
92
+ ```
93
+
94
+ or
95
+
96
+ ```ruby
97
+ operation.new(dependencies).tap do |op|
98
+ return op.run(params).success? ? op.subject : op.errors
99
+ end
100
+ ```
101
+
102
+ #### success block or method receive subject as argument
103
+ `(subject) -> { }`
104
+
105
+ or
106
+
107
+ ```ruby
108
+ def success_method(subject)
109
+ ...
110
+ end
111
+
112
+ ```
113
+ #### fail block or method receive subject and errors as argument
114
+ `(subject, errors) -> { }`
115
+
116
+ or
117
+
118
+ ```ruby
119
+ def fail_method(subject, errors)
120
+ ...
121
+ end
122
+
123
+ ```
124
+
22
125
  ## Usage
23
126
 
24
127
 
@@ -37,10 +140,11 @@ class ArticleVoteBumperOperation < LightOperations::Core
37
140
  article.vote = article.vote.next
38
141
  article.save
39
142
  end
143
+ { success: true }
40
144
  end
41
145
 
42
146
  def on_ar_error(_exception)
43
- fail!({ vote: 'could not be updated!' })
147
+ fail!(vote: 'could not be updated!')
44
148
  end
45
149
  end
46
150
  ```
@@ -50,14 +154,14 @@ Controller
50
154
  ```ruby
51
155
  class ArticleVotesController < ApplicationController
52
156
  def up
53
- response = article_vote_bumper_op.run.success? ? { success: true } : article_vote_bumper_op.errors
157
+ response = operation.run.success? ? response.subject : response.errors
54
158
  render :up, json: response
55
159
  end
56
160
 
57
161
  private
58
162
 
59
- def article_vote_bumper_op
60
- @article_vote_bumper_op ||= ArticleVoteBumperOperation.new(article_model: article)
163
+ def operation
164
+ @operation ||= ArticleVoteBumperOperation.new(article_model: article)
61
165
  end
62
166
 
63
167
  def article
@@ -66,7 +170,7 @@ class ArticleVotesController < ApplicationController
66
170
  end
67
171
  ```
68
172
 
69
- #### Basic recursion execution for collect newsfeeds from 2 sources
173
+ #### Basic recursive execution to collect newsfeeds from 2 sources
70
174
 
71
175
  Operation
72
176
 
@@ -92,7 +196,8 @@ class NewsFeedsController < ApplicationController
92
196
  BACKUP_NEWS_URL = 'http://rss.not_so_bad_news.pl'
93
197
  def news
94
198
  collect_feeds_op
95
- on(success: :display_news, fail: :second_attempt)
199
+ .bind_with(self)
200
+ .on(success: :display_news, fail: :second_attempt)
96
201
  .run(url: DEFAULT_NEWS_URL)
97
202
  end
98
203
 
@@ -105,7 +210,7 @@ class NewsFeedsController < ApplicationController
105
210
  end
106
211
 
107
212
  def display_news(news)
108
- render :display_news, locals { news: news }
213
+ render :display_news, locals: { news: news }
109
214
  end
110
215
 
111
216
  def display_old_news
@@ -121,7 +226,58 @@ class NewsFeedsController < ApplicationController
121
226
  end
122
227
  ```
123
228
 
229
+ #### Basic with active_model/active_record object
230
+
231
+ Operation
232
+
233
+ ```ruby
234
+ class AddBookOperation < LightOperations::Core
235
+ def execute(params = {})
236
+ dependency(:book_model).new(params).tap do |model|
237
+ model.valid? # this method automatically provide errors from model.errors
238
+ end
239
+ end
240
+ end
241
+ ```
242
+
243
+ Controller
244
+
245
+ ```ruby
246
+ class BooksController < ApplicationController
247
+ def index
248
+ render :index, locals: { collection: Book.all }
249
+ end
250
+
251
+ def new
252
+ render_book_form
253
+ end
254
+
255
+ def create
256
+ add_book_op
257
+ .bind_with(self)
258
+ .on(success: :book_created, fail: :render_book_form)
259
+ .run(permit_book_params)
260
+ end
261
+
262
+ private
263
+
264
+ def book_created(book)
265
+ redirect_to :index, notice: "book #{book.name} created"
266
+ end
267
+
268
+ def render_book_form(book = Book.new, _errors = nil)
269
+ render :new, locals: { book: book }
270
+ end
124
271
 
272
+ def add_book_op
273
+ @add_book_op ||= AddBookOperation.new(book_model: Book)
274
+ end
275
+
276
+ def permit_book_params
277
+ params.requre(:book)
278
+ end
279
+ end
280
+ ```
125
281
 
126
282
  #### Simple case when you want have user authorization
127
283
 
@@ -253,13 +409,27 @@ class AuthController < ApplicationController
253
409
  end
254
410
  ```
255
411
 
412
+ Register success and fails action is avialable by `#on` like :
413
+
414
+ ```ruby
415
+ def create
416
+ auth_op.bind_with(self).on(success: :dashboard, fail: :show_error).run(params)
417
+ end
418
+ ```
419
+
420
+ Operation have some helper methods (to improve recursive execution)
421
+
422
+ - `#clear!` => return operation to init state
423
+ - `#unbind!` => unbind binded object
424
+ - `#clear_subject_with_errors!` => clear subject and errors
425
+
256
426
  When operation status is most importent we can simply use `#success?` or `#fail?` on the executed operation
257
427
 
258
428
  Errors are available by `#errors` after operation is executed
259
429
 
260
430
  ## Contributing
261
431
 
262
- 1. Fork it ( https://github.com/[my-github-username]/swift_operations/fork )
432
+ 1. Fork it ( https://github.com/[my-github-username]/light_operations/fork )
263
433
  2. Create your feature branch (`git checkout -b my-new-feature`)
264
434
  3. Commit your changes (`git commit -am 'Add some feature'`)
265
435
  4. Push to the branch (`git push origin my-new-feature`)
@@ -13,6 +13,7 @@ module LightOperations
13
13
 
14
14
  # do no.t override this method
15
15
  def run(params = {})
16
+ clear_subject_with_errors!
16
17
  @subject = execute(params)
17
18
  execute_actions
18
19
  self
@@ -1,3 +1,3 @@
1
1
  module LightOperations
2
- VERSION = '0.0.3'
2
+ VERSION = '0.0.4'
3
3
  end
@@ -5,6 +5,16 @@ describe LightOperations::Core do
5
5
  let(:params) { { login: 'pawel', password: 'abc' } }
6
6
  let(:dependencies) { { login_service: login_service } }
7
7
 
8
+ let(:binding_object) do
9
+ Class.new(Object).tap do |klass|
10
+ klass.class_eval do
11
+ def success_action(_subject); end
12
+
13
+ def error_action(_subject, _errors); end
14
+ end
15
+ end.new
16
+ end
17
+
8
18
  def subject_factory(&block)
9
19
  Class.new(described_class).tap do |klass|
10
20
  klass.class_eval(&block)
@@ -18,15 +28,6 @@ describe LightOperations::Core do
18
28
  end
19
29
 
20
30
  context 'use cases' do
21
- let(:binding_object) do
22
- Class.new(Object).tap do |klass|
23
- klass.class_eval do
24
- def success_action(_subject); end
25
-
26
- def error_action(_subject, _errors); end
27
- end
28
- end.new
29
- end
30
31
 
31
32
  # dependency using
32
33
 
@@ -234,4 +235,27 @@ describe LightOperations::Core do
234
235
  subject.clear!
235
236
  end
236
237
  end
238
+
239
+ context 'Operation executed several times' do
240
+ subject do
241
+ subject_factory do
242
+ def execute(params = {})
243
+ fail!(:missing_result) unless params.key?(:result)
244
+ params[:result]
245
+ end
246
+ end
247
+ end
248
+
249
+ it 'always start with clean state of subject and errors' do
250
+
251
+ subject
252
+ .bind_with(binding_object)
253
+ .on(success: :success_action, fail: :error_action)
254
+
255
+ expect(binding_object).to receive(:error_action).with(nil, :missing_result)
256
+ subject.run
257
+ expect(binding_object).to receive(:success_action).with(:success)
258
+ subject.run(result: :success)
259
+ end
260
+ end
237
261
  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.3
4
+ version: 0.0.4
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-02-28 00:00:00.000000000 Z
11
+ date: 2015-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport