google-api-client 0.2.0 → 0.3.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.
@@ -13,565 +13,7 @@
13
13
  # limitations under the License.
14
14
 
15
15
 
16
- require 'json'
17
- require 'addressable/uri'
18
- require 'addressable/template'
19
-
20
- require 'google/inflection'
21
- require 'google/api_client/errors'
22
-
23
- module Google
24
- class APIClient
25
- ##
26
- # A service that has been described by a discovery document.
27
- class API
28
-
29
- ##
30
- # Creates a description of a particular version of a service.
31
- #
32
- # @param [String] api
33
- # The identifier for the service. Note that while this frequently
34
- # matches the first segment of all of the service's RPC names, this
35
- # should not be assumed. There is no requirement that these match.
36
- # @param [String] version
37
- # The identifier for the service version.
38
- # @param [Hash] api_description
39
- # The section of the discovery document that applies to this service
40
- # version.
41
- #
42
- # @return [Google::APIClient::API] The constructed service object.
43
- def initialize(document_base, discovery_document)
44
- @document_base = Addressable::URI.parse(document_base)
45
- @discovery_document = discovery_document
46
- metaclass = (class <<self; self; end)
47
- self.resources.each do |resource|
48
- method_name = Google::INFLECTOR.underscore(resource.name).to_sym
49
- if !self.respond_to?(method_name)
50
- metaclass.send(:define_method, method_name) { resource }
51
- end
52
- end
53
- self.methods.each do |method|
54
- method_name = Google::INFLECTOR.underscore(method.name).to_sym
55
- if !self.respond_to?(method_name)
56
- metaclass.send(:define_method, method_name) { method }
57
- end
58
- end
59
- end
60
-
61
- ##
62
- # Returns the id of the service.
63
- #
64
- # @return [String] The service id.
65
- def id
66
- return @discovery_document['id']
67
- end
68
-
69
- ##
70
- # Returns the identifier for the service.
71
- #
72
- # @return [String] The service identifier.
73
- def name
74
- return @discovery_document['name']
75
- end
76
-
77
- ##
78
- # Returns the version of the service.
79
- #
80
- # @return [String] The service version.
81
- def version
82
- return @discovery_document['version']
83
- end
84
-
85
- ##
86
- # Returns the parsed section of the discovery document that applies to
87
- # this version of the service.
88
- #
89
- # @return [Hash] The service description.
90
- def description
91
- return @discovery_document['description']
92
- end
93
-
94
- ##
95
- # Returns true if this is the preferred version of this API.
96
- #
97
- # @return [TrueClass, FalseClass]
98
- # Whether or not this is the preferred version of this API.
99
- def preferred
100
- return @discovery_document['preferred']
101
- end
102
-
103
- ##
104
- # Returns the base URI for the discovery document.
105
- #
106
- # @return [Addressable::URI] The base URI.
107
- attr_reader :document_base
108
-
109
- ##
110
- # Returns the base URI for this version of the service.
111
- #
112
- # @return [Addressable::URI] The base URI that methods are joined to.
113
- def method_base
114
- if @discovery_document['basePath']
115
- return @method_base ||= (
116
- self.document_base +
117
- Addressable::URI.parse(@discovery_document['basePath'])
118
- ).normalize
119
- else
120
- return nil
121
- end
122
- end
123
-
124
- ##
125
- # Updates the hierarchy of resources and methods with the new base.
126
- #
127
- # @param [Addressable::URI, #to_str, String] new_base
128
- # The new base URI to use for the service.
129
- def method_base=(new_method_base)
130
- @method_base = Addressable::URI.parse(new_method_base)
131
- self.resources.each do |resource|
132
- resource.method_base = @method_base
133
- end
134
- self.methods.each do |method|
135
- method.method_base = @method_base
136
- end
137
- end
138
-
139
- ##
140
- # A list of resources available at the root level of this version of the
141
- # service.
142
- #
143
- # @return [Array] A list of {Google::APIClient::Resource} objects.
144
- def resources
145
- return @resources ||= (
146
- (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
147
- accu << ::Google::APIClient::Resource.new(self.method_base, k, v)
148
- accu
149
- end
150
- )
151
- end
152
-
153
- ##
154
- # A list of methods available at the root level of this version of the
155
- # service.
156
- #
157
- # @return [Array] A list of {Google::APIClient::Method} objects.
158
- def methods
159
- return @methods ||= (
160
- (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
161
- accu << ::Google::APIClient::Method.new(self.method_base, k, v)
162
- accu
163
- end
164
- )
165
- end
166
-
167
- ##
168
- # Converts the service to a flat mapping of RPC names and method objects.
169
- #
170
- # @return [Hash] All methods available on the service.
171
- #
172
- # @example
173
- # # Discover available methods
174
- # method_names = client.discovered_api('buzz').to_h.keys
175
- def to_h
176
- return @hash ||= (begin
177
- methods_hash = {}
178
- self.methods.each do |method|
179
- methods_hash[method.id] = method
180
- end
181
- self.resources.each do |resource|
182
- methods_hash.merge!(resource.to_h)
183
- end
184
- methods_hash
185
- end)
186
- end
187
-
188
- ##
189
- # Returns a <code>String</code> representation of the service's state.
190
- #
191
- # @return [String] The service's state, as a <code>String</code>.
192
- def inspect
193
- sprintf(
194
- "#<%s:%#0x ID:%s>", self.class.to_s, self.object_id, self.id
195
- )
196
- end
197
- end
198
-
199
- ##
200
- # A resource that has been described by a discovery document.
201
- class Resource
202
-
203
- ##
204
- # Creates a description of a particular version of a resource.
205
- #
206
- # @param [Addressable::URI] base
207
- # The base URI for the service.
208
- # @param [String] resource_name
209
- # The identifier for the resource.
210
- # @param [Hash] resource_description
211
- # The section of the discovery document that applies to this resource.
212
- #
213
- # @return [Google::APIClient::Resource] The constructed resource object.
214
- def initialize(method_base, resource_name, discovery_document)
215
- @method_base = method_base
216
- @name = resource_name
217
- @discovery_document = discovery_document
218
- metaclass = (class <<self; self; end)
219
- self.resources.each do |resource|
220
- method_name = Google::INFLECTOR.underscore(resource.name).to_sym
221
- if !self.respond_to?(method_name)
222
- metaclass.send(:define_method, method_name) { resource }
223
- end
224
- end
225
- self.methods.each do |method|
226
- method_name = Google::INFLECTOR.underscore(method.name).to_sym
227
- if !self.respond_to?(method_name)
228
- metaclass.send(:define_method, method_name) { method }
229
- end
230
- end
231
- end
232
-
233
- ##
234
- # Returns the identifier for the resource.
235
- #
236
- # @return [String] The resource identifier.
237
- attr_reader :name
238
-
239
- ##
240
- # Returns the parsed section of the discovery document that applies to
241
- # this resource.
242
- #
243
- # @return [Hash] The resource description.
244
- attr_reader :description
245
-
246
- ##
247
- # Returns the base URI for this resource.
248
- #
249
- # @return [Addressable::URI] The base URI that methods are joined to.
250
- attr_reader :method_base
251
-
252
- ##
253
- # Updates the hierarchy of resources and methods with the new base.
254
- #
255
- # @param [Addressable::URI, #to_str, String] new_base
256
- # The new base URI to use for the resource.
257
- def method_base=(new_method_base)
258
- @method_base = Addressable::URI.parse(new_method_base)
259
- self.resources.each do |resource|
260
- resource.method_base = @method_base
261
- end
262
- self.methods.each do |method|
263
- method.method_base = @method_base
264
- end
265
- end
266
-
267
- ##
268
- # A list of sub-resources available on this resource.
269
- #
270
- # @return [Array] A list of {Google::APIClient::Resource} objects.
271
- def resources
272
- return @resources ||= (
273
- (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
274
- accu << ::Google::APIClient::Resource.new(self.method_base, k, v)
275
- accu
276
- end
277
- )
278
- end
279
-
280
- ##
281
- # A list of methods available on this resource.
282
- #
283
- # @return [Array] A list of {Google::APIClient::Method} objects.
284
- def methods
285
- return @methods ||= (
286
- (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
287
- accu << ::Google::APIClient::Method.new(self.method_base, k, v)
288
- accu
289
- end
290
- )
291
- end
292
-
293
- ##
294
- # Converts the resource to a flat mapping of RPC names and method
295
- # objects.
296
- #
297
- # @return [Hash] All methods available on the resource.
298
- def to_h
299
- return @hash ||= (begin
300
- methods_hash = {}
301
- self.methods.each do |method|
302
- methods_hash[method.id] = method
303
- end
304
- self.resources.each do |resource|
305
- methods_hash.merge!(resource.to_h)
306
- end
307
- methods_hash
308
- end)
309
- end
310
-
311
- ##
312
- # Returns a <code>String</code> representation of the resource's state.
313
- #
314
- # @return [String] The resource's state, as a <code>String</code>.
315
- def inspect
316
- sprintf(
317
- "#<%s:%#0x NAME:%s>", self.class.to_s, self.object_id, self.name
318
- )
319
- end
320
- end
321
-
322
- ##
323
- # A method that has been described by a discovery document.
324
- class Method
325
-
326
- ##
327
- # Creates a description of a particular method.
328
- #
329
- # @param [Addressable::URI] method_base
330
- # The base URI for the service.
331
- # @param [String] method_name
332
- # The identifier for the method.
333
- # @param [Hash] method_description
334
- # The section of the discovery document that applies to this method.
335
- #
336
- # @return [Google::APIClient::Method] The constructed method object.
337
- def initialize(method_base, method_name, discovery_document)
338
- @method_base = method_base
339
- @name = method_name
340
- @discovery_document = discovery_document
341
- end
342
-
343
- ##
344
- # Returns the identifier for the method.
345
- #
346
- # @return [String] The method identifier.
347
- attr_reader :name
348
-
349
- ##
350
- # Returns the parsed section of the discovery document that applies to
351
- # this method.
352
- #
353
- # @return [Hash] The method description.
354
- attr_reader :description
355
-
356
- ##
357
- # Returns the base URI for the method.
358
- #
359
- # @return [Addressable::URI]
360
- # The base URI that this method will be joined to.
361
- attr_reader :method_base
362
-
363
- ##
364
- # Updates the method with the new base.
365
- #
366
- # @param [Addressable::URI, #to_str, String] new_base
367
- # The new base URI to use for the method.
368
- def method_base=(new_method_base)
369
- @method_base = Addressable::URI.parse(new_method_base)
370
- @uri_template = nil
371
- end
372
-
373
- ##
374
- # Returns the method ID.
375
- #
376
- # @return [String] The method identifier.
377
- def id
378
- return @discovery_document['id']
379
- end
380
-
381
- ##
382
- # Returns the URI template for the method. A parameter list can be
383
- # used to expand this into a URI.
384
- #
385
- # @return [Addressable::Template] The URI template.
386
- def uri_template
387
- # TODO(bobaman) We shouldn't be calling #to_s here, this should be
388
- # a join operation on a URI, but we have to treat these as Strings
389
- # because of the way the discovery document provides the URIs.
390
- # This should be fixed soon.
391
- return @uri_template ||= Addressable::Template.new(
392
- self.method_base + @discovery_document['path']
393
- )
394
- end
395
-
396
- ##
397
- # Normalizes parameters, converting to the appropriate types.
398
- #
399
- # @param [Hash, Array] parameters
400
- # The parameters to normalize.
401
- #
402
- # @return [Hash] The normalized parameters.
403
- def normalize_parameters(parameters={})
404
- # Convert keys to Strings when appropriate
405
- if parameters.kind_of?(Hash) || parameters.kind_of?(Array)
406
- # Is a Hash or an Array a better return type? Do we ever need to
407
- # worry about the same parameter being sent twice with different
408
- # values?
409
- parameters = parameters.inject({}) do |accu, (k, v)|
410
- k = k.to_s if k.kind_of?(Symbol)
411
- k = k.to_str if k.respond_to?(:to_str)
412
- unless k.kind_of?(String)
413
- raise TypeError, "Expected String, got #{k.class}."
414
- end
415
- accu[k] = v
416
- accu
417
- end
418
- else
419
- raise TypeError,
420
- "Expected Hash or Array, got #{parameters.class}."
421
- end
422
- return parameters
423
- end
424
-
425
- ##
426
- # Expands the method's URI template using a parameter list.
427
- #
428
- # @param [Hash, Array] parameters
429
- # The parameter list to use.
430
- #
431
- # @return [Addressable::URI] The URI after expansion.
432
- def generate_uri(parameters={})
433
- parameters = self.normalize_parameters(parameters)
434
- self.validate_parameters(parameters)
435
- template_variables = self.uri_template.variables
436
- uri = self.uri_template.expand(parameters)
437
- query_parameters = parameters.reject do |k, v|
438
- template_variables.include?(k)
439
- end
440
- if query_parameters.size > 0
441
- uri.query_values = (uri.query_values || {}).merge(query_parameters)
442
- end
443
- # Normalization is necessary because of undesirable percent-escaping
444
- # during URI template expansion
445
- return uri.normalize
446
- end
447
-
448
- ##
449
- # Generates an HTTP request for this method.
450
- #
451
- # @param [Hash, Array] parameters
452
- # The parameters to send.
453
- # @param [String, StringIO] body The body for the HTTP request.
454
- # @param [Hash, Array] headers The HTTP headers for the request.
455
- #
456
- # @return [Array] The generated HTTP request.
457
- def generate_request(parameters={}, body='', headers=[])
458
- if body.respond_to?(:string)
459
- body = body.string
460
- elsif body.respond_to?(:to_str)
461
- body = body.to_str
462
- else
463
- raise TypeError, "Expected String or StringIO, got #{body.class}."
464
- end
465
- if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
466
- raise TypeError, "Expected Hash or Array, got #{headers.class}."
467
- end
468
- method = @discovery_document['httpMethod'] || 'GET'
469
- uri = self.generate_uri(parameters)
470
- headers = headers.to_a if headers.kind_of?(Hash)
471
- return [method, uri.to_str, headers, [body]]
472
- end
473
-
474
- ##
475
- # Returns a <code>Hash</code> of the parameter descriptions for
476
- # this method.
477
- #
478
- # @return [Hash] The parameter descriptions.
479
- def parameter_descriptions
480
- @parameter_descriptions ||= (
481
- @discovery_document['parameters'] || {}
482
- ).inject({}) { |h,(k,v)| h[k]=v; h }
483
- end
484
-
485
- ##
486
- # Returns an <code>Array</code> of the parameters for this method.
487
- #
488
- # @return [Array] The parameters.
489
- def parameters
490
- @parameters ||= ((
491
- @discovery_document['parameters'] || {}
492
- ).inject({}) { |h,(k,v)| h[k]=v; h }).keys
493
- end
494
-
495
- ##
496
- # Returns an <code>Array</code> of the required parameters for this
497
- # method.
498
- #
499
- # @return [Array] The required parameters.
500
- #
501
- # @example
502
- # # A list of all required parameters.
503
- # method.required_parameters
504
- def required_parameters
505
- @required_parameters ||= ((self.parameter_descriptions.select do |k, v|
506
- v['required']
507
- end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
508
- end
509
-
510
- ##
511
- # Returns an <code>Array</code> of the optional parameters for this
512
- # method.
513
- #
514
- # @return [Array] The optional parameters.
515
- #
516
- # @example
517
- # # A list of all optional parameters.
518
- # method.optional_parameters
519
- def optional_parameters
520
- @optional_parameters ||= ((self.parameter_descriptions.reject do |k, v|
521
- v['required']
522
- end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
523
- end
524
-
525
- ##
526
- # Verifies that the parameters are valid for this method. Raises an
527
- # exception if validation fails.
528
- #
529
- # @param [Hash, Array] parameters
530
- # The parameters to verify.
531
- #
532
- # @return [NilClass] <code>nil</code> if validation passes.
533
- def validate_parameters(parameters={})
534
- parameters = self.normalize_parameters(parameters)
535
- required_variables = ((self.parameter_descriptions.select do |k, v|
536
- v['required']
537
- end).inject({}) { |h,(k,v)| h[k]=v; h }).keys
538
- missing_variables = required_variables - parameters.keys
539
- if missing_variables.size > 0
540
- raise ArgumentError,
541
- "Missing required parameters: #{missing_variables.join(', ')}."
542
- end
543
- parameters.each do |k, v|
544
- if self.parameter_descriptions[k]
545
- enum = self.parameter_descriptions[k]['enum']
546
- if enum && !enum.include?(v)
547
- raise ArgumentError,
548
- "Parameter '#{k}' has an invalid value: #{v}. " +
549
- "Must be one of #{enum.inspect}."
550
- end
551
- pattern = self.parameter_descriptions[k]['pattern']
552
- if pattern
553
- regexp = Regexp.new("^#{pattern}$")
554
- if v !~ regexp
555
- raise ArgumentError,
556
- "Parameter '#{k}' has an invalid value: #{v}. " +
557
- "Must match: /^#{pattern}$/."
558
- end
559
- end
560
- end
561
- end
562
- return nil
563
- end
564
-
565
- ##
566
- # Returns a <code>String</code> representation of the method's state.
567
- #
568
- # @return [String] The method's state, as a <code>String</code>.
569
- def inspect
570
- sprintf(
571
- "#<%s:%#0x ID:%s>",
572
- self.class.to_s, self.object_id, self.id
573
- )
574
- end
575
- end
576
- end
577
- end
16
+ require 'google/api_client/discovery/api'
17
+ require 'google/api_client/discovery/resource'
18
+ require 'google/api_client/discovery/method'
19
+ require 'google/api_client/discovery/schema'