Просмотр исходного кода

Adding support for if-then-else formatter invocations.
Adding test cases to formatter.

Sam Jaffe 8 лет назад
Родитель
Сommit
a60606f7c0

+ 51 - 16
src/org/leumasjaffe/format/StringFormatter.java

@@ -24,21 +24,31 @@ public class StringFormatter {
 		}
 	}
 	
-	private final class FmtStateMachine {
-		final StringBuilder str = new StringBuilder(fmt.length());
+	private static final class FmtStateMachine {
+		final StringBuilder str;
 		
+		String fmt;
 		Object[] args;
-		int currentIdx = 0;
+		int currentIdx;
 		final NameMap named;
+		int lastCh, endPos = 0;
 
-		FmtStateMachine(Object... args) {
+		FmtStateMachine(String fmt, Object... args) {
+			this(fmt, 0, args, new NameMap(args), '\0');
+		}
+		
+		FmtStateMachine(String fmt, int idx, Object[] args, NameMap named, int lastCh) {
+			this.str = new StringBuilder(fmt.length());
+			this.fmt = fmt;
+			this.currentIdx = idx;
 			this.args = args;
-			this.named = new NameMap(args);
+			this.named = named;
+			this.lastCh = lastCh;
 		}
 		
 		FmtStateMachine formatMain() {
 			int lpos = 0;
-			for (int pos = fmt.indexOf('{'); pos != -1; lpos = pos+1, pos = fmt.indexOf('{', lpos)) {
+			for (int pos = fmt.indexOf('{'); pos != -1 && hasMore(pos); lpos = pos+1, pos = fmt.indexOf('{', lpos)) {
 				str.append(fmt.substring(lpos, pos).replaceAll("}}", "}"));
 				int epos = fmt.indexOf('}', pos);
 
@@ -48,25 +58,50 @@ public class StringFormatter {
 					epos = pos + 1;
 				} else if (epos == pos+1) {
 					// Unmarked '{}' -> get the next argument
-					str.append(args[currentIdx++]);
+					str.append(getToken(null));
 				} else {
-					formatToken(pos, epos);
+					epos = formatToken(pos, epos);
 				}
 				pos = epos;
 			}
-			str.append(fmt.substring(lpos).replaceAll("}}", "}"));
+			str.append(remaining(lpos).replaceAll("}}", "}"));
 			return this;
 		}
 
-		private void formatToken(int pos, int epos) {
-			final String token = fmt.substring(pos+1, epos);
+		private String remaining(int lpos) {
+			this.endPos = fmt.indexOf(lastCh, lpos);
+			return lastCh == '\0' ? fmt.substring(lpos) : fmt.substring(lpos, endPos++);
+		}
+
+		private boolean hasMore(int pos) {
+			return lastCh == '\0' || pos < fmt.indexOf(lastCh);
+		}
+		
+		private int formatToken(int pos, int epos) {
+			final String token = fmt.substring(++pos, epos);
 			// If token contains a '.', use reflection?
-			// If token contains a '?', make it an if-expression
 			// If token starts with '%', make it a c-format expression
-			if (Character.isDigit(token.charAt(0))) {
-				str.append(args[Integer.parseInt(token)]);
+			if (token.indexOf('?') != -1) {
+				final int b1 = fmt.indexOf('?', pos)+1;
+				boolean _if = (Boolean) getToken(token.substring(0, b1-pos-1));
+				FmtStateMachine then = new FmtStateMachine(fmt.substring(b1), currentIdx, args, named, ':').formatMain();
+				FmtStateMachine els = new FmtStateMachine(fmt.substring(then.endPos+b1), then.currentIdx, args, named, '}').formatMain();
+				currentIdx = els.currentIdx;
+				epos = els.endPos+then.endPos+b1-1;
+				str.append(_if ? then : els);
+			} else {
+				str.append(getToken(token));
+			}
+			return epos;
+		}
+
+		private Object getToken(final String token) {
+			if (token == null || token.isEmpty()) {
+				return args[currentIdx++];
+			} else if (Character.isDigit(token.charAt(0))) {
+				return args[Integer.parseInt(token)];
 			} else {
-				str.append(named.get(token));
+				return named.get(token);
 			}
 		}
 		
@@ -82,6 +117,6 @@ public class StringFormatter {
 	}
 	
 	public String format(Object... args) {
-		return this.new FmtStateMachine(args).formatMain().toString();
+		return new FmtStateMachine(fmt, args).formatMain().toString();
 	}
 }

+ 30 - 0
test/org/leumasjaffe/format/StringFormatterTest.java

@@ -0,0 +1,30 @@
+package org.leumasjaffe.format;
+
+import static org.junit.Assert.*;
+
+import org.junit.Test;
+import org.leumasjaffe.charsheet.util.StringHelper;
+
+public class StringFormatterTest {
+
+	@Test
+	public void testFormatLiteral() {
+		assertEquals("{}", new StringFormatter("{{}}").format());
+	}
+	
+	@Test
+	public void testFormatNumbered() {
+		assertEquals("1,0", new StringFormatter("{1},{0}").format(0, 1));
+	}
+	
+	@Test
+	public void testFormatCondition() {
+		assertEquals("1", new StringFormatter("{?{}:{}}").format(false, 0, 1));
+	}
+	
+	@Test
+	public void testFormatNumberedCondition() {
+		assertEquals("0 word + 1 word/2 levels", StringHelper.format("{0} {2} + {1} {2}/{3?level:{4} levels}", 0, 1, "word", false, 2));
+	}
+
+}