twilio-ruby 3.12.3 → 3.13.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 (42) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGES.md +12 -0
  3. data/README.md +14 -14
  4. data/Rakefile +2 -2
  5. data/docs/faq.rst +3 -3
  6. data/docs/getting-started.rst +17 -12
  7. data/docs/usage/accounts.rst +6 -6
  8. data/docs/usage/applications.rst +5 -5
  9. data/docs/usage/basics.rst +1 -1
  10. data/docs/usage/caller-ids.rst +4 -2
  11. data/docs/usage/conferences.rst +1 -1
  12. data/docs/usage/errors.rst +3 -3
  13. data/docs/usage/messages.rst +24 -16
  14. data/docs/usage/phone-calls.rst +10 -8
  15. data/docs/usage/phone-numbers.rst +15 -11
  16. data/docs/usage/sip.rst +9 -8
  17. data/docs/usage/twiml.rst +2 -2
  18. data/examples/examples.rb +44 -20
  19. data/lib/rack/twilio_webhook_authentication.rb +5 -1
  20. data/lib/twilio-ruby/rest/calls.rb +4 -4
  21. data/lib/twilio-ruby/rest/client.rb +25 -23
  22. data/lib/twilio-ruby/rest/conferences/participants.rb +2 -2
  23. data/lib/twilio-ruby/rest/incoming_phone_numbers.rb +1 -1
  24. data/lib/twilio-ruby/rest/instance_resource.rb +9 -5
  25. data/lib/twilio-ruby/rest/list_resource.rb +18 -10
  26. data/lib/twilio-ruby/rest/outgoing_caller_ids.rb +1 -1
  27. data/lib/twilio-ruby/rest/queues/members.rb +1 -1
  28. data/lib/twilio-ruby/rest/sip.rb +1 -3
  29. data/lib/twilio-ruby/rest/utils.rb +11 -3
  30. data/lib/twilio-ruby/util/capability.rb +4 -4
  31. data/lib/twilio-ruby/version.rb +1 -1
  32. data/spec/rack/twilio_webhook_authentication_spec.rb +18 -6
  33. data/spec/rest/account_spec.rb +24 -8
  34. data/spec/rest/call_spec.rb +6 -2
  35. data/spec/rest/client_spec.rb +37 -14
  36. data/spec/rest/conference_spec.rb +3 -1
  37. data/spec/rest/instance_resource_spec.rb +1 -1
  38. data/spec/rest/numbers_spec.rb +18 -6
  39. data/spec/rest/queue_spec.rb +3 -1
  40. data/spec/rest/recording_spec.rb +3 -1
  41. data/spec/util/url_encode_spec.rb +1 -1
  42. metadata +1 -1
@@ -27,9 +27,9 @@ under sip.twilio.com.
27
27
  @client = Twilio::REST::Client.new account_sid, auth_token
28
28
 
29
29
  @domain = @client.sip.domains.create(
30
- {:friendly_name => "The Office Domain",
31
- :voice_url => "http://example.com/voice",
32
- :domain_name => "dunder-mifflin-scranton.sip.twilio.com",}
30
+ friendly_name: "The Office Domain",
31
+ voice_url: "http://example.com/voice"
32
+ domain_name: "dunder-mifflin-scranton.sip.twilio.com"
33
33
  )
34
34
  puts @domain.sid
35
35
 
@@ -51,7 +51,7 @@ to individual ip addresses. To do this, you'll first need to create an
51
51
  @client = Twilio::REST::Client.new account_sid, auth_token
52
52
 
53
53
  @ip_acl = @client.sip.ip_access_control_lists.create(
54
- {:friendly_name => "The Office IpAccessControlList",}
54
+ friendly_name: "The Office IpAccessControlList"
55
55
  )
56
56
  puts @ip_acl.sid
57
57
 
@@ -71,10 +71,10 @@ Now it's time to add an :class:`IpAddress` to your new :class:`IpAccessControlLi
71
71
  @client = Twilio::REST::Client.new account_sid, auth_token
72
72
 
73
73
  @ip_address = @client.sip.ip_access_control_lists.get(
74
- "AL456", # IpAccessControlList sid
74
+ "AL456", # IpAccessControlList sid
75
75
  ).ip_addresses.create(
76
- {:friendly_name => "Dwights's Computer",
77
- :ip_address => "192.168.1.42",}
76
+ friendly_name: "Dwights's Computer",
77
+ ip_address: "192.168.1.42"
78
78
  )
79
79
  puts @ip_address.sid
80
80
 
@@ -97,7 +97,8 @@ associate them. To do this, create an :class:`IpAccessControlListMapping`.
97
97
  @ip_acl_mapping = @client.sip.domains.get(
98
98
  "SD456", # SIP Domain sid
99
99
  ).ip_access_control_list_mappings.create(
100
- {:ip_access_control_list_sid => "AL789"})
100
+ ip_access_control_list_sid: "AL789"
101
+ )
101
102
 
102
103
  puts @ip_acl_mapping.sid
103
104
 
@@ -35,7 +35,7 @@ All attributes are keyword arguments.
35
35
  require 'twilio-ruby'
36
36
 
37
37
  Twilio::TwiML::Response.new do |r|
38
- r.Play "https://api.twilio.com/cowbell.mp3", :loop => 5
38
+ r.Play "https://api.twilio.com/cowbell.mp3", loop: 5
39
39
  end.text
40
40
 
41
41
  .. code-block:: xml
@@ -53,7 +53,7 @@ Any example of nesting nouns in verbs
53
53
 
54
54
  Twilio::TwiML::Response.new do |r|
55
55
  r.Say "hello"
56
- r.Gather :finishOnKey => 4 do |g|
56
+ r.Gather finishOnKey: => 4 do |g|
57
57
  g.Say "world"
58
58
  end
59
59
  end.text
@@ -8,7 +8,7 @@
8
8
  ################ ACCOUNTS ################
9
9
 
10
10
  # shortcut to grab your account object (account_sid is inferred from the client's auth credentials)
11
- @account = @client.account
11
+ @account = @client.account
12
12
 
13
13
  # list your (sub)accounts
14
14
  @client.accounts.list
@@ -19,12 +19,16 @@
19
19
  puts @account.friendly_name
20
20
 
21
21
  # update an account's friendly name
22
- @client.accounts.get(@account_sid).update(:friendly_name => 'A Fabulous Friendly Name')
22
+ @client.accounts.get(@account_sid).update(friendly_name: 'A Fabulous Friendly Name')
23
23
 
24
24
  ################ CALLS ################
25
25
 
26
26
  # print a list of calls (all parameters optional)
27
- @account.calls.list({:page => 0, :page_size => 1000, :start_time => '2010-09-01'}).each do |call|
27
+ @account.calls.list(
28
+ page: 0,
29
+ page_size: 1000,
30
+ start_time: '2010-09-01'
31
+ ).each do |call|
28
32
  puts call.sid
29
33
  end
30
34
 
@@ -34,18 +38,23 @@ end
34
38
  end
35
39
 
36
40
  # make a new outgoing call. returns a call object just like calls.get
37
- @call = @account.calls.create({:from => '+14159341234', :to => '+18004567890', :url => 'http://example.com/call-handler'})
41
+ @call = @account.calls.create(
42
+ from: '+14159341234',
43
+ to: '+18004567890',
44
+ url: 'http://example.com/call-handler'
45
+ )
38
46
 
39
47
  # cancel the call if not already in progress
40
- @account.calls.get(@call.sid).update({:status => 'canceled'})
48
+ @account.calls.get(@call.sid).update(status: 'canceled')
41
49
  # or equivalently
42
- @call.update({:status => 'canceled'})
50
+ @call.update(status: 'canceled')
43
51
  # or simply
44
52
  @call.cancel
45
53
 
46
54
  # redirect and then terminate a call
47
- @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:url => 'http://example.com/call-redirect'})
48
- @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:status => 'completed'})
55
+ @call = @account.calls.get('CA386025c9bf5d6052a1d1ea42b4d16662')
56
+ @call.update(url: 'http://example.com/call-redirect')
57
+ @call.update(status: 'completed')
49
58
  # or, use the aliases...
50
59
  @call.redirect_to('http://example.com/call-redirect')
51
60
  @call.hangup
@@ -53,7 +62,7 @@ end
53
62
  ################ SMS MESSAGES ################
54
63
 
55
64
  # print a list of messages
56
- @account.messages.list({:date_sent => '2010-09-01'}).each do |message|
65
+ @account.messages.list(date_sent: '2010-09-01').each do |message|
57
66
  puts message.body
58
67
  end
59
68
 
@@ -61,10 +70,18 @@ end
61
70
  puts @account.messages.get('SMXXXXXXXX').body
62
71
 
63
72
  # send an sms
64
- @account.messages.create(:from => '+14159341234', :to => '+16105557069', :body => 'Hey there!')
73
+ @account.messages.create(
74
+ from: '+14159341234',
75
+ to: '+16105557069',
76
+ body: 'Hey there!'
77
+ )
65
78
 
66
79
  # send an mms
67
- @account.messages.create(:from => '+14159341234', :to => '+16105557069', :media_urls => 'http://example.com/media.png')
80
+ @account.messages.create(
81
+ from: '+14159341234',
82
+ to: '+16105557069',
83
+ media_urls: 'http://example.com/media.png'
84
+ )
68
85
 
69
86
  ################ PHONE NUMBERS ################
70
87
 
@@ -72,22 +89,28 @@ puts @account.messages.get('SMXXXXXXXX').body
72
89
  @account.available_phone_numbers.list
73
90
 
74
91
  # print some available numbers
75
- @numbers = @account.available_phone_numbers.get('US').local.list({:contains => 'AWESOME'})
76
- @numbers.each {|num| puts num.phone_number}
92
+ @numbers = @account.available_phone_numbers.get('US').local.list(
93
+ contains: 'AWESOME'
94
+ )
95
+ @numbers.each { |num| puts num.phone_number }
77
96
 
78
97
  # buy the first one
79
- @account.incoming_phone_numbers.create(:phone_number => @numbers[0].phone_number)
98
+ @account.incoming_phone_numbers.create(phone_number: @numbers[0].phone_number)
80
99
 
81
100
  # update an existing phone number's voice url
82
- @account.incoming_phone_numbers.get('PNdba508c5616a7f5e141789f44f022cc3').update({:voice_url => 'http://example.com/voice'})
101
+ number = @account.incoming_phone_numbers.get('PNdba508c5616a7f5e141789f44f022cc3')
102
+ number.update(voice_url: 'http://example.com/voice')
83
103
 
84
104
  # decommission an existing phone number
85
- numbers = @account.incoming_phone_numbers.list(:friendly_name => 'A Fabulous Friendly Name')
105
+ numbers = @account.incoming_phone_numbers.list(
106
+ friendly_name: 'A Fabulous Friendly Name'
107
+ )
86
108
  numbers[0].delete
87
109
  ################ CONFERENCES ################
88
110
 
89
111
  # get a particular conference's participants object and stash it
90
- @participants = @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants
112
+ conference = @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39')
113
+ @participants = conference.participants
91
114
 
92
115
  # list participants
93
116
  @participants.list.each do |p|
@@ -95,17 +118,18 @@ numbers[0].delete
95
118
  end
96
119
 
97
120
  # update a conference participant
98
- @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:muted => 'true'})
121
+ @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update(muted: 'true')
99
122
  # or an easier way
100
123
  @participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').mute
101
124
 
102
125
  # and, since we're lazy loading, this would only incur one http request
103
- @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants.get('CA386025c9bf5d6052a1d1ea42b4d16662').update({:muted => 'true'})
126
+ @account.conferences.get('CFbbe46ff1274e283f7e3ac1df0072ab39').participants
127
+ .get('CA386025c9bf5d6052a1d1ea42b4d16662').update(muted: 'true')
104
128
 
105
129
  ################ QUEUES ###################
106
130
 
107
131
  # create a new queue
108
- @queue = @account.queues.create(:friendly_name => 'MyQueue', :max_size => 50)
132
+ @queue = @account.queues.create(friendly_name: 'MyQueue', max_size: 50)
109
133
 
110
134
  # get a list of queues for this account
111
135
  @queues = @account.queues.list
@@ -33,7 +33,11 @@ module Rack
33
33
  if validator.validate(original_url, params, signature)
34
34
  @app.call(env)
35
35
  else
36
- [403, {'Content-Type' => 'text/plain'}, ["Twilio Request Validation Failed."]]
36
+ [
37
+ 403,
38
+ {'Content-Type' => 'text/plain'},
39
+ ["Twilio Request Validation Failed."]
40
+ ]
37
41
  end
38
42
  end
39
43
  end
@@ -7,7 +7,7 @@ module Twilio
7
7
  end
8
8
 
9
9
  def make(from, to, url)
10
- create :from => from, :to => to, :url => url
10
+ create from: from, to: to, url: url
11
11
  end
12
12
  end
13
13
 
@@ -18,15 +18,15 @@ module Twilio
18
18
  end
19
19
 
20
20
  def redirect_to(url)
21
- update :url => url
21
+ update url: url
22
22
  end
23
23
 
24
24
  def cancel
25
- update :status => 'canceled'
25
+ update status: 'canceled'
26
26
  end
27
27
 
28
28
  def hangup
29
- update :status => 'completed'
29
+ update status: 'completed'
30
30
  end
31
31
  end
32
32
  end
@@ -63,21 +63,23 @@ module Twilio
63
63
  HTTP_HEADERS = {
64
64
  'Accept' => 'application/json',
65
65
  'Accept-Charset' => 'utf-8',
66
- 'User-Agent' => "twilio-ruby/#{Twilio::VERSION} (#{engine}/#{RUBY_PLATFORM} #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})",
66
+ 'User-Agent' => "twilio-ruby/#{Twilio::VERSION}" \
67
+ " (#{engine}/#{RUBY_PLATFORM}" \
68
+ " #{RUBY_VERSION}-p#{RUBY_PATCHLEVEL})"
67
69
  }
68
70
 
69
71
  DEFAULTS = {
70
- :host => 'api.twilio.com',
71
- :port => 443,
72
- :use_ssl => true,
73
- :ssl_verify_peer => true,
74
- :ssl_ca_file => File.dirname(__FILE__) + '/../../../conf/cacert.pem',
75
- :timeout => 30,
76
- :proxy_addr => nil,
77
- :proxy_port => nil,
78
- :proxy_user => nil,
79
- :proxy_pass => nil,
80
- :retry_limit => 1,
72
+ host: 'api.twilio.com',
73
+ port: 443,
74
+ use_ssl: true,
75
+ ssl_verify_peer: true,
76
+ ssl_ca_file: File.dirname(__FILE__) + '/../../../conf/cacert.pem',
77
+ timeout: 30,
78
+ proxy_addr: nil,
79
+ proxy_port: nil,
80
+ proxy_user: nil,
81
+ proxy_pass: nil,
82
+ retry_limit: 1
81
83
  }
82
84
 
83
85
  attr_reader :account_sid, :account, :accounts, :last_request,
@@ -91,36 +93,36 @@ module Twilio
91
93
  # hash of connection configuration options. the following keys are
92
94
  # supported:
93
95
  #
94
- # === <tt>:host => 'api.twilio.com'</tt>
96
+ # === <tt>host: 'api.twilio.com'</tt>
95
97
  #
96
98
  # The domain to which you'd like the client to make HTTP requests. Useful
97
99
  # for testing. Defaults to 'api.twilio.com'.
98
100
  #
99
- # === <tt>:port => 443</tt>
101
+ # === <tt>port: 443</tt>
100
102
  #
101
103
  # The port on which to connect to the above domain. Defaults to 443 and
102
104
  # should be left that way except in testing environments.
103
105
  #
104
- # === <tt>:use_ssl => true</tt>
106
+ # === <tt>use_ssl: true</tt>
105
107
  #
106
108
  # Declare whether ssl should be used for connections to the above domain.
107
109
  # Defaults to true and should be left alone except when testing.
108
110
  #
109
- # === <tt>:ssl_verify_peer => true</tt>
111
+ # === <tt>ssl_verify_peer: true</tt>
110
112
  #
111
113
  # Declare whether to verify the host's ssl cert when setting up the
112
114
  # connection to the above domain. Defaults to true, but can be turned off
113
115
  # to avoid ssl certificate verification failures in environments without
114
116
  # the necessary ca certificates.
115
117
  #
116
- # === <tt>:ssl_ca_file => '/path/to/ca/file'</tt>
118
+ # === <tt>ssl_ca_file: '/path/to/ca/file'</tt>
117
119
  #
118
120
  # Specify the path to the certificate authority bundle you'd like to use
119
121
  # to verify Twilio's SSL certificate on each request. If not specified, a
120
122
  # certificate bundle extraced from Firefox is packaged with the gem and
121
123
  # used by default.
122
124
  #
123
- # === <tt>:timeout => 30</tt>
125
+ # === <tt>timeout: 30</tt>
124
126
  #
125
127
  # Set the time in seconds to wait before timing out the HTTP request.
126
128
  # Defaults to 30 seconds. If you aren't fetching giant pages of call or
@@ -128,24 +130,24 @@ module Twilio
128
130
  # lower. In paricular if you are sending SMS you can set this to 1 second
129
131
  # or less and swallow the exception if you don't care about the response.
130
132
  #
131
- # === <tt>:proxy_addr => 'proxy.host.domain'</tt>
133
+ # === <tt>proxy_addr: 'proxy.host.domain'</tt>
132
134
  #
133
135
  # The domain of a proxy through which you'd like the client to make HTTP
134
136
  # requests. Defaults to nil.
135
137
  #
136
- # === <tt>:proxy_port => 3128</tt>
138
+ # === <tt>proxy_port: 3128</tt>
137
139
  #
138
140
  # The port on which to connect to the above proxy. Defaults to nil.
139
141
  #
140
- # === <tt>:proxy_user => 'username'</tt>
142
+ # === <tt>proxy_user: 'username'</tt>
141
143
  #
142
144
  # The user name to use for authentication with the proxy. Defaults to nil.
143
145
  #
144
- # === <tt>:proxy_pass => 'password'</tt>
146
+ # === <tt>proxy_pass: 'password'</tt>
145
147
  #
146
148
  # The password to use for authentication with the proxy. Defaults to nil.
147
149
  #
148
- # === <tt>:retry_limit => 1</tt>
150
+ # === <tt>retry_limit: 1</tt>
149
151
  #
150
152
  # The number of times to retry a request that has failed before throwing
151
153
  # an exception. Defaults to one.
@@ -10,11 +10,11 @@ module Twilio
10
10
 
11
11
  class Participant < InstanceResource
12
12
  def mute
13
- update :muted => 'true'
13
+ update muted: 'true'
14
14
  end
15
15
 
16
16
  def unmute
17
- update :muted => 'false'
17
+ update muted: 'false'
18
18
  end
19
19
 
20
20
  alias :kick :delete
@@ -8,7 +8,7 @@ module Twilio
8
8
  end
9
9
 
10
10
  def buy(phone_number)
11
- create :phone_number => phone_number
11
+ create phone_number: phone_number
12
12
  end
13
13
  end
14
14
 
@@ -32,7 +32,7 @@ module Twilio
32
32
  # to handle the update. For example, to update the +VoiceUrl+ of a Twilio
33
33
  # Application you could write:
34
34
  #
35
- # @app.update :voice_url => 'http://my.other.app.com/handle_voice'
35
+ # @app.update voice_url: 'http://my.other.app.com/handle_voice'
36
36
  #
37
37
  # After returning, the object will contain the most recent state of the
38
38
  # instance resource, including the newly updated properties.
@@ -77,23 +77,27 @@ module Twilio
77
77
  hash.each do |p,v|
78
78
  property = detwilify p
79
79
  unless ['client', 'updated'].include? property
80
- eigenclass.send :define_method, property.to_sym, &lambda {v}
80
+ eigenclass.send :define_method, property.to_sym, &lambda { v }
81
81
  end
82
82
  end
83
83
  @updated = !hash.keys.empty?
84
84
  end
85
85
 
86
86
  def resource(*resources)
87
- custom_resource_names = {:sms => 'SMS', :sip => 'SIP'}
87
+ custom_resource_names = { sms: 'SMS', sip: 'SIP' }
88
88
  resources.each do |r|
89
89
  resource = twilify r
90
90
  relative_path = custom_resource_names.fetch(r, resource)
91
91
  path = "#{@path}/#{relative_path}"
92
- enclosing_module = @submodule == nil ? (Twilio::REST) : (Twilio::REST.const_get(@submodule))
92
+ enclosing_module = if @submodule == nil
93
+ Twilio::REST
94
+ else
95
+ Twilio::REST.const_get(@submodule)
96
+ end
93
97
  resource_class = enclosing_module.const_get resource
94
98
  instance_variable_set("@#{r}", resource_class.new(path, @client))
95
99
  end
96
- self.class.instance_eval {attr_reader *resources}
100
+ self.class.instance_eval { attr_reader *resources }
97
101
  end
98
102
 
99
103
  end
@@ -5,9 +5,9 @@ module Twilio
5
5
 
6
6
  def initialize(path, client)
7
7
  custom_names = {
8
- 'Media' => 'MediaInstance',
9
- 'IpAddresses' => 'IpAddress',
10
- 'Feedback' => 'FeedbackInstance',
8
+ 'Media' => 'MediaInstance',
9
+ 'IpAddresses' => 'IpAddress',
10
+ 'Feedback' => 'FeedbackInstance'
11
11
  }
12
12
  @path, @client = path, client
13
13
  resource_name = self.class.name.split('::')[-1]
@@ -16,7 +16,11 @@ module Twilio
16
16
  # The next line grabs the enclosing module. Necessary for resources
17
17
  # contained in their own submodule like /SMS/Messages
18
18
  parent_module = self.class.to_s.split('::')[-2]
19
- full_module_path = parent_module == 'REST' ? (Twilio::REST) : (Twilio::REST.const_get parent_module)
19
+ full_module_path = if parent_module == "REST"
20
+ Twilio::REST
21
+ else
22
+ Twilio::REST.const_get parent_module
23
+ end
20
24
 
21
25
  @instance_class = full_module_path.const_get instance_name
22
26
  @list_key, @instance_id_key = detwilify(resource_name), 'sid'
@@ -49,7 +53,7 @@ module Twilio
49
53
  client, list_class = @client, self.class
50
54
  resource_list.instance_eval do
51
55
  eigenclass = class << self; self; end
52
- eigenclass.send :define_method, :total, &lambda {response['total']}
56
+ eigenclass.send :define_method, :total, &lambda { response['total'] }
53
57
  eigenclass.send :define_method, :next_page, &lambda {
54
58
  if response['next_page_uri']
55
59
  list_class.new(response['next_page_uri'], client).list({}, true)
@@ -70,7 +74,7 @@ module Twilio
70
74
  # +total+ attribute as well.
71
75
  def total
72
76
  raise "Can't get a resource total without a REST Client" unless @client
73
- @client.get(@path, :page_size => 1)['total']
77
+ @client.get(@path, page_size: 1)['total']
74
78
  end
75
79
 
76
80
  ##
@@ -98,18 +102,22 @@ module Twilio
98
102
 
99
103
  def resource(*resources)
100
104
  custom_resource_names = {
101
- :sms => 'SMS',
102
- :sip => 'SIP',
105
+ sms: 'SMS',
106
+ sip: 'SIP'
103
107
  }
104
108
  resources.each do |r|
105
109
  resource = twilify r
106
110
  relative_path = custom_resource_names.fetch(r, resource)
107
111
  path = "#{@path}/#{relative_path}"
108
- enclosing_module = @submodule == nil ? (Twilio::REST) : (Twilio::REST.const_get(@submodule))
112
+ enclosing_module = if @submodule == nil
113
+ Twilio::REST
114
+ else
115
+ Twilio::REST.const_get(@submodule)
116
+ end
109
117
  resource_class = enclosing_module.const_get resource
110
118
  instance_variable_set("@#{r}", resource_class.new(path, @client))
111
119
  end
112
- self.class.instance_eval {attr_reader *resources}
120
+ self.class.instance_eval { attr_reader *resources }
113
121
  end
114
122
  end
115
123
  end