lotus-utils 0.3.4 → 0.3.5
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/CHANGELOG.md +5 -0
- data/lib/lotus/interactor.rb +429 -0
- data/lib/lotus/utils/basic_object.rb +53 -0
- data/lib/lotus/utils/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fbc9ff8be5d774d9e30695445d43995a66cbf21d
|
4
|
+
data.tar.gz: 4f5ccb96067b17d2c6f77b5b0d5eb5ccd2def30f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d254f1b09c52c91198986bc340f17b9cfe35146bcbeed9464c4f99d390e45eb8dbe8e11cb6672b42716e7136294a00300fe0cb207636a8e0e24cbc80f1d2eeef
|
7
|
+
data.tar.gz: 18bcf46df8ab2013f334d962ed859919df1e6711562b89c2a8eec959141551f901b975c2dfdd084f00b894f53cd53f460dca6881add6d63c9cb176a13de3c35c
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
# Lotus::Utils
|
2
2
|
Ruby core extentions and class utilities for Lotus
|
3
3
|
|
4
|
+
## v0.3.5 - 2015-03-12
|
5
|
+
### Added
|
6
|
+
- [Luca Guidi] Introduced `Lotus::Interactor`
|
7
|
+
- [Luca Guidi] Introduced `Lotus::Utils::BasicObject`
|
8
|
+
|
4
9
|
## v0.3.4 - 2015-01-30
|
5
10
|
### Added
|
6
11
|
- [Alfonso Uceda Pompa] Aliased `Lotus::Utils::Attributes#get` with `#[]`
|
@@ -0,0 +1,429 @@
|
|
1
|
+
require 'lotus/utils/basic_object'
|
2
|
+
require 'lotus/utils/hash'
|
3
|
+
|
4
|
+
module Lotus
|
5
|
+
# Lotus Interactor
|
6
|
+
#
|
7
|
+
# @since 0.3.5
|
8
|
+
module Interactor
|
9
|
+
# Result of an operation
|
10
|
+
#
|
11
|
+
# @since 0.3.5
|
12
|
+
class Result < Utils::BasicObject
|
13
|
+
# Concrete methods
|
14
|
+
#
|
15
|
+
# @since 0.3.5
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
# @see Lotus::Interactor::Result#respond_to_missing?
|
19
|
+
METHODS = {initialize: true, success?: true, fail!: true, prepare!: true, errors: true, error: true}.freeze
|
20
|
+
|
21
|
+
# Initialize a new result
|
22
|
+
#
|
23
|
+
# @param payload [Hash] a payload to carry on
|
24
|
+
#
|
25
|
+
# @return [Lotus::Interactor::Result]
|
26
|
+
#
|
27
|
+
# @since 0.3.5
|
28
|
+
# @api private
|
29
|
+
def initialize(payload = {})
|
30
|
+
@payload = _payload(payload)
|
31
|
+
@success = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# Check if the current status is successful
|
35
|
+
#
|
36
|
+
# @return [TrueClass,FalseClass] the result of the check
|
37
|
+
#
|
38
|
+
# @since 0.3.5
|
39
|
+
def success?
|
40
|
+
@success && errors.empty?
|
41
|
+
end
|
42
|
+
|
43
|
+
# Force the status to be a failure
|
44
|
+
#
|
45
|
+
# @since 0.3.5
|
46
|
+
def fail!
|
47
|
+
@success = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Returns all the errors collected during an operation
|
51
|
+
#
|
52
|
+
# @return [Array] the errors
|
53
|
+
#
|
54
|
+
# @since 0.3.5
|
55
|
+
#
|
56
|
+
# @see Lotus::Interactor::Result#error
|
57
|
+
# @see Lotus::Interactor#call
|
58
|
+
# @see Lotus::Interactor#error
|
59
|
+
# @see Lotus::Interactor#error!
|
60
|
+
def errors
|
61
|
+
@payload.fetch(:_errors) { [] }
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns the first errors collected during an operation
|
65
|
+
#
|
66
|
+
# @return [nil,String] the error, if present
|
67
|
+
#
|
68
|
+
# @since 0.3.5
|
69
|
+
#
|
70
|
+
# @see Lotus::Interactor::Result#errors
|
71
|
+
# @see Lotus::Interactor#call
|
72
|
+
# @see Lotus::Interactor#error
|
73
|
+
# @see Lotus::Interactor#error!
|
74
|
+
def error
|
75
|
+
errors.first
|
76
|
+
end
|
77
|
+
|
78
|
+
# Prepare the result before to be returned
|
79
|
+
#
|
80
|
+
# @param payload [Hash] an updated payload
|
81
|
+
#
|
82
|
+
# @since 0.3.5
|
83
|
+
# @api private
|
84
|
+
def prepare!(payload)
|
85
|
+
@payload.merge!(_payload(payload))
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
protected
|
90
|
+
# @since 0.3.5
|
91
|
+
# @api private
|
92
|
+
def method_missing(m, *)
|
93
|
+
@payload.fetch(m) { super }
|
94
|
+
end
|
95
|
+
|
96
|
+
# @since 0.3.5
|
97
|
+
# @api private
|
98
|
+
def respond_to_missing?(method_name, include_all)
|
99
|
+
method_name = method_name.to_sym
|
100
|
+
METHODS[method_name] || @payload.key?(method_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
# @since 0.3.5
|
104
|
+
# @api private
|
105
|
+
def _payload(payload)
|
106
|
+
Utils::Hash.new(payload).symbolize!
|
107
|
+
end
|
108
|
+
|
109
|
+
# @since 0.3.5
|
110
|
+
# @api private
|
111
|
+
def __inspect
|
112
|
+
" @success=#{ @success } @payload=#{ @payload.inspect }"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Override for <tt>Module#included</tt>.
|
117
|
+
#
|
118
|
+
# @since 0.3.5
|
119
|
+
# @api private
|
120
|
+
def self.included(base)
|
121
|
+
super
|
122
|
+
|
123
|
+
base.class_eval do
|
124
|
+
prepend Interface
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Interactor interface
|
129
|
+
#
|
130
|
+
# @since 0.3.5
|
131
|
+
module Interface
|
132
|
+
# Initialize an interactor
|
133
|
+
#
|
134
|
+
# It accepts arbitrary number of arguments.
|
135
|
+
# Developers can override it.
|
136
|
+
#
|
137
|
+
# @param args [Array<Object>] arbitrary number of arguments
|
138
|
+
#
|
139
|
+
# @return [Lotus::Interactor] the interactor
|
140
|
+
#
|
141
|
+
# @since 0.3.5
|
142
|
+
#
|
143
|
+
# @example Override #initialize
|
144
|
+
# require 'lotus/interactor'
|
145
|
+
#
|
146
|
+
# class UpdateProfile
|
147
|
+
# include Lotus::Interactor
|
148
|
+
#
|
149
|
+
# def initialize(person, params)
|
150
|
+
# @person = person
|
151
|
+
# @params = params
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# def call
|
155
|
+
# # ...
|
156
|
+
# end
|
157
|
+
# end
|
158
|
+
def initialize(*args)
|
159
|
+
super
|
160
|
+
ensure
|
161
|
+
@__result = ::Lotus::Interactor::Result.new
|
162
|
+
@_errors = []
|
163
|
+
end
|
164
|
+
|
165
|
+
# Triggers the operation and return a result.
|
166
|
+
#
|
167
|
+
# All the instance variables will be available in the result.
|
168
|
+
#
|
169
|
+
# ATTENTION: This must be implemented by the including class.
|
170
|
+
#
|
171
|
+
# @return [Lotus::Interactor::Result] the result of the operation
|
172
|
+
#
|
173
|
+
# @raise [NoMethodError] if this isn't implemented by the including class.
|
174
|
+
#
|
175
|
+
# @example Instance variables in result payload
|
176
|
+
# require 'lotus/interactor'
|
177
|
+
#
|
178
|
+
# class Signup
|
179
|
+
# def initialize(params)
|
180
|
+
# @params = params
|
181
|
+
# @user = User.new(@params)
|
182
|
+
# @foo = 'bar'
|
183
|
+
# end
|
184
|
+
#
|
185
|
+
# def call
|
186
|
+
# @user = UserRepository.persist(@user)
|
187
|
+
# end
|
188
|
+
# end
|
189
|
+
#
|
190
|
+
# result = Signup.new(name: 'Luca').call
|
191
|
+
# result.success? # => true
|
192
|
+
#
|
193
|
+
# result.user # => #<User:0x007fa311105778 @id=1 @name="Luca">
|
194
|
+
# result.params # => { :name=>"Luca" }
|
195
|
+
# result.foo # => "Bar"
|
196
|
+
#
|
197
|
+
# @example Failed precondition
|
198
|
+
# require 'lotus/interactor'
|
199
|
+
#
|
200
|
+
# class Signup
|
201
|
+
# def initialize(params)
|
202
|
+
# @params = params
|
203
|
+
# @user = User.new(@params)
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# # THIS WON'T BE INVOKED BECAUSE #valid? WILL RETURN false
|
207
|
+
# def call
|
208
|
+
# @user = UserRepository.persist(@user)
|
209
|
+
# end
|
210
|
+
#
|
211
|
+
# private
|
212
|
+
# def valid?
|
213
|
+
# @params.valid?
|
214
|
+
# end
|
215
|
+
# end
|
216
|
+
#
|
217
|
+
# result = Signup.new(name: nil).call
|
218
|
+
# result.success? # => false
|
219
|
+
#
|
220
|
+
# result.user # => #<User:0x007fa311105778 @id=nil @name="Luca">
|
221
|
+
#
|
222
|
+
# @example Bad usage
|
223
|
+
# require 'lotus/interactor'
|
224
|
+
#
|
225
|
+
# class Signup
|
226
|
+
# include Lotus::Interactor
|
227
|
+
#
|
228
|
+
# # Method #call is not defined
|
229
|
+
# end
|
230
|
+
#
|
231
|
+
# Signup.new.call # => NoMethodError
|
232
|
+
def call
|
233
|
+
_call { super }
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
private
|
238
|
+
# Check if proceed with <tt>#call</tt> invokation.
|
239
|
+
# By default it returns <tt>true</tt>.
|
240
|
+
#
|
241
|
+
# Developers can override it.
|
242
|
+
#
|
243
|
+
# @return [TrueClass,FalseClass] the result of the check
|
244
|
+
#
|
245
|
+
# @since 0.3.5
|
246
|
+
def valid?
|
247
|
+
true
|
248
|
+
end
|
249
|
+
|
250
|
+
# Fail and interrupt the current flow.
|
251
|
+
#
|
252
|
+
# @since 0.3.5
|
253
|
+
#
|
254
|
+
# @example
|
255
|
+
# require 'lotus/interactor'
|
256
|
+
#
|
257
|
+
# class CreateEmailTest
|
258
|
+
# include Lotus::Interactor
|
259
|
+
#
|
260
|
+
# def initialize(params)
|
261
|
+
# @params = params
|
262
|
+
# @email_test = EmailTest.new(@params)
|
263
|
+
# end
|
264
|
+
#
|
265
|
+
# def call
|
266
|
+
# persist_email_test!
|
267
|
+
# capture_screenshot!
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# private
|
271
|
+
# def persist_email_test!
|
272
|
+
# @email_test = EmailTestRepository.persist(@email_test)
|
273
|
+
# end
|
274
|
+
#
|
275
|
+
# # IF THIS RAISES AN EXCEPTION WE FORCE A FAILURE
|
276
|
+
# def capture_screenshot!
|
277
|
+
# Screenshot.new(@email_test).capture!
|
278
|
+
# rescue
|
279
|
+
# fail!
|
280
|
+
# end
|
281
|
+
# end
|
282
|
+
#
|
283
|
+
# result = CreateEmailTest.new(account_id: 1).call
|
284
|
+
# result.success? # => false
|
285
|
+
def fail!
|
286
|
+
@__result.fail!
|
287
|
+
throw :fail
|
288
|
+
end
|
289
|
+
|
290
|
+
# Log an error without interrupting the flow.
|
291
|
+
#
|
292
|
+
# When used, the returned result won't be successful.
|
293
|
+
#
|
294
|
+
# @param message [String] the error message
|
295
|
+
#
|
296
|
+
# @since 0.3.5
|
297
|
+
#
|
298
|
+
# @see Lotus::Interactor#error!
|
299
|
+
#
|
300
|
+
# @example
|
301
|
+
# require 'lotus/interactor'
|
302
|
+
#
|
303
|
+
# class CreateRecord
|
304
|
+
# include Lotus::Interactor
|
305
|
+
#
|
306
|
+
# def initialize
|
307
|
+
# @logger = []
|
308
|
+
# end
|
309
|
+
#
|
310
|
+
# def call
|
311
|
+
# prepare_data!
|
312
|
+
# persist!
|
313
|
+
# sync!
|
314
|
+
# end
|
315
|
+
#
|
316
|
+
# private
|
317
|
+
# def prepare_data!
|
318
|
+
# @logger << __method__
|
319
|
+
# error "Prepare data error"
|
320
|
+
# end
|
321
|
+
#
|
322
|
+
# def persist!
|
323
|
+
# @logger << __method__
|
324
|
+
# error "Persist error"
|
325
|
+
# end
|
326
|
+
#
|
327
|
+
# def sync!
|
328
|
+
# @logger << __method__
|
329
|
+
# end
|
330
|
+
# end
|
331
|
+
#
|
332
|
+
# result = CreateRecord.new.call
|
333
|
+
# result.success? # => false
|
334
|
+
#
|
335
|
+
# result.errors # => ["Prepare data error", "Persist error"]
|
336
|
+
# result.logger # => [:prepare_data!, :persist!, :sync!]
|
337
|
+
def error(message)
|
338
|
+
@_errors << message
|
339
|
+
end
|
340
|
+
|
341
|
+
# Log an error AND interrupting the flow.
|
342
|
+
#
|
343
|
+
# When used, the returned result won't be successful.
|
344
|
+
#
|
345
|
+
# @param message [String] the error message
|
346
|
+
#
|
347
|
+
# @since 0.3.5
|
348
|
+
#
|
349
|
+
# @see Lotus::Interactor#error
|
350
|
+
#
|
351
|
+
# @example
|
352
|
+
# require 'lotus/interactor'
|
353
|
+
#
|
354
|
+
# class CreateRecord
|
355
|
+
# include Lotus::Interactor
|
356
|
+
#
|
357
|
+
# def initialize
|
358
|
+
# @logger = []
|
359
|
+
# end
|
360
|
+
#
|
361
|
+
# def call
|
362
|
+
# prepare_data!
|
363
|
+
# persist!
|
364
|
+
# sync!
|
365
|
+
# end
|
366
|
+
#
|
367
|
+
# private
|
368
|
+
# def prepare_data!
|
369
|
+
# @logger << __method__
|
370
|
+
# error "Prepare data error"
|
371
|
+
# end
|
372
|
+
#
|
373
|
+
# def persist!
|
374
|
+
# @logger << __method__
|
375
|
+
# error! "Persist error"
|
376
|
+
# end
|
377
|
+
#
|
378
|
+
# # THIS WILL NEVER BE INVOKED BECAUSE WE USE #error! IN #persist!
|
379
|
+
# def sync!
|
380
|
+
# @logger << __method__
|
381
|
+
# end
|
382
|
+
# end
|
383
|
+
#
|
384
|
+
# result = CreateRecord.new.call
|
385
|
+
# result.success? # => false
|
386
|
+
#
|
387
|
+
# result.errors # => ["Prepare data error", "Persist error"]
|
388
|
+
# result.logger # => [:prepare_data!, :persist!]
|
389
|
+
def error!(message)
|
390
|
+
error(message)
|
391
|
+
fail!
|
392
|
+
end
|
393
|
+
|
394
|
+
# @since 0.3.5
|
395
|
+
# @api private
|
396
|
+
def _call
|
397
|
+
catch :fail do
|
398
|
+
validate!
|
399
|
+
yield
|
400
|
+
end
|
401
|
+
|
402
|
+
_prepare!
|
403
|
+
end
|
404
|
+
|
405
|
+
# @since 0.3.5
|
406
|
+
def validate!
|
407
|
+
fail! unless valid?
|
408
|
+
end
|
409
|
+
|
410
|
+
# @since 0.3.5
|
411
|
+
# @api private
|
412
|
+
def _prepare!
|
413
|
+
@__result.prepare!(_instance_variables)
|
414
|
+
end
|
415
|
+
|
416
|
+
# @since 0.3.5
|
417
|
+
# @api private
|
418
|
+
def _instance_variables
|
419
|
+
Hash[].tap do |result|
|
420
|
+
instance_variables.each do |iv|
|
421
|
+
name = iv.to_s.sub(/\A@/, '')
|
422
|
+
next if name.match(/\A__/)
|
423
|
+
|
424
|
+
result[name.to_sym] = instance_variable_get(iv)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Lotus
|
2
|
+
module Utils
|
3
|
+
# BasicObject
|
4
|
+
#
|
5
|
+
# @since 0.3.5
|
6
|
+
class BasicObject < ::BasicObject
|
7
|
+
# Return the class for debugging purposes.
|
8
|
+
#
|
9
|
+
# @since 0.3.5
|
10
|
+
#
|
11
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-class
|
12
|
+
def class
|
13
|
+
(class << self; self end).superclass
|
14
|
+
end
|
15
|
+
|
16
|
+
# Bare minimum inspect for debugging purposes.
|
17
|
+
#
|
18
|
+
# @return [String] the inspect string
|
19
|
+
#
|
20
|
+
# @since 0.3.5
|
21
|
+
#
|
22
|
+
# @see http://ruby-doc.org/core/Object.html#method-i-inspect
|
23
|
+
def inspect
|
24
|
+
"#<#{ self.class }:#{'%x' % (__id__ << 1)}#{ __inspect }>"
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns true if responds to the given method.
|
28
|
+
#
|
29
|
+
# @return [TrueClass,FalseClass] the result of the check
|
30
|
+
#
|
31
|
+
# @since 0.3.5
|
32
|
+
#
|
33
|
+
# @see http://ruby-doc.org/core-2.2.1/Object.html#method-i-respond_to-3F
|
34
|
+
def respond_to?(method_name, include_all = false)
|
35
|
+
respond_to_missing?(method_name, include_all)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
# Must be overridden by descendants
|
40
|
+
#
|
41
|
+
# @since 0.3.5
|
42
|
+
# @api private
|
43
|
+
def respond_to_missing?(method_name, include_all)
|
44
|
+
::Kernel.raise ::NotImplementedError
|
45
|
+
end
|
46
|
+
|
47
|
+
# @since 0.3.5
|
48
|
+
# @api private
|
49
|
+
def __inspect
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/lotus/utils/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lotus-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Guidi
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-
|
12
|
+
date: 2015-03-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -64,8 +64,10 @@ files:
|
|
64
64
|
- CHANGELOG.md
|
65
65
|
- LICENSE.md
|
66
66
|
- README.md
|
67
|
+
- lib/lotus/interactor.rb
|
67
68
|
- lib/lotus/utils.rb
|
68
69
|
- lib/lotus/utils/attributes.rb
|
70
|
+
- lib/lotus/utils/basic_object.rb
|
69
71
|
- lib/lotus/utils/callbacks.rb
|
70
72
|
- lib/lotus/utils/class.rb
|
71
73
|
- lib/lotus/utils/class_attribute.rb
|