Implemented comment support for root-level keys based on @ZerothAngel's AnnotatedYAMLConfiguration

Dieser Commit ist enthalten in:
zml2008 2012-01-14 22:16:14 -08:00
Ursprung 28d29d3927
Commit 3942410ba8

Datei anzeigen

@ -19,6 +19,7 @@
package com.sk89q.util.yaml; package com.sk89q.util.yaml;
import com.sk89q.util.StringUtil;
import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.Yaml;
import org.yaml.snakeyaml.constructor.SafeConstructor; import org.yaml.snakeyaml.constructor.SafeConstructor;
@ -30,9 +31,7 @@ import org.yaml.snakeyaml.representer.Represent;
import org.yaml.snakeyaml.representer.Representer; import org.yaml.snakeyaml.representer.Representer;
import java.io.*; import java.io.*;
import java.util.HashMap; import java.util.*;
import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* YAML configuration loader. To use this class, construct it with path to * YAML configuration loader. To use this class, construct it with path to
@ -66,12 +65,19 @@ import java.util.Map;
* @author sk89q * @author sk89q
*/ */
public class YAMLProcessor extends YAMLNode { public class YAMLProcessor extends YAMLNode {
private Yaml yaml; public static final String LINE_BREAK = DumperOptions.LineBreak.getPlatformLineBreak().getString();
private File file; public static final char COMMENT_CHAR = '#';
private String header = null; protected final Yaml yaml;
protected final File file;
protected String header = null;
protected YAMLFormat format;
// Map from property key to comment. Comment may have multiple lines that are newline-separated.
private final Map<String, String> comments = new HashMap<String, String>();
public YAMLProcessor(File file, boolean writeDefaults, YAMLFormat format) { public YAMLProcessor(File file, boolean writeDefaults, YAMLFormat format) {
super(new HashMap<String, Object>(), writeDefaults); super(new LinkedHashMap<String, Object>(), writeDefaults);
this.format = format;
DumperOptions options = new FancyDumperOptions(); DumperOptions options = new FancyDumperOptions();
options.setIndent(4); options.setIndent(4);
@ -123,7 +129,7 @@ public class YAMLProcessor extends YAMLNode {
for (String line : headerLines) { for (String line : headerLines) {
if (header.length() > 0) { if (header.length() > 0) {
header.append("\r\n"); header.append(LINE_BREAK);
} }
header.append(line); header.append(line);
} }
@ -172,9 +178,23 @@ public class YAMLProcessor extends YAMLNode {
OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8"); OutputStreamWriter writer = new OutputStreamWriter(stream, "UTF-8");
if (header != null) { if (header != null) {
writer.append(header); writer.append(header);
writer.append("\r\n"); writer.append(LINE_BREAK);
}
// Iterate over each root-level property and dump
for (Iterator<Map.Entry<String, Object>> i = root.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, Object> entry = i.next();
// Output comment, if present
String comment = comments.get(entry.getKey());
if (comment != null) {
writer.append(LINE_BREAK);
writer.append(comment);
writer.append(LINE_BREAK);
}
// Dump property
yaml.dump(Collections.singletonMap(entry.getKey(), entry.getValue()), writer);
} }
yaml.dump(root, writer);
return true; return true;
} catch (IOException e) { } catch (IOException e) {
} finally { } finally {
@ -194,7 +214,7 @@ public class YAMLProcessor extends YAMLNode {
if (null == input) { if (null == input) {
root = new LinkedHashMap<String, Object>(); root = new LinkedHashMap<String, Object>();
} else { } else {
root = (Map<String, Object>) input; root = new LinkedHashMap<String, Object>((Map<String, Object>) input);
} }
} catch (ClassCastException e) { } catch (ClassCastException e) {
throw new YAMLProcessorException("Root document must be an key-value structure"); throw new YAMLProcessorException("Root document must be an key-value structure");
@ -209,21 +229,82 @@ public class YAMLProcessor extends YAMLNode {
return new FileOutputStream(file); return new FileOutputStream(file);
} }
/**
* Returns a root-level comment.
*
* @param key the property key
* @return the comment or <code>null</code>
*/
public String getComment(String key) {
return comments.get(key);
}
public void setComment(String key, String comment) {
if (comment != null) {
setComment(key, comment.split("\\r?\\n"));
} else {
comments.remove(key);
}
}
/**
* Set a root-level comment.
*
* @param key the property key
* @param comment the comment. May be <code>null</code>, in which case the comment
* is removed.
*/
public void setComment(String key, String... comment) {
if (comment != null && comment.length > 0) {
for (int i = 0; i < comment.length; ++i) {
if (!comment[i].matches("^" + COMMENT_CHAR + " ?")) {
comment[i] = COMMENT_CHAR + " " + comment[i];
}
}
String s = StringUtil.joinString(comment, LINE_BREAK);
comments.put(key, s);
} else {
comments.remove(key);
}
}
/**
* Returns root-level comments.
*
* @return map of root-level comments
*/
public Map<String, String> getComments() {
return Collections.unmodifiableMap(comments);
}
/**
* Set root-level comments from a map.
*
* @param comments comment map
*/
public void setComments(Map<String, String> comments) {
this.comments.clear();
if (comments != null) {
this.comments.putAll(comments);
}
}
/** /**
* This method returns an empty ConfigurationNode for using as a * This method returns an empty ConfigurationNode for using as a
* default in methods that select a node from a node list. * default in methods that select a node from a node list.
* @return * @return
*/ */
public static YAMLNode getEmptyNode(boolean writeDefaults) { public static YAMLNode getEmptyNode(boolean writeDefaults) {
return new YAMLNode(new HashMap<String, Object>(), writeDefaults); return new YAMLNode(new LinkedHashMap<String, Object>(), writeDefaults);
} }
// This will be included in snakeyaml 1.10, but until then we have to do it manually. // This will be included in snakeyaml 1.10, but until then we have to do it manually.
private static class FancyDumperOptions extends DumperOptions { private class FancyDumperOptions extends DumperOptions {
@Override @Override
public DumperOptions.ScalarStyle calculateScalarStyle(ScalarAnalysis analysis, public DumperOptions.ScalarStyle calculateScalarStyle(ScalarAnalysis analysis,
DumperOptions.ScalarStyle style) { DumperOptions.ScalarStyle style) {
if (analysis.scalar.contains("\n") || analysis.scalar.contains("\r")) { if (format == YAMLFormat.EXTENDED
&& (analysis.scalar.contains("\n") || analysis.scalar.contains("\r"))) {
return ScalarStyle.LITERAL; return ScalarStyle.LITERAL;
} else { } else {
return super.calculateScalarStyle(analysis, style); return super.calculateScalarStyle(analysis, style);