punchblock 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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,81 @@
1
+ module Punchblock
2
+ module Command
3
+ class Join < CommandNode
4
+ register :join, :core
5
+
6
+ ##
7
+ # Create a join message
8
+ #
9
+ # @param [Hash] options
10
+ # @option options [String, Optional] :other_call_id the call ID to join
11
+ # @option options [String, Optional] :mixer_id the mixer name to join
12
+ # @option options [Symbol, Optional] :direction the direction in which media should flow
13
+ # @option options [Symbol, Optional] :media the method by which to negotiate media
14
+ #
15
+ # @return [Command::Join] a formatted Rayo join command
16
+ #
17
+ def self.new(options = {})
18
+ super().tap do |new_node|
19
+ case options
20
+ when Nokogiri::XML::Node
21
+ new_node.inherit options
22
+ when Hash
23
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
24
+ end
25
+ end
26
+ end
27
+
28
+ ##
29
+ # @return [String] the call ID to join
30
+ def other_call_id
31
+ read_attr :'call-id'
32
+ end
33
+
34
+ ##
35
+ # @param [String] other the call ID to join
36
+ def other_call_id=(other)
37
+ write_attr :'call-id', other
38
+ end
39
+
40
+ ##
41
+ # @return [String] the mixer name to join
42
+ def mixer_id
43
+ read_attr :'mixer-id'
44
+ end
45
+
46
+ ##
47
+ # @param [String] other the mixer name to join
48
+ def mixer_id=(other)
49
+ write_attr :'mixer-id', other
50
+ end
51
+
52
+ ##
53
+ # @return [String] the direction in which media should flow
54
+ def direction
55
+ read_attr :direction, :to_sym
56
+ end
57
+
58
+ ##
59
+ # @param [String] other the direction in which media should flow. Can be :duplex, :recv or :send
60
+ def direction=(other)
61
+ write_attr :direction, other
62
+ end
63
+
64
+ ##
65
+ # @return [String] the method by which to negotiate media
66
+ def media
67
+ read_attr :media, :to_sym
68
+ end
69
+
70
+ ##
71
+ # @param [String] other the method by which to negotiate media. Can be :direct or :bridge
72
+ def media=(other)
73
+ write_attr :media, other
74
+ end
75
+
76
+ def inspect_attributes # :nodoc:
77
+ [:other_call_id, :mixer_id, :direction, :media] + super
78
+ end
79
+ end # Join
80
+ end # Command
81
+ end # Punchblock
@@ -0,0 +1,7 @@
1
+ module Punchblock
2
+ module Command
3
+ class Mute < CommandNode
4
+ register :mute, :core
5
+ end # Mute
6
+ end # Command
7
+ end # Punchblock
@@ -0,0 +1,49 @@
1
+ module Punchblock
2
+ module Command
3
+ class Redirect < CommandNode
4
+ register :redirect, :core
5
+
6
+ include HasHeaders
7
+
8
+ ##
9
+ # Create an Rayo redirect message
10
+ #
11
+ # @param [Hash] options
12
+ # @option options [String] :to redirect target
13
+ # @option options [Array[Header], Hash, Optional] :headers SIP headers to attach to
14
+ # the new call. Can be either a hash of key-value pairs, or an array of
15
+ # Header objects.
16
+ #
17
+ # @return [Command::Redirect] a formatted Rayo redirect command
18
+ #
19
+ # @example
20
+ # Redirect.new(:to => 'tel:+14045551234').to_xml
21
+ #
22
+ # returns:
23
+ # <redirect to="tel:+14045551234" xmlns="urn:xmpp:rayo:1"/>
24
+ #
25
+ def self.new(options = {})
26
+ super().tap do |new_node|
27
+ new_node.to = options[:to]
28
+ new_node.headers = options[:headers]
29
+ end
30
+ end
31
+
32
+ ##
33
+ # @return [String] the redirect target
34
+ def to
35
+ read_attr :to
36
+ end
37
+
38
+ ##
39
+ # @param [String] redirect_to redirect target
40
+ def to=(redirect_to)
41
+ write_attr :to, redirect_to
42
+ end
43
+
44
+ def inspect_attributes # :nodoc:
45
+ [:to] + super
46
+ end
47
+ end # Redirect
48
+ end # Command
49
+ end # Punchblock
@@ -0,0 +1,61 @@
1
+ module Punchblock
2
+ module Command
3
+ class Reject < CommandNode
4
+ register :reject, :core
5
+
6
+ include HasHeaders
7
+
8
+ VALID_REASONS = [:busy, :decline, :error].freeze
9
+
10
+ ##
11
+ # Create an Rayo reject message
12
+ #
13
+ # @param [Hash] options
14
+ # @option options [Symbol] :reason for rejecting the call. Can be any one of VALID_REASONS. Defaults to :decline
15
+ # @option options [Array[Header], Hash, Optional] :headers SIP headers to attach to
16
+ # the call. Can be either a hash of key-value pairs, or an array of
17
+ # Header objects.
18
+ #
19
+ # @return [Command::Reject] a formatted Rayo reject command
20
+ #
21
+ # @example
22
+ # Reject.new(:reason => :busy).to_xml
23
+ #
24
+ # returns:
25
+ # <reject xmlns="urn:xmpp:rayo:1"><busy/></reject
26
+ #
27
+ def self.new(options = {})
28
+ super().tap do |new_node|
29
+ new_node.reason = options[:reason] || :decline
30
+ new_node.headers = options[:headers]
31
+ end
32
+ end
33
+
34
+ ##
35
+ # @return [Symbol] the reason type for rejecting a call
36
+ #
37
+ def reason
38
+ children.select { |c| c.is_a? Nokogiri::XML::Element }.first.name.to_sym
39
+ end
40
+
41
+ ##
42
+ # Set the reason for rejecting the call
43
+ #
44
+ # @param [Symbol] reject_reason Can be any one of :busy, :dclined or :error.
45
+ #
46
+ # @raises ArgumentError if reject_reason is not one of the allowed reasons
47
+ #
48
+ def reason=(reject_reason)
49
+ if reject_reason && !VALID_REASONS.include?(reject_reason.to_sym)
50
+ raise ArgumentError, "Invalid Reason (#{reject_reason}), use: #{VALID_REASONS*' '}"
51
+ end
52
+ children.each &:remove
53
+ self << RayoNode.new(reject_reason)
54
+ end
55
+
56
+ def inspect_attributes # :nodoc:
57
+ [:reason] + super
58
+ end
59
+ end # Reject
60
+ end # Command
61
+ end # Punchblock
@@ -0,0 +1,50 @@
1
+ module Punchblock
2
+ module Command
3
+ class Unjoin < CommandNode
4
+ register :unjoin, :core
5
+
6
+ ##
7
+ # Create an ujoin message
8
+ #
9
+ # @param [Hash] options
10
+ # @option options [String, Optional] :other_call_id the call ID to unjoin
11
+ # @option options [String, Optional] :mixer_id the mixer name to unjoin
12
+ #
13
+ # @return [Command::Unjoin] a formatted Rayo unjoin command
14
+ #
15
+ def self.new(options = {})
16
+ super().tap do |new_node|
17
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
18
+ end
19
+ end
20
+
21
+ ##
22
+ # @return [String] the call ID to unjoin
23
+ def other_call_id
24
+ read_attr :'call-id'
25
+ end
26
+
27
+ ##
28
+ # @param [String] other the call ID to unjoin
29
+ def other_call_id=(other)
30
+ write_attr :'call-id', other
31
+ end
32
+
33
+ ##
34
+ # @return [String] the mixer name to unjoin
35
+ def mixer_id
36
+ read_attr :'mixer-id'
37
+ end
38
+
39
+ ##
40
+ # @param [String] other the mixer name to unjoin
41
+ def mixer_id=(other)
42
+ write_attr :'mixer-id', other
43
+ end
44
+
45
+ def inspect_attributes # :nodoc:
46
+ [:other_call_id, :mixer_id] + super
47
+ end
48
+ end # Unjoin
49
+ end # Command
50
+ end # Punchblock
@@ -0,0 +1,7 @@
1
+ module Punchblock
2
+ module Command
3
+ class Unmute < CommandNode
4
+ register :unmute, :core
5
+ end # Mute
6
+ end # Command
7
+ end # Punchblock
@@ -0,0 +1,16 @@
1
+ module Punchblock
2
+ module Command
3
+ extend ActiveSupport::Autoload
4
+
5
+ autoload :Accept
6
+ autoload :Answer
7
+ autoload :Dial
8
+ autoload :Hangup
9
+ autoload :Join
10
+ autoload :Mute
11
+ autoload :Redirect
12
+ autoload :Reject
13
+ autoload :Unjoin
14
+ autoload :Unmute
15
+ end # Command
16
+ end # Punchblock
@@ -0,0 +1,46 @@
1
+ require 'state_machine'
2
+
3
+ module Punchblock
4
+ class CommandNode < RayoNode
5
+ def self.new(options = {})
6
+ super().tap do |new_node|
7
+ new_node.call_id = options[:call_id]
8
+ new_node.component_id = options[:component_id]
9
+ end
10
+ end
11
+
12
+ def initialize(*args)
13
+ super
14
+ @response = FutureResource.new
15
+ end
16
+
17
+ state_machine :state, :initial => :new do
18
+ event :request do
19
+ transition :new => :requested
20
+ end
21
+
22
+ event :execute do
23
+ transition :requested => :executing
24
+ end
25
+
26
+ event :complete do
27
+ transition :executing => :complete
28
+ end
29
+ end
30
+
31
+ def write_attr(*args)
32
+ raise StandardError, "Cannot alter attributes of a requested command" unless new?
33
+ super
34
+ end
35
+
36
+ def response(timeout = nil)
37
+ @response.resource timeout
38
+ end
39
+
40
+ def response=(other)
41
+ return if @response.set_yet?
42
+ @response.resource = other
43
+ execute!
44
+ end
45
+ end # CommandNode
46
+ end # Punchblock
@@ -0,0 +1,320 @@
1
+ module Punchblock
2
+ module Component
3
+ class Input < ComponentNode
4
+ register :input, :input
5
+
6
+ ##
7
+ # Create an input message
8
+ #
9
+ # @param [Hash] options for inputing/prompting a specific call
10
+ # @option options [Choices, Hash] :choices to allow the user to input
11
+ # @option options [Prompt, Hash, Optional] :prompt to play/read to the caller as the question
12
+ # @option options [Symbol, Optional] :mode by which to accept input. Can be :speech, :dtmf or :any
13
+ # @option options [Integer, Optional] :timeout to wait for user input
14
+ # @option options [Boolean, Optional] :bargein wether or not to allow the caller to begin their response before the prompt finishes
15
+ # @option options [String, Optional] :recognizer to use for speech recognition
16
+ # @option options [String, Optional] :terminator by which to signal the end of input
17
+ # @option options [Float, Optional] :min_confidence with which to consider a response acceptable
18
+ #
19
+ # @return [Command::Input] a formatted Rayo input command
20
+ #
21
+ # @example
22
+ # input :prompt => {:text => 'Please enter your postal code.', :voice => 'simon'},
23
+ # :choices => {:value => '[5 DIGITS]'},
24
+ # :timeout => 30,
25
+ # :recognizer => 'es-es'
26
+ #
27
+ # returns:
28
+ # <input xmlns="urn:xmpp:tropo:input:1" timeout="30" recognizer="es-es">
29
+ # <prompt voice='simon'>Please enter your postal code.</prompt>
30
+ # <choices content-type="application/grammar+voxeo">[5 DIGITS]</choices>
31
+ # </input>
32
+ #
33
+ def self.new(options = {})
34
+ super().tap do |new_node|
35
+ options.each_pair { |k,v| new_node.send :"#{k}=", v }
36
+ end
37
+ end
38
+
39
+ ##
40
+ # @return [Boolean] wether or not to allow the caller to begin their response before the prompt finishes
41
+ #
42
+ def max_digits
43
+ read_attr :'max-digits', :to_i
44
+ end
45
+
46
+ ##
47
+ # @param [Boolean] bargein wether or not to allow the caller to begin their response before the prompt finishes
48
+ #
49
+ def max_digits=(other)
50
+ write_attr :'max-digits', other
51
+ end
52
+
53
+ ##
54
+ # @return [Float] Confidence with which to consider a response acceptable
55
+ #
56
+ def min_confidence
57
+ read_attr 'min-confidence', :to_f
58
+ end
59
+
60
+ ##
61
+ # @param [Float] min_confidence with which to consider a response acceptable
62
+ #
63
+ def min_confidence=(min_confidence)
64
+ write_attr 'min-confidence', min_confidence
65
+ end
66
+
67
+ ##
68
+ # @return [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
69
+ #
70
+ def mode
71
+ read_attr :mode, :to_sym
72
+ end
73
+
74
+ ##
75
+ # @param [Symbol] mode by which to accept input. Can be :speech, :dtmf or :any
76
+ #
77
+ def mode=(mode)
78
+ write_attr :mode, mode
79
+ end
80
+
81
+ ##
82
+ # @return [String] recognizer to use for speech recognition
83
+ #
84
+ def recognizer
85
+ read_attr :recognizer
86
+ end
87
+
88
+ ##
89
+ # @param [String] recognizer to use for speech recognition
90
+ #
91
+ def recognizer=(recognizer)
92
+ write_attr :recognizer, recognizer
93
+ end
94
+
95
+ ##
96
+ # @return [String] terminator by which to signal the end of input
97
+ #
98
+ def terminator
99
+ read_attr :terminator
100
+ end
101
+
102
+ ##
103
+ # @param [String] terminator by which to signal the end of input
104
+ #
105
+ def terminator=(terminator)
106
+ write_attr :terminator, terminator
107
+ end
108
+
109
+ ##
110
+ # @return [Integer] timeout to wait for user input
111
+ #
112
+ def sensitivity
113
+ read_attr :sensitivity, :to_f
114
+ end
115
+
116
+ ##
117
+ # @param [Integer] timeout to wait for user input
118
+ #
119
+ def sensitivity=(other)
120
+ write_attr :sensitivity, other
121
+ end
122
+
123
+ ##
124
+ # @return [Integer] timeout to wait for user input
125
+ #
126
+ def initial_timeout
127
+ read_attr :'initial-timeout', :to_i
128
+ end
129
+
130
+ ##
131
+ # @param [Integer] timeout to wait for user input
132
+ #
133
+ def initial_timeout=(other)
134
+ write_attr :'initial-timeout', other
135
+ end
136
+
137
+ ##
138
+ # @return [Integer] timeout to wait for user input
139
+ #
140
+ def inter_digit_timeout
141
+ read_attr :'inter-digit-timeout', :to_i
142
+ end
143
+
144
+ ##
145
+ # @param [Integer] timeout to wait for user input
146
+ #
147
+ def inter_digit_timeout=(other)
148
+ write_attr :'inter-digit-timeout', other
149
+ end
150
+
151
+ ##
152
+ # @return [Integer] timeout to wait for user input
153
+ #
154
+ def term_timeout
155
+ read_attr :'term-timeout', :to_i
156
+ end
157
+
158
+ ##
159
+ # @param [Integer] timeout to wait for user input
160
+ #
161
+ def term_timeout=(other)
162
+ write_attr :'term-timeout', other
163
+ end
164
+
165
+ ##
166
+ # @return [Integer] timeout to wait for user input
167
+ #
168
+ def complete_timeout
169
+ read_attr :'complete-timeout', :to_i
170
+ end
171
+
172
+ ##
173
+ # @param [Integer] timeout to wait for user input
174
+ #
175
+ def complete_timeout=(other)
176
+ write_attr :'complete-timeout', other
177
+ end
178
+
179
+ ##
180
+ # @return [Integer] timeout to wait for user input
181
+ #
182
+ def incomplete_timeout
183
+ read_attr :'incomplete-timeout', :to_i
184
+ end
185
+
186
+ ##
187
+ # @param [Integer] timeout to wait for user input
188
+ #
189
+ def incomplete_timeout=(other)
190
+ write_attr :'incomplete-timeout', other
191
+ end
192
+
193
+ ##
194
+ # @return [Choices] the choices available
195
+ #
196
+ def grammar
197
+ Grammar.new find_first('ns:grammar', :ns => self.class.registered_ns)
198
+ end
199
+
200
+ ##
201
+ # @param [Hash] choices
202
+ # @option choices [String] :content_type
203
+ # @option choices [String] :value the choices available
204
+ #
205
+ def grammar=(other)
206
+ remove_children :grammar
207
+ grammar = Grammar.new(other) unless other.is_a?(Grammar)
208
+ self << grammar
209
+ end
210
+
211
+ def inspect_attributes # :nodoc:
212
+ [:mode, :terminator, :max_digits, :recognizer, :initial_timeout, :inter_digit_timeout, :term_timeout, :complete_timeout, :incomplete_timeout, :sensitivity, :min_confidence, :choices] + super
213
+ end
214
+
215
+ class Grammar < RayoNode
216
+ ##
217
+ # @param [Hash] options
218
+ # @option options [String] :content_type
219
+ # @option options [String] :value the choices available
220
+ #
221
+ def self.new(options = {})
222
+ super(:grammar).tap do |new_node|
223
+ case options
224
+ when Nokogiri::XML::Node
225
+ new_node.inherit options
226
+ when Hash
227
+ new_node.content_type = options[:content_type]
228
+ new_node.value = options[:value]
229
+ end
230
+ end
231
+ end
232
+
233
+ ##
234
+ # @return [String] the choice content type
235
+ #
236
+ def content_type
237
+ read_attr 'content-type'
238
+ end
239
+
240
+ ##
241
+ # @param [String] content_type Defaults to the Voxeo Simple Grammar
242
+ #
243
+ def content_type=(content_type)
244
+ write_attr 'content-type', content_type || 'application/grammar+grxml'
245
+ end
246
+
247
+ ##
248
+ # @return [String] the choices available
249
+ def value
250
+ content
251
+ end
252
+
253
+ ##
254
+ # @param [String] value the choices available
255
+ def value=(value)
256
+ Nokogiri::XML::Builder.with(self) do |xml|
257
+ xml.cdata " #{value} "
258
+ end
259
+ end
260
+
261
+ # Compare two Choices objects by content type, and value
262
+ # @param [Header] o the Choices object to compare against
263
+ # @return [true, false]
264
+ def eql?(o, *fields)
265
+ super o, *(fields + [:content_type, :value])
266
+ end
267
+
268
+ def inspect_attributes # :nodoc:
269
+ [:content_type, :value] + super
270
+ end
271
+ end # Choices
272
+
273
+ class Complete
274
+ class Success < Event::Complete::Reason
275
+ register :success, :input_complete
276
+
277
+ ##
278
+ # @return [Symbol] the mode by which the question was answered. May be :speech or :dtmf
279
+ #
280
+ def mode
281
+ read_attr :mode, :to_sym
282
+ end
283
+
284
+ ##
285
+ # @return [Float] A measure of the confidence of the result, between 0-1
286
+ #
287
+ def confidence
288
+ read_attr :confidence, :to_f
289
+ end
290
+
291
+ ##
292
+ # @return [String] An intelligent interpretation of the meaning of the response.
293
+ #
294
+ def interpretation
295
+ find_first('//ns:interpretation', :ns => self.registered_ns).text
296
+ end
297
+
298
+ ##
299
+ # @return [String] The exact response gained
300
+ #
301
+ def utterance
302
+ find_first('//ns:utterance', :ns => self.registered_ns).text
303
+ end
304
+
305
+ def inspect_attributes # :nodoc:
306
+ [:mode, :confidence, :interpretation, :utterance] + super
307
+ end
308
+ end
309
+
310
+ class NoMatch < Event::Complete::Reason
311
+ register :nomatch, :input_complete
312
+ end
313
+
314
+ class NoInput < Event::Complete::Reason
315
+ register :noinput, :input_complete
316
+ end
317
+ end # Complete
318
+ end # Input
319
+ end # Command
320
+ end # Punchblock