ghost_google-api-client 0.4.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG.md +77 -0
  2. data/Gemfile +30 -0
  3. data/Gemfile.lock +80 -0
  4. data/LICENSE +202 -0
  5. data/README.md +71 -0
  6. data/Rakefile +42 -0
  7. data/bin/google-api +545 -0
  8. data/lib/compat/multi_json.rb +17 -0
  9. data/lib/google/api_client.rb +802 -0
  10. data/lib/google/api_client/batch.rb +296 -0
  11. data/lib/google/api_client/client_secrets.rb +106 -0
  12. data/lib/google/api_client/discovery.rb +19 -0
  13. data/lib/google/api_client/discovery/api.rb +287 -0
  14. data/lib/google/api_client/discovery/media.rb +77 -0
  15. data/lib/google/api_client/discovery/method.rb +369 -0
  16. data/lib/google/api_client/discovery/resource.rb +150 -0
  17. data/lib/google/api_client/discovery/schema.rb +119 -0
  18. data/lib/google/api_client/environment.rb +42 -0
  19. data/lib/google/api_client/errors.rb +49 -0
  20. data/lib/google/api_client/media.rb +172 -0
  21. data/lib/google/api_client/reference.rb +305 -0
  22. data/lib/google/api_client/result.rb +161 -0
  23. data/lib/google/api_client/service_account.rb +134 -0
  24. data/lib/google/api_client/version.rb +31 -0
  25. data/lib/google/inflection.rb +28 -0
  26. data/spec/fixtures/files/sample.txt +33 -0
  27. data/spec/google/api_client/batch_spec.rb +241 -0
  28. data/spec/google/api_client/discovery_spec.rb +670 -0
  29. data/spec/google/api_client/media_spec.rb +143 -0
  30. data/spec/google/api_client/result_spec.rb +185 -0
  31. data/spec/google/api_client/service_account_spec.rb +58 -0
  32. data/spec/google/api_client_spec.rb +139 -0
  33. data/spec/spec_helper.rb +7 -0
  34. data/tasks/gem.rake +97 -0
  35. data/tasks/git.rake +45 -0
  36. data/tasks/metrics.rake +22 -0
  37. data/tasks/spec.rake +57 -0
  38. data/tasks/wiki.rake +82 -0
  39. data/tasks/yard.rake +29 -0
  40. metadata +253 -0
@@ -0,0 +1,119 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ require 'time'
17
+ require 'multi_json'
18
+ require 'compat/multi_json'
19
+ require 'base64'
20
+ require 'autoparse'
21
+ require 'addressable/uri'
22
+ require 'addressable/template'
23
+
24
+ require 'google/inflection'
25
+ require 'google/api_client/errors'
26
+
27
+
28
+ module Google
29
+ class APIClient
30
+ module Schema
31
+ def self.parse(api, schema_data)
32
+ # This method is super-long, but hard to break up due to the
33
+ # unavoidable dependence on closures and execution context.
34
+ schema_name = schema_data['id']
35
+
36
+ # Due to an oversight, schema IDs may not be URI references.
37
+ # TODO(bobaman): Remove this code once this has been resolved.
38
+ schema_uri = (
39
+ api.document_base +
40
+ (schema_name[0..0] != '#' ? '#' + schema_name : schema_name)
41
+ )
42
+ # puts schema_uri
43
+
44
+ # Due to an oversight, schema IDs may not be URI references.
45
+ # TODO(bobaman): Remove this whole lambda once this has been resolved.
46
+ reformat_references = lambda do |data|
47
+ # This code is not particularly efficient due to recursive traversal
48
+ # and excess object creation, but this hopefully shouldn't be an
49
+ # issue since it should only be called only once per schema per
50
+ # process.
51
+ if data.kind_of?(Hash) &&
52
+ data['$ref'] && !data['$ref'].kind_of?(Hash)
53
+ if data['$ref'].respond_to?(:to_str)
54
+ reference = data['$ref'].to_str
55
+ else
56
+ raise TypeError, "Expected String, got #{data['$ref'].class}"
57
+ end
58
+ reference = '#' + reference if reference[0..0] != '#'
59
+ data.merge({
60
+ '$ref' => reference
61
+ })
62
+ elsif data.kind_of?(Hash)
63
+ data.inject({}) do |accu, (key, value)|
64
+ if value.kind_of?(Hash)
65
+ accu[key] = reformat_references.call(value)
66
+ else
67
+ accu[key] = value
68
+ end
69
+ accu
70
+ end
71
+ else
72
+ data
73
+ end
74
+ end
75
+ schema_data = reformat_references.call(schema_data)
76
+ # puts schema_data.inspect
77
+
78
+ if schema_name
79
+ api_name_string =
80
+ Google::INFLECTOR.camelize(api.name)
81
+ api_version_string =
82
+ Google::INFLECTOR.camelize(api.version).gsub('.', '_')
83
+ # This is for compatibility with Ruby 1.8.7.
84
+ # TODO(bobaman) Remove this when we eventually stop supporting 1.8.7.
85
+ args = []
86
+ args << false if Class.method(:const_defined?).arity != 1
87
+ if Google::APIClient::Schema.const_defined?(api_name_string, *args)
88
+ api_name = Google::APIClient::Schema.const_get(
89
+ api_name_string, *args
90
+ )
91
+ else
92
+ api_name = Google::APIClient::Schema.const_set(
93
+ api_name_string, Module.new
94
+ )
95
+ end
96
+ if api_name.const_defined?(api_version_string, *args)
97
+ api_version = api_name.const_get(api_version_string, *args)
98
+ else
99
+ api_version = api_name.const_set(api_version_string, Module.new)
100
+ end
101
+ if api_version.const_defined?(schema_name, *args)
102
+ schema_class = api_version.const_get(schema_name, *args)
103
+ end
104
+ end
105
+
106
+ # It's possible the schema has already been defined. If so, don't
107
+ # redefine it. This means that reloading a schema which has already
108
+ # been loaded into memory is not possible.
109
+ unless schema_class
110
+ schema_class = AutoParse.generate(schema_data, :uri => schema_uri)
111
+ if schema_name
112
+ api_version.const_set(schema_name, schema_class)
113
+ end
114
+ end
115
+ return schema_class
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ class APIClient
18
+ module ENV
19
+ OS_VERSION = begin
20
+ if RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/
21
+ # TODO(bobaman)
22
+ # Confirm that all of these Windows environments actually have access
23
+ # to the `ver` command.
24
+ `ver`.sub(/\s*\[Version\s*/, '/').sub(']', '').strip
25
+ elsif RUBY_PLATFORM =~ /darwin/i
26
+ "Mac OS X/#{`sw_vers -productVersion`}"
27
+ elsif RUBY_PLATFORM == 'java'
28
+ # Get the information from java system properties to avoid spawning a
29
+ # sub-process, which is not friendly in some contexts (web servers).
30
+ require 'java'
31
+ name = java.lang.System.getProperty('os.name')
32
+ version = java.lang.System.getProperty('os.version')
33
+ "#{name}/#{version}"
34
+ else
35
+ `uname -sr`.sub(' ', '/')
36
+ end
37
+ rescue Exception
38
+ RUBY_PLATFORM
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,49 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ module Google
17
+ class APIClient
18
+ ##
19
+ # An error which is raised when there is an unexpected response or other
20
+ # transport error that prevents an operation from succeeding.
21
+ class TransmissionError < StandardError
22
+ end
23
+
24
+ ##
25
+ # An exception that is raised if a method is called with missing or
26
+ # invalid parameter values.
27
+ class ValidationError < StandardError
28
+ end
29
+
30
+ ##
31
+ # A 4xx class HTTP error occurred.
32
+ class ClientError < TransmissionError
33
+ end
34
+
35
+ ##
36
+ # A 5xx class HTTP error occurred.
37
+ class ServerError < TransmissionError
38
+ end
39
+
40
+ ##
41
+ # An exception that is raised if an ID token could not be validated.
42
+ class InvalidIDTokenError < StandardError
43
+ end
44
+
45
+ # Error class for problems in batch requests.
46
+ class BatchError < StandardError
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,172 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ module Google
16
+ class APIClient
17
+ ##
18
+ # Uploadable media support. Holds an IO stream & content type.
19
+ #
20
+ # @see Faraday::UploadIO
21
+ # @example
22
+ # media = Google::APIClient::UploadIO.new('mymovie.m4v', 'video/mp4')
23
+ class UploadIO < Faraday::UploadIO
24
+ ##
25
+ # Get the length of the stream
26
+ # @return [Integer]
27
+ # Length of stream, in bytes
28
+ def length
29
+ io.respond_to?(:length) ? io.length : File.size(local_path)
30
+ end
31
+ end
32
+
33
+ ##
34
+ # Resumable uploader.
35
+ #
36
+ class ResumableUpload
37
+ attr_reader :result
38
+ attr_accessor :client
39
+ attr_accessor :chunk_size
40
+ attr_accessor :media
41
+ attr_accessor :location
42
+
43
+ ##
44
+ # Creates a new uploader.
45
+ #
46
+ # @param [Google::APIClient::Result] result
47
+ # Result of the initial request that started the upload
48
+ # @param [Google::APIClient::UploadIO] media
49
+ # Media to upload
50
+ # @param [String] location
51
+ # URL to upload to
52
+ def initialize(result, media, location)
53
+ self.media = media
54
+ self.location = location
55
+ self.chunk_size = 256 * 1024
56
+
57
+ @api_method = result.reference.api_method
58
+ @result = result
59
+ @offset = 0
60
+ @complete = false
61
+ end
62
+
63
+ ##
64
+ # Sends all remaining chunks to the server
65
+ #
66
+ # @param [Google::APIClient] api_client
67
+ # API Client instance to use for sending
68
+ def send_all(api_client)
69
+ until complete?
70
+ send_chunk(api_client)
71
+ break unless result.status == 308
72
+ end
73
+ return result
74
+ end
75
+
76
+
77
+ ##
78
+ # Sends the next chunk to the server
79
+ #
80
+ # @param [Google::APIClient] api_client
81
+ # API Client instance to use for sending
82
+ def send_chunk(api_client)
83
+ if @offset.nil?
84
+ return resync_range(api_client)
85
+ end
86
+
87
+ start_offset = @offset
88
+ self.media.io.pos = start_offset
89
+ chunk = self.media.io.read(chunk_size)
90
+ content_length = chunk.bytesize
91
+
92
+ end_offset = start_offset + content_length - 1
93
+ @result = api_client.execute(
94
+ :uri => self.location,
95
+ :http_method => :put,
96
+ :headers => {
97
+ 'Content-Length' => "#{content_length}",
98
+ 'Content-Type' => self.media.content_type,
99
+ 'Content-Range' => "bytes #{start_offset}-#{end_offset}/#{media.length}" },
100
+ :body => chunk)
101
+ return process_result(@result)
102
+ end
103
+
104
+ ##
105
+ # Check if upload is complete
106
+ #
107
+ # @return [TrueClass, FalseClass]
108
+ # Whether or not the upload complete successfully
109
+ def complete?
110
+ return @complete
111
+ end
112
+
113
+ ##
114
+ # Check if the upload URL expired (upload not completed in alotted time.)
115
+ # Expired uploads must be restarted from the beginning
116
+ #
117
+ # @return [TrueClass, FalseClass]
118
+ # Whether or not the upload has expired and can not be resumed
119
+ def expired?
120
+ return @result.status == 404 || @result.status == 410
121
+ end
122
+
123
+ ##
124
+ # Get the last saved range from the server in case an error occurred
125
+ # and the offset is not known.
126
+ #
127
+ # @param [Google::APIClient] api_client
128
+ # API Client instance to use for sending
129
+ def resync_range(api_client)
130
+ r = api_client.execute(
131
+ :uri => self.location,
132
+ :http_method => :put,
133
+ :headers => {
134
+ 'Content-Length' => "0",
135
+ 'Content-Range' => "bytes */#{media.length}" })
136
+ return process_result(r)
137
+ end
138
+
139
+ ##
140
+ # Check the result from the server, updating the offset and/or location
141
+ # if available.
142
+ #
143
+ # @param [Google::APIClient::Result] r
144
+ # Result of a chunk upload or range query
145
+ def process_result(result)
146
+ case result.status
147
+ when 200...299
148
+ @complete = true
149
+ if @api_method
150
+ # Inject the original API method so data is parsed correctly
151
+ result.reference.api_method = @api_method
152
+ end
153
+ return result
154
+ when 308
155
+ range = result.headers['range']
156
+ if range
157
+ @offset = range.scan(/\d+/).collect{|x| Integer(x)}.last + 1
158
+ end
159
+ if result.headers['location']
160
+ self.location = result.headers['location']
161
+ end
162
+ when 500...599
163
+ # Invalidate the offset to mark it needs to be queried on the
164
+ # next request
165
+ @offset = nil
166
+ end
167
+ return nil
168
+ end
169
+
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,305 @@
1
+ # Copyright 2010 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+
16
+ gem 'faraday', '~> 0.8.1'
17
+ require 'faraday'
18
+ require 'faraday/utils'
19
+ require 'multi_json'
20
+ require 'compat/multi_json'
21
+ require 'addressable/uri'
22
+ require 'stringio'
23
+ require 'google/api_client/discovery'
24
+
25
+ # TODO - needs some serious cleanup
26
+
27
+ module Google
28
+ class APIClient
29
+ class Reference
30
+ MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze
31
+
32
+ def initialize(options={})
33
+ # We only need this to do lookups on method ID String values
34
+ # It's optional, but method ID lookups will fail if the client is
35
+ # omitted.
36
+ @client = options[:client]
37
+ @version = options[:version] || 'v1'
38
+
39
+ self.connection = options[:connection] || Faraday.default_connection
40
+ self.authorization = options[:authorization]
41
+ self.api_method = options[:api_method]
42
+ self.parameters = options[:parameters] || {}
43
+ # These parameters are handled differently because they're not
44
+ # parameters to the API method, but rather to the API system.
45
+ if self.parameters.kind_of?(Array)
46
+ if options[:key]
47
+ self.parameters.reject! { |k, _| k == 'key' }
48
+ self.parameters << ['key', options[:key]]
49
+ end
50
+ if options[:user_ip]
51
+ self.parameters.reject! { |k, _| k == 'userIp' }
52
+ self.parameters << ['userIp', options[:user_ip]]
53
+ end
54
+ elsif self.parameters.kind_of?(Hash)
55
+ self.parameters['key'] ||= options[:key] if options[:key]
56
+ self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip]
57
+ # Convert to Array, because they're easier to work with when
58
+ # repeated parameters are an issue.
59
+ self.parameters = self.parameters.to_a
60
+ else
61
+ raise TypeError,
62
+ "Expected Array or Hash, got #{self.parameters.class}."
63
+ end
64
+ self.headers = options[:headers] || {}
65
+ if options[:media]
66
+ self.media = options[:media]
67
+ upload_type = self.parameters.find { |(k, _)| ['uploadType', 'upload_type'].include?(k) }.last
68
+ case upload_type
69
+ when "media"
70
+ if options[:body] || options[:body_object]
71
+ raise ArgumentError,
72
+ "Can not specify body & body object for simple uploads."
73
+ end
74
+ self.headers['Content-Type'] ||= self.media.content_type
75
+ self.body = self.media
76
+ when "multipart"
77
+ unless options[:body_object]
78
+ raise ArgumentError, "Multipart requested but no body object."
79
+ end
80
+ # This is all a bit of a hack due to Signet requiring body to be a
81
+ # string. Ideally, update Signet to delay serialization so we can
82
+ # just pass streams all the way down through to the HTTP library.
83
+ metadata = StringIO.new(serialize_body(options[:body_object]))
84
+ env = {
85
+ :request_headers => {
86
+ 'Content-Type' =>
87
+ "multipart/related;boundary=#{MULTIPART_BOUNDARY}"
88
+ },
89
+ :request => {:boundary => MULTIPART_BOUNDARY}
90
+ }
91
+ multipart = Faraday::Request::Multipart.new
92
+ self.body = multipart.create_multipart(env, [
93
+ [nil, Faraday::UploadIO.new(
94
+ metadata, 'application/json', 'file.json'
95
+ )],
96
+ [nil, self.media]])
97
+ self.headers.update(env[:request_headers])
98
+ when "resumable"
99
+ file_length = self.media.length
100
+ self.headers['X-Upload-Content-Type'] = self.media.content_type
101
+ self.headers['X-Upload-Content-Length'] = file_length.to_s
102
+ if options[:body_object]
103
+ self.headers['Content-Type'] ||= 'application/json'
104
+ self.body = serialize_body(options[:body_object])
105
+ else
106
+ self.body = ''
107
+ end
108
+ else
109
+ raise ArgumentError, "Invalid uploadType for media."
110
+ end
111
+ elsif options[:body]
112
+ self.body = options[:body]
113
+ elsif options[:body_object]
114
+ self.headers['Content-Type'] ||= 'application/json'
115
+ self.body = serialize_body(options[:body_object])
116
+ else
117
+ self.body = ''
118
+ end
119
+ unless self.api_method
120
+ self.http_method = options[:http_method] || 'GET'
121
+ self.uri = options[:uri]
122
+ unless self.parameters.empty?
123
+ query_values = (self.uri.query_values(Array) || [])
124
+ self.uri.query = Addressable::URI.form_encode(
125
+ (query_values + self.parameters).sort
126
+ )
127
+ self.uri.query = nil if self.uri.query == ""
128
+ end
129
+ end
130
+ end
131
+
132
+ def serialize_body(body)
133
+ return body.to_json if body.respond_to?(:to_json)
134
+ return MultiJson.dump(options[:body_object].to_hash) if body.respond_to?(:to_hash)
135
+ raise TypeError, 'Could not convert body object to JSON.' +
136
+ 'Must respond to :to_json or :to_hash.'
137
+ end
138
+
139
+ def media
140
+ return @media
141
+ end
142
+
143
+ def media=(media)
144
+ @media = (media)
145
+ end
146
+
147
+ def authorization
148
+ return @authorization
149
+ end
150
+
151
+ def authorization=(new_authorization)
152
+ @authorization = new_authorization
153
+ end
154
+
155
+ def connection
156
+ return @connection
157
+ end
158
+
159
+ def connection=(new_connection)
160
+ if new_connection.kind_of?(Faraday::Connection)
161
+ @connection = new_connection
162
+ else
163
+ raise TypeError,
164
+ "Expected Faraday::Connection, got #{new_connection.class}."
165
+ end
166
+ end
167
+
168
+ def api_method
169
+ return @api_method
170
+ end
171
+
172
+ def api_method=(new_api_method)
173
+ if new_api_method.kind_of?(Google::APIClient::Method) ||
174
+ new_api_method == nil
175
+ @api_method = new_api_method
176
+ elsif new_api_method.respond_to?(:to_str) ||
177
+ new_api_method.kind_of?(Symbol)
178
+ unless @client
179
+ raise ArgumentError,
180
+ "API method lookup impossible without client instance."
181
+ end
182
+ new_api_method = new_api_method.to_s
183
+ # This method of guessing the API is unreliable. This will fail for
184
+ # APIs where the first segment of the RPC name does not match the
185
+ # service name. However, this is a fallback mechanism anyway.
186
+ # Developers should be passing in a reference to the method, rather
187
+ # than passing in a string or symbol. This should raise an error
188
+ # in the case of a mismatch.
189
+ api = new_api_method[/^([^.]+)\./, 1]
190
+ @api_method = @client.discovered_method(
191
+ new_api_method, api, @version
192
+ )
193
+ if @api_method
194
+ # Ditch the client reference, we won't need it again.
195
+ @client = nil
196
+ else
197
+ raise ArgumentError, "API method could not be found."
198
+ end
199
+ else
200
+ raise TypeError,
201
+ "Expected Google::APIClient::Method, got #{new_api_method.class}."
202
+ end
203
+ end
204
+
205
+ def parameters
206
+ return @parameters
207
+ end
208
+
209
+ def parameters=(new_parameters)
210
+ # No type-checking needed, the Method class handles this.
211
+ @parameters = new_parameters
212
+ end
213
+
214
+ def body
215
+ return @body
216
+ end
217
+
218
+ def body=(new_body)
219
+ if new_body.respond_to?(:to_str)
220
+ @body = new_body.to_str
221
+ elsif new_body.respond_to?(:read)
222
+ @body = new_body.read()
223
+ elsif new_body.respond_to?(:inject)
224
+ @body = (new_body.inject(StringIO.new) do |accu, chunk|
225
+ accu.write(chunk)
226
+ accu
227
+ end).string
228
+ else
229
+ raise TypeError,
230
+ "Expected body to be String, IO, or Enumerable chunks."
231
+ end
232
+ end
233
+
234
+ def headers
235
+ return @headers ||= {}
236
+ end
237
+
238
+ def headers=(new_headers)
239
+ if new_headers.kind_of?(Array) || new_headers.kind_of?(Hash)
240
+ @headers = new_headers
241
+ else
242
+ raise TypeError, "Expected Hash or Array, got #{new_headers.class}."
243
+ end
244
+ end
245
+
246
+ def http_method
247
+ return @http_method ||= self.api_method.http_method
248
+ end
249
+
250
+ def http_method=(new_http_method)
251
+ if new_http_method.kind_of?(Symbol)
252
+ @http_method = new_http_method.to_s.upcase
253
+ elsif new_http_method.respond_to?(:to_str)
254
+ @http_method = new_http_method.to_str.upcase
255
+ else
256
+ raise TypeError,
257
+ "Expected String or Symbol, got #{new_http_method.class}."
258
+ end
259
+ end
260
+
261
+ def uri
262
+ return @uri ||= self.api_method.generate_uri(self.parameters)
263
+ end
264
+
265
+ def uri=(new_uri)
266
+ @uri = Addressable::URI.parse(new_uri)
267
+ end
268
+
269
+ def to_request
270
+ if self.api_method
271
+ return self.api_method.generate_request(
272
+ self.parameters, self.body, self.headers,
273
+ :connection => self.connection
274
+ )
275
+ else
276
+ return self.connection.build_request(
277
+ self.http_method.to_s.downcase.to_sym
278
+ ) do |req|
279
+ req.url(Addressable::URI.parse(self.uri).normalize.to_s)
280
+ req.headers = Faraday::Utils::Headers.new(self.headers)
281
+ req.body = self.body
282
+ end
283
+ end
284
+ end
285
+
286
+ def to_hash
287
+ options = {}
288
+ if self.api_method
289
+ options[:api_method] = self.api_method
290
+ options[:parameters] = self.parameters
291
+ else
292
+ options[:http_method] = self.http_method
293
+ options[:uri] = self.uri
294
+ end
295
+ options[:headers] = self.headers
296
+ options[:body] = self.body
297
+ options[:connection] = self.connection
298
+ unless self.authorization.nil?
299
+ options[:authorization] = self.authorization
300
+ end
301
+ return options
302
+ end
303
+ end
304
+ end
305
+ end