punchblock 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. data/.document +5 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.markdown +31 -0
  7. data/Rakefile +23 -0
  8. data/assets/ozone/ask-1.0.xsd +56 -0
  9. data/assets/ozone/conference-1.0.xsd +17 -0
  10. data/assets/ozone/ozone-1.0.xsd +127 -0
  11. data/assets/ozone/say-1.0.xsd +24 -0
  12. data/assets/ozone/transfer-1.0.xsd +32 -0
  13. data/bin/punchblock-console +125 -0
  14. data/lib/punchblock/command/accept.rb +30 -0
  15. data/lib/punchblock/command/answer.rb +30 -0
  16. data/lib/punchblock/command/dial.rb +88 -0
  17. data/lib/punchblock/command/hangup.rb +25 -0
  18. data/lib/punchblock/command/join.rb +81 -0
  19. data/lib/punchblock/command/mute.rb +7 -0
  20. data/lib/punchblock/command/redirect.rb +49 -0
  21. data/lib/punchblock/command/reject.rb +61 -0
  22. data/lib/punchblock/command/unjoin.rb +50 -0
  23. data/lib/punchblock/command/unmute.rb +7 -0
  24. data/lib/punchblock/command.rb +16 -0
  25. data/lib/punchblock/command_node.rb +46 -0
  26. data/lib/punchblock/component/input.rb +320 -0
  27. data/lib/punchblock/component/output.rb +449 -0
  28. data/lib/punchblock/component/record.rb +216 -0
  29. data/lib/punchblock/component/tropo/ask.rb +197 -0
  30. data/lib/punchblock/component/tropo/conference.rb +328 -0
  31. data/lib/punchblock/component/tropo/say.rb +113 -0
  32. data/lib/punchblock/component/tropo/transfer.rb +178 -0
  33. data/lib/punchblock/component/tropo.rb +12 -0
  34. data/lib/punchblock/component.rb +73 -0
  35. data/lib/punchblock/connection.rb +209 -0
  36. data/lib/punchblock/core_ext/blather/stanza/presence.rb +11 -0
  37. data/lib/punchblock/core_ext/blather/stanza.rb +26 -0
  38. data/lib/punchblock/dsl.rb +46 -0
  39. data/lib/punchblock/event/answered.rb +7 -0
  40. data/lib/punchblock/event/complete.rb +65 -0
  41. data/lib/punchblock/event/dtmf.rb +19 -0
  42. data/lib/punchblock/event/end.rb +15 -0
  43. data/lib/punchblock/event/info.rb +15 -0
  44. data/lib/punchblock/event/joined.rb +50 -0
  45. data/lib/punchblock/event/offer.rb +29 -0
  46. data/lib/punchblock/event/ringing.rb +7 -0
  47. data/lib/punchblock/event/unjoined.rb +50 -0
  48. data/lib/punchblock/event.rb +16 -0
  49. data/lib/punchblock/generic_connection.rb +18 -0
  50. data/lib/punchblock/has_headers.rb +34 -0
  51. data/lib/punchblock/header.rb +47 -0
  52. data/lib/punchblock/media_container.rb +39 -0
  53. data/lib/punchblock/media_node.rb +17 -0
  54. data/lib/punchblock/protocol_error.rb +16 -0
  55. data/lib/punchblock/rayo_node.rb +88 -0
  56. data/lib/punchblock/ref.rb +26 -0
  57. data/lib/punchblock/version.rb +3 -0
  58. data/lib/punchblock.rb +42 -0
  59. data/log/.gitkeep +0 -0
  60. data/punchblock.gemspec +42 -0
  61. data/spec/punchblock/command/accept_spec.rb +13 -0
  62. data/spec/punchblock/command/answer_spec.rb +13 -0
  63. data/spec/punchblock/command/dial_spec.rb +54 -0
  64. data/spec/punchblock/command/hangup_spec.rb +13 -0
  65. data/spec/punchblock/command/join_spec.rb +21 -0
  66. data/spec/punchblock/command/mute_spec.rb +11 -0
  67. data/spec/punchblock/command/redirect_spec.rb +19 -0
  68. data/spec/punchblock/command/reject_spec.rb +43 -0
  69. data/spec/punchblock/command/unjoin_spec.rb +19 -0
  70. data/spec/punchblock/command/unmute_spec.rb +11 -0
  71. data/spec/punchblock/command_node_spec.rb +80 -0
  72. data/spec/punchblock/component/input_spec.rb +188 -0
  73. data/spec/punchblock/component/output_spec.rb +531 -0
  74. data/spec/punchblock/component/record_spec.rb +235 -0
  75. data/spec/punchblock/component/tropo/ask_spec.rb +183 -0
  76. data/spec/punchblock/component/tropo/conference_spec.rb +360 -0
  77. data/spec/punchblock/component/tropo/say_spec.rb +171 -0
  78. data/spec/punchblock/component/tropo/transfer_spec.rb +153 -0
  79. data/spec/punchblock/component_spec.rb +126 -0
  80. data/spec/punchblock/connection_spec.rb +194 -0
  81. data/spec/punchblock/event/answered_spec.rb +23 -0
  82. data/spec/punchblock/event/complete_spec.rb +80 -0
  83. data/spec/punchblock/event/dtmf_spec.rb +24 -0
  84. data/spec/punchblock/event/end_spec.rb +30 -0
  85. data/spec/punchblock/event/info_spec.rb +30 -0
  86. data/spec/punchblock/event/joined_spec.rb +32 -0
  87. data/spec/punchblock/event/offer_spec.rb +35 -0
  88. data/spec/punchblock/event/ringing_spec.rb +23 -0
  89. data/spec/punchblock/event/unjoined_spec.rb +32 -0
  90. data/spec/punchblock/header_spec.rb +44 -0
  91. data/spec/punchblock/protocol_error_spec.rb +9 -0
  92. data/spec/punchblock/ref_spec.rb +21 -0
  93. data/spec/spec_helper.rb +43 -0
  94. metadata +353 -0
@@ -0,0 +1,197 @@
1
+ module Punchblock
2
+ module Component
3
+ module Tropo
4
+ class Ask < ComponentNode
5
+ register :ask, :ask
6
+
7
+ ##
8
+ # Create an ask message
9
+ #
10
+ # @param [Hash] options for asking/prompting a specific call
11
+ # @option options [Choices, Hash] :choices to allow the user to input
12
+ # @option options [Prompt, Hash, Optional] :prompt to play/read to the caller as the question
13
+ # @option options [Symbol, Optional] :mode by which to accept input. Can be :speech, :dtmf or :any
14
+ # @option options [Integer, Optional] :timeout to wait for user input
15
+ # @option options [Boolean, Optional] :bargein wether or not to allow the caller to begin their response before the prompt finishes
16
+ # @option options [String, Optional] :recognizer to use for speech recognition
17
+ # @option options [String, Optional] :terminator by which to signal the end of input
18
+ # @option options [Float, Optional] :min_confidence with which to consider a response acceptable
19
+ #
20
+ # @return [Command::Ask] a formatted Rayo ask command
21
+ #
22
+ # @example
23
+ # ask :prompt => {:text => 'Please enter your postal code.', :voice => 'simon'},
24
+ # :choices => {:value => '[5 DIGITS]'},
25
+ # :timeout => 30,
26
+ # :recognizer => 'es-es'
27
+ #
28
+ # returns:
29
+ # <ask xmlns="urn:xmpp:tropo:ask:1" timeout="30" recognizer="es-es">
30
+ # <prompt voice='simon'>Please enter your postal code.</prompt>
31
+ # <choices content-type="application/grammar+voxeo">[5 DIGITS]</choices>
32
+ # </ask>
33
+ #
34
+ def self.new(options = {})
35
+ super().tap do |new_node|
36
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
37
+ end
38
+ end
39
+
40
+ ##
41
+ # @return [Boolean] wether or not to allow the caller to begin their response before the prompt finishes
42
+ #
43
+ def bargein
44
+ read_attr(:bargein) == "true"
45
+ end
46
+
47
+ ##
48
+ # @param [Boolean] bargein wether or not to allow the caller to begin their response before the prompt finishes
49
+ #
50
+ def bargein=(bargein)
51
+ write_attr :bargein, bargein.to_s
52
+ end
53
+
54
+ ##
55
+ # @return [Float] Confidence with which to consider a response acceptable
56
+ #
57
+ def min_confidence
58
+ read_attr 'min-confidence', :to_f
59
+ end
60
+
61
+ ##
62
+ # @param [Float] min_confidence with which to consider a response acceptable
63
+ #
64
+ def min_confidence=(min_confidence)
65
+ write_attr 'min-confidence', min_confidence
66
+ end
67
+
68
+ ##
69
+ # @return [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
70
+ #
71
+ def mode
72
+ read_attr :mode, :to_sym
73
+ end
74
+
75
+ ##
76
+ # @param [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
77
+ #
78
+ def mode=(mode)
79
+ write_attr :mode, mode
80
+ end
81
+
82
+ ##
83
+ # @return [String] recognizer to use for speech recognition
84
+ #
85
+ def recognizer
86
+ read_attr :recognizer
87
+ end
88
+
89
+ ##
90
+ # @param [String] recognizer to use for speech recognition
91
+ #
92
+ def recognizer=(recognizer)
93
+ write_attr :recognizer, recognizer
94
+ end
95
+
96
+ ##
97
+ # @return [String] terminator by which to signal the end of input
98
+ #
99
+ def terminator
100
+ read_attr :terminator
101
+ end
102
+
103
+ ##
104
+ # @param [String] terminator by which to signal the end of input
105
+ #
106
+ def terminator=(terminator)
107
+ write_attr :terminator, terminator
108
+ end
109
+
110
+ ##
111
+ # @return [Integer] timeout to wait for user input
112
+ #
113
+ def timeout
114
+ read_attr :timeout, :to_i
115
+ end
116
+
117
+ ##
118
+ # @param [Integer] timeout to wait for user input
119
+ #
120
+ def timeout=(timeout)
121
+ write_attr :timeout, timeout
122
+ end
123
+
124
+ ##
125
+ # @return [Prompt] the prompt by which to introduce the question
126
+ #
127
+ def prompt
128
+ Prompt.new find_first('//ns:prompt', :ns => self.registered_ns)
129
+ end
130
+
131
+ ##
132
+ # @param [Hash] p
133
+ # @option p [String] :text to read the caller via TTS as the question
134
+ # @option p [String] :voice to use for speech synthesis
135
+ #
136
+ def prompt=(p)
137
+ remove_children :prompt
138
+ p = Prompt.new(p) unless p.is_a?(Prompt)
139
+ self << p
140
+ end
141
+
142
+ class Prompt < MediaNode
143
+ register :prompt, :ask
144
+ end
145
+
146
+ ##
147
+ # @return [Choices] the choices available
148
+ #
149
+ def choices
150
+ Choices.new find_first('ns:choices', :ns => self.class.registered_ns)
151
+ end
152
+
153
+ ##
154
+ # @param [Hash] choices
155
+ # @option choices [String] :content_type
156
+ # @option choices [String] :value the choices available
157
+ #
158
+ def choices=(choices)
159
+ remove_children :choices
160
+ choices = Choices.new(choices) unless choices.is_a?(Choices)
161
+ self << choices
162
+ end
163
+
164
+ def inspect_attributes # :nodoc:
165
+ [:bargein, :min_confidence, :mode, :recognizer, :terminator, :timeout, :prompt, :choices] + super
166
+ end
167
+
168
+ class Choices < Input::Grammar
169
+ ##
170
+ # @param [Hash] options
171
+ # @option options [String] :content_type
172
+ # @option options [String] :value the choices available
173
+ #
174
+ def self.new(options = {})
175
+ super(options).tap do |new_node|
176
+ new_node.name = 'choices'
177
+ end
178
+ end
179
+ end # Choices
180
+
181
+ class Complete
182
+ class Success < Input::Complete::Success
183
+ register :success, :ask_complete
184
+ end
185
+
186
+ class NoMatch < Input::Complete::NoMatch
187
+ register :nomatch, :ask_complete
188
+ end
189
+
190
+ class NoInput < Input::Complete::NoInput
191
+ register :noinput, :ask_complete
192
+ end
193
+ end # Complete
194
+ end # Ask
195
+ end # Tropo
196
+ end # Command
197
+ end # Punchblock
@@ -0,0 +1,328 @@
1
+ module Punchblock
2
+ module Component
3
+ module Tropo
4
+ class Conference < ComponentNode
5
+ register :conference, :conference
6
+
7
+ ##
8
+ # Creates an Rayo conference command
9
+ #
10
+ # @param [Hash] options
11
+ # @option options [String] :name room id to with which to create or join the conference
12
+ # @option options [Announcement, Hash, Optional] :announcement to play on entry
13
+ # @option options [Music, Hash, Optional] :music to play to the participant when no moderator is present
14
+ # @option options [Boolean, Optional] :mute If set to true, the user will be muted in the conference
15
+ # @option options [Boolean, Optional] :moderator Whether or not the conference should be moderated
16
+ # @option options [Boolean, Optional] :tone_passthrough Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
17
+ # @option options [String, Optional] :terminator This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
18
+ #
19
+ # @return [Command::Conference] a formatted Rayo conference command
20
+ #
21
+ # @example
22
+ # conference :name => 'the_one_true_conference', :terminator => '#'
23
+ #
24
+ # returns:
25
+ # <conference xmlns="urn:xmpp:tropo:conference:1" name="the_one_true_conference" terminator="#"/>
26
+ def self.new(options = {})
27
+ super().tap do |new_node|
28
+ options.each_pair do |k,v|
29
+ new_node.send :"#{k}=", v
30
+ end
31
+ end
32
+ end
33
+
34
+ ##
35
+ # @return [String] the name of the conference
36
+ #
37
+ def name
38
+ read_attr :name
39
+ end
40
+
41
+ ##
42
+ # @param [String] name of the conference
43
+ #
44
+ def name=(name)
45
+ write_attr :name, name
46
+ end
47
+
48
+ ##
49
+ # @return [Boolean] If set to true, the user will be muted in the conference.
50
+ #
51
+ def mute
52
+ read_attr(:mute) == 'true'
53
+ end
54
+
55
+ ##
56
+ # @param [Boolean] mute If set to true, the user will be muted in the conference
57
+ #
58
+ def mute=(mute)
59
+ write_attr :mute, mute.to_s
60
+ end
61
+
62
+ ##
63
+ # @return [String] This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
64
+ #
65
+ def terminator
66
+ read_attr :terminator
67
+ end
68
+
69
+ ##
70
+ # @param [String] terminator This is the touch-tone key (also known as "DTMF digit") used to exit the conference.
71
+ #
72
+ def terminator=(terminator)
73
+ write_attr :terminator, terminator
74
+ end
75
+
76
+ ##
77
+ # @return [Boolean] Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
78
+ #
79
+ def tone_passthrough
80
+ read_attr('tone-passthrough') == 'true'
81
+ end
82
+
83
+ ##
84
+ # @param [Boolean] tone_passthrough Identifies whether or not conference members can hear the tone generated when a a key on the phone is pressed.
85
+ #
86
+ def tone_passthrough=(tone_passthrough)
87
+ write_attr 'tone-passthrough', tone_passthrough.to_s
88
+ end
89
+
90
+ ##
91
+ # @return [Boolean] Whether or not the conference should be moderated
92
+ #
93
+ def moderator
94
+ read_attr(:moderator) == 'true'
95
+ end
96
+
97
+ ##
98
+ # @param [Boolean] moderator Whether or not the conference should be moderated
99
+ #
100
+ def moderator=(moderator)
101
+ write_attr :moderator, moderator.to_s
102
+ end
103
+
104
+ ##
105
+ # @return [Announcement] the announcement to play to the participant on entry
106
+ #
107
+ def announcement
108
+ node = find_first '//ns:announcement', :ns => self.registered_ns
109
+ Announcement.new node if node
110
+ end
111
+
112
+ ##
113
+ # @param [Announcement, Hash] ann
114
+ # @option ann [String] :text Text to speak to the caller as an announcement
115
+ # @option ann [String] :url URL to play to the caller as an announcement
116
+ #
117
+ def announcement=(ann)
118
+ ann = Announcement.new(ann) unless ann.is_a? Announcement
119
+ self << ann
120
+ end
121
+
122
+ ##
123
+ # @return [Music] the music to play to the participant on entry if there's no moderator present
124
+ #
125
+ def music
126
+ node = find_first '//ns:music', :ns => self.registered_ns
127
+ Music.new node if node
128
+ end
129
+
130
+ ##
131
+ # @param [Music, Hash] m
132
+ # @option m [String] :text Text to speak to the caller
133
+ # @option m [String] :url URL to play to the caller
134
+ #
135
+ def music=(m)
136
+ m = Music.new(m) unless m.is_a? Announcement
137
+ self << m
138
+ end
139
+
140
+ class Announcement < MediaNode
141
+ register :announcement, :conference
142
+ end
143
+
144
+ class Music < MediaNode
145
+ register :music, :conference
146
+ end
147
+
148
+ def inspect_attributes # :nodoc:
149
+ [:name, :mute, :terminator, :tone_passthrough, :moderator, :announcement, :music] + super
150
+ end
151
+
152
+ def transition_state!(event)
153
+ super
154
+ case event
155
+ when OnHold
156
+ onhold!
157
+ when OffHold
158
+ offhold!
159
+ end
160
+ end
161
+
162
+ state_machine :state do
163
+ after_transition :new => :requested do |command, transition|
164
+ command.mute ? command.muted! : command.unmuted!
165
+ end
166
+ end
167
+
168
+ state_machine :mute_status, :initial => :unknown_mute do
169
+ event :muted do
170
+ transition [:unmuted, :unknown_mute] => :muted
171
+ end
172
+
173
+ event :unmuted do
174
+ transition [:muted, :unknown_mute] => :unmuted
175
+ end
176
+ end
177
+
178
+ state_machine :hold_status, :initial => :unknown_hold do
179
+ event :onhold do
180
+ transition [:offhold, :unknown_hold] => :onhold
181
+ end
182
+
183
+ event :offhold do
184
+ transition [:onhold, :unknown_hold] => :offhold
185
+ end
186
+ end
187
+
188
+ class OnHold < Event
189
+ register :'on-hold', :conference
190
+ end
191
+
192
+ class OffHold < Event
193
+ register :'off-hold', :conference
194
+ end
195
+
196
+ module ActiveSpeaker
197
+ def speaking_call_id
198
+ read_attr :'call-id'
199
+ end
200
+ end
201
+
202
+ class Speaking < Event
203
+ register :speaking, :conference
204
+ include ActiveSpeaker
205
+ end
206
+
207
+ class FinishedSpeaking < Event
208
+ register :'finished-speaking', :conference
209
+ include ActiveSpeaker
210
+ end
211
+
212
+ class Complete
213
+ class Kick < Event::Complete::Reason
214
+ register :kick, :conference_complete
215
+
216
+ alias :details :text
217
+
218
+ def inspect_attributes # :nodoc:
219
+ [:details] + super
220
+ end
221
+ end
222
+
223
+ class Terminator < Event::Complete::Reason
224
+ register :terminator, :conference_complete
225
+ end
226
+ end
227
+
228
+ ##
229
+ # Create an Rayo mute message for the current conference
230
+ #
231
+ # @return [Command::Conference::Mute] an Rayo mute message
232
+ #
233
+ # @example
234
+ # conf_obj.mute_action.to_xml
235
+ #
236
+ # returns:
237
+ # <mute xmlns="urn:xmpp:tropo:conference:1"/>
238
+ #
239
+ def mute_action
240
+ Command::Mute.new :component_id => component_id, :call_id => call_id
241
+ end
242
+
243
+ ##
244
+ # Sends an Rayo mute message for the current Conference
245
+ #
246
+ def mute!
247
+ raise InvalidActionError, "Cannot mute a Conference that is already muted" if muted?
248
+ mute_action.tap do |action|
249
+ result = write_action action
250
+ muted! if result
251
+ end
252
+ end
253
+
254
+ ##
255
+ # Create an Rayo unmute message for the current conference
256
+ #
257
+ # @return [Command::Conference::Unmute] an Rayo unmute message
258
+ #
259
+ # @example
260
+ # conf_obj.unmute_action.to_xml
261
+ #
262
+ # returns:
263
+ # <unmute xmlns="urn:xmpp:tropo:conference:1"/>
264
+ #
265
+ def unmute_action
266
+ Command::Unmute.new :component_id => component_id, :call_id => call_id
267
+ end
268
+
269
+ ##
270
+ # Sends an Rayo unmute message for the current Conference
271
+ #
272
+ def unmute!
273
+ raise InvalidActionError, "Cannot unmute a Conference that is not muted" unless muted?
274
+ unmute_action.tap do |action|
275
+ result = write_action action
276
+ unmuted! if result
277
+ end
278
+ end
279
+
280
+ ##
281
+ # Create an Rayo conference kick message
282
+ #
283
+ # @param [Hash] options
284
+ # @option options [String] :message to explain the reason for kicking
285
+ #
286
+ # @return [Command::Conference::Kick] an Rayo conference kick message
287
+ #
288
+ # @example
289
+ # conf_obj.kick_action(:message => 'bye!').to_xml
290
+ #
291
+ # returns:
292
+ # <kick xmlns="urn:xmpp:tropo:conference:1">bye!</kick>
293
+ #
294
+ def kick_action(options = {})
295
+ Kick.new options.merge(:component_id => component_id, :call_id => call_id)
296
+ end
297
+
298
+ ##
299
+ # Sends an Rayo kick message for the current Conference
300
+ #
301
+ # @param [Hash] options
302
+ # @option options [String] :message to explain the reason for kicking
303
+ #
304
+ def kick!(options = {})
305
+ raise InvalidActionError, "Cannot kick a Conference that is not executing" unless executing?
306
+ kick_action.tap do |action|
307
+ write_action action
308
+ end
309
+ end
310
+
311
+ class Kick < CommandNode # :nodoc:
312
+ register :kick, :conference
313
+
314
+ def self.new(options = {})
315
+ super.tap do |new_node|
316
+ new_node.message = options[:message]
317
+ end
318
+ end
319
+
320
+ def message=(m)
321
+ self << m if m
322
+ end
323
+ end
324
+
325
+ end # Conference
326
+ end # Tropo
327
+ end # Command
328
+ end # Punchblock
@@ -0,0 +1,113 @@
1
+ module Punchblock
2
+ module Component
3
+ module Tropo
4
+ class Say < ComponentNode
5
+ register :say, :say
6
+
7
+ include MediaContainer
8
+
9
+ ##
10
+ # Creates an Rayo Say command
11
+ #
12
+ # @param [Hash] options
13
+ # @option options [String, Optional] :text to speak back
14
+ # @option options [String, Optional] :voice with which to render TTS
15
+ # @option options [String, Optional] :ssml document to render TTS
16
+ #
17
+ # @return [Command::Say] an Rayo "say" command
18
+ #
19
+ # @example
20
+ # say :text => 'Hello brown cow.'
21
+ #
22
+ # returns:
23
+ # <say xmlns="urn:xmpp:tropo:say:1">Hello brown cow.</say>
24
+ #
25
+ def self.new(options = {})
26
+ super().tap do |new_node|
27
+ case options
28
+ when Hash
29
+ new_node.voice = options.delete(:voice) if options[:voice]
30
+ new_node.ssml = options.delete(:ssml) if options[:ssml]
31
+ new_node << options.delete(:text) if options[:text]
32
+ when Nokogiri::XML::Element
33
+ new_node.inherit options
34
+ end
35
+ end
36
+ end
37
+
38
+ state_machine :state do
39
+ event :paused do
40
+ transition :executing => :paused
41
+ end
42
+
43
+ event :resumed do
44
+ transition :paused => :executing
45
+ end
46
+ end
47
+
48
+ # Pauses a running Say
49
+ #
50
+ # @return [Command::Say::Pause] an Rayo pause message for the current Say
51
+ #
52
+ # @example
53
+ # say_obj.pause_action.to_xml
54
+ #
55
+ # returns:
56
+ # <pause xmlns="urn:xmpp:tropo:say:1"/>
57
+ def pause_action
58
+ Pause.new :component_id => component_id, :call_id => call_id
59
+ end
60
+
61
+ ##
62
+ # Sends an Rayo pause message for the current Say
63
+ #
64
+ def pause!
65
+ raise InvalidActionError, "Cannot pause a Say that is not executing" unless executing?
66
+ pause_action.tap do |action|
67
+ result = write_action action
68
+ paused! if result
69
+ end
70
+ end
71
+
72
+ ##
73
+ # Create an Rayo resume message for the current Say
74
+ #
75
+ # @return [Command::Say::Resume] an Rayo resume message
76
+ #
77
+ # @example
78
+ # say_obj.resume_action.to_xml
79
+ #
80
+ # returns:
81
+ # <resume xmlns="urn:xmpp:tropo:say:1"/>
82
+ def resume_action
83
+ Resume.new :component_id => component_id, :call_id => call_id
84
+ end
85
+
86
+ ##
87
+ # Sends an Rayo resume message for the current Say
88
+ #
89
+ def resume!
90
+ raise InvalidActionError, "Cannot resume a Say that is not paused." unless paused?
91
+ resume_action.tap do |action|
92
+ result = write_action action
93
+ resumed! if result
94
+ end
95
+ end
96
+
97
+ class Pause < CommandNode # :nodoc:
98
+ register :pause, :say
99
+ end
100
+
101
+ class Resume < CommandNode # :nodoc:
102
+ register :resume, :say
103
+ end
104
+
105
+ class Complete
106
+ class Success < Event::Complete::Reason
107
+ register :success, :say_complete
108
+ end
109
+ end
110
+ end # Say
111
+ end # Tropo
112
+ end # Command
113
+ end # Punchblock