class Transitions::Event

rubocop:disable Metrics/ClassLength

Attributes

name[R]
success[R]
timestamp[R]

Public Class Methods

new(machine, name, options = {}, &block) click to toggle source

:reek: TooManyStatements: { max_statements: 13 }

# File lib/transitions/event.rb, line 7
def initialize(machine, name, options = {}, &block)
  @machine = machine
  @name = name
  @transitions = []
  @timestamps = []
  if machine
    machine.klass.send(:define_method, "#{name}!") do |*args|
      machine.fire_event(name, self, true, *args)
    end

    machine.klass.send(:define_method, name.to_s) do |*args|
      machine.fire_event(name, self, false, *args)
    end

    machine.klass.send(:define_method, "can_#{name}?") do |*_args|
      machine.events_for(current_state).include?(name.to_sym)
    end

    machine.klass.send(:define_method, "can_execute_#{name}?") do |*args|
      event = name.to_sym

      send("can_#{name}?", *args) &&
        machine.events[event].can_execute_transition_from_state?(current_state, self, *args)
    end
  end
  update(options, &block)
end

Public Instance Methods

==(other) click to toggle source
# File lib/transitions/event.rb, line 61
def ==(other)
  if other.is_a? Symbol
    name == other
  else
    name == other.name
  end
end
can_execute_transition_from_state?(state, obj, *args) click to toggle source
# File lib/transitions/event.rb, line 57
def can_execute_transition_from_state?(state, obj, *args)
  @transitions.select { |t| t.from? state }.any? { |t| t.executable?(obj, *args) }
end
fire(obj, to_state = nil, *args) click to toggle source
# File lib/transitions/event.rb, line 35
def fire(obj, to_state = nil, *args)
  transitions = @transitions.select { |t| t.from == obj.current_state }
  fail InvalidTransition, error_message_for_invalid_transitions(obj) if transitions.size == 0

  next_state = nil
  transitions.each do |transition|
    next if to_state && !Array(transition.to).include?(to_state)
    next unless transition.executable?(obj, *args)

    next_state = to_state || Array(transition.to).first
    transition.execute(obj, *args)
    update_event_timestamp(obj, next_state) if timestamp_defined?
    break
  end
  # Update timestamps on obj if a timestamp has been defined
  next_state
end
timestamp=(values) click to toggle source

Set the timestamp attribute. @raise [ArgumentError] timestamp should be either a String, Symbol or true

# File lib/transitions/event.rb, line 90
def timestamp=(values)
  values.each do |value|
    case value
    when String, Symbol, TrueClass
      @timestamps << value
    else
      fail ArgumentError, 'timestamp must be either: true, a String or a Symbol'
    end
  end
end
timestamp_defined?() click to toggle source

Has the timestamp option been specified for this event?

# File lib/transitions/event.rb, line 70
def timestamp_defined?
  !@timestamps.nil?
end
transitions_from_state?(state) click to toggle source
# File lib/transitions/event.rb, line 53
def transitions_from_state?(state)
  @transitions.any? { |t| t.from? state }
end
update(options = {}, &block) click to toggle source
# File lib/transitions/event.rb, line 74
def update(options = {}, &block)
  @success       = build_success_callback(options[:success]) if options.key?(:success)
  self.timestamp = Array(options[:timestamp]) if options[:timestamp]
  instance_eval(&block) if block
  self
end
update_event_timestamp(obj, next_state) click to toggle source

update the timestamp attribute on obj

# File lib/transitions/event.rb, line 82
def update_event_timestamp(obj, next_state)
  @timestamps.each do |timestamp|
    obj.public_send "#{timestamp_attribute_name(obj, next_state, timestamp)}=", Time.now
  end
end

Private Instance Methods

build_success_callback(callback_names) click to toggle source
# File lib/transitions/event.rb, line 129
def build_success_callback(callback_names)
  case callback_names
  when Array
    lambda do |record|
      callback_names.each do |callback|
        build_success_callback(callback).call(record)
      end
    end
  when Proc
    callback_names
  when Symbol
    ->(record) { record.send(callback_names) }
  end
end
default_timestamp_name(obj, next_state) click to toggle source

If @timestamp is true, try a default timestamp name

# File lib/transitions/event.rb, line 111
def default_timestamp_name(obj, next_state)
  at_name = "#{next_state}_at"
  on_name = "#{next_state}_on"
  case
  when obj.respond_to?(at_name) then at_name
  when obj.respond_to?(on_name) then on_name
  else
    fail NoMethodError, "Couldn't find a suitable timestamp field for event: #{@name}.
      Please define #{at_name} or #{on_name} in #{obj.class}"
  end
end
error_message_for_invalid_transitions(obj) click to toggle source
# File lib/transitions/event.rb, line 144
def error_message_for_invalid_transitions(obj)
  "Can't fire event `#{name}` in current state `#{obj.current_state}` for `#{obj.class.name}`"\
  " #{obj.respond_to?(:id) ? "with ID #{obj.id} " : nil}"
end
timestamp_attribute_name(obj, next_state, user_timestamp) click to toggle source

Returns the name of the timestamp attribute for this event If the timestamp was simply true it returns the default_timestamp_name otherwise, returns the user-specified timestamp name

# File lib/transitions/event.rb, line 106
def timestamp_attribute_name(obj, next_state, user_timestamp)
  user_timestamp == true ? default_timestamp_name(obj, next_state) : user_timestamp
end
transitions(trans_opts) click to toggle source
# File lib/transitions/event.rb, line 123
def transitions(trans_opts)
  Array(trans_opts[:from]).each do |s|
    @transitions << StateTransition.new(trans_opts.merge(from: s.to_sym))
  end
end