Class: FlowChat::App

Inherits:
Object
  • Object
show all
Defined in:
lib/flow_chat/app.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(context) ⇒ App

Returns a new instance of App.



5
6
7
8
9
# File 'lib/flow_chat/app.rb', line 5

def initialize(context)
  @context = context
  @input = build_input
  @navigation_stack = []
end

Instance Attribute Details

#contextObject (readonly)

Returns the value of attribute context.



3
4
5
# File 'lib/flow_chat/app.rb', line 3

def context
  @context
end

#inputObject (readonly)

Returns the value of attribute input.



3
4
5
# File 'lib/flow_chat/app.rb', line 3

def input
  @input
end

Returns the value of attribute navigation_stack.



3
4
5
# File 'lib/flow_chat/app.rb', line 3

def navigation_stack
  @navigation_stack
end

Instance Method Details

#attachmentObject



128
129
130
# File 'lib/flow_chat/app.rb', line 128

def attachment
  input.attachment
end

#attachment_typeObject



132
133
134
# File 'lib/flow_chat/app.rb', line 132

def attachment_type
  input.attachment_type
end

#consume_turn!Object

Consume this turn's message, so no screen answers it later.

A flow that reads the inbound outside the screen system says so with this. Routing on the opening message is the usual reason: the flow consumes the message itself, and FlowChat cannot see that read, so #screen would hand the same message to the first prompt the run reaches. That prompt is then answered without ever being asked, and its message never goes out.

Records the first-message marker that #screen would have written, so the gate it guards does not fire a turn late and swallow the customer's reply as though it were the opener.

Returns the turn, so the caller can read its text and any attachment. The context keeps both: what is given up is only this turn's right to answer a screen, not the message itself. Contrast #clear_turn!, which discards the turn outright because a restart has to rebuild the App without it.



51
52
53
54
55
56
# File 'lib/flow_chat/app.rb', line 51

def consume_turn!
  taken = input
  maybe_note_first_message!(taken)
  @input_consumed = true
  taken
end

#contactObject



124
125
126
# File 'lib/flow_chat/app.rb', line 124

def contact
  input.contact
end

#contact_nameObject

The sender's display name — distinct from a contact card they may share (that's #contact).



104
105
106
# File 'lib/flow_chat/app.rb', line 104

def contact_name
  context["request.user_name"]
end

#gatewayObject



82
83
84
# File 'lib/flow_chat/app.rb', line 82

def gateway
  context["request.gateway"]
end

#go_backObject



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/flow_chat/app.rb', line 58

def go_back
  return false if navigation_stack.empty?

  # go_back raises RestartFlow, which the executor handles by rebuilding a
  # fresh App from this same context. A per-instance @input_consumed flag
  # would be lost on that rebuild, so clear the turn on the shared context
  # too — otherwise the restarted screen re-consumes the back-trigger
  # input/attachment as its answer instead of re-prompting.
  clear_turn!
  current_screen = navigation_stack.last
  session.delete(current_screen)

  # Restart the flow from the beginning
  raise FlowChat::Interrupt::RestartFlow.new
end

#locationObject



120
121
122
# File 'lib/flow_chat/app.rb', line 120

def location
  input.location
end

#mediaObject

Always an ArrayFlowChat::Media (empty when none) — a list even on single-media platforms, so callers iterate uniformly.



116
117
118
# File 'lib/flow_chat/app.rb', line 116

def media
  input.media
end

#message_idObject



94
95
96
# File 'lib/flow_chat/app.rb', line 94

def message_id
  context["request.message_id"]
end

#msisdnObject



90
91
92
# File 'lib/flow_chat/app.rb', line 90

def msisdn
  context["request.msisdn"]
end

#platformObject



78
79
80
# File 'lib/flow_chat/app.rb', line 78

def platform
  context["request.platform"]
end

#say(msg, media: nil) ⇒ Object



74
75
76
# File 'lib/flow_chat/app.rb', line 74

def say(msg, media: nil)
  raise FlowChat::Interrupt::Terminate.new(msg, media: media)
end

#screen(key) ⇒ Object

Raises:

  • (ArgumentError)


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# File 'lib/flow_chat/app.rb', line 11

def screen(key)
  raise ArgumentError, "a block is expected" unless block_given?
  raise ArgumentError, "screen has already been presented" if navigation_stack.include?(key)

  navigation_stack << key
  # A screen is answered once its key is stored — even when the stored value is
  # blank (a caption-less attachment yields ""). Guard on presence-in-session
  # (non-nil), not truthiness, so media-only (and false/blank) answers stick
  # instead of re-asking every turn.
  cached = session.get(key)
  return cached unless cached.nil?

  user_input = prepare_user_input
  prompt = FlowChat::Prompt.new user_input
  # The turn has been handed to a screen; later screens in this run must not
  # re-consume it. We mark it consumed rather than discarding it, so the
  # read accessors (text/media/...) stay available for the rest of the run.
  @input_consumed = true

  value = yield prompt
  session.set(key, value)
  value
end

#sessionObject



136
137
138
# File 'lib/flow_chat/app.rb', line 136

def session
  @context.session
end

#textObject

Read accessors for the turn delegate to the Input value object, which is the single source of truth for this turn's text and attachments.



110
111
112
# File 'lib/flow_chat/app.rb', line 110

def text
  input.text
end

#timestampObject



98
99
100
# File 'lib/flow_chat/app.rb', line 98

def timestamp
  context["request.timestamp"]
end

#user_idObject



86
87
88
# File 'lib/flow_chat/app.rb', line 86

def user_id
  context["request.user_id"]
end