ghost_google-api-client 0.4.7.1

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 (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