Allow automatic method name clash resolution (#605)
If the method name is generated from the request type, there is a possibility of a clash if two methods take the same request type. For example, if two unique methods take the request type "CreateRoleRequest", both methods will be generated with the method name "create_role", which causes generation to fail with an exception. This commit resolves that issue by first generating a method name from the request type of each method, and keeping track of which names are duplicates. For methods that will generate a duplicate name from the request type, the name is generated from the method ID instead (the resulting name is guaranteed to be unique).
This commit is contained in:
parent
8e701f7f41
commit
b87af01703
|
@ -27,8 +27,9 @@ module Google
|
||||||
Discovery = Google::Apis::DiscoveryV1
|
Discovery = Google::Apis::DiscoveryV1
|
||||||
|
|
||||||
# Load templates
|
# Load templates
|
||||||
def initialize(api_names: nil)
|
def initialize(api_names: nil, api_names_out: nil)
|
||||||
@names = Google::Apis::Generator::Names.new(api_names || File.join(Google::Apis::ROOT, 'api_names.yaml'))
|
@names = Google::Apis::Generator::Names.new(api_names_out || File.join(Google::Apis::ROOT, 'api_names_out.yaml'),
|
||||||
|
api_names || File.join(Google::Apis::ROOT, 'api_names.yaml'))
|
||||||
@module_template = Template.load('module.rb')
|
@module_template = Template.load('module.rb')
|
||||||
@service_template = Template.load('service.rb')
|
@service_template = Template.load('service.rb')
|
||||||
@classes_template = Template.load('classes.rb')
|
@classes_template = Template.load('classes.rb')
|
||||||
|
|
|
@ -41,13 +41,17 @@ module Google
|
||||||
include Google::Apis::Core::Logging
|
include Google::Apis::Core::Logging
|
||||||
include NameHelpers
|
include NameHelpers
|
||||||
|
|
||||||
def initialize(file_path = nil)
|
def initialize(names_out_file_path = nil, names_file_path = nil)
|
||||||
if file_path
|
if names_out_file_path
|
||||||
logger.info { sprintf('Loading API names from %s', file_path) }
|
logger.info { sprintf('Loading API names from %s', names_out_file_path) }
|
||||||
@names = YAML.load(File.read(file_path)) || {}
|
@names = YAML.load(File.read(names_out_file_path)) || {}
|
||||||
else
|
else
|
||||||
@names = {}
|
@names = {}
|
||||||
end
|
end
|
||||||
|
if names_file_path
|
||||||
|
logger.info { sprintf('Loading API names from %s', names_file_path) }
|
||||||
|
@names = @names.merge(YAML.load(File.read(names_file_path)) || {})
|
||||||
|
end
|
||||||
@path = []
|
@path = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -64,13 +68,6 @@ module Google
|
||||||
pick_name(normalize_param_name(@path.last))
|
pick_name(normalize_param_name(@path.last))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Determine the ruby method name to generate for a given method in discovery.
|
|
||||||
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
|
||||||
# Fragment of the discovery doc describing the method
|
|
||||||
def infer_method_name(method)
|
|
||||||
pick_name(infer_method_name_for_rpc(method) || infer_method_name_from_id(method))
|
|
||||||
end
|
|
||||||
|
|
||||||
def infer_property_name
|
def infer_property_name
|
||||||
pick_name(normalize_property_name(@path.last))
|
pick_name(normalize_property_name(@path.last))
|
||||||
end
|
end
|
||||||
|
@ -85,6 +82,10 @@ module Google
|
||||||
preferred_name
|
preferred_name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def [](key)
|
||||||
|
@names[key]
|
||||||
|
end
|
||||||
|
|
||||||
def []=(key, value)
|
def []=(key, value)
|
||||||
@names[key] = value
|
@names[key] = value
|
||||||
end
|
end
|
||||||
|
@ -101,12 +102,11 @@ module Google
|
||||||
@names[sprintf('%s?%s', key, opt_name)]
|
@names[sprintf('%s?%s', key, opt_name)]
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
# For RPC style methods, pick a name based off the request objects.
|
# For RPC style methods, pick a name based off the request objects.
|
||||||
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
# @param [Google::Apis::DiscoveryV1::RestMethod] method
|
||||||
|
# @param [Boolean] pick_name
|
||||||
# Fragment of the discovery doc describing the method
|
# Fragment of the discovery doc describing the method
|
||||||
def infer_method_name_for_rpc(method)
|
def infer_method_name_for_rpc(method, pick_name = true)
|
||||||
return nil if method.request.nil?
|
return nil if method.request.nil?
|
||||||
parts = method.id.split('.')
|
parts = method.id.split('.')
|
||||||
parts.shift
|
parts.shift
|
||||||
|
@ -122,8 +122,12 @@ module Google
|
||||||
name = name.split('_').insert(1, resource_name).join('_')
|
name = name.split('_').insert(1, resource_name).join('_')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if pick_name
|
||||||
|
pick_name(name)
|
||||||
|
else
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# For REST style methods, build a method name from the verb/resource(s) in the method
|
# For REST style methods, build a method name from the verb/resource(s) in the method
|
||||||
# id. IDs are in the form <api>.<resource>.<verb>
|
# id. IDs are in the form <api>.<resource>.<verb>
|
||||||
|
@ -149,7 +153,7 @@ module Google
|
||||||
end.join('_') + '_' + resource_name
|
end.join('_') + '_' + resource_name
|
||||||
end
|
end
|
||||||
method_name = verb.split('_').insert(1, resource_path.split('_')).join('_')
|
method_name = verb.split('_').insert(1, resource_path.split('_')).join('_')
|
||||||
method_name
|
pick_name(method_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -180,9 +184,33 @@ module Google
|
||||||
@deferred_types = []
|
@deferred_types = []
|
||||||
@strip_prefixes = []
|
@strip_prefixes = []
|
||||||
@all_methods = {}
|
@all_methods = {}
|
||||||
|
@dup_method_names_for_rpc = collect_dup_method_names_for_rpc
|
||||||
@path = []
|
@path = []
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def collect_method_names_for_rpc(resource, method_names_for_rpc)
|
||||||
|
resource.api_methods.each do |_k, v|
|
||||||
|
# First look for the method name in the `@names` hash. If there's
|
||||||
|
# no override set, generate it without inserting the generated name
|
||||||
|
# into the `@names` hash.
|
||||||
|
method_name_for_rpc = @names[@names.key]
|
||||||
|
if method_name_for_rpc.nil?
|
||||||
|
method_name_for_rpc = @names.infer_method_name_for_rpc(v, false)
|
||||||
|
end
|
||||||
|
method_names_for_rpc << method_name_for_rpc if method_name_for_rpc
|
||||||
|
end unless resource.api_methods.nil?
|
||||||
|
|
||||||
|
resource.resources.each do |_k, v|
|
||||||
|
collect_method_names_for_rpc(v, method_names_for_rpc)
|
||||||
|
end unless resource.resources.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def collect_dup_method_names_for_rpc
|
||||||
|
method_names_for_rpc = []
|
||||||
|
collect_method_names_for_rpc(@rest_description, method_names_for_rpc)
|
||||||
|
method_names_for_rpc.group_by{ |e| e }.select { |k, v| v.size > 1 }.map(&:first)
|
||||||
|
end
|
||||||
|
|
||||||
def annotate_api
|
def annotate_api
|
||||||
@names.with_path(@rest_description.id) do
|
@names.with_path(@rest_description.id) do
|
||||||
@strip_prefixes << @rest_description.name
|
@strip_prefixes << @rest_description.name
|
||||||
|
@ -240,7 +268,20 @@ module Google
|
||||||
def annotate_method(method, parent_resource = nil)
|
def annotate_method(method, parent_resource = nil)
|
||||||
@names.with_path(method.id) do
|
@names.with_path(method.id) do
|
||||||
method.parent = parent_resource
|
method.parent = parent_resource
|
||||||
method.generated_name = @names.infer_method_name(method)
|
# Grab the method name generated from the request object without
|
||||||
|
# inserting into, or querying, the names hash.
|
||||||
|
method_name_for_rpc = @names.infer_method_name_for_rpc(method, false)
|
||||||
|
# If `method_name_for_rpc` is a duplicate (more than one method in
|
||||||
|
# the API will generate this name), generate the method name from
|
||||||
|
# the method ID instead.
|
||||||
|
if @dup_method_names_for_rpc.include?(method_name_for_rpc)
|
||||||
|
method.generated_name = @names.infer_method_name_from_id(method)
|
||||||
|
# Otherwise, proceed as normal.
|
||||||
|
elsif method_name_for_rpc
|
||||||
|
method.generated_name = @names.infer_method_name_for_rpc(method)
|
||||||
|
else
|
||||||
|
method.generated_name = @names.infer_method_name_from_id(method)
|
||||||
|
end
|
||||||
check_duplicate_method(method)
|
check_duplicate_method(method)
|
||||||
annotate_parameters(method.parameters)
|
annotate_parameters(method.parameters)
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue