dancroak-twilio 2.3.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +39 -0
  3. data/Rakefile +49 -0
  4. data/VERSION.yml +4 -0
  5. data/lib/twilio.rb +42 -0
  6. data/lib/twilio/account.rb +12 -0
  7. data/lib/twilio/call.rb +33 -0
  8. data/lib/twilio/connection.rb +24 -0
  9. data/lib/twilio/incoming_phone_number.rb +16 -0
  10. data/lib/twilio/local_phone_number.rb +21 -0
  11. data/lib/twilio/notification.rb +20 -0
  12. data/lib/twilio/outgoing_caller_id.rb +32 -0
  13. data/lib/twilio/recording.rb +24 -0
  14. data/lib/twilio/toll_free_phone_number.rb +21 -0
  15. data/lib/twilio/twilio_object.rb +16 -0
  16. data/lib/twilio/verb.rb +315 -0
  17. data/test/fixtures/xml/account.xml +11 -0
  18. data/test/fixtures/xml/account_renamed.xml +11 -0
  19. data/test/fixtures/xml/call.xml +18 -0
  20. data/test/fixtures/xml/call_new.xml +14 -0
  21. data/test/fixtures/xml/calls.xml +36 -0
  22. data/test/fixtures/xml/incoming_phone_number.xml +12 -0
  23. data/test/fixtures/xml/incoming_phone_numbers.xml +24 -0
  24. data/test/fixtures/xml/notification.xml +19 -0
  25. data/test/fixtures/xml/notifications.xml +32 -0
  26. data/test/fixtures/xml/outgoing_caller_id.xml +10 -0
  27. data/test/fixtures/xml/outgoing_caller_id_new.xml +7 -0
  28. data/test/fixtures/xml/outgoing_caller_ids.xml +20 -0
  29. data/test/fixtures/xml/recording.xml +10 -0
  30. data/test/fixtures/xml/recordings.xml +20 -0
  31. data/test/fixtures/xml/transcription.xml +13 -0
  32. data/test/fixtures/xml/transcriptions.xml +26 -0
  33. data/test/fixtures/yml/verb_responses.yml +119 -0
  34. data/test/test_helper.rb +29 -0
  35. data/test/twilio/account_test.rb +35 -0
  36. data/test/twilio/call_test.rb +72 -0
  37. data/test/twilio/connection_test.rb +26 -0
  38. data/test/twilio/incoming_phone_number_test.rb +35 -0
  39. data/test/twilio/local_phone_number_test.rb +35 -0
  40. data/test/twilio/notification_test.rb +40 -0
  41. data/test/twilio/outgoing_caller_id_test.rb +51 -0
  42. data/test/twilio/recording_test.rb +53 -0
  43. data/test/twilio/toll_free_phone_number_test.rb +35 -0
  44. data/test/twilio/verb_test.rb +204 -0
  45. metadata +127 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Phil Misiowiec, Webficient LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,39 @@
1
+ = Twilio Gem
2
+
3
+ The Twilio gem provides two major pieces of functionality: (1) a Ruby wrapper for the Twilio REST API and (2) response handlers based on the Twilio Markup XML (TwiML).
4
+
5
+ See http://www.twilio.com/docs/index for Twilio's API documentation.
6
+
7
+ For an overview of the Twilio Gem and a sample use case, check out http://www.webficient.com/2009/06/22/hello-this-is-your-rails-app-calling-you.
8
+
9
+ == Calling the Twilio REST API
10
+
11
+ First set your credentials by calling the connect method:
12
+
13
+ Twilio.connect('my_twilio_sid', 'my_auth_token')
14
+
15
+ Now call any of the Twilio classes:
16
+
17
+ Twilio::Call.make('1234567890', '9876543210', 'http://mysite.com/connected_call')
18
+ Twilio::Recording.list
19
+
20
+ == Responding to Twilio
21
+
22
+ When Twilio calls your application URL, your response must use the Twilio Markup XML (http://www.twilio.com/docs/api_reference/TwiML/). The Twilio gem makes this very easy
23
+ by providing a Twilio Verb class.
24
+
25
+ For example, in a Ruby on Rails application, you could do the following inside a controller class:
26
+
27
+ Twilio::Verb.dial('415-123-4567')
28
+
29
+ and you can nest multiple verbs inside a block:
30
+
31
+ verb = Twilio::Verb.new { |v|
32
+ v.say("The time is #{Time.now}")
33
+ v.hangup
34
+ }
35
+ verb.response
36
+
37
+ == Copyright
38
+
39
+ Copyright (c) 2009 Phil Misiowiec, Webficient LLC. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,49 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "twilio"
8
+ gem.summary = %Q{Twilio API Client}
9
+ gem.email = "github@webficient.com"
10
+ gem.homepage = "http://github.com/webficient/twilio"
11
+ gem.authors = ["Phil Misiowiec"]
12
+ gem.add_dependency 'builder'
13
+ gem.add_dependency 'httparty'
14
+ end
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+ require 'rake/rdoctask'
20
+ Rake::RDocTask.new do |rdoc|
21
+ rdoc.rdoc_dir = 'rdoc'
22
+ rdoc.title = 'twilio'
23
+ rdoc.options << '--line-numbers' << '--inline-source'
24
+ rdoc.rdoc_files.include('README*')
25
+ rdoc.rdoc_files.include('lib/**/*.rb')
26
+ end
27
+
28
+ require 'rake/testtask'
29
+ Rake::TestTask.new(:test) do |test|
30
+ test.libs << 'lib' << 'test'
31
+ test.pattern = 'test/**/*_test.rb'
32
+ test.verbose = false
33
+ end
34
+
35
+ begin
36
+ require 'rcov/rcovtask'
37
+ Rcov::RcovTask.new do |test|
38
+ test.libs << 'test'
39
+ test.pattern = 'test/**/*_test.rb'
40
+ test.verbose = true
41
+ end
42
+ rescue LoadError
43
+ task :rcov do
44
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
+ end
46
+ end
47
+
48
+
49
+ task :default => :test
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 0
3
+ :major: 2
4
+ :minor: 3
data/lib/twilio.rb ADDED
@@ -0,0 +1,42 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ #--
4
+ # Copyright (c) 2009 Phil Misiowiec, phil@webficient.com
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ require 'rubygems'
27
+ gem 'httparty', '>= 0.4.3'
28
+ require 'httparty'
29
+ gem 'builder', '>= 2.1.2'
30
+ require 'builder'
31
+
32
+ require 'twilio/twilio_object'
33
+ require 'twilio/account'
34
+ require 'twilio/call'
35
+ require 'twilio/connection'
36
+ require 'twilio/incoming_phone_number'
37
+ require 'twilio/local_phone_number'
38
+ require 'twilio/notification'
39
+ require 'twilio/outgoing_caller_id'
40
+ require 'twilio/recording'
41
+ require 'twilio/toll_free_phone_number'
42
+ require 'twilio/verb'
@@ -0,0 +1,12 @@
1
+ module Twilio
2
+ # The Account resource represents your Twilio Account.
3
+ class Account < TwilioObject
4
+ def get
5
+ Twilio.get('')
6
+ end
7
+
8
+ def update_name(name)
9
+ Twilio.put('', :body => {:FriendlyName => name})
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ module Twilio
2
+ # A Call represenents a connection between a telephone and Twilio. This may be
3
+ # inbound, when a person calls your application, or outbound when your application
4
+ # initiates the call, either via the REST API, or during a call via the Dial Verb.
5
+ class Call < TwilioObject
6
+ # Example:
7
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
8
+ # Twilio::Call.make(CALLER_ID, user_number, 'http://myapp.com/twilio_response_handler')
9
+ def make(caller, called, url, optional = {})
10
+ Twilio.post("/Calls", :body => {:Caller => caller, :Called => called, :Url => url}.merge(optional))
11
+ end
12
+
13
+ def list(optional = {})
14
+ Twilio.get("/Calls", :query => optional)
15
+ end
16
+
17
+ def get(call_sid)
18
+ Twilio.get("/Calls/#{call_sid}")
19
+ end
20
+
21
+ def segments(call_sid, call_segment_sid = nil)
22
+ Twilio.get("/Calls/#{call_sid}/Segments#{ '/' + call_segment_sid if call_segment_sid }")
23
+ end
24
+
25
+ def recordings(call_sid)
26
+ Twilio.get("/Calls/#{call_sid}/Recordings")
27
+ end
28
+
29
+ def notifications(call_sid)
30
+ Twilio.get("/Calls/#{call_sid}/Notifications")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,24 @@
1
+ module Twilio
2
+ include HTTParty
3
+ TWILIO_URL = "https://api.twilio.com/2008-08-01/Accounts"
4
+
5
+ # The connect method caches your Twilio account id and authentication token
6
+ # Example:
7
+ # Twilio.connect('AC309475e5fede1b49e100272a8640f438', '3a2630a909aadbf60266234756fb15a0')
8
+ def self.connect(account_sid, auth_token)
9
+ self.base_uri "#{TWILIO_URL}/#{account_sid}"
10
+ self.basic_auth account_sid, auth_token
11
+ end
12
+
13
+ # DEPRECATED - use Twilio.connect
14
+ class Connection
15
+ include HTTParty
16
+ TWILIO_URL = "https://api.twilio.com/2008-08-01/Accounts"
17
+
18
+ def initialize(account_sid, auth_token)
19
+ self.class.base_uri "#{TWILIO_URL}/#{account_sid}"
20
+ self.class.basic_auth account_sid, auth_token
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,16 @@
1
+ module Twilio
2
+ # An IncomingPhoneNumber resource represents a phone number given to you by
3
+ # Twilio to receive incoming phone calls.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::IncomingPhoneNumber.list
7
+ class IncomingPhoneNumber < TwilioObject
8
+ def list(optional = {})
9
+ Twilio.get("/IncomingPhoneNumbers", :query => optional)
10
+ end
11
+
12
+ def get(incoming_sid)
13
+ Twilio.get("/IncomingPhoneNumbers/#{incoming_sid}")
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,21 @@
1
+ module Twilio
2
+ # This sub-resource represents only Local phone numbers, or in other words, not toll-free numbers.
3
+ # Also allows you to request a new local phone number be added to your account.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::LocalPhoneNumber.list
7
+ class LocalPhoneNumber < TwilioObject
8
+ def create(url, area_code = nil, method = 'POST', friendly_name = nil)
9
+ Twilio.post("/IncomingPhoneNumbers/Local", :body => {
10
+ :Url => url,
11
+ :AreaCode => area_code,
12
+ :Method => method,
13
+ :FriendlyName => friendly_name
14
+ })
15
+ end
16
+
17
+ def list
18
+ Twilio.get("/IncomingPhoneNumbers/Local")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ module Twilio
2
+ # A Notification represenents a log entry made by Twilio in the course of handling
3
+ # your calls or using the REST API.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::Notification.list
7
+ class Notification < TwilioObject
8
+ def list(optional = {})
9
+ Twilio.get('/Notifications', :query => optional)
10
+ end
11
+
12
+ def get(notification_sid)
13
+ Twilio.get("/Notifications/#{notification_sid}")
14
+ end
15
+
16
+ def delete(notification_sid)
17
+ Twilio.delete("/Notifications/#{notification_sid}")
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,32 @@
1
+ module Twilio
2
+ # An OutgoingCallerId resource represents an outgoing Caller ID that you have
3
+ # registered with Twilio for use when making an outgoing call or using the Dial Verb.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::OutgoingCallerId.list
7
+ class OutgoingCallerId < TwilioObject
8
+ def create(phone_number, friendly_name = phone_number, call_delay = 0)
9
+ Twilio.post("/OutgoingCallerIds", :body => {
10
+ :PhoneNumber => phone_number,
11
+ :FriendlyName => friendly_name,
12
+ :CallDelay => call_delay
13
+ })
14
+ end
15
+
16
+ def list(optional = {})
17
+ Twilio.get("/OutgoingCallerIds", :query => optional)
18
+ end
19
+
20
+ def get(callerid_sid)
21
+ Twilio.get("/OutgoingCallerIds/#{callerid_sid}")
22
+ end
23
+
24
+ def update_name(callerid_sid, name)
25
+ Twilio.put("/OutgoingCallerIds/#{callerid_sid}", :body => {:FriendlyName => name})
26
+ end
27
+
28
+ def delete(callerid_sid)
29
+ Twilio.delete("/OutgoingCallerIds/#{callerid_sid}")
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,24 @@
1
+ module Twilio
2
+ # Recordings are generated when you use the Record Verb. Those recordings are
3
+ # hosted on Twilio's REST API for you to access.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::Recording.list
7
+ class Recording < TwilioObject
8
+ def list(optional = {})
9
+ Twilio.get("/Recordings", :query => optional)
10
+ end
11
+
12
+ def get(recording_sid)
13
+ Twilio.get("/Recordings/#{recording_sid}")
14
+ end
15
+
16
+ def delete(recording_sid)
17
+ Twilio.delete("/Recordings/#{recording_sid}")
18
+ end
19
+
20
+ def transcriptions(recording_sid, transcription_sid = nil)
21
+ Twilio.get("/Recordings/#{recording_sid}/Transcriptions#{ '/' + transcription_sid if transcription_sid }")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ module Twilio
2
+ # This sub-resource represents only Toll Free phone numbers, or in other words, not local numbers.
3
+ # Also allows you to request a new toll free phone number be added to your account.
4
+ # Example:
5
+ # Twilio.connect('my_twilio_sid', 'my_auth_token')
6
+ # Twilio::TollFreePhoneNumber.list
7
+ class TollFreePhoneNumber < TwilioObject
8
+ def create(url, area_code = nil, method = 'POST', friendly_name = nil)
9
+ Twilio.post("/IncomingPhoneNumbers/TollFree", :body => {
10
+ :Url => url,
11
+ :AreaCode => area_code,
12
+ :Method => method,
13
+ :FriendlyName => friendly_name
14
+ })
15
+ end
16
+
17
+ def list
18
+ Twilio.get("/IncomingPhoneNumbers/TollFree")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,16 @@
1
+ module Twilio
2
+ class TwilioObject #:nodoc: all
3
+ attr_reader :connection
4
+
5
+ def initialize(connection = nil)
6
+ @connection = connection
7
+ end
8
+
9
+ class << self
10
+ def method_missing(method_id, *args) #:nodoc:
11
+ o = self.new
12
+ o.send(method_id, *args)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,315 @@
1
+ module Twilio
2
+ # Twilio Verbs enable your application to respond to Twilio requests (to your app) with XML responses.
3
+ # There are 5 primary verbs (say, play, gather, record, dial) and 3 secondary (hangup, pause, redirect).
4
+ # Verbs can be chained and, in some cases, nested.
5
+ #
6
+ # If your response consists of a single verb, you can call a Verb class method:
7
+ #
8
+ # Twilio::Verb.say('The time is 9:35 PM.')
9
+ #
10
+ # But if you need to chain several verbs together, just wrap them in an instance block and call the 'response' attribute:
11
+ #
12
+ # verb = Twilio::Verb.new { |v|
13
+ # v.dial('415-123-4567')
14
+ # v.redirect('http://www.foo.com/nextInstructions')
15
+ # }
16
+ # verb.response
17
+ class Verb
18
+
19
+ attr_reader :response
20
+
21
+ class << self
22
+ def method_missing(method_id, *args) #:nodoc:
23
+ v = Verb.new
24
+ v.send(method_id, *args)
25
+ end
26
+ end
27
+
28
+ def initialize(&block)
29
+ @xml = Builder::XmlMarkup.new
30
+ @xml.instruct!
31
+
32
+ if block_given?
33
+ @chain = true
34
+ @response = @xml.Response { block.call(self) }
35
+ end
36
+ end
37
+
38
+ # The Say verb converts text to speech that is read back to the caller.
39
+ # Say is useful for dynamic text that is difficult to prerecord.
40
+ #
41
+ # Examples:
42
+ # Twilio::Verb.say('The time is 9:35 PM.')
43
+ # Twilio::Verb.say('The time is 9:35 PM.', :loop => 3)
44
+ #
45
+ # With numbers, 12345 will be spoken as "twelve thousand three hundred forty five" while
46
+ # 1 2 3 4 5 will be spoken as "one two three four five."
47
+ #
48
+ # Twilio::Verb.say('Your PIN is 1234', :loop => 4)
49
+ # Twilio::Verb.say('Your PIN is 1 2 3 4', :loop => 4)
50
+ #
51
+ # If you need a longer pause between each loop, instead of explicitly calling the Pause
52
+ # verb within a block, you can set the convenient pause option:
53
+ #
54
+ # Twilio::Verb.say('Your PIN is 1 2 3 4', :loop => 4, :pause => true)
55
+ #
56
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/say) are passed in as a hash:
57
+ #
58
+ # Twilio::Verb.say('The time is 9:35 PM.', :voice => 'woman')
59
+ # Twilio::Verb.say('The time is 9:35 PM.', {:voice => 'woman', :language => 'es'})
60
+ def say(*args)
61
+ options = {:voice => 'man', :language => 'en', :loop => 1}
62
+ args.each do |arg|
63
+ case arg
64
+ when String
65
+ options[:text_to_speak] = arg
66
+ when Hash
67
+ options.merge!(arg)
68
+ else
69
+ raise ArgumentError, 'say expects String or Hash argument'
70
+ end
71
+ end
72
+
73
+ output {
74
+ if options[:pause]
75
+ loop_with_pause(options[:loop], @xml) do
76
+ @xml.Say(options[:text_to_speak], :voice => options[:voice], :language => options[:language])
77
+ end
78
+ else
79
+ @xml.Say(options[:text_to_speak], :voice => options[:voice], :language => options[:language], :loop => options[:loop])
80
+ end
81
+ }
82
+ end
83
+
84
+ # The Play verb plays an audio URL back to the caller.
85
+ # Examples:
86
+ # Twilio::Verb.play('http://foo.com/cowbell.mp3')
87
+ # Twilio::Verb.play('http://foo.com/cowbell.mp3', :loop => 3)
88
+ #
89
+ # If you need a longer pause between each loop, instead of explicitly calling the Pause
90
+ # verb within a block, you can set the convenient pause option:
91
+ #
92
+ # Twilio::Verb.play('http://foo.com/cowbell.mp3', :loop => 3, :pause => true)
93
+ #
94
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/play) are passed in as a hash,
95
+ # but only 'loop' is currently supported.
96
+ def play(*args)
97
+ options = {:loop => 1}
98
+ args.each do |arg|
99
+ case arg
100
+ when String
101
+ options[:audio_url] = arg
102
+ when Hash
103
+ options.merge!(arg)
104
+ else
105
+ raise ArgumentError, 'play expects String or Hash argument'
106
+ end
107
+ end
108
+
109
+ output {
110
+ if options[:pause]
111
+ loop_with_pause(options[:loop], @xml) do
112
+ @xml.Play(options[:audio_url])
113
+ end
114
+ else
115
+ @xml.Play(options[:audio_url], :loop => options[:loop])
116
+ end
117
+ }
118
+ end
119
+
120
+ # The Gather verb collects digits entered by a caller into their telephone keypad.
121
+ # When the caller is done entering data, Twilio submits that data to a provided URL,
122
+ # as either a HTTP GET or POST request, just like a web browser submits data from an HTML form.
123
+ #
124
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/gather) are passed in as a hash
125
+ #
126
+ # Examples:
127
+ # Twilio::Verb.gather
128
+ # Twilio::Verb.gather(:action => 'http://foobar.com')
129
+ # Twilio::Verb.gather(:finishOnKey => '*')
130
+ # Twilio::Verb.gather(:action => 'http://foobar.com', :finishOnKey => '*')
131
+ #
132
+ # Gather also lets you nest the Play, Say, and Pause verbs:
133
+ #
134
+ # verb = Twilio::Verb.new { |v|
135
+ # v.gather(:action => '/process_gather', :method => 'GET) {
136
+ # v.say('Please enter your account number followed by the pound sign')
137
+ # }
138
+ # v.say("We didn't receive any input. Goodbye!")
139
+ # }
140
+ # verb.response # represents the final xml output
141
+ def gather(*args, &block)
142
+ options = args.shift || {}
143
+ output {
144
+ if block_given?
145
+ @xml.Gather(options) { block.call }
146
+ else
147
+ @xml.Gather(options)
148
+ end
149
+ }
150
+ end
151
+
152
+ #play, say, pause
153
+
154
+ # The Record verb records the caller's voice and returns a URL that links to a file
155
+ # containing the audio recording.
156
+ #
157
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/record) are passed in as a hash
158
+ #
159
+ # Examples:
160
+ # Twilio::Verb.record
161
+ # Twilio::Verb.record(:action => 'http://foobar.com')
162
+ # Twilio::Verb.record(:finishOnKey => '*')
163
+ # Twilio::Verb.record(:transcribe => true, :transcribeCallback => '/handle_transcribe')
164
+ def record(*args)
165
+ options = args.shift
166
+ output { @xml.Record(options) }
167
+ end
168
+
169
+ # The Dial verb connects the current caller to an another phone. If the called party picks up,
170
+ # the two parties are connected and can communicate until one hangs up. If the called party does
171
+ # not pick up, if a busy signal is received, or the number doesn't exist, the dial verb will finish.
172
+ #
173
+ # If an action verb is provided, Twilio will submit the outcome of the call attempt to the action URL.
174
+ # If no action is provided, Dial will fall through to the next verb in the document.
175
+ #
176
+ # Note: this is different than the behavior of Record and Gather. Dial does not submit back to the
177
+ # current document URL if no action is provided.
178
+ #
179
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/dial) are passed in as a hash
180
+ #
181
+ # Examples:
182
+ # Twilio::Verb.dial('415-123-4567')
183
+ # Twilio::Verb.dial('415-123-4567', :action => 'http://foobar.com')
184
+ # Twilio::Verb.dial('415-123-4567', {:timeout => 10, :callerId => '858-987-6543'})
185
+ #
186
+ # Twilio also supports an alternate form in which a Number object is nested inside Dial:
187
+ #
188
+ # verb = Twilio::Verb.new { |v|
189
+ # v.dial {
190
+ # v.number('415-123-4567')
191
+ # v.number('415-123-4568')
192
+ # v.number('415-123-4569')
193
+ # }
194
+ # }
195
+ # verb.response # represents the final xml output
196
+ def dial(*args, &block)
197
+ number_to_dial = ''
198
+ options = {}
199
+ args.each do |arg|
200
+ case arg
201
+ when String
202
+ number_to_dial = arg
203
+ when Hash
204
+ options.merge!(arg)
205
+ else
206
+ raise ArgumentError, 'dial expects String or Hash argument'
207
+ end
208
+ end
209
+
210
+ output {
211
+ if block_given?
212
+ @xml.Dial(options) { block.call }
213
+ else
214
+ @xml.Dial(number_to_dial, options)
215
+ end
216
+ }
217
+ end
218
+
219
+ # The Pause (secondary) verb waits silently for a number of seconds.
220
+ # It is normally chained with other verbs.
221
+ #
222
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/pause) are passed in as a hash
223
+ #
224
+ # Examples:
225
+ # verb = Twilio::Verb.new { |v|
226
+ # v.say('greetings')
227
+ # v.pause(:length => 2)
228
+ # v.say('have a nice day')
229
+ # }
230
+ # verb.response
231
+ def pause(*args)
232
+ options = args.shift
233
+ output { @xml.Pause(options) }
234
+ end
235
+
236
+ # The Redirect (secondary) verb transfers control to a different URL.
237
+ # It is normally chained with other verbs.
238
+ #
239
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/redirect) are passed in as a hash
240
+ #
241
+ # Examples:
242
+ # verb = Twilio::Verb.new { |v|
243
+ # v.dial('415-123-4567')
244
+ # v.redirect('http://www.foo.com/nextInstructions')
245
+ # }
246
+ # verb.response
247
+ def redirect(*args)
248
+ redirect_to_url = ''
249
+ options = {}
250
+ args.each do |arg|
251
+ case arg
252
+ when String
253
+ redirect_to_url = arg
254
+ when Hash
255
+ options.merge!(arg)
256
+ else
257
+ raise ArgumentError, 'dial expects String or Hash argument'
258
+ end
259
+ end
260
+
261
+ output { @xml.Redirect(redirect_to_url, options) }
262
+ end
263
+
264
+ # The Hangup (secondary) verb ends the call.
265
+ #
266
+ # Examples:
267
+ # If your response is only a hangup:
268
+ #
269
+ # Twilio::Verb.hangup
270
+ #
271
+ # If your response is chained:
272
+ #
273
+ # verb = Twilio::Verb.new { |v|
274
+ # v.say("The time is #{Time.now}")
275
+ # v.hangup
276
+ # }
277
+ # verb.response
278
+ def hangup
279
+ output { @xml.Hangup }
280
+ end
281
+
282
+ # The Number element specifies a phone number. The number element has two optional attributes: sendDigits and url.
283
+ # Number elements can only be nested in Dial verbs
284
+ def number(*args)
285
+ number_to_dial = ''
286
+ options = {}
287
+ args.each do |arg|
288
+ case arg
289
+ when String
290
+ number_to_dial = arg
291
+ when Hash
292
+ options.merge!(arg)
293
+ else
294
+ raise ArgumentError, 'dial expects String or Hash argument'
295
+ end
296
+ end
297
+
298
+ output { @xml.Number(number_to_dial, options) }
299
+ end
300
+
301
+ private
302
+
303
+ def output
304
+ @chain ? yield : @xml.Response { yield }
305
+ end
306
+
307
+ def loop_with_pause(loop_count, xml, &verb_action)
308
+ last_iteration = loop_count-1
309
+ loop_count.times do |i|
310
+ yield verb_action
311
+ xml.Pause unless i == last_iteration
312
+ end
313
+ end
314
+ end
315
+ end