class Object

Public Instance Methods

guard!(inner, getter, state) click to toggle source
Calls superclass method
# File lib/workflow/join.rb, line 43
def guard!(inner, getter, state)
  return if getter.nil? || (slave = getter.call(self)).nil? # I’ll be back, hasta la vista, baby :)

  slave.class.send :define_method, "on_#{state}_entry".to_sym do |old_state, event, *args|
    pending_callbacks.each do |master|
      master.reload if master.respond_to?(:reload)
      next unless master.pending_transitions?
      master.try_pending_transitions!
      # halted is automagically removed after successful transition
      # the line below is unneeded
      # master.halted = master.pending_transitions?
    end
    super(old_state, event, *args) rescue nil # no super no cry
  end

  lambda do |_, to, name, *|
    slave.reload if slave.respond_to?(:reload)
    if to.to_sym == inner && !slave.send("#{state}?".to_sym)
      pending_transition! name
      slave.pending_callback!(self)
      halt("Waiting for guard workflow to enter “:#{state}” state")
    end
  end
end
guards!() click to toggle source
# File lib/workflow/join.rb, line 28
def guards!
  spec.instance_variable_set(:@original_before_transition_proc, spec.before_transition_proc) \
    unless spec.instance_variable_defined?(:@original_before_transition_proc)

  λλs = spec.guards.map do |inner, outers|
          outers.map do |getter, state|
            guard! inner, getter, state
          end.compact
        end.flatten

  (original_before_transition_proc = spec.instance_variable_get(:@original_before_transition_proc)) && \
    λλs << original_before_transition_proc
  spec.before_transition_proc = ->(from, to, name, *args) { λλs.each { |λ| λ.(from, to, name, *args) } }
end
new(*) click to toggle source
Calls superclass method
# File lib/workflow/join.rb, line 73
def new(*)
  super.tap(&:guards!)
end
workflow(&specification) click to toggle source
Calls superclass method
# File lib/workflow/join.rb, line 19
def workflow(&specification)
  # extend instances
  prepend(Module.new do # this should be safe, since there could not be two subsequent workflow DSL
    if Workflow::Join.const_defined?('ActiveRecord')
      include Workflow::Join::ActiveRecord # AR pending transitions and callbacks implementation
    else
      include Workflow::Join::Simple # simple pending transitions and callbacks implementation
    end

    def guards!
      spec.instance_variable_set(:@original_before_transition_proc, spec.before_transition_proc) \
        unless spec.instance_variable_defined?(:@original_before_transition_proc)

      λλs = spec.guards.map do |inner, outers|
              outers.map do |getter, state|
                guard! inner, getter, state
              end.compact
            end.flatten

      (original_before_transition_proc = spec.instance_variable_get(:@original_before_transition_proc)) && \
        λλs << original_before_transition_proc
      spec.before_transition_proc = ->(from, to, name, *args) { λλs.each { |λ| λ.(from, to, name, *args) } }
    end

    def guard!(inner, getter, state)
      return if getter.nil? || (slave = getter.call(self)).nil? # I’ll be back, hasta la vista, baby :)

      slave.class.send :define_method, "on_#{state}_entry".to_sym do |old_state, event, *args|
        pending_callbacks.each do |master|
          master.reload if master.respond_to?(:reload)
          next unless master.pending_transitions?
          master.try_pending_transitions!
          # halted is automagically removed after successful transition
          # the line below is unneeded
          # master.halted = master.pending_transitions?
        end
        super(old_state, event, *args) rescue nil # no super no cry
      end

      lambda do |_, to, name, *|
        slave.reload if slave.respond_to?(:reload)
        if to.to_sym == inner && !slave.send("#{state}?".to_sym)
          pending_transition! name
          slave.pending_callback!(self)
          halt("Waiting for guard workflow to enter “:#{state}” state")
        end
      end
    end
  end)

  if respond_to?(:after_commit)
    after_commit { guards! }
  else
    singleton_class.prepend(Module.new do
      def new(*)
        super.tap(&:guards!)
      end
    end)
  end

  super
end