A base interactor to support management of bussiness logic.
This gem is inspired by interactor specs.
- ruby 2.3+
- activesupport 5.0+
Add this line to your application's Gemfile:
gem 'ii_interactor'
Then execute:
$ bundle
Create interactor with call
method and call it as follows:
class Interactor < IIInteractor::Base
context_in :message
context_out :result
def call
@context.result = "called by #{@context.message}"
end
end
Interactor.call(message: 'something')
#=> #<IIInteractor::Context message="something", result="called by something">
The first argument of Interactor.call
is set to @context
.
The return value of Interactor.call
is the same as @context
.
You can define context variables used in interactor explicitly.
context_in
copies context to instance variables of interactor,
while context_out
copies instance variables of interactor to context.
You can define required context as follows:
class Interactor < IIInteractor::Base
context_in :input, required: true
end
Interactor.call
#=> IIInteractor::RequiredContextError (missing required context: input2)
You can also define default value as follows:
class Interactor < IIInteractor::Base
context_in :input, default: 'input'
def call
puts @input
end
end
Interactor.call
#=> input
You can also set context from return value of call
method:
class Interactor < IIInteractor::Base
context_out :result, from_return: true
def call
'returned value'
end
end
Interactor.call.result
#=> returned value
You can call other interactors in the same context using coact
:
class AInteractor < IIInteractor::Base
def call
puts self.class.name
end
end
class BInteractor < IIInteractor::Base
def call
puts self.class.name
end
end
class MainInteractor < IIInteractor::Base
coact AInteractor
coact BInteractor
end
MainInteractor.call
#=> AInteractor
# BInteractor
See coactive for more coact
examples:
You can stop interactions as follows:
class AInteractor < IIInteractor::Base
def call
puts self.class.name
stop!(message: "something happened!")
end
end
class BInteractor < IIInteractor::Base
def call
puts self.class.name
end
end
class MainInteractor < IIInteractor::Base
coact AInteractor
coact BInteractor
end
context = MainInteractor.call
#=> AInteractor
context.message
#=> something happened!
context.stopped?
#=> true
context.success?
#=> true
You can fail interactions and rollback called interactors as follows:
class AInteractor < IIInteractor::Base
def call
puts self.class.name
end
def rollback
puts "rollback #{self.class.name}"
end
end
class BInteractor < IIInteractor::Base
def call
fail!(message: "something happened!")
end
def rollback
puts "rollback #{self.class.name}"
end
end
class MainInteractor < IIInteractor::Base
coact AInteractor
coact BInteractor
end
context = MainInteractor.call
#=> AInteractor
# rollback AInteractor
context.message
#=> something happened!
context.failure?
#=> true
Following callbacks are available:
before_all
,around_all
,after_all
before_call
,around_call
,after_call
*_all
wraps all coactors, and *_call
wraps call
method.
That is, before_all
is called before running all coactors, and before_call
is called before running call
method.
For example:
class Interactor < IIInteractor::Base
before_all do
puts "before_all"
end
before_call do
puts "before_call"
end
def call
puts @context.message
end
end
Interactor.call(message: 'something')
#=> before_all
# before_call
# something
You can pass a block to call
method of a interactor.
The block is kept in the context and you can call it by inform
as you like:
class AInteractor < IIInteractor::Base
def call
inform('called A')
end
end
class BInteractor < IIInteractor::Base
def call
inform('called B')
end
end
class MainInteractor < IIInteractor::Base
coact AInteractor
coact BInteractor
end
MainInteractor.call do |interactor, message|
puts "#{interactor.class}: #{message}"
end
#=> AInteractor: called A
# BInteractor: called B
Interactor supports instrumentation hook supplied by ActiveSupport::Notifications
.
You can enable log subscriber as follows:
IIInteractor::LogSubscriber.attach_to :ii_interactor
This subscriber will write logs in debug mode as the following example:
Calling BasicInteractor with #<IIInteractor::Context ...>
...
Called BasicInteractor (Duration: 0.1ms, Allocations: 4)
Bug reports and pull requests are welcome at https://github.com/kanety/ii_interactor.
The gem is available as open source under the terms of the MIT License.