diff --git a/docs/generators/crystal.md b/docs/generators/crystal.md index ba481b67e4da..ea2b3cc400db 100644 --- a/docs/generators/crystal.md +++ b/docs/generators/crystal.md @@ -94,7 +94,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • if
  • in
  • include
  • -
  • instance
  • +
  • instance_sizeof
  • is_a?
  • lib
  • macro
  • @@ -102,9 +102,11 @@ These options may be applied as additional-properties (cli) or configOptions (pl
  • next
  • nil
  • nil?
  • +
  • object_id
  • of
  • out
  • pointerof
  • +
  • previous_def
  • private
  • protected
  • require
  • diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java index f8bddd40330d..29bb9e09ab95 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CrystalClientCodegen.java @@ -29,8 +29,7 @@ import org.openapitools.codegen.model.OperationMap; import org.openapitools.codegen.model.OperationsMap; import org.openapitools.codegen.templating.mustache.PrefixWithHashLambda; -import org.openapitools.codegen.templating.mustache.UppercaseLambda; -import org.openapitools.codegen.templating.mustache.TitlecaseLambda; +import org.openapitools.codegen.templating.mustache.PascalCaseLambda; import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -85,28 +84,32 @@ public CrystalClientCodegen() { SecurityFeature.BasicAuth, SecurityFeature.BearerToken, SecurityFeature.ApiKey, - SecurityFeature.OAuth2_Implicit)) + SecurityFeature.OAuth2_Implicit + )) .excludeGlobalFeatures( GlobalFeature.XMLStructureDefinitions, GlobalFeature.Callbacks, GlobalFeature.LinkObjects, GlobalFeature.ParameterStyling, GlobalFeature.ParameterizedServer, - GlobalFeature.MultiServer) + GlobalFeature.MultiServer + ) .includeSchemaSupportFeatures( - SchemaSupportFeature.Polymorphism) + SchemaSupportFeature.Polymorphism + ) .excludeParameterFeatures( - ParameterFeature.Cookie) + ParameterFeature.Cookie + ) .includeClientModificationFeatures( ClientModificationFeature.BasePath, - ClientModificationFeature.UserAgent)); - - generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata) - .stability(Stability.BETA) - .build(); + ClientModificationFeature.UserAgent + ) + ); supportsInheritance = true; + generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata).stability(Stability.BETA).build(); + // clear import mapping (from default generator) as crystal does not use it // at the moment importMapping.clear(); @@ -130,19 +133,24 @@ public CrystalClientCodegen() { hideGenerationTimestamp = Boolean.TRUE; // reserved word. Ref: - // https://github.com/crystal-lang/crystal/wiki/Crystal-for-Rubyists#available-keywords + // https://crystal-lang.org/reference/1.18/crystal_for_rubyists/index.html#available-keywords + // https://crystal-lang.org/api/1.18.2/Reference.html reservedWords = new HashSet<>( Arrays.asList( - "abstract", "annotation", "do", "if", "nil?", "select", "union", - "alias", "else", "in", "of", "self", "unless", - "as", "elsif", "include", "out", "sizeof", "until", - "as?", "end", "instance", "sizeof", "pointerof", "struct", "verbatim", - "asm", "ensure", "is_a?", "private", "super", "when", - "begin", "enum", "lib", "protected", "then", "while", - "break", "extend", "macro", "require", "true", "with", - "case", "false", "module", "rescue", "type", "yield", - "class", "for", "next", "responds_to?", "typeof", - "def", "fun", "nil", "return", "uninitialized")); + // language reserved words (keywords) + "abstract", "do", "if", "nil?", "return", "uninitialized", + "alias", "else", "in", "of", "select", "union", + "as", "elsif", "include", "out", "self", "unless", + "as?", "end", "instance_sizeof", "pointerof", "sizeof", "until", + "asm", "ensure", "is_a?", "previous_def", "struct", "verbatim", + "begin", "enum", "lib", "private", "super", "when", + "break", "extend", "macro", "protected", "then", "while", + "case", "false", "module", "require", "true", "with", + "class", "for", "next", "rescue", "type", "yield", + "def", "fun", "nil", "responds_to?", "typeof", + // additional reserved words (methods) + "annotation", "object_id" + )); languageSpecificPrimitives.clear(); languageSpecificPrimitives.add("String"); @@ -174,8 +182,8 @@ public CrystalClientCodegen() { typeMapping.put("List", "Array"); typeMapping.put("set", "Set"); typeMapping.put("map", "Hash"); - typeMapping.put("object", "Object"); - typeMapping.put("AnyType", "Object"); + typeMapping.put("object", "JSON::Any"); + typeMapping.put("AnyType", "JSON::Any"); typeMapping.put("file", "::File"); typeMapping.put("binary", "String"); typeMapping.put("ByteArray", "String"); @@ -188,31 +196,18 @@ public CrystalClientCodegen() { primitiveTypes = new ArrayList(typeMapping.values()); // remove modelPackage and apiPackage added by default - cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) || - CodegenConstants.API_PACKAGE.equals(opt.getOpt())); + cliOptions.removeIf(opt -> CodegenConstants.MODEL_PACKAGE.equals(opt.getOpt()) || CodegenConstants.API_PACKAGE.equals(opt.getOpt())); cliOptions.add(new CliOption(SHARD_NAME, "shard name (e.g. twitter_client").defaultValue("openapi_client")); - cliOptions.add(new CliOption(MODULE_NAME, "module name (e.g. TwitterClient").defaultValue("OpenAPIClient")); - cliOptions.add(new CliOption(SHARD_VERSION, "shard version.").defaultValue("1.0.0")); - cliOptions.add(new CliOption(SHARD_LICENSE, "shard license.").defaultValue("unlicense")); - cliOptions.add(new CliOption(SHARD_HOMEPAGE, "shard homepage.").defaultValue("http://org.openapitools")); - cliOptions.add(new CliOption(SHARD_DESCRIPTION, "shard description.").defaultValue("This shard maps to a REST API")); - cliOptions.add(new CliOption(SHARD_AUTHOR, "shard author (only one is supported).")); - cliOptions.add(new CliOption(SHARD_AUTHOR_EMAIL, "shard author email (only one is supported).")); - - cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, - CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).defaultValue(Boolean.TRUE.toString())); - - cliOptions.add(new CliOption(PARAMS_ENCODER, - "params_encoder setting (e.g. Crest::NestedParamsEncoder, Crest::EnumeratedFlatParamsEncoder, Crest::ZeroEnumeratedFlatParamsEncoder"). - defaultValue("Crest::NestedParamsEncoder")); + cliOptions.add(new CliOption(CodegenConstants.HIDE_GENERATION_TIMESTAMP, CodegenConstants.HIDE_GENERATION_TIMESTAMP_DESC).defaultValue(Boolean.TRUE.toString())); + cliOptions.add(new CliOption(PARAMS_ENCODER, "params_encoder setting (e.g. Crest::NestedParamsEncoder, Crest::EnumeratedFlatParamsEncoder, Crest::ZeroEnumeratedFlatParamsEncoder").defaultValue("Crest::NestedParamsEncoder")); } @Override @@ -220,51 +215,63 @@ public void processOpts() { super.processOpts(); if (StringUtils.isEmpty(System.getenv("CRYSTAL_POST_PROCESS_FILE"))) { - LOGGER.info( - "Hint: Environment variable 'CRYSTAL_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export CRYSTAL_POST_PROCESS_FILE=\"/usr/local/bin/crystal tool format\"' (Linux/Mac)"); + LOGGER.info("Hint: Environment variable 'CRYSTAL_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export CRYSTAL_POST_PROCESS_FILE=\"/usr/local/bin/crystal tool format\"' (Linux/Mac)"); } else if (!this.isEnablePostProcessFile()) { LOGGER.info("Warning: Environment variable 'CRYSTAL_POST_PROCESS_FILE' is set but file post-processing is not enabled. To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI)."); } if (additionalProperties.containsKey(SHARD_NAME)) { setShardName((String) additionalProperties.get(SHARD_NAME)); + } else { + additionalProperties.put(SHARD_NAME, shardName); } - additionalProperties.put(SHARD_NAME, shardName); if (additionalProperties.containsKey(MODULE_NAME)) { setModuleName((String) additionalProperties.get(MODULE_NAME)); + } else { + additionalProperties.put(MODULE_NAME, moduleName); } - additionalProperties.put(MODULE_NAME, moduleName); if (additionalProperties.containsKey(SHARD_VERSION)) { setShardVersion((String) additionalProperties.get(SHARD_VERSION)); } else { - // not set, pass the default value to template additionalProperties.put(SHARD_VERSION, shardVersion); } if (additionalProperties.containsKey(SHARD_LICENSE)) { setShardLicense((String) additionalProperties.get(SHARD_LICENSE)); + } else { + additionalProperties.put(SHARD_LICENSE, shardLicense); } if (additionalProperties.containsKey(SHARD_HOMEPAGE)) { setShardHomepage((String) additionalProperties.get(SHARD_HOMEPAGE)); + } else { + additionalProperties.put(SHARD_HOMEPAGE, shardHomepage); } if (additionalProperties.containsKey(SHARD_SUMMARY)) { setShardSummary((String) additionalProperties.get(SHARD_SUMMARY)); + } else { + additionalProperties.put(SHARD_SUMMARY, shardSummary); } if (additionalProperties.containsKey(SHARD_DESCRIPTION)) { setShardDescription((String) additionalProperties.get(SHARD_DESCRIPTION)); + } else { + additionalProperties.put(SHARD_DESCRIPTION, shardDescription); } if (additionalProperties.containsKey(SHARD_AUTHOR)) { setShardAuthor((String) additionalProperties.get(SHARD_AUTHOR)); + } else { + additionalProperties.put(SHARD_AUTHOR, shardAuthor); } if (additionalProperties.containsKey(SHARD_AUTHOR_EMAIL)) { setShardAuthorEmail((String) additionalProperties.get(SHARD_AUTHOR_EMAIL)); + } else { + additionalProperties.put(SHARD_AUTHOR_EMAIL, shardAuthorEmail); } if (additionalProperties.containsKey(PARAMS_ENCODER)) { @@ -290,18 +297,14 @@ public void processOpts() { supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); supportingFiles.add(new SupportingFile("git_push.sh.mustache", "", "git_push.sh")); supportingFiles.add(new SupportingFile("gitignore.mustache", "", ".gitignore")); - supportingFiles.add(new SupportingFile("travis.mustache", "", ".travis.yml")); supportingFiles.add(new SupportingFile("shard.mustache", "", "shard.yml")); // crystal spec files - supportingFiles.add(new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.cr") - .doNotOverwrite()); + supportingFiles.add(new SupportingFile("spec_helper.mustache", specFolder, "spec_helper.cr").doNotOverwrite()); // add lambda for mustache templates additionalProperties.put("lambdaPrefixWithHash", new PrefixWithHashLambda()); - additionalProperties.put("lambdaUppercase", new UppercaseLambda()); - additionalProperties.put("lambdaTitlecase", new TitlecaseLambda()); - + additionalProperties.put("lambdaPascalcase", new PascalCaseLambda()); } @Override @@ -321,14 +324,12 @@ public String getName() { @Override public String apiFileFolder() { - return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator - + apiPackage.replace("/", File.separator); + return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + apiPackage.replace("/", File.separator); } @Override public String modelFileFolder() { - return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator - + modelPackage.replace("/", File.separator); + return outputFolder + File.separator + srcFolder + File.separator + shardName + File.separator + modelPackage.replace("/", File.separator); } @Override @@ -407,9 +408,9 @@ public String toModelName(final String name) { // model name starts with number if (modelName.matches("^\\d.*")) { - LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", modelName, - camelize("model_" + modelName)); - modelName = "model_" + modelName; // e.g. 200Response => Model200Response (after camelize) + LOGGER.warn("{} (model name starts with number) cannot be used as model name. Renamed to {}", modelName, camelize("model_" + modelName)); + // e.g. 200Response => Model200Response (after camelize) + modelName = "model_" + modelName; } // camelize the model name @@ -548,8 +549,7 @@ public String toOperationId(String operationId) { // operationId starts with a number if (operationId.matches("^\\d.*")) { - LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, - underscore(sanitizeName("call_" + operationId))); + LOGGER.warn("{} (starting with a number) cannot be used as method name. Renamed to {}", operationId, underscore(sanitizeName("call_" + operationId))); operationId = "call_" + operationId; } @@ -576,6 +576,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List modelMaps = ModelMap.toCodegenModelMap(allModels); HashMap processedModelMaps = new HashMap<>(); @@ -607,8 +608,7 @@ public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List modelMaps, - HashMap processedModelMap) { + private String constructExampleCode(CodegenParameter codegenParameter, HashMap modelMaps, HashMap processedModelMap) { if (codegenParameter.isArray) { // array if (codegenParameter.items == null) { return "[]"; @@ -675,8 +675,7 @@ private String constructExampleCode(CodegenParameter codegenParameter, HashMap modelMaps, - HashMap processedModelMap) { + private String constructExampleCode(CodegenProperty codegenProperty, HashMap modelMaps, HashMap processedModelMap) { if (codegenProperty.isArray) { // array return "[" + constructExampleCode(codegenProperty.items, modelMaps, processedModelMap) + "]"; } else if (codegenProperty.isMap) { @@ -743,8 +742,7 @@ private String constructExampleCode(CodegenProperty codegenProperty, HashMap modelMaps, - HashMap processedModelMap) { + private String constructExampleCode(CodegenModel codegenModel, HashMap modelMaps, HashMap processedModelMap) { // break infinite recursion. Return, in case a model is already processed in the // current context. String model = codegenModel.name; @@ -758,15 +756,24 @@ private String constructExampleCode(CodegenModel codegenModel, HashMap> enumVars = (List>) codegenModel.allowableValues - .get("enumVars"); + List> enumVars = (List>) codegenModel.allowableValues.get("enumVars"); return moduleName + "::" + codegenModel.classname + "::" + enumVars.get(0).get("name"); } else if (codegenModel.oneOf != null && !codegenModel.oneOf.isEmpty()) { String subModel = (String) codegenModel.oneOf.toArray()[0]; if (modelMaps.get(subModel) == null) { - LOGGER.warn("Cannot find codegen for SubModel: {} (model: {})", subModel, model); - return ""; + if (subModel.startsWith("Array(")) { + subModel = StringUtils.removeEnd(subModel.substring(6), ")"); + if (modelMaps.get(subModel) == null) { + LOGGER.warn("Cannot find codegen for SubModel: {} (model: {})", subModel, model); + return ""; + } else { + LOGGER.info("Found Array codegen for SubModel: {} (model: {})", subModel, model); + String oneOf = "[" + constructExampleCode(modelMaps.get(subModel), modelMaps, processedModelMap) + "]"; + return oneOf; + } + } } else { + LOGGER.info("Found codegen for SubModel: {} (model: {})", subModel, model); String oneOf = constructExampleCode(modelMaps.get(subModel), modelMaps, processedModelMap); return oneOf; } @@ -781,7 +788,7 @@ private String constructExampleCode(CodegenModel codegenModel, HashMap + * Register: + *
    + * additionalProperties.put("pascalcase", new PascalCaseLambda());
    + * 
    + *

    + * Use: + *

    + * {{#pascalcase}}{{name}}{{/pascalcase}}
    + * 
    + */ +public class PascalCaseLambda implements Mustache.Lambda { + public PascalCaseLambda() { + } + + @Override + public void execute(Template.Fragment fragment, Writer writer) throws IOException { + String text = fragment.execute(); + text = camelize(text); + writer.write(text); + } +} diff --git a/modules/openapi-generator/src/main/resources/crystal/api.mustache b/modules/openapi-generator/src/main/resources/crystal/api.mustache index 01a51a2d028f..fe6b5857f8d2 100644 --- a/modules/openapi-generator/src/main/resources/crystal/api.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/api.mustache @@ -159,25 +159,25 @@ module {{moduleName}} # http body (model) post_body = {{#bodyParam}}{{{paramName}}}.to_json{{/bodyParam}}{{^bodyParam}}nil{{/bodyParam}} - # return_type - return_type = {{#returnType}}"{{{.}}}"{{/returnType}}{{^returnType}}nil{{/returnType}} - # auth_names auth_names = {{#authMethods}}{{#-first}}[{{/-first}}"{{name}}"{{^-last}}, {{/-last}}{{#-last}}]{{/-last}}{{/authMethods}}{{^authMethods}}[] of String{{/authMethods}} - data, status_code, headers = @api_client.call_api(:{{httpMethod}}, - local_var_path, - :"{{classname}}.{{operationId}}", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :{{httpMethod}}, + path: local_var_path, + operation: :"{{classname}}.{{operationId}}", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: {{classname}}#{{operationId}}\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return {{#returnType}}{{{.}}}.from_json(data){{/returnType}}{{^returnType}}nil{{/returnType}}, status_code, headers end {{^-last}} diff --git a/modules/openapi-generator/src/main/resources/crystal/api_client.mustache b/modules/openapi-generator/src/main/resources/crystal/api_client.mustache index 3eff533c447a..dc3cb6872de3 100644 --- a/modules/openapi-generator/src/main/resources/crystal/api_client.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/api_client.mustache @@ -119,7 +119,7 @@ module {{moduleName}} # # @return [Array<(Object, Integer, Hash)>] an array of 3 elements: # the data deserialized from response body (could be nil), response status code and response headers. - def call_api(http_method : Symbol, path : String, operation : Symbol, return_type : String?, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File)) + def call_api(http_method : Symbol, path : String, operation : Symbol, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File)) #ssl_options = { # :ca_file => @config.ssl_ca_file, # :verify => @config.ssl_verify, @@ -139,8 +139,9 @@ module {{moduleName}} form_or_body = form_params end - request = Crest::Request.new(http_method, - build_request_url(path, operation), + request = Crest::Request.new( + method: http_method, + url: build_request_url(path, operation), params: query_params, headers: header_params, cookies: cookie_params, diff --git a/modules/openapi-generator/src/main/resources/crystal/base_object.mustache b/modules/openapi-generator/src/main/resources/crystal/base_object.mustache index 1256b0bfc53f..4ee4a276ca0f 100644 --- a/modules/openapi-generator/src/main/resources/crystal/base_object.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/base_object.mustache @@ -1,78 +1,3 @@ - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - {{#parent}} - super(attributes) - {{/parent}} - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = {{moduleName}}.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -100,6 +25,8 @@ # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/modules/openapi-generator/src/main/resources/crystal/model.mustache b/modules/openapi-generator/src/main/resources/crystal/model.mustache index 31cd656198f8..2de5ed1b7780 100644 --- a/modules/openapi-generator/src/main/resources/crystal/model.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/model.mustache @@ -1,10 +1,5 @@ # {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}} -require "big" -require "json" -require "yaml" -require "time" - module {{moduleName}} {{#models}} {{#model}} diff --git a/modules/openapi-generator/src/main/resources/crystal/partial_model_generic.mustache b/modules/openapi-generator/src/main/resources/crystal/partial_model_generic.mustache index 791a2084ddda..8d0ded604024 100644 --- a/modules/openapi-generator/src/main/resources/crystal/partial_model_generic.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/partial_model_generic.mustache @@ -56,7 +56,7 @@ {{#vars}} {{#isEnum}} {{^isContainer}} - class EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}} < EnumAttributeValidator + class EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}} < EnumAttributeValidator @attribute : String @allowable_values : Array(Int32 | Int64 | Float32 | Float64 | String) @@ -118,7 +118,7 @@ {{#vars}} {{#isEnum}} {{^isContainer}} - {{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new + {{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new if !{{{name}}}_validator.valid?(@{{{name}}}) message = {{{name}}}_validator.message invalid_properties.push(message) @@ -181,7 +181,7 @@ {{#vars}} {{#isEnum}} {{^isContainer}} - {{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new + {{{name}}}_validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new return false unless {{{name}}}_validator.valid?(@{{{name}}}) {{/isContainer}} {{/isEnum}} @@ -234,7 +234,7 @@ # Custom attribute writer method checking allowed values (enum). # @param [Object] {{{name}}} Object to be assigned def {{{name}}}=({{{name}}}) - validator = EnumAttributeValidatorFor{{#lambdaTitlecase}}{{{name}}}{{/lambdaTitlecase}}.new + validator = EnumAttributeValidatorFor{{#lambdaPascalcase}}{{{name}}}{{/lambdaPascalcase}}.new unless validator.valid?({{{name}}}) raise ArgumentError.new(validator.message) end diff --git a/modules/openapi-generator/src/main/resources/crystal/partial_oneof_module.mustache b/modules/openapi-generator/src/main/resources/crystal/partial_oneof_module.mustache index ffd0c190d313..f18cd6f6d9cd 100644 --- a/modules/openapi-generator/src/main/resources/crystal/partial_oneof_module.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/partial_oneof_module.mustache @@ -1,135 +1,104 @@ {{#description}} # {{{.}}} {{/description}} - module {{classname}} + class {{classname}} + include JSON::Serializable + include YAML::Serializable + + class SchemaMismatchError < Exception + end + {{#oneOf}} {{#-first}} # List of class defined in oneOf (OpenAPI v3) def self.openapi_one_of [ {{/-first}} - :"{{{.}}}"{{^-last}},{{/-last}} + {{{.}}}{{^-last}},{{/-last}} {{#-last}} ] end {{/-last}} {{/oneOf}} - {{#discriminator}} - {{#propertyName}} - # Discriminator's property name (OpenAPI v3) - def self.openapi_discriminator_name - :"{{{.}}}" - end - {{/propertyName}} - {{#mappedModels}} - {{#-first}} - # Discriminator's mapping (OpenAPI v3) - def self.openapi_discriminator_mapping - { - {{/-first}} - :"{{{mappingName}}}" => :"{{{modelName}}}"{{^-last}},{{/-last}} - {{#-last}} - } - end - - {{/-last}} - {{/mappedModels}} - {{/discriminator}} - # Builds the object - # @param [Mixed] Data to be matched against the list of oneOf items - # @return [Object] Returns the model or the data itself - def self.build(data) {{#discriminator}} - discriminator_value = data[openapi_discriminator_name] - return nil unless discriminator_value - {{#mappedModels}} - {{#-first}} - - klass = openapi_discriminator_mapping[discriminator_value.to_sym] - return nil unless klass - - {{moduleName}}.const_get(klass).build_from_hash(data) - {{/-first}} - {{/mappedModels}} - {{^mappedModels}} - {{moduleName}}.const_get(discriminator_value).build_from_hash(data) - {{/mappedModels}} + use_yaml_discriminator {{#propertyName}}"{{{.}}}"{{/propertyName}}, { + {{#mappedModels}}{{{mappingName}}}: {{{modelName}}}{{^-last}},{{/-last}}{{/mappedModels}} + } {{/discriminator}} - {{^discriminator}} - # Go through the list of oneOf items and attempt to identify the appropriate one. - # Note: - # - We do not attempt to check whether exactly one item matches. - # - No advanced validation of types in some cases (e.g. "x: { type: string }" will happily match { x: 123 }) - # due to the way the deserialization is made in the base_object template (it just casts without verifying). - # - TODO: scalar values are de facto behaving as if they were nullable. - # - TODO: logging when debugging is set. + + def self.build(data) openapi_one_of.each do |klass| begin - next if klass == :AnyType # "nullable: true" typed_data = find_and_cast_into_type(klass, data) return typed_data if typed_data - rescue # rescue all errors so we keep iterating even if the current item lookup raises + rescue ex + # rescue all errors so we keep iterating even if the current item lookup raises + Log.trace { ex.message } end end - openapi_one_of.includes?(:AnyType) ? data : nil - {{/discriminator}} + nil end - {{^discriminator}} - SchemaMismatchError = Class.new(StandardError) - - # Note: 'File' is missing here because in the regular case we get the data _after_ a call to JSON.parse. - private def self.find_and_cast_into_type(klass, data) + {{#oneOf}} + private def self.find_and_cast_into_type(klass : {{{.}}}.class, data) return if data.nil? - begin - case klass.to_s - when "Boolean" - return data if data.instance_of?(TrueClass) || data.instance_of?(FalseClass) - when "Float" - return data if data.instance_of?(Float) - when "Integer" - return data if data.instance_of?(Integer) - when "Time" - return Time.parse(data) - when "Date" - return Date.parse(data) - when "String" - return data if data.instance_of?(String) - when "Object" # "type: object" - return data if data.instance_of?(Hash) - when /\AArray<(?.+)>\z/ # "type: array" - if data.instance_of?(Array) - sub_type = Regexp.last_match[:sub_type] - return data.map { |item| find_and_cast_into_type(sub_type, item) } - end - when /\AHash.+)>\z/ # "type: object" with "additionalProperties: { ... }" - if data.instance_of?(Hash) && data.keys.all? { |k| k.instance_of?(Symbol) || k.instance_of?(String) } - sub_type = Regexp.last_match[:sub_type] - return data.each_with_object({} of String | Symbol => Bool | Float | Integer | Time | Date | String | Array | Hash) { |(k, v), hsh| hsh[k] = find_and_cast_into_type(sub_type, v) } - end - else # model - const = {{moduleName}}.const_get(klass) - if const - if const.respond_to?(:openapi_one_of) # nested oneOf model - model = const.build(data) - return model if model - else - # raise if data contains keys that are not known to the model - raise unless (data.keys - const.acceptable_attributes).empty? - model = const.build_from_hash(data) - return model if model && model.valid? - end - end + Log.trace { "INSPECTING DATA" } + Log.trace { data.inspect } + + case data + when NetboxClient::RecursiveHash + if value = cast_value(array_data: false, array_class: array_class?(klass), klass: klass, data: data) + return new(value) + end + when Array(NetboxClient::RecursiveHash) + if value = cast_value(array_data: true, array_class: array_class?(klass), klass: klass, data: data) + return new(value) end + else + raise SchemaMismatchError.new("#{data} doesn't match the #{klass} type") + end + end + {{/oneOf}} + + private def self.cast_value(array_data : Bool, array_class : Bool, klass, data) + if array_class == true && array_data == true + Log.debug { "Building array of classes: #{klass} / #{data}" } - raise # if no match by now, raise - rescue - raise SchemaMismatchError, "#{data} doesn't match the #{klass} type" + klass.from_json(data.to_json) + elsif array_class == false && array_data == false + Log.debug { "Building single class: #{klass} / #{data}" } + + klass.from_json(data.to_json) + end + end + + private def self.array_class?(klass) + klass.name.starts_with?("Array(") + end + + {{#oneOf}} + def initialize(@value : {{{.}}}) + end + + {{/oneOf}} + + delegate :to_yaml, to: @value + delegate :to_json, to: @value + + def to_any_h + {"value" => to_h} + end + + def to_h + val = @value + if val.is_a?(Int32) + val + else + val.to_h end end - {{/discriminator}} end diff --git a/modules/openapi-generator/src/main/resources/crystal/shard.mustache b/modules/openapi-generator/src/main/resources/crystal/shard.mustache index 6a1c86894e47..08a392a1a491 100644 --- a/modules/openapi-generator/src/main/resources/crystal/shard.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/shard.mustache @@ -1,10 +1,15 @@ name: {{{shardName}}} + version: {{{shardVersion}}} + authors: - {{{shardAuthors}}} + description: | - {{{ shardDescription}}} + crystal: ">= 0.35.1" + dependencies: any_hash: github: Sija/any_hash.cr @@ -13,9 +18,6 @@ dependencies: version: ~> 1.3.13 development_dependencies: - kemal: - github: kemalcr/kemal - version: ~>1.5.0 ameba: github: crystal-ameba/ameba spectator: diff --git a/modules/openapi-generator/src/main/resources/crystal/shard_name.mustache b/modules/openapi-generator/src/main/resources/crystal/shard_name.mustache index 16e645c5e66c..85e39816da44 100644 --- a/modules/openapi-generator/src/main/resources/crystal/shard_name.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/shard_name.mustache @@ -1,9 +1,15 @@ # {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}} -# Dependencies +# Stdlib dependencies +require "big" +require "json" +require "log" +require "time" +require "yaml" + +# External dependencies require "any_hash" require "crest" -require "log" module {{moduleName}} Log = ::Log.for("{{moduleName}}") # => Log for {{moduleName}} source diff --git a/modules/openapi-generator/src/main/resources/crystal/spec_helper.mustache b/modules/openapi-generator/src/main/resources/crystal/spec_helper.mustache index 98890dcc2462..2f89b5a69715 100644 --- a/modules/openapi-generator/src/main/resources/crystal/spec_helper.mustache +++ b/modules/openapi-generator/src/main/resources/crystal/spec_helper.mustache @@ -2,14 +2,4 @@ # load modules require "spectator" -require "json" -require "time" require "../src/{{{shardName}}}" - -def assert_compilation_error(path : String, message : String) : Nil - buffer = IO::Memory.new - result = Process.run("crystal", ["run", "--no-color", "--no-codegen", path], error: buffer) - result.success?.should be_false - buffer.to_s.should contain message - buffer.close -end diff --git a/modules/openapi-generator/src/main/resources/crystal/travis.mustache b/modules/openapi-generator/src/main/resources/crystal/travis.mustache deleted file mode 100644 index 21509cfe82ae..000000000000 --- a/modules/openapi-generator/src/main/resources/crystal/travis.mustache +++ /dev/null @@ -1,8 +0,0 @@ -# {{#lambdaPrefixWithHash}}{{> api_info}}{{/lambdaPrefixWithHash}} - -language: crystal - -script: - - crystal spec -# uncomment below to check the code format -# - crystal tool format --check diff --git a/samples/client/petstore/crystal/.openapi-generator/FILES b/samples/client/petstore/crystal/.openapi-generator/FILES index 30a8f1ce4b53..27f0b76ec782 100644 --- a/samples/client/petstore/crystal/.openapi-generator/FILES +++ b/samples/client/petstore/crystal/.openapi-generator/FILES @@ -1,5 +1,4 @@ .gitignore -.travis.yml README.md git_push.sh shard.yml diff --git a/samples/client/petstore/crystal/shard.yml b/samples/client/petstore/crystal/shard.yml index 583b30f688ab..966c45d917fd 100644 --- a/samples/client/petstore/crystal/shard.yml +++ b/samples/client/petstore/crystal/shard.yml @@ -1,10 +1,15 @@ name: petstore + version: 1.0.0 + authors: - + description: | - - + - This shard maps to a REST API + crystal: ">= 0.35.1" + dependencies: any_hash: github: Sija/any_hash.cr @@ -13,13 +18,10 @@ dependencies: version: ~> 1.3.13 development_dependencies: - kemal: - github: kemalcr/kemal - version: ~>1.5.0 ameba: github: crystal-ameba/ameba spectator: gitlab: arctic-fox/spectator version: ~> 0.12.0 -license: +license: unlicense diff --git a/samples/client/petstore/crystal/spec/spec_helper.cr b/samples/client/petstore/crystal/spec/spec_helper.cr index d1cb88f5a39a..6e10fb2392a0 100644 --- a/samples/client/petstore/crystal/spec/spec_helper.cr +++ b/samples/client/petstore/crystal/spec/spec_helper.cr @@ -10,14 +10,4 @@ # load modules require "spectator" -require "json" -require "time" require "../src/petstore" - -def assert_compilation_error(path : String, message : String) : Nil - buffer = IO::Memory.new - result = Process.run("crystal", ["run", "--no-color", "--no-codegen", path], error: buffer) - result.success?.should be_false - buffer.to_s.should contain message - buffer.close -end diff --git a/samples/client/petstore/crystal/src/petstore.cr b/samples/client/petstore/crystal/src/petstore.cr index 50599155e969..8c4accd94d4c 100644 --- a/samples/client/petstore/crystal/src/petstore.cr +++ b/samples/client/petstore/crystal/src/petstore.cr @@ -8,10 +8,16 @@ #Generator version: 7.19.0-SNAPSHOT # -# Dependencies +# Stdlib dependencies +require "big" +require "json" +require "log" +require "time" +require "yaml" + +# External dependencies require "any_hash" require "crest" -require "log" module Petstore Log = ::Log.for("Petstore") # => Log for Petstore source diff --git a/samples/client/petstore/crystal/src/petstore/api/fake_api.cr b/samples/client/petstore/crystal/src/petstore/api/fake_api.cr index aa1bf1bd4d3e..b6b6a2cf6306 100644 --- a/samples/client/petstore/crystal/src/petstore/api/fake_api.cr +++ b/samples/client/petstore/crystal/src/petstore/api/fake_api.cr @@ -83,25 +83,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"FakeApi.get_parameter_name_mapping", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"FakeApi.get_parameter_name_mapping", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: FakeApi#get_parameter_name_mapping\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end end diff --git a/samples/client/petstore/crystal/src/petstore/api/pet_api.cr b/samples/client/petstore/crystal/src/petstore/api/pet_api.cr index fa2be55965f9..07d5dd377865 100644 --- a/samples/client/petstore/crystal/src/petstore/api/pet_api.cr +++ b/samples/client/petstore/crystal/src/petstore/api/pet_api.cr @@ -60,25 +60,25 @@ module Petstore # http body (model) post_body = pet.to_json - # return_type - return_type = "Pet" - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"PetApi.add_pet", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"PetApi.add_pet", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#add_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Pet.from_json(data), status_code, headers end @@ -122,25 +122,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:DELETE, - local_var_path, - :"PetApi.delete_pet", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :DELETE, + path: local_var_path, + operation: :"PetApi.delete_pet", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#delete_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -186,25 +186,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "Array(Pet)" - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"PetApi.find_pets_by_status", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"PetApi.find_pets_by_status", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#find_pets_by_status\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Array(Pet).from_json(data), status_code, headers end @@ -250,25 +250,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "Array(Pet)" - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"PetApi.find_pets_by_tags", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"PetApi.find_pets_by_tags", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#find_pets_by_tags\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Array(Pet).from_json(data), status_code, headers end @@ -313,25 +313,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "Pet" - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"PetApi.get_pet_by_id", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"PetApi.get_pet_by_id", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#get_pet_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Pet.from_json(data), status_code, headers end @@ -378,25 +378,25 @@ module Petstore # http body (model) post_body = pet.to_json - # return_type - return_type = "Pet" - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:PUT, - local_var_path, - :"PetApi.update_pet", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :PUT, + path: local_var_path, + operation: :"PetApi.update_pet", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#update_pet\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Pet.from_json(data), status_code, headers end @@ -443,25 +443,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"PetApi.update_pet_with_form", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"PetApi.update_pet_with_form", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#update_pet_with_form\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -510,25 +510,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "ApiResponse" - # auth_names auth_names = ["petstore_auth"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"PetApi.upload_file", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"PetApi.upload_file", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: PetApi#upload_file\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return ApiResponse.from_json(data), status_code, headers end end diff --git a/samples/client/petstore/crystal/src/petstore/api/store_api.cr b/samples/client/petstore/crystal/src/petstore/api/store_api.cr index 3ece615e869f..97343d84835f 100644 --- a/samples/client/petstore/crystal/src/petstore/api/store_api.cr +++ b/samples/client/petstore/crystal/src/petstore/api/store_api.cr @@ -56,25 +56,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:DELETE, - local_var_path, - :"StoreApi.delete_order", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :DELETE, + path: local_var_path, + operation: :"StoreApi.delete_order", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: StoreApi#delete_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -113,25 +113,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "Hash(String, Int32)" - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"StoreApi.get_inventory", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"StoreApi.get_inventory", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: StoreApi#get_inventory\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Hash(String, Int32).from_json(data), status_code, headers end @@ -184,25 +184,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "Order" - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"StoreApi.get_order_by_id", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"StoreApi.get_order_by_id", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: StoreApi#get_order_by_id\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Order.from_json(data), status_code, headers end @@ -249,25 +249,25 @@ module Petstore # http body (model) post_body = order.to_json - # return_type - return_type = "Order" - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"StoreApi.place_order", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"StoreApi.place_order", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: StoreApi#place_order\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return Order.from_json(data), status_code, headers end end diff --git a/samples/client/petstore/crystal/src/petstore/api/user_api.cr b/samples/client/petstore/crystal/src/petstore/api/user_api.cr index 2f349cac381b..6eac08612c11 100644 --- a/samples/client/petstore/crystal/src/petstore/api/user_api.cr +++ b/samples/client/petstore/crystal/src/petstore/api/user_api.cr @@ -58,25 +58,25 @@ module Petstore # http body (model) post_body = user.to_json - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"UserApi.create_user", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"UserApi.create_user", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#create_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -121,25 +121,25 @@ module Petstore # http body (model) post_body = user.to_json - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"UserApi.create_users_with_array_input", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"UserApi.create_users_with_array_input", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#create_users_with_array_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -184,25 +184,25 @@ module Petstore # http body (model) post_body = user.to_json - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:POST, - local_var_path, - :"UserApi.create_users_with_list_input", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :POST, + path: local_var_path, + operation: :"UserApi.create_users_with_list_input", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#create_users_with_list_input\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -245,25 +245,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:DELETE, - local_var_path, - :"UserApi.delete_user", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :DELETE, + path: local_var_path, + operation: :"UserApi.delete_user", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#delete_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -308,25 +308,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "User" - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"UserApi.get_user_by_name", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"UserApi.get_user_by_name", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#get_user_by_name\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return User.from_json(data), status_code, headers end @@ -384,25 +384,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = "String" - # auth_names auth_names = [] of String - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"UserApi.login_user", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"UserApi.login_user", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#login_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return String.from_json(data), status_code, headers end @@ -439,25 +439,25 @@ module Petstore # http body (model) post_body = nil - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:GET, - local_var_path, - :"UserApi.logout_user", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :GET, + path: local_var_path, + operation: :"UserApi.logout_user", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#logout_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end @@ -508,25 +508,25 @@ module Petstore # http body (model) post_body = user.to_json - # return_type - return_type = nil - # auth_names auth_names = ["api_key"] - data, status_code, headers = @api_client.call_api(:PUT, - local_var_path, - :"UserApi.update_user", - return_type, - post_body, - auth_names, - header_params, - query_params, - cookie_params, - form_params) + data, status_code, headers = @api_client.call_api( + http_method: :PUT, + path: local_var_path, + operation: :"UserApi.update_user", + post_body: post_body, + auth_names: auth_names, + header_params: header_params, + query_params: query_params, + cookie_params: cookie_params, + form_params: form_params + ) + if @api_client.config.debugging Log.debug {"API called: UserApi#update_user\nData: #{data.inspect}\nStatus code: #{status_code}\nHeaders: #{headers}"} end + return nil, status_code, headers end end diff --git a/samples/client/petstore/crystal/src/petstore/api_client.cr b/samples/client/petstore/crystal/src/petstore/api_client.cr index 8f842e530009..3e62e6fea087 100644 --- a/samples/client/petstore/crystal/src/petstore/api_client.cr +++ b/samples/client/petstore/crystal/src/petstore/api_client.cr @@ -127,7 +127,7 @@ module Petstore # # @return [Array<(Object, Integer, Hash)>] an array of 3 elements: # the data deserialized from response body (could be nil), response status code and response headers. - def call_api(http_method : Symbol, path : String, operation : Symbol, return_type : String?, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File)) + def call_api(http_method : Symbol, path : String, operation : Symbol, post_body : String?, auth_names = [] of String, header_params = {} of String => String, query_params = {} of String => String, cookie_params = {} of String => String, form_params = {} of Symbol => (String | ::File)) #ssl_options = { # :ca_file => @config.ssl_ca_file, # :verify => @config.ssl_verify, @@ -147,8 +147,9 @@ module Petstore form_or_body = form_params end - request = Crest::Request.new(http_method, - build_request_url(path, operation), + request = Crest::Request.new( + method: http_method, + url: build_request_url(path, operation), params: query_params, headers: header_params, cookies: cookie_params, diff --git a/samples/client/petstore/crystal/src/petstore/models/another_property_name_mapping.cr b/samples/client/petstore/crystal/src/petstore/models/another_property_name_mapping.cr index d670a1266a57..da09d66dcd7e 100644 --- a/samples/client/petstore/crystal/src/petstore/models/another_property_name_mapping.cr +++ b/samples/client/petstore/crystal/src/petstore/models/another_property_name_mapping.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore class AnotherPropertyNameMapping include JSON::Serializable @@ -72,78 +67,6 @@ module Petstore [http_debug_operation, underscore_type, _type, type_with_underscore].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -172,6 +95,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/api_response.cr b/samples/client/petstore/crystal/src/petstore/models/api_response.cr index 2ae4be110740..e5235921eb68 100644 --- a/samples/client/petstore/crystal/src/petstore/models/api_response.cr +++ b/samples/client/petstore/crystal/src/petstore/models/api_response.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # Describes the result of uploading an image resource class ApiResponse @@ -69,78 +64,6 @@ module Petstore [code, _type, message].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -168,6 +91,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/category.cr b/samples/client/petstore/crystal/src/petstore/models/category.cr index fefff9d8fed4..7618edd3b95f 100644 --- a/samples/client/petstore/crystal/src/petstore/models/category.cr +++ b/samples/client/petstore/crystal/src/petstore/models/category.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # A category for a pet class Category @@ -82,78 +77,6 @@ module Petstore [id, name].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -180,6 +103,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/format_test.cr b/samples/client/petstore/crystal/src/petstore/models/format_test.cr index 3e36ff41c4ef..1e5736eef5a9 100644 --- a/samples/client/petstore/crystal/src/petstore/models/format_test.cr +++ b/samples/client/petstore/crystal/src/petstore/models/format_test.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore class FormatTest include JSON::Serializable @@ -318,78 +313,6 @@ module Petstore [integer, int32, int64, number, float, double, decimal, string, byte, binary, date, date_time, uuid, password, pattern_with_digits, pattern_with_digits_and_delimiter].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -430,6 +353,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/order.cr b/samples/client/petstore/crystal/src/petstore/models/order.cr index bbb55de5e90e..faa2ad6958ef 100644 --- a/samples/client/petstore/crystal/src/petstore/models/order.cr +++ b/samples/client/petstore/crystal/src/petstore/models/order.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # An order for a pets from the pet store class Order @@ -136,78 +131,6 @@ module Petstore [id, pet_id, quantity, ship_date, status, complete].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -238,6 +161,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/pet.cr b/samples/client/petstore/crystal/src/petstore/models/pet.cr index d08a04fe5f22..d4f6f75d1778 100644 --- a/samples/client/petstore/crystal/src/petstore/models/pet.cr +++ b/samples/client/petstore/crystal/src/petstore/models/pet.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # A pet for sale in the pet store class Pet @@ -137,78 +132,6 @@ module Petstore [id, category, name, photo_urls, tags, status].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -239,6 +162,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/tag.cr b/samples/client/petstore/crystal/src/petstore/models/tag.cr index 5dc2ce4ffeb2..e203f1aca442 100644 --- a/samples/client/petstore/crystal/src/petstore/models/tag.cr +++ b/samples/client/petstore/crystal/src/petstore/models/tag.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # A tag for a pet class Tag @@ -65,78 +60,6 @@ module Petstore [id, name].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -163,6 +86,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) } diff --git a/samples/client/petstore/crystal/src/petstore/models/user.cr b/samples/client/petstore/crystal/src/petstore/models/user.cr index 8a56a5844875..a1a7a72530d1 100644 --- a/samples/client/petstore/crystal/src/petstore/models/user.cr +++ b/samples/client/petstore/crystal/src/petstore/models/user.cr @@ -8,11 +8,6 @@ #Generator version: 7.19.0-SNAPSHOT # -require "big" -require "json" -require "yaml" -require "time" - module Petstore # A User who is purchasing from the pet store class User @@ -90,78 +85,6 @@ module Petstore [id, username, first_name, last_name, email, password, phone, user_status].hash end - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def self.build_from_hash(attributes) - new.build_from_hash(attributes) - end - - # Builds the object from hash - # @param [Hash] attributes Model attributes in the form of hash - # @return [Object] Returns the model itself - def build_from_hash(attributes) - return nil unless attributes.is_a?(Hash) - self.class.openapi_types.each_pair do |key, type| - if !attributes[self.class.attribute_map[key]]? && self.class.openapi_nullable.includes?(key) - self.send("#{key}=", nil) - elsif type =~ /\AArray<(.*)>/i - # check to ensure the input is an array given that the attribute - # is documented as an array but the input is not - if attributes[self.class.attribute_map[key]].is_a?(Array) - self.send("#{key}=", attributes[self.class.attribute_map[key]].map { |v| _deserialize($1, v) }) - end - elsif !attributes[self.class.attribute_map[key]].nil? - self.send("#{key}=", _deserialize(type, attributes[self.class.attribute_map[key]])) - end - end - - self - end - - # Deserializes the data based on type - # @param string type Data type - # @param string value Value to be deserialized - # @return [Object] Deserialized data - def _deserialize(type, value) - case type.to_sym - when :Time - Time.parse(value) - when :Date - Date.parse(value) - when :String - value.to_s - when :Integer - value.to_i - when :Float - value.to_f - when :Boolean - if value.to_s =~ /\A(true|t|yes|y|1)\z/i - true - else - false - end - when :Object - # generic object (usually a Hash), return directly - value - when /\AArray<(?.+)>\z/ - inner_type = Regexp.last_match[:inner_type] - value.map { |v| _deserialize(inner_type, v) } - when /\AHash<(?.+?), (?.+)>\z/ - k_type = Regexp.last_match[:k_type] - v_type = Regexp.last_match[:v_type] - ({} of Symbol => String).tap do |hash| - value.each do |k, v| - hash[_deserialize(k_type, k)] = _deserialize(v_type, v) - end - end - else # model - # models (e.g. Pet) or oneOf - klass = Petstore.const_get(type) - klass.respond_to?(:openapi_one_of) ? klass.build(value) : klass.build_from_hash(value) - end - end - # Returns the string representation of the object # @return [String] String presentation of the object def to_s @@ -194,6 +117,8 @@ module Petstore # @param [Object] value Any valid value # @return [Hash] Returns the value in the form of hash private def _to_h(value) + return nil if value.nil? + if value.is_a?(Hash) hash = NetboxClient::RecursiveHash.new value.each { |k, v| hash[k] = _to_h(v) }