Merge pull request #2871 from zlx/feature/rails5

Feature/rails5
This commit is contained in:
wing328
2016-05-16 11:54:38 +08:00
123 changed files with 2542 additions and 1 deletions

View File

@@ -7,13 +7,16 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Arrays;
public class CodegenOperation {
public final List<CodegenProperty> responseHeaders = new ArrayList<CodegenProperty>();
public Boolean hasAuthMethods, hasConsumes, hasProduces, hasParams, hasOptionalParams,
returnTypeIsPrimitive, returnSimpleType, subresourceOperation, isMapContainer,
isListContainer, isMultipart, hasMore = Boolean.TRUE,
isResponseBinary = Boolean.FALSE, hasReference = Boolean.FALSE;
isResponseBinary = Boolean.FALSE, hasReference = Boolean.FALSE,
isRestfulIndex, isRestfulShow, isRestfulCreate, isRestfulUpdate, isRestfulDestroy,
isRestful;
public String path, operationId, returnType, httpMethod, returnBaseType,
returnContainer, summary, unescapedNotes, notes, baseName, defaultResponse, discriminator;
public List<Map<String, String>> consumes, produces;
@@ -88,6 +91,81 @@ public class CodegenOperation {
return nonempty(formParams);
}
/**
* Check if act as Restful index method
*
* @return true if act as Restful index method, false otherwise
*/
public boolean isRestfulIndex() {
return "GET".equals(httpMethod) && "".equals(pathWithoutBaseName());
}
/**
* Check if act as Restful show method
*
* @return true if act as Restful show method, false otherwise
*/
public boolean isRestfulShow() {
return "GET".equals(httpMethod) && isMemberPath();
}
/**
* Check if act as Restful create method
*
* @return true if act as Restful create method, false otherwise
*/
public boolean isRestfulCreate() {
return "POST".equals(httpMethod) && "".equals(pathWithoutBaseName());
}
/**
* Check if act as Restful update method
*
* @return true if act as Restful update method, false otherwise
*/
public boolean isRestfulUpdate() {
return Arrays.asList("PUT", "PATCH").contains(httpMethod) && isMemberPath();
}
/**
* Check if act as Restful destroy method
*
* @return true if act as Restful destroy method, false otherwise
*/
public boolean isRestfulDestroy() {
return "DELETE".equals(httpMethod) && isMemberPath();
}
/**
* Check if Restful-style
*
* @return true if Restful-style, false otherwise
*/
public boolean isRestful() {
return isRestfulIndex() || isRestfulShow() || isRestfulCreate() || isRestfulUpdate() || isRestfulDestroy();
}
/**
* Get the substring except baseName from path
*
* @return the substring
*/
private String pathWithoutBaseName() {
return baseName != null ? path.replace("/" + baseName.toLowerCase(), "") : path;
}
/**
* Check if the path match format /xxx/:id
*
* @return true if path act as member
*/
private boolean isMemberPath() {
if (pathParams.size() != 1) return false;
String id = pathParams.get(0).baseName;
return ("/{" + id + "}").equals(pathWithoutBaseName());
}
@Override
public String toString() {
return String.format("%s(%s)", baseName, path);

View File

@@ -1847,6 +1847,14 @@ public class DefaultCodegen {
}
op.externalDocs = operation.getExternalDocs();
// set Restful Flag
op.isRestfulShow = op.isRestfulShow();
op.isRestfulIndex = op.isRestfulIndex();
op.isRestfulCreate = op.isRestfulCreate();
op.isRestfulUpdate = op.isRestfulUpdate();
op.isRestfulDestroy = op.isRestfulDestroy();
op.isRestful = op.isRestful();
return op;
}

View File

@@ -0,0 +1,323 @@
package io.swagger.codegen.languages;
import com.fasterxml.jackson.core.JsonProcessingException;
import io.swagger.codegen.CodegenConfig;
import io.swagger.codegen.CodegenType;
import io.swagger.codegen.DefaultCodegen;
import io.swagger.codegen.SupportingFile;
import io.swagger.models.properties.ArrayProperty;
import io.swagger.models.properties.MapProperty;
import io.swagger.models.properties.Property;
import io.swagger.models.Swagger;
import io.swagger.util.Yaml;
import java.io.File;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Rails5ServerCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(Rails5ServerCodegen.class);
protected String gemName;
protected String moduleName;
protected String gemVersion = "1.0.0";
protected String appFolder = "app";
protected String channelsFolder = appFolder + File.separator + "channels";
protected String applicationCableFolder = channelsFolder + File.separator + "application_cable";
protected String controllersFolder = appFolder + File.separator + "controllers";
protected String jobsFolder = appFolder + File.separator + "jobs";
protected String mailersFolder = appFolder + File.separator + "mailers";
protected String modelsFolder = appFolder + File.separator + "models";
protected String viewsFolder = appFolder + File.separator + "views";
protected String layoutsFolder = viewsFolder + File.separator + "layouts";
protected String binFolder = "bin";
protected String configFolder = "config";
protected String environmentsFolder = configFolder + File.separator + "config";
protected String initializersFolder = configFolder + File.separator + "initializers";
protected String localesFolder = configFolder + File.separator + "locales";
protected String dbFolder = "db";
protected String migrateFolder = dbFolder + File.separator + "migrate";
protected String libFolder = "lib";
protected String tasksFolder = libFolder + File.separator + "tasks";
protected String logFolder = "log";
protected String publicFolder = "public";
protected String testFolder = "test";
protected String tmpFolder = "tmp";
protected String cacheFolder = tmpFolder + File.separator + "cache";
protected String pidFolder = tmpFolder + File.separator + "pids";
protected String socketsFolder = tmpFolder + File.separator + "sockets";
protected String vendorFolder = "vendor";
public Rails5ServerCodegen() {
super();
apiPackage = "app/controllers";
outputFolder = "generated-code" + File.separator + "rails5";
// no model
modelTemplateFiles.clear();
apiTemplateFiles.put("controller.mustache", ".rb");
embeddedTemplateDir = templateDir = "rails5";
typeMapping.clear();
languageSpecificPrimitives.clear();
setReservedWordsLowerCase(
Arrays.asList(
"__FILE__", "and", "def", "end", "in", "or", "self", "unless", "__LINE__",
"begin", "defined?", "ensure", "module", "redo", "super", "until", "BEGIN",
"break", "do", "false", "next", "rescue", "then", "when", "END", "case",
"else", "for", "nil", "retry", "true", "while", "alias", "class", "elsif",
"if", "not", "return", "undef", "yield")
);
languageSpecificPrimitives.add("int");
languageSpecificPrimitives.add("array");
languageSpecificPrimitives.add("map");
languageSpecificPrimitives.add("string");
languageSpecificPrimitives.add("DateTime");
typeMapping.put("long", "int");
typeMapping.put("integer", "int");
typeMapping.put("Array", "array");
typeMapping.put("String", "string");
typeMapping.put("List", "array");
typeMapping.put("map", "map");
//TODO binary should be mapped to byte array
// mapped to String as a workaround
typeMapping.put("binary", "string");
// remove modelPackage and apiPackage added by default
cliOptions.clear();
}
@Override
public void processOpts() {
super.processOpts();
// use constant model/api package (folder path)
//setModelPackage("models");
setApiPackage("app/controllers");
supportingFiles.add(new SupportingFile("Gemfile", "", "Gemfile"));
supportingFiles.add(new SupportingFile("README.md", "", "README.md"));
supportingFiles.add(new SupportingFile("Rakefile", "", "Rakefile"));
supportingFiles.add(new SupportingFile("config.ru", "", "config.ru"));
supportingFiles.add(new SupportingFile("channel.rb", applicationCableFolder, "channel.rb"));
supportingFiles.add(new SupportingFile("connection.rb", applicationCableFolder, "connection.rb"));
supportingFiles.add(new SupportingFile("application_controller.rb", controllersFolder, "application_controller.rb"));
supportingFiles.add(new SupportingFile("application_job.rb", jobsFolder, "application_job.rb"));
supportingFiles.add(new SupportingFile("application_mailer.rb", mailersFolder, "application_mailer.rb"));
supportingFiles.add(new SupportingFile("application_record.rb", modelsFolder, "application_record.rb"));
supportingFiles.add(new SupportingFile("mailer.html.erb", layoutsFolder, "mailer.html.erb"));
supportingFiles.add(new SupportingFile("mailer.text.erb", layoutsFolder, "mailer.text.erb"));
supportingFiles.add(new SupportingFile("bundle", binFolder, "bundle"));
supportingFiles.add(new SupportingFile("rails", binFolder, "rails"));
supportingFiles.add(new SupportingFile("rake", binFolder, "rake"));
supportingFiles.add(new SupportingFile("setup", binFolder, "setup"));
supportingFiles.add(new SupportingFile("update", binFolder, "update"));
supportingFiles.add(new SupportingFile("development.rb", environmentsFolder, "development.rb"));
supportingFiles.add(new SupportingFile("production.rb", environmentsFolder, "production.rb"));
supportingFiles.add(new SupportingFile("active_record_belongs_to_required_by_default.rb", initializersFolder, "active_record_belongs_to_required_by_default.rb"));
supportingFiles.add(new SupportingFile("application_controller_renderer.rb", initializersFolder, "application_controller_renderer.rb"));
supportingFiles.add(new SupportingFile("backtrace_silencers.rb", initializersFolder, "backtrace_silencers.rb"));
supportingFiles.add(new SupportingFile("callback_terminator.rb", initializersFolder, "callback_terminator.rb"));
supportingFiles.add(new SupportingFile("cors.rb", initializersFolder, "cors.rb"));
supportingFiles.add(new SupportingFile("filter_parameter_logging.rb", initializersFolder, "filter_parameter_logging.rb"));
supportingFiles.add(new SupportingFile("inflections.rb", initializersFolder, "inflections.rb"));
supportingFiles.add(new SupportingFile("mime_types.rb", initializersFolder, "mime_types.rb"));
supportingFiles.add(new SupportingFile("ssl_options.rb", initializersFolder, "ssl_options.rb"));
supportingFiles.add(new SupportingFile("to_time_preserves_timezone.rb", initializersFolder, "to_time_preserves_timezone.rb"));
supportingFiles.add(new SupportingFile("en.yml", localesFolder, "en.yml"));
supportingFiles.add(new SupportingFile("application.rb", configFolder, "application.rb"));
supportingFiles.add(new SupportingFile("boot.rb", configFolder, "boot.rb"));
supportingFiles.add(new SupportingFile("cable.yml", configFolder, "cable.yml"));
supportingFiles.add(new SupportingFile("database.yml", configFolder, "database.yml"));
supportingFiles.add(new SupportingFile("environment.rb", configFolder, "environment.rb"));
supportingFiles.add(new SupportingFile("puma.rb", configFolder, "puma.rb"));
supportingFiles.add(new SupportingFile("routes.mustache", configFolder, "routes.rb"));
supportingFiles.add(new SupportingFile("secrets.yml", configFolder, "secrets.yml"));
supportingFiles.add(new SupportingFile("spring.rb", configFolder, "spring.rb"));
supportingFiles.add(new SupportingFile(".keep", migrateFolder, ".keep"));
supportingFiles.add(new SupportingFile("schema.rb", dbFolder, "schema.rb"));
supportingFiles.add(new SupportingFile("seeds.rb", dbFolder, "seeds.rb"));
supportingFiles.add(new SupportingFile(".keep", tasksFolder, ".keep"));
supportingFiles.add(new SupportingFile(".keep", logFolder, ".keep"));
supportingFiles.add(new SupportingFile("404.html", publicFolder, "404.html"));
supportingFiles.add(new SupportingFile("422.html", publicFolder, "422.html"));
supportingFiles.add(new SupportingFile("500.html", publicFolder, "500.html"));
supportingFiles.add(new SupportingFile("apple-touch-icon-precomposed.png", publicFolder, "apple-touch-icon-precomposed.png"));
supportingFiles.add(new SupportingFile("apple-touch-icon.png", publicFolder, "apple-touch-icon.png"));
supportingFiles.add(new SupportingFile("favicon.ico", publicFolder, "favicon.ico"));
supportingFiles.add(new SupportingFile("robots.txt", publicFolder, "robots.txt"));
supportingFiles.add(new SupportingFile("robots.txt", publicFolder, "robots.txt"));
supportingFiles.add(new SupportingFile("test_helper.rb", testFolder, "test_helper.rb"));
supportingFiles.add(new SupportingFile(".keep", cacheFolder, ".keep"));
supportingFiles.add(new SupportingFile(".keep", pidFolder, ".keep"));
supportingFiles.add(new SupportingFile(".keep", socketsFolder, ".keep"));
supportingFiles.add(new SupportingFile("restart.txt", tmpFolder, "restart.txt"));
supportingFiles.add(new SupportingFile(".keep", vendorFolder, ".keep"));
}
@Override
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public String getName() {
return "rails5";
}
@Override
public String getHelp() {
return "Generates a Rails5 server library.";
}
@Override
public String escapeReservedWord(String name) {
return "_" + name;
}
@Override
public String apiFileFolder() {
return outputFolder + File.separator + apiPackage.replace("/", File.separator);
}
@Override
public String getTypeDeclaration(Property p) {
if (p instanceof ArrayProperty) {
ArrayProperty ap = (ArrayProperty) p;
Property inner = ap.getItems();
return getSwaggerType(p) + "[" + getTypeDeclaration(inner) + "]";
} else if (p instanceof MapProperty) {
MapProperty mp = (MapProperty) p;
Property inner = mp.getAdditionalProperties();
return getSwaggerType(p) + "[string," + getTypeDeclaration(inner) + "]";
}
return super.getTypeDeclaration(p);
}
@Override
public String getSwaggerType(Property p) {
String swaggerType = super.getSwaggerType(p);
String type = null;
if (typeMapping.containsKey(swaggerType)) {
type = typeMapping.get(swaggerType);
if (languageSpecificPrimitives.contains(type)) {
return type;
}
} else {
type = swaggerType;
}
if (type == null) {
return null;
}
return type;
}
@Override
public String toDefaultValue(Property p) {
return "null";
}
@Override
public String toVarName(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// if it's all uppper case, convert to lower case
if (name.matches("^[A-Z_]*$")) {
name = name.toLowerCase();
}
// camelize (lower first character) the variable name
// petId => pet_id
name = underscore(name);
// for reserved word or word starting with number, append _
if (isReservedWord(name) || name.matches("^\\d.*")) {
name = escapeReservedWord(name);
}
return name;
}
@Override
public String toParamName(String name) {
// should be the same as variable name
return toVarName(name);
}
@Override
public String toModelName(String name) {
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
}
// camelize the model name
// phone_number => PhoneNumber
return camelize(name);
}
@Override
public String toModelFilename(String name) {
// model name cannot use reserved keyword, e.g. return
if (isReservedWord(name)) {
throw new RuntimeException(name + " (reserved word) cannot be used as a model name");
}
// underscore the model file name
// PhoneNumber.rb => phone_number.rb
return underscore(name);
}
@Override
public String toApiFilename(String name) {
// replace - with _ e.g. created-at => created_at
name = name.replaceAll("-", "_"); // FIXME: a parameter should not be assigned. Also declare the methods parameters as 'final'.
// e.g. PhoneNumberApi.rb => phone_number_api.rb
return underscore(name) + "_controllers";
}
@Override
public String toApiName(String name) {
if (name.length() == 0) {
return "ApiController";
}
// e.g. phone_number_api => PhoneNumberApi
return camelize(name) + "Controller";
}
@Override
public String toOperationId(String operationId) {
// method name cannot use reserved keyword, e.g. return
if (isReservedWord(operationId)) {
throw new RuntimeException(operationId + " (reserved word) cannot be used as method name");
}
return underscore(operationId);
}
@Override
public Map<String, Object> postProcessSupportingFileData(Map<String, Object> objs) {
Swagger swagger = (Swagger)objs.get("swagger");
if(swagger != null) {
try {
objs.put("swagger-yaml", Yaml.mapper().writeValueAsString(swagger));
} catch (JsonProcessingException e) {
LOGGER.error(e.getMessage(), e);
}
}
return super.postProcessSupportingFileData(objs);
}
}