15
15
*/
16
16
package com .diffplug .freshmark ;
17
17
18
+ import java .util .function .Function ;
19
+ import java .util .regex .Matcher ;
20
+ import java .util .regex .Pattern ;
21
+
18
22
import javax .script .ScriptEngine ;
19
23
import javax .script .ScriptException ;
20
24
29
33
* A CommentScript has the following form:
30
34
* <pre>
31
35
* {@code
32
- * [INTRON] sectionName
36
+ * [COMMENT_START sectionName
33
37
* script
34
38
* script
35
- * [EXON ]
36
- * lastProgramExecutionResult
37
- * lastProgramExecutionResult
38
- * lastProgramExecutionResult
39
- * [INTRON] /sectionName [EXON ]
39
+ * COMMENT_END ]
40
+ * body
41
+ * body
42
+ * body
43
+ * [COMMENT_START /sectionName COMMENT_END ]
40
44
* }
41
45
* </pre>
42
46
* This class is a minimal implementation of a CommentScript. To create a CommentScript,
43
47
* you must provide:
44
48
* <ul>
45
- * <li>The intron and exon strings in the constructor .</li>
49
+ * <li>A {@link Parser} to split the comment text from the body text .</li>
46
50
* <li>{@link #keyToValue} - defines how template keys in the script string are transformed into values</li>
47
51
* <li>{@link #setupScriptEngine} - initializes any functions or variables which should be available to the script</li>
48
52
* </ul>
49
- * See {@link FreshMark} for a sample implementation.
53
+ * @see FreshMark
50
54
*/
51
- public abstract class CommentScript {
55
+ public abstract class CommentScript implements Parser . SectionCompiler {
52
56
/**
53
57
* Creates a CommentScript using the given parser to
54
58
* delineate and combine comment blocks.
@@ -61,30 +65,37 @@ protected CommentScript(Parser parser) {
61
65
final Parser parser ;
62
66
63
67
/** Compiles a single section/script/input combo into the appropriate output. */
64
- final ParserIntronExon .SectionCompiler compiler = new ParserIntronExon .SectionCompiler () {
65
- @ Override
66
- public String compileSection (String section , String script , String input ) {
67
- return Errors .rethrow ().get (() -> {
68
- ScriptEngine engine = setupScriptEngine (section );
68
+ @ Override
69
+ public String compileSection (String section , String script , String input ) {
70
+ return Errors .rethrow ().get (() -> {
71
+ ScriptEngine engine = setupScriptEngine (section );
69
72
70
- // apply the templating engine to the script
71
- String templatedProgram = template (section , script );
72
- // populate the input data
73
- engine .put ("input" , input );
74
- // evaluate the script and get the result
75
- engine .eval (templatedProgram );
76
- return Check .cast (engine .get ("output" ), String .class );
77
- });
78
- }
79
- };
73
+ // apply the templating engine to the script
74
+ String templatedProgram = template (section , script );
75
+ // populate the input data
76
+ engine .put ("input" , input );
77
+ // evaluate the script and get the result
78
+ engine .eval (templatedProgram );
79
+ return Check .cast (engine .get ("output" ), String .class );
80
+ });
81
+ }
80
82
81
83
/** Compiles the given input string. Input must contain only unix newlines, output is guaranteed to be the same. */
82
84
public String compile (String input ) {
83
- return parser .compile (input , compiler );
85
+ return parser .compile (input , this );
84
86
}
85
87
86
- /** For the given section, perform templating on the given script. */
87
- protected abstract String template (String section , String script );
88
+ /**
89
+ * Performs templating on the script before passing it to the {@link ScriptEngine} created by {@link #setupScriptEngine}.
90
+ * <p>
91
+ * Defaults to mustache-based templating which uses {@link #keyToValue(String, String)} to decode keys.
92
+ */
93
+ protected String template (String section , String script ) {
94
+ return mustacheTemplate (script , key -> keyToValue (section , key ));
95
+ }
96
+
97
+ /** For the given section, return the templated value for the given key. */
98
+ protected abstract String keyToValue (String section , String script );
88
99
89
100
/**
90
101
* For the given section, setup any built-in functions and variables.
@@ -93,4 +104,22 @@ public String compile(String input) {
93
104
* be extracted for you, but you must do everything else.
94
105
*/
95
106
protected abstract ScriptEngine setupScriptEngine (String section ) throws ScriptException ;
107
+
108
+ /** Mustache templating. */
109
+ static String mustacheTemplate (String input , Function <String , String > keyToValue ) {
110
+ Matcher matcher = MUSTACHE_PATTERN .matcher (input );
111
+ StringBuilder result = new StringBuilder (input .length () * 3 / 2 );
112
+
113
+ int lastElement = 0 ;
114
+ while (matcher .find ()) {
115
+ result .append (matcher .group (1 ));
116
+ result .append (keyToValue .apply (matcher .group (2 )));
117
+ lastElement = matcher .end ();
118
+ }
119
+ result .append (input .substring (lastElement ));
120
+ return result .toString ();
121
+ }
122
+
123
+ /** Regex which matches for {@code {{key}}}. */
124
+ private static final Pattern MUSTACHE_PATTERN = Pattern .compile ("(.*?)\\ {\\ {(.*?)\\ }\\ }" , Pattern .DOTALL );
96
125
}
0 commit comments