diff --git a/lib/google/api_client/discovery.rb b/lib/google/api_client/discovery.rb index 4a72acf60..bb01d67ce 100644 --- a/lib/google/api_client/discovery.rb +++ b/lib/google/api_client/discovery.rb @@ -16,3 +16,4 @@ require 'google/api_client/discovery/api' require 'google/api_client/discovery/resource' require 'google/api_client/discovery/method' +require 'google/api_client/discovery/schema' diff --git a/lib/google/api_client/discovery/api.rb b/lib/google/api_client/discovery/api.rb index 8d20310a9..6ee870462 100644 --- a/lib/google/api_client/discovery/api.rb +++ b/lib/google/api_client/discovery/api.rb @@ -135,15 +135,32 @@ module Google end end + ## + # A list of schemas available for this version of the API. + # + # @return [Hash] A list of {Google::APIClient::Schema} objects. + def schemas + return @schemas ||= ( + (@discovery_document['schemas'] || []).inject({}) do |accu, (k, v)| + accu[k] = Google::APIClient::Schema.new( + self, self.name, self.version, v + ) + accu + end + ) + end + ## # A list of resources available at the root level of this version of the - # service. + # API. # # @return [Array] A list of {Google::APIClient::Resource} objects. def resources return @resources ||= ( (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)| - accu << Google::APIClient::Resource.new(self.method_base, k, v) + accu << Google::APIClient::Resource.new( + self, self.method_base, k, v + ) accu end ) @@ -151,13 +168,13 @@ module Google ## # A list of methods available at the root level of this version of the - # service. + # API. # # @return [Array] A list of {Google::APIClient::Method} objects. def methods return @methods ||= ( (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)| - accu << Google::APIClient::Method.new(self.method_base, k, v) + accu << Google::APIClient::Method.new(self, self.method_base, k, v) accu end ) diff --git a/lib/google/api_client/discovery/method.rb b/lib/google/api_client/discovery/method.rb index de79bf752..945e4809a 100644 --- a/lib/google/api_client/discovery/method.rb +++ b/lib/google/api_client/discovery/method.rb @@ -35,7 +35,8 @@ module Google # The section of the discovery document that applies to this method. # # @return [Google::APIClient::Method] The constructed method object. - def initialize(method_base, method_name, discovery_document) + def initialize(api, method_base, method_name, discovery_document) + @api = api @method_base = method_base @name = method_name @discovery_document = discovery_document @@ -102,6 +103,32 @@ module Google ) end + ## + # Returns the Schema object for the method's request, if any. + # + # @return [Google::APIClient::Schema] The request schema. + def request_schema + if @discovery_document['request'] + schema_name = @discovery_document['request']['$ref'] + return @api.schemas[schema_name] + else + return nil + end + end + + ## + # Returns the Schema object for the method's response, if any. + # + # @return [Google::APIClient::Schema] The response schema. + def response_schema + if @discovery_document['response'] + schema_name = @discovery_document['response']['$ref'] + return @api.schemas[schema_name] + else + return nil + end + end + ## # Normalizes parameters, converting to the appropriate types. # diff --git a/lib/google/api_client/discovery/resource.rb b/lib/google/api_client/discovery/resource.rb index 6d2d6bddb..649ba3052 100644 --- a/lib/google/api_client/discovery/resource.rb +++ b/lib/google/api_client/discovery/resource.rb @@ -35,7 +35,8 @@ module Google # The section of the discovery document that applies to this resource. # # @return [Google::APIClient::Resource] The constructed resource object. - def initialize(method_base, resource_name, discovery_document) + def initialize(api, method_base, resource_name, discovery_document) + @api = api @method_base = method_base @name = resource_name @discovery_document = discovery_document @@ -95,7 +96,9 @@ module Google def resources return @resources ||= ( (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)| - accu << Google::APIClient::Resource.new(self.method_base, k, v) + accu << Google::APIClient::Resource.new( + @api, self.method_base, k, v + ) accu end ) @@ -108,7 +111,7 @@ module Google def methods return @methods ||= ( (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)| - accu << Google::APIClient::Method.new(self.method_base, k, v) + accu << Google::APIClient::Method.new(@api, self.method_base, k, v) accu end ) diff --git a/lib/google/api_client/discovery/schema.rb b/lib/google/api_client/discovery/schema.rb new file mode 100644 index 000000000..ecd09a809 --- /dev/null +++ b/lib/google/api_client/discovery/schema.rb @@ -0,0 +1,126 @@ +# Copyright 2010 Google Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +require 'json' +require 'addressable/uri' +require 'addressable/template' + +require 'google/inflection' +require 'google/api_client/errors' + +module Google + class APIClient + class Schema + def initialize(api, api_name, api_version, discovery_document) + # This constructor is super-long, but hard to break up due to the + # unavoidable dependence on closures and execution context. + @api = api + @discovery_document = discovery_document + api_name_string = + Google::INFLECTOR.camelize(api_name) + api_version_string = + Google::INFLECTOR.camelize(api_version).gsub('.', '_') + @schema_name = @discovery_document['id'] + if Google::APIClient::Schema.const_defined?(api_name_string) + @api_name = Google::APIClient::Schema.const_get(api_name_string) + else + @api_name = Google::APIClient::Schema.const_set( + api_name_string, Class.new + ) + end + if @api_name.const_defined?(api_version_string) + @api_version = @api_name.const_get(api_version_string) + else + @api_version = @api_name.const_set(api_version_string, Class.new) + end + if @api_version.const_defined?(@schema_name) + @schema_class = @api_version.const_get(@schema_name) + else + @schema_class = @api_version.const_set( + @schema_name, + Class.new(APIObject) do |klass| + discovery_document['properties'].each do |(k, v)| + property_name = Google::INFLECTOR.underscore(k) + define_method(property_name + '_property') do + v + end + case v['type'] + when 'string' + define_method(property_name) do + self[k] + end + define_method(property_name + '=') do |value| + if value.respond_to?(:to_str) + self[k] = value.to_str + elsif value.kind_of?(Symbol) + self[k] = value.to_s + else + raise TypeError, + "Expected String or Symbol, got #{value.class}." + end + end + else + # TODO(bobaman): + # Implement the remainder of the types. + + # Don't know what this is, default to anything goes. + define_method(property_name) do + self[k] + end + define_method(property_name + '=') do |value| + self[k] = value + end + end + end + end + ) + end + end + + def schema_name + return @schema_name + end + + def schema_class + return @schema_class + end + + ## + # Returns a String representation of the resource's state. + # + # @return [String] The resource's state, as a String. + def inspect + sprintf( + "#<%s:%#0x CLASS:%s>", + self.class.to_s, self.object_id, self.schema_class.name + ) + end + end + + class APIObject + def initialize(data) + @data = data + end + + def [](key) + return @data[key] + end + + def []=(key, value) + return @data[key] = value + end + end + end +end