Java tutorial
/* * Copyright 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.template.soy.pysrc.restricted; import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Iterables; import java.util.ArrayDeque; import java.util.Deque; import java.util.LinkedHashMap; import java.util.Map; /** * * A class for building code for a function call expression in Python. * It builds to a PyExpr so it could be used function call code recursively. * * <p> Sample Output: * {@code some_func_call(1, "str", foo='bar', foo=nested_call(42))} * * */ public final class PyFunctionExprBuilder { private static final Function<Map.Entry<String, PyExpr>, String> KEYWORD_ARG_MAPPER = new Function<Map.Entry<String, PyExpr>, String>() { @Override public String apply(Map.Entry<String, PyExpr> entry) { String key = entry.getKey(); PyExpr value = entry.getValue(); return key + "=" + value.getText(); } }; private static final Function<PyExpr, String> LIST_ARG_MAPPER = new Function<PyExpr, String>() { @Override public String apply(PyExpr arg) { return arg.getText(); } }; private final String funcName; private final Deque<PyExpr> argList; private final Map<String, PyExpr> kwargMap; private String unpackedKwargs = null; /** * @param funcName The name of the function. */ public PyFunctionExprBuilder(String funcName) { this.funcName = funcName; this.argList = new ArrayDeque<>(); this.kwargMap = new LinkedHashMap<>(); } public PyFunctionExprBuilder addArg(PyExpr arg) { this.argList.add(arg); return this; } public PyFunctionExprBuilder addArg(String str) { this.argList.add(new PyStringExpr("'" + str + "'")); return this; } public PyFunctionExprBuilder addArg(boolean b) { this.argList.add(new PyExpr(b ? "True" : "False", Integer.MAX_VALUE)); return this; } public PyFunctionExprBuilder addArg(int i) { this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } public PyFunctionExprBuilder addArg(double i) { this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } public PyFunctionExprBuilder addArg(long i) { this.argList.add(new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } public String getFuncName() { return this.funcName; } public PyFunctionExprBuilder addKwarg(String key, PyExpr argValue) { kwargMap.put(key, argValue); return this; } public PyFunctionExprBuilder addKwarg(String key, String str) { kwargMap.put(key, new PyStringExpr("'" + str + "'")); return this; } public PyFunctionExprBuilder addKwarg(String key, int i) { kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } public PyFunctionExprBuilder addKwarg(String key, double i) { kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } public PyFunctionExprBuilder addKwarg(String key, long i) { kwargMap.put(key, new PyExpr(String.valueOf(i), Integer.MAX_VALUE)); return this; } /** * Unpacking keyword arguments will expand a dictionary into a series of keyword arguments. * * <p>NOTE: Keyword unpacking behavior is only guaranteed for mapping expressions. Non-mapping * expressions which attempt to unpack will result in Python runtime errors. * * @param mapping The mapping expression to unpack. * @return This PyFunctionExprBuilder instance. */ public PyFunctionExprBuilder setUnpackedKwargs(PyExpr mapping) { if (unpackedKwargs != null) { throw new UnsupportedOperationException("Only one kwarg unpacking allowed per expression."); } StringBuilder expr = new StringBuilder("**"); if (mapping.getPrecedence() < Integer.MAX_VALUE) { expr.append("(").append(mapping.getText()).append(")"); } else { expr.append(mapping.getText()); } unpackedKwargs = expr.toString(); return this; } /** * Returns a valid Python function call as a String. */ public String build() { StringBuilder sb = new StringBuilder(funcName + "("); Joiner joiner = Joiner.on(", ").skipNulls(); // Join args and kwargs into simple strings. String args = joiner.join(Iterables.transform(argList, LIST_ARG_MAPPER)); String kwargs = joiner.join(Iterables.transform(kwargMap.entrySet(), KEYWORD_ARG_MAPPER)); // Strip empty strings. args = Strings.emptyToNull(args); kwargs = Strings.emptyToNull(kwargs); // Join all pieces together. joiner.appendTo(sb, args, kwargs, unpackedKwargs); sb.append(")"); return sb.toString(); } /* * Use when the output function is unknown in Python runtime. * * @return A PyExpr represents the function code. */ public PyExpr asPyExpr() { return new PyExpr(build(), Integer.MAX_VALUE); } /* * Use when the output function is known to be a String in Python runtime. * * @return A PyStringExpr represents the function code. */ public PyStringExpr asPyStringExpr() { return new PyStringExpr(build()); } }