twilio 1.4.0

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 +24 -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 +34 -0
  8. data/lib/twilio/connection.rb +17 -0
  9. data/lib/twilio/incoming_phone_number.rb +13 -0
  10. data/lib/twilio/local_phone_number.rb +18 -0
  11. data/lib/twilio/notification.rb +17 -0
  12. data/lib/twilio/outgoing_caller_id.rb +29 -0
  13. data/lib/twilio/recording.rb +21 -0
  14. data/lib/twilio/toll_free_phone_number.rb +18 -0
  15. data/lib/twilio/twilio_object.rb +11 -0
  16. data/lib/twilio/verb.rb +186 -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 +89 -0
  34. data/test/test_helper.rb +29 -0
  35. data/test/twilio/account_test.rb +23 -0
  36. data/test/twilio/call_test.rb +59 -0
  37. data/test/twilio/connection_test.rb +15 -0
  38. data/test/twilio/incoming_phone_number_test.rb +22 -0
  39. data/test/twilio/local_phone_number_test.rb +23 -0
  40. data/test/twilio/notification_test.rb +28 -0
  41. data/test/twilio/outgoing_caller_id_test.rb +42 -0
  42. data/test/twilio/recording_test.rb +42 -0
  43. data/test/twilio/toll_free_phone_number_test.rb +23 -0
  44. data/test/twilio/verb_test.rb +126 -0
  45. metadata +126 -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,24 @@
1
+ = twilio
2
+
3
+ This wrapper defines each of the interfaces currently supported by Twilio REST API.
4
+
5
+ Sample Usage:
6
+
7
+ First create a connection object:
8
+
9
+ c = Twilio::Connection.new('my_twilio_sid', 'my_auth_token')
10
+
11
+ Now instantiate other objects by passing in the connection:
12
+
13
+ a = Twilio::Account.new(c)
14
+ a.update_name('sparky')
15
+
16
+ call = Twilio::Call.new(c)
17
+ call.make('1234567890', '9876543210', 'http://mysite.com/connected_call')
18
+
19
+ recording = Twilio::Recording.new(c)
20
+ recording.list
21
+
22
+ == Copyright
23
+
24
+ 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
+ :minor: 4
3
+ :patch: 0
4
+ :major: 1
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
+ self.connection.class.get('')
6
+ end
7
+
8
+ def update_name(name)
9
+ self.connection.class.put('', :body => {:FriendlyName => name})
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
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
+ # c = Twilio::Connection.new('my_twilio_sid', 'my_auth_token')
8
+ # call = Twilio::Call.new(c)
9
+ # response = call.make(CALLER_ID, user_number, 'http://myapp.com/twilio_response_handler')
10
+ def make(caller, called, url, optional = {})
11
+ self.connection.class.post("/Calls", :body => {:Caller => caller, :Called => called, :Url => url}.merge(optional))
12
+ end
13
+
14
+ def list(optional = {})
15
+ self.connection.class.get("/Calls", :query => optional)
16
+ end
17
+
18
+ def get(call_sid)
19
+ self.connection.class.get("/Calls/#{call_sid}")
20
+ end
21
+
22
+ def segments(call_sid, call_segment_sid = nil)
23
+ self.connection.class.get("/Calls/#{call_sid}/Segments#{ '/' + call_segment_sid if call_segment_sid }")
24
+ end
25
+
26
+ def recordings(call_sid)
27
+ self.connection.class.get("/Calls/#{call_sid}/Recordings")
28
+ end
29
+
30
+ def notifications(call_sid)
31
+ self.connection.class.get("/Calls/#{call_sid}/Notifications")
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,17 @@
1
+ module Twilio
2
+ # The Connection class caches the Twilio API base path and authentication credentials.
3
+ # It is passed into the constructor of other TwilioObject's, avoiding the need to
4
+ # explicitly set credentials with each API call.
5
+ #
6
+ # Example:
7
+ # c = Twilio::Connection.new('my_twilio_sid', 'my_auth_token')
8
+ class Connection
9
+ include HTTParty
10
+ TWILIO_URL = "https://api.twilio.com/2008-08-01/Accounts"
11
+
12
+ def initialize(account_sid, auth_token)
13
+ self.class.base_uri "#{TWILIO_URL}/#{account_sid}"
14
+ self.class.basic_auth account_sid, auth_token
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ module Twilio
2
+ # An IncomingPhoneNumber resource represents a phone number given to you by
3
+ # Twilio to receive incoming phone calls.
4
+ class IncomingPhoneNumber < TwilioObject
5
+ def list(optional = {})
6
+ self.connection.class.get("/IncomingPhoneNumbers", :query => optional)
7
+ end
8
+
9
+ def get(incoming_sid)
10
+ self.connection.class.get("/IncomingPhoneNumbers/#{incoming_sid}")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
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
+ class LocalPhoneNumber < TwilioObject
5
+ def create(url, area_code = nil, method = 'POST', friendly_name = nil)
6
+ self.connection.class.post("/IncomingPhoneNumbers/Local", :body => {
7
+ :Url => url,
8
+ :AreaCode => area_code,
9
+ :Method => method,
10
+ :FriendlyName => friendly_name
11
+ })
12
+ end
13
+
14
+ def list
15
+ self.connection.class.get("/IncomingPhoneNumbers/Local")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
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
+ class Notification < TwilioObject
5
+ def list(optional = {})
6
+ self.connection.class.get('/Notifications', :query => optional)
7
+ end
8
+
9
+ def get(notification_sid)
10
+ self.connection.class.get("/Notifications/#{notification_sid}")
11
+ end
12
+
13
+ def delete(notification_sid)
14
+ self.connection.class.delete("/Notifications/#{notification_sid}")
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,29 @@
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
+ class OutgoingCallerId < TwilioObject
5
+ def create(phone_number, friendly_name = phone_number, call_delay = 0)
6
+ self.connection.class.post("/OutgoingCallerIds", :body => {
7
+ :PhoneNumber => phone_number,
8
+ :FriendlyName => friendly_name,
9
+ :CallDelay => call_delay
10
+ })
11
+ end
12
+
13
+ def list(optional = {})
14
+ self.connection.class.get("/OutgoingCallerIds", :query => optional)
15
+ end
16
+
17
+ def get(callerid_sid)
18
+ self.connection.class.get("/OutgoingCallerIds/#{callerid_sid}")
19
+ end
20
+
21
+ def update_name(callerid_sid, name)
22
+ self.connection.class.put("/OutgoingCallerIds/#{callerid_sid}", :body => {:FriendlyName => name})
23
+ end
24
+
25
+ def delete(callerid_sid)
26
+ self.connection.class.delete("/OutgoingCallerIds/#{callerid_sid}")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
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
+ class Recording < TwilioObject
5
+ def list(optional = {})
6
+ self.connection.class.get("/Recordings", :query => optional)
7
+ end
8
+
9
+ def get(recording_sid)
10
+ self.connection.class.get("/Recordings/#{recording_sid}")
11
+ end
12
+
13
+ def delete(recording_sid)
14
+ self.connection.class.delete("/Recordings/#{recording_sid}")
15
+ end
16
+
17
+ def transcriptions(recording_sid, transcription_sid = nil)
18
+ self.connection.class.get("/Recordings/#{recording_sid}/Transcriptions#{ '/' + transcription_sid if transcription_sid }")
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,18 @@
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
+ class TollFreePhoneNumber < TwilioObject
5
+ def create(url, area_code = nil, method = 'POST', friendly_name = nil)
6
+ self.connection.class.post("/IncomingPhoneNumbers/TollFree", :body => {
7
+ :Url => url,
8
+ :AreaCode => area_code,
9
+ :Method => method,
10
+ :FriendlyName => friendly_name
11
+ })
12
+ end
13
+
14
+ def list
15
+ self.connection.class.get("/IncomingPhoneNumbers/TollFree")
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ module Twilio
2
+ class TwilioObject #:nodoc: all
3
+ include HTTParty
4
+
5
+ attr_reader :connection
6
+
7
+ def initialize(connection)
8
+ @connection = connection
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,186 @@
1
+ module Twilio
2
+ # Twilio Verbs enable your application to respond to Twilio requests (to your app) with XML responses.
3
+ #
4
+ # In addition to the 5 verbs supported by Twilio (say, play, gather, record, dial),
5
+ # this class also implements dynamic interfaces that allow you to combine useful
6
+ # operations into a single call. See below methods for examples.
7
+ class Verb
8
+ class << self
9
+ # The Say verb converts text to speech that is read back to the caller.
10
+ # Say is useful for dynamic text that is difficult to prerecord.
11
+ #
12
+ # Examples:
13
+ # Twilio::Verb.say('The time is 9:35 PM.')
14
+ # Twilio::Verb.say_3_times('The time is 9:35 PM.')
15
+ #
16
+ # With numbers, 12345 will be spoken as "twelve thousand three hundred forty five" while
17
+ # 1 2 3 4 5 will be spoken as "one two three four five."
18
+ #
19
+ # Twilio::Verb.say_4_times('Your PIN is 1234')
20
+ # Twilio::Verb.say_4_times('Your PIN is 1 2 3 4')
21
+ #
22
+ # If you need a longer pause between each loop, use the pause form:
23
+ #
24
+ # Twilio::Verb.say_4_times_with_pause('Your PIN is 1 2 3 4')
25
+ #
26
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/say) are passed in as a hash:
27
+ #
28
+ # Twilio::Verb.say('The time is 9:35 PM.', :voice => 'woman')
29
+ # Twilio::Verb.say('The time is 9:35 PM.', {:voice => 'woman', :language => 'es'})
30
+ def say(*args, &block)
31
+ options = {:voice => 'man', :language => 'en', :loop => 1}
32
+ args.each do |arg|
33
+ case arg
34
+ when String
35
+ options[:text_to_speak] = arg
36
+ when Hash
37
+ options.merge!(arg)
38
+ else
39
+ raise ArgumentError, 'say expects String or Hash argument'
40
+ end
41
+ end
42
+
43
+ xml = Builder::XmlMarkup.new
44
+ xml.instruct!
45
+ xml.Response {
46
+ if options[:pause]
47
+ loop_with_pause(options[:loop], xml) do
48
+ xml.Say(options[:text_to_speak], :voice => options[:voice], :language => options[:language])
49
+ end
50
+ else
51
+ xml.Say(options[:text_to_speak], :voice => options[:voice], :language => options[:language], :loop => options[:loop])
52
+ end
53
+ }
54
+ end
55
+
56
+ # The Play verb plays an audio URL back to the caller.
57
+ # Examples:
58
+ # Twilio::Verb.play('http://foo.com/cowbell.mp3')
59
+ # Twilio::Verb.play_3_times('http://foo.com/cowbell.mp3')
60
+ #
61
+ # If you need a longer pause between each loop, use the pause form:
62
+ #
63
+ # Twilio::Verb.play_3_times_with_pause('http://foo.com/cowbell.mp3')
64
+ #
65
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/play) are passed in as a hash,
66
+ # however, since the Play verb only supports 'loop' as the current option, you can instead use the
67
+ # above form to keep things concise.
68
+ def play(*args, &block)
69
+ options = {:loop => 1}
70
+ args.each do |arg|
71
+ case arg
72
+ when String
73
+ options[:audio_url] = arg
74
+ when Hash
75
+ options.merge!(arg)
76
+ else
77
+ raise ArgumentError, 'play expects String or Hash argument'
78
+ end
79
+ end
80
+
81
+ xml = Builder::XmlMarkup.new
82
+ xml.instruct!
83
+ xml.Response {
84
+ if options[:pause]
85
+ loop_with_pause(options[:loop], xml) do
86
+ xml.Play(options[:audio_url])
87
+ end
88
+ else
89
+ xml.Play(options[:audio_url], :loop => options[:loop])
90
+ end
91
+ }
92
+ end
93
+
94
+ # The Gather verb collects digits entered by a caller into their telephone keypad.
95
+ # When the caller is done entering data, Twilio submits that data to a provided URL,
96
+ # as either a HTTP GET or POST request, just like a web browser submits data from an HTML form.
97
+ #
98
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/gather) are passed in as a hash
99
+ #
100
+ # Examples:
101
+ # Twilio::Verb.gather
102
+ # Twilio::Verb.gather(:action => 'http://foobar.com')
103
+ # Twilio::Verb.gather(:finishOnKey => '*')
104
+ # Twilio::Verb.gather(:action => 'http://foobar.com', :finishOnKey => '*')
105
+ def gather(*args, &block)
106
+ options = args.shift
107
+ xml = Builder::XmlMarkup.new
108
+ xml.instruct!
109
+ xml.Response { xml.Gather(options) }
110
+ end
111
+
112
+ # The Record verb records the caller's voice and returns a URL that links to a file
113
+ # containing the audio recording.
114
+ #
115
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/record) are passed in as a hash
116
+ #
117
+ # Examples:
118
+ # Twilio::Verb.record
119
+ # Twilio::Verb.record(:action => 'http://foobar.com')
120
+ # Twilio::Verb.record(:finishOnKey => '*')
121
+ # Twilio::Verb.record(:transcribe => true, :transcribeCallback => '/handle_transcribe')
122
+ def record(*args, &block)
123
+ options = args.shift
124
+ xml = Builder::XmlMarkup.new
125
+ xml.instruct!
126
+ xml.Response { xml.Record(options) }
127
+ end
128
+
129
+ # The Dial verb connects the current caller to an another phone. If the called party picks up,
130
+ # the two parties are connected and can communicate until one hangs up. If the called party does
131
+ # not pick up, if a busy signal is received, or the number doesn't exist, the dial verb will finish.
132
+ #
133
+ # If an action verb is provided, Twilio will submit the outcome of the call attempt to the action URL.
134
+ # If no action is provided, Dial will fall through to the next verb in the document.
135
+ #
136
+ # Note: this is different than the behavior of Record and Gather. Dial does not submit back to the
137
+ # current document URL if no action is provided.
138
+ #
139
+ # Options (see http://www.twilio.com/docs/api_reference/TwiML/dial) are passed in as a hash
140
+ #
141
+ # Examples:
142
+ # Twilio::Verb.dial('415-123-4567')
143
+ # Twilio::Verb.dial('415-123-4567', :action => 'http://foobar.com')
144
+ # Twilio::Verb.dial('415-123-4567', {:timeout => 10, :callerId => '858-987-6543'})
145
+ def dial(*args, &block)
146
+ number_to_dial = ''
147
+ options = {}
148
+ args.each do |arg|
149
+ case arg
150
+ when String
151
+ number_to_dial = arg
152
+ when Hash
153
+ options.merge!(arg)
154
+ else
155
+ raise ArgumentError, 'dial expects String or Hash argument'
156
+ end
157
+ end
158
+
159
+ xml = Builder::XmlMarkup.new
160
+ xml.instruct!
161
+ xml.Response { xml.Dial(number_to_dial, options) }
162
+ end
163
+
164
+ def method_missing(method_id, *args) #:nodoc:
165
+ if match = /(say|play|gather|record|dial)(_(\d+)_)times(_with_pause$*)/.match(method_id.to_s)
166
+ verb = match.captures.first
167
+ how_many_times = match.captures[1]
168
+ pause = match.captures[2] == '_with_pause'
169
+ self.send(verb, args.first, { :loop => Integer(how_many_times), :pause => pause})
170
+ else
171
+ raise NoMethodError.new("Method --- #{method_id} --- not found")
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def loop_with_pause(loop_count, xml, &verb_action)
178
+ last_iteration = loop_count-1
179
+ loop_count.times do |i|
180
+ yield verb_action
181
+ xml.Pause unless i == last_iteration
182
+ end
183
+ end
184
+ end
185
+ end
186
+ end