Skip to content

Commit afb2388

Browse files
ackintoshwing328
authored andcommitted
[Ruby] Abstract Ruby Codegen (#562)
* Add AbstractRubyCodegen * Refactor constructor * Move escapeReservedWord() to AbstractRubyCodegen * Move getTypeDeclaration() to AbstractRubyCodegen * Move toDefaultValue() to AbstractRubyCodegen * Move toVarName() to AbstractRubyCodegen * Move toParamName() to AbstractRubyCodegen * Move toOperationId() to AbstractRubyCodegen * Move escapeQuotationMark() to AbstractRubyCodegen * Move escapeUnsafeCharacters() to AbstractRubyCodegen * Use super.escapeReservedWord() * RubyClientCodegen extends AbstractRubyCodegen * Add the differences with AbstractRubyCodegen to "reservedWords" * cliOptions.clear() is not a language specific matter - Rails, Sinatra requires cliOptions.clear() - Ruby client doesn't requires that * Remove duplicated statements with AbstractRubyCodegen * Remove duplicated methods with AbstractRubyCodegen * Merge toVarName() into AbstractRubyCodegen * Merge getTypeDeclaration() into AbstractRubyCodegen * Merge toDefaultValue() into AbstractRubyCodegen * Update Ruby related samples - bin/ruby-client-petstore.sh - bin/ruby-on-rails-server-petstore.sh - bin/ruby-sinatra-server-petstore.sh * Remove unnecessary 'import' * Avoid unnecessary HTML escaping
1 parent a055dc0 commit afb2388

8 files changed

Lines changed: 214 additions & 391 deletions

File tree

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
/*
2+
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
3+
* Copyright 2018 SmartBear Software
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.openapitools.codegen.languages;
19+
20+
import io.swagger.v3.oas.models.media.ArraySchema;
21+
import io.swagger.v3.oas.models.media.Schema;
22+
import org.openapitools.codegen.*;
23+
import org.openapitools.codegen.utils.ModelUtils;
24+
import org.slf4j.Logger;
25+
import org.slf4j.LoggerFactory;
26+
27+
import java.util.Arrays;
28+
29+
abstract class AbstractRubyCodegen extends DefaultCodegen implements CodegenConfig {
30+
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractRubyCodegen.class);
31+
32+
AbstractRubyCodegen() {
33+
super();
34+
35+
setReservedWordsLowerCase(
36+
Arrays.asList(
37+
"__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__",
38+
"begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN",
39+
"break", "do", "false", "next", "rescue", "then", "when", "END", "case",
40+
"else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif",
41+
"if", "not", "return", "undef", "yield")
42+
);
43+
44+
languageSpecificPrimitives.clear();
45+
languageSpecificPrimitives.add("String");
46+
languageSpecificPrimitives.add("Integer");
47+
languageSpecificPrimitives.add("Float");
48+
languageSpecificPrimitives.add("Date");
49+
languageSpecificPrimitives.add("DateTime");
50+
languageSpecificPrimitives.add("Array");
51+
languageSpecificPrimitives.add("Hash");
52+
languageSpecificPrimitives.add("File");
53+
languageSpecificPrimitives.add("Object");
54+
55+
typeMapping.clear();
56+
typeMapping.put("string", "String");
57+
typeMapping.put("char", "String");
58+
typeMapping.put("int", "Integer");
59+
typeMapping.put("integer", "Integer");
60+
typeMapping.put("long", "Integer");
61+
typeMapping.put("short", "Integer");
62+
typeMapping.put("float", "Float");
63+
typeMapping.put("double", "Float");
64+
typeMapping.put("number", "Float");
65+
typeMapping.put("date", "Date");
66+
typeMapping.put("DateTime", "DateTime");
67+
typeMapping.put("array", "Array");
68+
typeMapping.put("List", "Array");
69+
typeMapping.put("map", "Hash");
70+
typeMapping.put("object", "Object");
71+
typeMapping.put("file", "File");
72+
typeMapping.put("binary", "String");
73+
typeMapping.put("ByteArray", "String");
74+
typeMapping.put("UUID", "String");
75+
}
76+
77+
@Override
78+
public String escapeReservedWord(String name) {
79+
if (this.reservedWordsMappings().containsKey(name)) {
80+
return this.reservedWordsMappings().get(name);
81+
}
82+
return "_" + name;
83+
}
84+
85+
@Override
86+
public String getTypeDeclaration(Schema schema) {
87+
if (ModelUtils.isArraySchema(schema)) {
88+
Schema inner = ((ArraySchema) schema).getItems();
89+
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
90+
} else if (ModelUtils.isMapSchema(schema)) {
91+
Schema inner = (Schema) schema.getAdditionalProperties();
92+
return getSchemaType(schema) + "<String, " + getTypeDeclaration(inner) + ">";
93+
}
94+
95+
return super.getTypeDeclaration(schema);
96+
}
97+
98+
@Override
99+
public String toDefaultValue(Schema p) {
100+
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
101+
if (p.getDefault() != null) {
102+
return p.getDefault().toString();
103+
}
104+
} else if (ModelUtils.isStringSchema(p)) {
105+
if (p.getDefault() != null) {
106+
return "'" + escapeText((String) p.getDefault()) + "'";
107+
}
108+
}
109+
110+
return null;
111+
}
112+
113+
@Override
114+
public String toVarName(String name) {
115+
// sanitize name
116+
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
117+
// if it's all uppper case, convert to lower case
118+
if (name.matches("^[A-Z_]*$")) {
119+
name = name.toLowerCase();
120+
}
121+
122+
// camelize (lower first character) the variable name
123+
// petId => pet_id
124+
name = underscore(name);
125+
126+
// for reserved word or word starting with number, append _
127+
if (isReservedWord(name) || name.matches("^\\d.*")) {
128+
name = escapeReservedWord(name);
129+
}
130+
131+
return name;
132+
}
133+
134+
@Override
135+
public String toParamName(String name) {
136+
// should be the same as variable name
137+
return toVarName(name);
138+
}
139+
140+
@Override
141+
public String toOperationId(String operationId) {
142+
// method name cannot use reserved keyword, e.g. return
143+
if (isReservedWord(operationId)) {
144+
String newOperationId = underscore("call_" + operationId);
145+
LOGGER.warn(operationId + " (reserved word) cannot be used as method name. Renamed to " + newOperationId);
146+
return newOperationId;
147+
}
148+
149+
return underscore(operationId);
150+
}
151+
152+
@Override
153+
public String escapeQuotationMark(String input) {
154+
// remove ' to avoid code injection
155+
return input.replace("'", "");
156+
}
157+
158+
@Override
159+
public String escapeUnsafeCharacters(String input) {
160+
return input.replace("=end", "=_end").replace("=begin", "=_begin");
161+
}
162+
}

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RubyClientCodegen.java

Lines changed: 8 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,11 @@
1818
package org.openapitools.codegen.languages;
1919

2020
import org.openapitools.codegen.CliOption;
21-
import org.openapitools.codegen.CodegenConfig;
2221
import org.openapitools.codegen.CodegenConstants;
2322
import org.openapitools.codegen.CodegenParameter;
2423
import org.openapitools.codegen.CodegenProperty;
2524
import org.openapitools.codegen.CodegenType;
26-
import org.openapitools.codegen.DefaultCodegen;
2725
import org.openapitools.codegen.SupportingFile;
28-
import org.openapitools.codegen.utils.ModelUtils;
2926

3027
import java.io.File;
3128
import java.util.Arrays;
@@ -37,7 +34,7 @@
3734
import org.slf4j.Logger;
3835
import org.slf4j.LoggerFactory;
3936

40-
public class RubyClientCodegen extends DefaultCodegen implements CodegenConfig {
37+
public class RubyClientCodegen extends AbstractRubyCodegen {
4138
private static final Logger LOGGER = LoggerFactory.getLogger(RubyClientCodegen.class);
4239
public static final String GEM_NAME = "gemName";
4340
public static final String MODULE_NAME = "moduleName";
@@ -89,59 +86,22 @@ public RubyClientCodegen() {
8986
// default HIDE_GENERATION_TIMESTAMP to true
9087
hideGenerationTimestamp = Boolean.TRUE;
9188

92-
setReservedWordsLowerCase(
93-
Arrays.asList(
94-
// local variable names used in API methods (endpoints)
95-
"local_var_path", "query_params", "header_params", "_header_accept", "_header_accept_result",
96-
"_header_content_type", "form_params", "post_body", "auth_names",
97-
// ruby reserved keywords
98-
"__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__",
99-
"begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN",
100-
"break", "do", "false", "next", "rescue", "then", "when", "END", "case",
101-
"else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif",
102-
"if", "not", "return", "undef", "yield")
103-
);
104-
105-
typeMapping.clear();
106-
languageSpecificPrimitives.clear();
89+
// local variable names used in API methods (endpoints)
90+
for (String word : Arrays.asList(
91+
"local_var_path", "query_params", "header_params", "_header_accept", "_header_accept_result",
92+
"_header_content_type", "form_params", "post_body", "auth_names")) {
93+
reservedWords.add(word.toLowerCase());
94+
}
95+
10796

10897
// primitives in ruby lang
10998
languageSpecificPrimitives.add("int");
11099
languageSpecificPrimitives.add("array");
111100
languageSpecificPrimitives.add("map");
112101
languageSpecificPrimitives.add("string");
113102
// primitives in the typeMapping
114-
languageSpecificPrimitives.add("String");
115-
languageSpecificPrimitives.add("Integer");
116-
languageSpecificPrimitives.add("Float");
117-
languageSpecificPrimitives.add("Date");
118-
languageSpecificPrimitives.add("DateTime");
119103
languageSpecificPrimitives.add("BOOLEAN");
120-
languageSpecificPrimitives.add("Array");
121-
languageSpecificPrimitives.add("Hash");
122-
languageSpecificPrimitives.add("File");
123-
languageSpecificPrimitives.add("Object");
124-
125-
typeMapping.put("string", "String");
126-
typeMapping.put("char", "String");
127-
typeMapping.put("int", "Integer");
128-
typeMapping.put("integer", "Integer");
129-
typeMapping.put("long", "Integer");
130-
typeMapping.put("short", "Integer");
131-
typeMapping.put("float", "Float");
132-
typeMapping.put("double", "Float");
133-
typeMapping.put("number", "Float");
134-
typeMapping.put("date", "Date");
135-
typeMapping.put("DateTime", "DateTime");
136104
typeMapping.put("boolean", "BOOLEAN");
137-
typeMapping.put("array", "Array");
138-
typeMapping.put("List", "Array");
139-
typeMapping.put("map", "Hash");
140-
typeMapping.put("object", "Object");
141-
typeMapping.put("file", "File");
142-
typeMapping.put("binary", "String");
143-
typeMapping.put("ByteArray", "String");
144-
typeMapping.put("UUID", "String");
145105

146106
// remove modelPackage and apiPackage added by default
147107
Iterator<CliOption> itr = cliOptions.iterator();
@@ -308,14 +268,6 @@ public String generateGemName(String moduleName) {
308268
return underscore(moduleName.replaceAll("[^\\w]+", ""));
309269
}
310270

311-
@Override
312-
public String escapeReservedWord(String name) {
313-
if (this.reservedWordsMappings().containsKey(name)) {
314-
return this.reservedWordsMappings().get(name);
315-
}
316-
return "_" + name;
317-
}
318-
319271
@Override
320272
public String apiFileFolder() {
321273
return outputFolder + File.separator + libFolder + File.separator + gemName + File.separator + apiPackage.replace("/", File.separator);
@@ -346,34 +298,6 @@ public String modelDocFileFolder() {
346298
return (outputFolder + "/" + modelDocPath).replace('/', File.separatorChar);
347299
}
348300

349-
@Override
350-
public String getTypeDeclaration(Schema schema) {
351-
if (ModelUtils.isArraySchema(schema)) {
352-
Schema inner = ((ArraySchema) schema).getItems();
353-
return getSchemaType(schema) + "<" + getTypeDeclaration(inner) + ">";
354-
} else if (ModelUtils.isMapSchema(schema)) {
355-
Schema inner = (Schema) schema.getAdditionalProperties();
356-
return getSchemaType(schema) + "<String, " + getTypeDeclaration(inner) + ">";
357-
}
358-
359-
return super.getTypeDeclaration(schema);
360-
}
361-
362-
@Override
363-
public String toDefaultValue(Schema p) {
364-
if (ModelUtils.isIntegerSchema(p) || ModelUtils.isNumberSchema(p) || ModelUtils.isBooleanSchema(p)) {
365-
if (p.getDefault() != null) {
366-
return p.getDefault().toString();
367-
}
368-
} else if (ModelUtils.isStringSchema(p)) {
369-
if (p.getDefault() != null) {
370-
return "'" + escapeText((String) p.getDefault()) + "'";
371-
}
372-
}
373-
374-
return null;
375-
}
376-
377301
@Override
378302
public String getSchemaType(Schema schema) {
379303
String openAPIType = super.getSchemaType(schema);
@@ -394,33 +318,6 @@ public String getSchemaType(Schema schema) {
394318
return toModelName(type);
395319
}
396320

397-
@Override
398-
public String toVarName(String name) {
399-
// sanitize name
400-
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
401-
// if it's all uppper case, convert to lower case
402-
if (name.matches("^[A-Z_]*$")) {
403-
name = name.toLowerCase();
404-
}
405-
406-
// camelize (lower first character) the variable name
407-
// petId => pet_id
408-
name = underscore(name);
409-
410-
// for reserved word or word starting with number, append _
411-
if (isReservedWord(name) || name.matches("^\\d.*")) {
412-
name = escapeReservedWord(name);
413-
}
414-
415-
return name;
416-
}
417-
418-
@Override
419-
public String toParamName(String name) {
420-
// should be the same as variable name
421-
return toVarName(name);
422-
}
423-
424321
@Override
425322
public String toModelName(String name) {
426323
name = sanitizeName(name); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
@@ -684,16 +581,4 @@ public boolean shouldOverwrite(String filename) {
684581
//
685582
//return super.shouldOverwrite(filename) && !filename.endsWith("_spec.rb");
686583
}
687-
688-
@Override
689-
public String escapeQuotationMark(String input) {
690-
// remove ' to avoid code injection
691-
return input.replace("'", "");
692-
}
693-
694-
@Override
695-
public String escapeUnsafeCharacters(String input) {
696-
return input.replace("=end", "=_end").replace("=begin", "=_begin");
697-
}
698-
699584
}

0 commit comments

Comments
 (0)