google-api-client 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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'