Created
February 21, 2020 12:53
-
-
Save alebian/d378d4d254af5ee8167439b8cfbc90fe to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class BaseCommand | |
def initialize(params: {}, context: {}) | |
@params = params | |
@context = context | |
end | |
def call; end | |
def undo; end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class CommandComposer | |
attr_reader :error, :intermediate_results | |
def initialize | |
@commands = [] | |
@instances = [] | |
@intermediate_results = [] | |
@results_as_context = {} | |
@current_command_idx = -1 | |
@success = true | |
@error = nil | |
@logger = Rails.logger | |
end | |
def call # rubocop:disable Metrics/MethodLength | |
@commands.each_with_index do |command, idx| | |
@current_command_idx = idx | |
@logger.info( | |
"About to execute step #{idx + 1}: #{command[:klass]} with params: #{command[:params]}" | |
) | |
instance = create_instance(command) | |
begin | |
calculate_instance_result(instance, command) | |
rescue StandardError => e | |
handle_exception(e, command) | |
return self | |
end | |
end | |
self | |
end | |
def add_command(command_klass, options = {}) | |
if command_klass | |
hash = { | |
klass: command_klass, | |
params: (options[:params] || {}), | |
result_as: options[:result_as] | |
} | |
@commands << hash | |
end | |
self | |
end | |
def success? | |
@success | |
end | |
def result | |
@intermediate_results[-1] | |
end | |
private | |
def create_instance(command) | |
instance = command[:klass].new( | |
params: command[:params], context: @results_as_context | |
) | |
@instances << instance | |
instance | |
end | |
def calculate_instance_result(instance, command) | |
result = instance.call | |
@intermediate_results << result | |
@results_as_context[command[:result_as]] = result if command[:result_as] | |
result | |
end | |
def handle_exception(exception, command) | |
@logger.error( | |
"#{exception.class} in step #{@current_command_idx + 1}: #{command[:klass]}. Rolling back." | |
) | |
@logger.error("Error: #{exception.message}") | |
@error = exception | |
@success = false | |
rollback | |
end | |
def rollback | |
(0..@current_command_idx).reverse_each do |idx| | |
instance = @instances[idx] | |
@logger.info("Undoing step #{idx + 1}: #{instance.class}") | |
instance.undo | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment