Class: GLCommand::Chainable

Inherits:
Callable show all
Defined in:
lib/gl_command/chainable.rb

Constant Summary collapse

UNCHAINED_MESSAGE =
'#chain method not called in GLCommand::Chainable #call. ' \
"The #call method *must* include 'chain(args)' or 'super' " \
'for chaining to take place!'

Constants inherited from Callable

GLCommand::Callable::DEFAULT_OPTS, GLCommand::Callable::RESERVED_WORDS

Instance Attribute Summary

Attributes inherited from Callable

#context

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Callable

allows, arguments, arguments_and_returns, build_context, call, call!, error_handlers, #initialize, #perform_call, requires, rescue_from, returns, #rollback, #stop_and_fail!

Methods included from Validatable

#validatable_valid?, #validate_validatable!

Constructor Details

This class inherits a constructor from GLCommand::Callable

Class Method Details

.chain(*commands) ⇒ Object



14
15
16
# File 'lib/gl_command/chainable.rb', line 14

def chain(*commands)
  @commands = commands.flatten
end

.chain?Boolean

Returns:

  • (Boolean)


10
11
12
# File 'lib/gl_command/chainable.rb', line 10

def chain?
  true
end

.chain_argumentsObject



26
27
28
# File 'lib/gl_command/chainable.rb', line 26

def chain_arguments
  @chain_arguments ||= commands.map(&:arguments).flatten.uniq
end

.chain_arguments_and_returnsObject



22
23
24
# File 'lib/gl_command/chainable.rb', line 22

def chain_arguments_and_returns(*)
  (chain_arguments + chain_returns).uniq.zip([]).to_h
end

.chain_returnsObject



30
31
32
# File 'lib/gl_command/chainable.rb', line 30

def chain_returns
  @chain_returns ||= commands.map(&:returns).flatten.uniq
end

.commandsObject



18
19
20
# File 'lib/gl_command/chainable.rb', line 18

def commands
  @commands || []
end

Instance Method Details

#call(**args) ⇒ Object



75
76
77
# File 'lib/gl_command/chainable.rb', line 75

def call(**args)
  chain(args)
end

#chain(args) ⇒ Object

rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Lint/UnderscorePrefixedVariableName



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/gl_command/chainable.rb', line 36

def chain(args)
  return if @chain_skipped

  @chain_called = true
  context.assign_parameters(**args)

  commands.map do |command|
    cargs = context.chain_arguments_and_returns.slice(*command.arguments)
                   .merge(context.opts_hash).merge(in_chain: true)

    # using _result to make sure it doesn't cause naming conflicts with other uses of result
    _result = command.call(**cargs)
    context.assign_parameters(skip_unknown_parameters: true, **_result.returns)

    if _result.success?
      context.called << command
    else
      @notified = true # chained command already notified
      errors&.merge!(_result.errors)
      stop_and_fail!(_result.error, no_notify: _result.no_notify?)
      break
    end
  end
end

#chain_rollbackObject



66
67
68
69
70
71
72
73
# File 'lib/gl_command/chainable.rb', line 66

def chain_rollback
  context.called.reverse_each do |command|
    chain_params = context.chain_arguments_and_returns
                          .slice(*command.arguments_and_returns)

    command.new(command.build_context(**chain_params)).rollback
  end
end

#commandsObject

rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Lint/UnderscorePrefixedVariableName



62
63
64
# File 'lib/gl_command/chainable.rb', line 62

def commands
  self.class.commands
end

#skip_chainObject



79
80
81
# File 'lib/gl_command/chainable.rb', line 79

def skip_chain
  @chain_skipped = true
end