Class: Stator::Integration

Inherits:
Object
  • Object
show all
Defined in:
lib/stator/integration.rb

Instance Method Summary collapse

Constructor Details

#initialize(machine, record) ⇒ Integration

Returns a new instance of Integration.



10
11
12
13
# File 'lib/stator/integration.rb', line 10

def initialize(machine, record)
  @machine = machine
  @record  = record
end

Instance Method Details

#in_state_at?(state, t) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/stator/integration.rb', line 71

def in_state_at?(state, t)
  state = state.to_s
  t = t.to_time

  state_at = @record.send("#{state}_#{@machine.field}_at")

  # if we've never been in the state, the answer is no
  return false if state_at.nil?

  # if we came into this state later in life, the answer is no
  return false if state_at > t

  all_states = @machine.states.reverse

  # grab all the states and their timestamps that occur on or after state_at and on or before the time in question
  later_states = all_states.map do |s|
    next if state == s

    at = @record.send("#{s}_#{@machine.field}_at")

    next if at.nil?
    next if at < state_at
    next if at > t

    { state: s, at: at }
  end.compact

  # if there were no states on or after the state_at, the answer is yes
  return true if later_states.empty?

  # grab the states that were present at the lowest timestamp
  later_groups = later_states.group_by { |s| s[:at] }
  later_group_key = later_groups.keys.min
  later_states = later_groups[later_group_key]

  # if the lowest timestamp is the same as the state's timestamp, evaluate based on state index
  if later_states[0][:at] == state_at
    return all_states.index(state) < all_states.index(later_states[0][:state])
  end

  false
end

#invalid_state!Object

TODO: i18n



54
55
56
# File 'lib/stator/integration.rb', line 54

def invalid_state!
  @record.errors.add(@machine.field, "is not a valid state")
end

#invalid_transition!(was, is) ⇒ Object



58
59
60
# File 'lib/stator/integration.rb', line 58

def invalid_transition!(was, is)
  @record.errors.add(@machine.field, "cannot transition to #{is.inspect} from #{was.inspect}")
end

#likely_state_at(t) ⇒ Object



114
115
116
# File 'lib/stator/integration.rb', line 114

def likely_state_at(t)
  @machine.states.reverse.detect { |s| in_state_at?(s, t) }
end

#stateObject



19
20
21
# File 'lib/stator/integration.rb', line 19

def state
  @record.send(@machine.field)
end

#state=(new_value) ⇒ Object



15
16
17
# File 'lib/stator/integration.rb', line 15

def state=(new_value)
  @record.send("#{@machine.field}=", new_value)
end

#state_changed?(use_previous = false) ⇒ Boolean

Returns:

  • (Boolean)


31
32
33
34
35
36
37
# File 'lib/stator/integration.rb', line 31

def state_changed?(use_previous = false)
  if use_previous
    !!@record.previous_changes[@machine.field.to_s]
  else
    @record.send("#{@machine.field}_changed?")
  end
end

#state_was(use_previous = false) ⇒ Object



23
24
25
26
27
28
29
# File 'lib/stator/integration.rb', line 23

def state_was(use_previous = false)
  if use_previous
    @record.previous_changes[@machine.field.to_s].try(:[], 0)
  else
    @record.send("#{@machine.field}_was")
  end
end

#track_transitionObject



62
63
64
65
66
67
68
69
# File 'lib/stator/integration.rb', line 62

def track_transition
  return if @machine.skip_transition_tracking

  attempt_to_track_state(state)
  attempt_to_track_state_changed_timestamp

  true
end

#validate_transitionObject



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/stator/integration.rb', line 39

def validate_transition
  return unless state_changed?
  return if @machine.skip_validations

  was = state_was
  is  = state

  if @record.new_record?
    invalid_state! unless @machine.matching_transition(::Stator::Transition::ANY, is)
  else
    invalid_transition!(was, is) unless @machine.matching_transition(was, is)
  end
end