Class: Stator::Integration

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(machine, record) ⇒ Integration

Returns a new instance of Integration.



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

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

Instance Attribute Details

#skip_transition_trackingObject (readonly)

Returns the value of attribute skip_transition_tracking.



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

def skip_transition_tracking
  @skip_transition_tracking
end

#skip_validationsObject (readonly)

Returns the value of attribute skip_validations.



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

def skip_validations
  @skip_validations
end

Instance Method Details

#in_state_at?(state, t) ⇒ Boolean

Returns:

  • (Boolean)


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
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/stator/integration.rb', line 82

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



65
66
67
# File 'lib/stator/integration.rb', line 65

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

#invalid_transition!(was, is) ⇒ Object



69
70
71
# File 'lib/stator/integration.rb', line 69

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

#likely_state_at(t) ⇒ Object



125
126
127
# File 'lib/stator/integration.rb', line 125

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

#stateObject



22
23
24
# File 'lib/stator/integration.rb', line 22

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

#state=(new_value) ⇒ Object



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

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

#state_by?(state, time) ⇒ Boolean

Returns:

  • (Boolean)


34
35
36
37
38
39
40
# File 'lib/stator/integration.rb', line 34

def state_by?(state, time)
  field_name = "#{state}_#{@machine.field}_at"
  return false unless @record.respond_to?(field_name)
  return false if @record.send(field_name).nil?
  return true if time.nil?
  @record.send(field_name) <= time
end

#state_changed?(use_previous = false) ⇒ Boolean

Returns:

  • (Boolean)


42
43
44
45
46
47
48
# File 'lib/stator/integration.rb', line 42

def state_changed?(use_previous = false)
  if use_previous
    @record.saved_change_to_attribute?(@machine.field)
  else
    @record.will_save_change_to_attribute?(@machine.field)
  end
end

#state_was(use_previous = false) ⇒ Object



26
27
28
29
30
31
32
# File 'lib/stator/integration.rb', line 26

def state_was(use_previous = false)
  if use_previous
    @record.attribute_before_last_save(@machine.field)
  else
    @record.attribute_in_database(@machine.field)
  end
end

#track_transitionObject



73
74
75
76
77
78
79
80
# File 'lib/stator/integration.rb', line 73

def track_transition
  return if skip_transition_tracking

  attempt_to_track_state(state)
  attempt_to_track_state_changed_timestamp

  true
end

#validate_transitionObject



50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/stator/integration.rb', line 50

def validate_transition
  return unless state_changed?
  return if 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

#without_transition_trackingObject



137
138
139
140
141
142
143
# File 'lib/stator/integration.rb', line 137

def without_transition_tracking
  was = @skip_transition_tracking
  @skip_transition_tracking = true
  yield @record
ensure
  @skip_transition_tracking = was
end

#without_validationObject



129
130
131
132
133
134
135
# File 'lib/stator/integration.rb', line 129

def without_validation
  was = @skip_validations
  @skip_validations = true
  yield @record
ensure
  @skip_validations = was
end