module Ni::Main::ClassMethods

Attributes

defined_actions[RW]

Public Instance Methods

action(*args, &block) click to toggle source
# File lib/ni/main.rb, line 134
def action(*args, &block)
  self.defined_actions ||= {}

  name, description = args
  description ||= 'No description'

  ActionChain.new(self, name, description, &block)
ensure
  unless respond_to?(name)
    define_singleton_method name do |*args, **params|
      context = args.first

      perform_custom(name, context, params)
    end
  end
end
action_by_name(name) click to toggle source
# File lib/ni/main.rb, line 306
def action_by_name(name)
  return nil unless defined_actions.present?

  action = defined_actions.find { |(action_name, _), _| action_name == name }

  Array(action).last
end
define_action!(name) click to toggle source
# File lib/ni/main.rb, line 182
def define_action!(name)
  raise 'Action not described' unless action_by_name(name).present?

  action_units = action_by_name(name).units
  action_failure_callback = action_by_name(name).failure_callback
  action_exceptions = action_by_name(name).rescues

  define_method name do
    if context.should_be_restored?
      unless self.class.context_storage_klass.present? && self.class.metadata_repository_klass.present?
        raise "Storages was not configured"
      end
      
      self.class.context_storage_klass.new(context, self.class.metadata_repository_klass).fetch  
      on_context_restored(name)
    end

    before_action(name)

    action_units.each do |unit|
      return if context.execution_halted?
      return if context.chain_skipped?
      
      if context.wait_for_execution?
        # Send to other interactor chain
        if unit.respond_to?(:handle_current_wait?) && unit.handle_current_wait?(context, context.continue_from)
          rescue_callback, ex = safe_context name do
            handle_exceptions action_exceptions do
              unit.call_for_wait_continue(self.context, wait_completed_for: context.continue_from, system_uid: context.system_uid)                    
            end                  
          end  
          next unless rescue_callback.present?
        elsif unit.is_a?(Ni::Flows::WaitForCondition)
          
          on_checking_continue_signal(unit)
          wait_cheking_result = unit.wait_or_continue(context.continue_from, context, self.class.metadata_repository_klass)
          on_continue_signal_checked(unit, wait_cheking_result)
          
          case wait_cheking_result
          when Ni::Flows::WaitForCondition::SKIP                    
            next
          when Ni::Flows::WaitForCondition::WAIT
            return
          when Ni::Flows::WaitForCondition::COMPLETED
            context.wait_completed!
            unit.clear_timer!(context, self.class.metadata_repository_klass)
            next                   
          end    
        else  
          next
        end    
      end              


      # This can't be replaced with if ... else
      # The wait checking hooks can change the context so need to ensure if block can be performed
      # And from other side the performing block is also able to change context and terminate execution
      if can_perform_next_step?              
        # Previous step could send flow to existing chain
        rescue_callback, ex = safe_context name do
          handle_exceptions action_exceptions do
            if unit.is_a?(Proc)
              instance_eval(&unit)
            elsif unit.is_a?(Symbol)
              send(unit)
            elsif unit.is_a?(String)      
              unit.to_s.split('.').reduce(self) {|memo, name| memo.send(name) }
            elsif unit.kind_of?(Ni::Flows::Base)
              unit.call(self.context)
            elsif unit.kind_of?(Ni::Flows::WaitForCondition)
              if self.class.context_storage_klass.present? && self.class.metadata_repository_klass.present?
                self.class.context_storage_klass.new(context, self.class.metadata_repository_klass).store  
              else
                raise "WaitFor require a store and metadata repository"
              end

              unit.setup_timer!(context, self.class.metadata_repository_klass)
              context.halt_execution!
              
              return
            end
          end
        end

        if rescue_callback.present?
          instance_exec(ex, &rescue_callback)

          context.failure!
        end
      end

      unless can_perform_next_step?
        instance_eval(&action_failure_callback) if context.failed? && action_failure_callback.present?
        
        {
          :failed?     => :on_failure,
          :canceled?   => :on_cancel,
          :terminated? => :on_terminate
        }.each do |predicate, callback|
          if context.public_send(predicate)                  
            if unit.respond_to?(callback) && unit.public_send(callback).present?
              if unit.public_send(callback).is_a?(Proc)
                instance_exec(&unit.public_send(callback))                      
              end
              
              if unit.public_send(callback).is_a?(Class)
                unit.public_send(callback).perform(context)
              end
            end                    
  
            self.public_send(callback, name)
          end   
        end                

        after_action(name)
        return
      end
    end

    after_action(name)
    on_success(name)
  end
end
define_actions!() click to toggle source
# File lib/ni/main.rb, line 178
def define_actions!
  defined_actions.keys.map(&:first).each { |name| define_action!(name) }
end
interactor_id() click to toggle source

without specified ID will use class name

# File lib/ni/main.rb, line 126
def interactor_id
  @unique_interactor_id || name
end
interactor_id!() click to toggle source
# File lib/ni/main.rb, line 130
def interactor_id!
  @unique_interactor_id || raise("The #{self.name} requires an explicit definition of the unique id")
end
perform(*args, **params) click to toggle source
# File lib/ni/main.rb, line 153
def perform(*args, **params)
  context = args.first

  perform_custom(:perform, context, params)
end
perform_custom(*args, **params) click to toggle source
# File lib/ni/main.rb, line 159
def perform_custom(*args, **params)
  object = self.new

  name, context = args

  system_uid = params.delete(:system_uid)
  wait_completed_for = params.delete(:wait_completed_for)

  context ||= Ni::Context.new(object, name, system_uid)
  context.continue_from!(wait_completed_for) if wait_completed_for.present?
  context.assign_data!(params)
  context.assign_current_interactor!(object)

  object.context = context
  object.public_send(name)

  Ni::Result.new object.context.resultify!, object.returned_values(name)
end
unique_id(id=nil) click to toggle source
# File lib/ni/main.rb, line 120
def unique_id(id=nil)
  @unique_interactor_id = id
  Ni::Main.register_unique_interactor(interactor_id, self)
end
units_by_interface(interface) click to toggle source
# File lib/ni/main.rb, line 314
def units_by_interface(interface)
  defined_actions.values.map(&:units).flatten.select { |u| u.respond_to?(interface) }
end