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



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



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



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



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