Skip to content

Commit

Permalink
Allow for decorating rendered text using a VariableWrapper
Browse files Browse the repository at this point in the history
  • Loading branch information
michel-kraemer committed Nov 16, 2016
1 parent 34f4315 commit e474383
Show file tree
Hide file tree
Showing 11 changed files with 255 additions and 7 deletions.
11 changes: 9 additions & 2 deletions buildSrc/src/main/groovy/SourceGenerator.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ class SourceGenerator {
if (p.required) {
attrs.requiredProps += p
}
p.enumType = (p.type.equals("CSLType") || p.type.equals("CSLLabel"))
p.enumType = (p.type.equals("CSLType") || p.type.equals("CSLLabel") || p.type.equals("Context"))
p.cslType = (p.type.startsWith("CSL"))
if (p.type.endsWith("[]")) {
p.arrayType = true
Expand All @@ -117,7 +117,11 @@ class SourceGenerator {
}
attrs.props.removeAll(attrs.requiredProps)
}


if (attrs.additionalImports == null) {
attrs.additionalImports = []
}

if (attrs.additionalMethods == null) {
attrs.additionalMethods = []
}
Expand Down Expand Up @@ -184,6 +188,7 @@ class SourceGenerator {
def dst = new File(project.projectDir, 'src-gen/main/java')
dst.mkdirs()

renderTemplatesInternal('Context', dst, true)
renderTemplatesInternal('CSLType', dst, true)
renderTemplatesInternal('CSLLabel', dst, true)
renderTemplatesInternal('SecondFieldAlign', dst, true)
Expand All @@ -203,6 +208,8 @@ class SourceGenerator {

renderTemplatesInternal('Bibliography', dst)
renderTemplatesInternal('Citation', dst)

renderTemplatesInternal('VariableWrapperParams', dst)

renderParserTemplate('EndNoteParser', dst)
renderParserTemplate('RISParser', dst)
Expand Down
26 changes: 24 additions & 2 deletions citeproc-java/src/main/java/de/undercouch/citeproc/CSL.java
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,28 @@ public CSL(ItemDataProvider itemDataProvider, LocaleProvider localeProvider,
public CSL(ItemDataProvider itemDataProvider, LocaleProvider localeProvider,
AbbreviationProvider abbreviationProvider, String style,
String lang, boolean forceLang) throws IOException {
this(itemDataProvider, localeProvider, abbreviationProvider, null,
style, lang, forceLang);
}

/**
* Constructs a new citation processor
* @param itemDataProvider an object that provides citation item data
* @param localeProvider an object that provides CSL locales
* @param abbreviationProvider an object that provides abbreviations
* @param variableWrapper an object that decorates rendered items
* @param style the citation style to use. May either be a serialized
* XML representation of the style or a style's name such as <code>ieee</code>.
* In the latter case, the processor loads the style from the classpath (e.g.
* <code>/ieee.csl</code>)
* @param lang an RFC 4646 identifier for the citation locale (e.g. <code>en-US</code>)
* @param forceLang true if the given locale should overwrite any default locale
* @throws IOException if the underlying JavaScript files or the CSL style
* could not be loaded
*/
public CSL(ItemDataProvider itemDataProvider, LocaleProvider localeProvider,
AbbreviationProvider abbreviationProvider, VariableWrapper variableWrapper,
String style, String lang, boolean forceLang) throws IOException {
runner = getRunner();

//load style if needed
Expand All @@ -250,7 +272,7 @@ public CSL(ItemDataProvider itemDataProvider, LocaleProvider localeProvider,
try {
engine = runner.callMethod("makeCsl", Object.class,
style, lang, forceLang, runner, itemDataProvider,
localeProvider, abbreviationProvider);
localeProvider, abbreviationProvider, variableWrapper);
} catch (ScriptRunnerException e) {
throw new IllegalArgumentException("Could not parse arguments", e);
}
Expand Down Expand Up @@ -468,7 +490,7 @@ public void setAbbreviations(String name) {
throw new IllegalArgumentException("Could not set abbreviations", e);
}
}

/**
* Introduces the given citation IDs to the processor. The processor will
* call {@link ItemDataProvider#retrieveItem(String)} for each ID to get
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Copyright 2016 Michel Kraemer
//
// 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 de.undercouch.citeproc;

/**
* Decorates individual items in citations and bibliographies
* @author Michel Kraemer
*/
public interface VariableWrapper {
/**
* This method will be called by the citation processor when an item in a
* citation or bibliography is about to be rendered. The method may change
* the way the item is rendered, for example, by prepending or appending
* strings, or by completely replacing the item. The default implementation
* of this method always returns <code>prePunct + str + postPunct</code>.
* @param params a number of parameters that specify the context in which
* rendering happens, the citation item that is currently being rendered,
* and additional information.
* @param prePunct the text that precedes the item to render
* @param str the item to render
* @param postPunct the text that follows the item to render
* @return the string to be rendered
*/
String wrap(VariableWrapperParams params, String prePunct, String str, String postPunct);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

import de.undercouch.citeproc.VariableWrapper;
import de.undercouch.citeproc.VariableWrapperParams;
import de.undercouch.citeproc.helper.json.JsonBuilder;
import de.undercouch.citeproc.helper.json.JsonObject;
import de.undercouch.citeproc.helper.json.StringJsonBuilder;
Expand Down Expand Up @@ -136,13 +138,51 @@ private Object[] convertArguments(Object[] args) throws ScriptException {
Object o = args[i];
//convert JSON objects, collections, arrays, and maps, but do
//not convert script objects (such as Bindings)
if (o instanceof JsonObject || o instanceof Collection || o.getClass().isArray() ||
if (o == null) {
result[i] = null;
} else if (o instanceof JsonObject || o instanceof Collection || o.getClass().isArray() ||
(o instanceof Map && o.getClass().getPackage().getName().startsWith("java."))) {
result[i] = engine.eval("(" + createJsonBuilder().toJson(o).toString() + ")");
} else if (o instanceof VariableWrapper) {
o = new VariableWrapperWrapper((VariableWrapper)o);
result[i] = o;
} else {
result[i] = o;
}
}
return result;
}

/**
* <p>Wraps around {@link VariableWrapper} and converts
* {@link VariableWrapperParams} objects to JSON objects</p>
* <p>Note: this class must be public so Nashorn can inspect it and
* find the <code>wrap()</code> method.</p>
* @author Michel Kraemer
*/
public static class VariableWrapperWrapper {
private final VariableWrapper wrapper;

/**
* Creates a new wrapper
* @param wrapper the variable wrapper to wrap around
*/
public VariableWrapperWrapper(VariableWrapper wrapper) {
this.wrapper = wrapper;
}

/**
* Call the {@link VariableWrapper} with the given parameters
* @param params the context in which an item should be rendered
* @param prePunct the text that precedes the item to render
* @param str the item to render
* @param postPunct the text that follows the item to render
* @return the string to be rendered
*/
public String wrap(Map<String, Object> params, String prePunct,
String str, String postPunct) {
VariableWrapperParams p = VariableWrapperParams.fromJson(params);
return wrapper.wrap(p, prePunct, str, postPunct);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
import de.undercouch.citeproc.AbbreviationProvider;
import de.undercouch.citeproc.ItemDataProvider;
import de.undercouch.citeproc.LocaleProvider;
import de.undercouch.citeproc.VariableWrapper;
import de.undercouch.citeproc.VariableWrapperParams;
import de.undercouch.citeproc.csl.CSLAbbreviationList;
import de.undercouch.citeproc.csl.CSLItemData;
import de.undercouch.citeproc.helper.json.JsonBuilder;
Expand Down Expand Up @@ -223,7 +225,9 @@ private V8Array convertArguments(Object[] args, Set<V8Value> newValues) {
//convert the values
for (int i = 0; i < args.length; ++i) {
Object o = args[i];
if (o instanceof JsonObject || o instanceof Collection ||
if (o == null) {
result.push(V8Value.NULL);
} else if (o instanceof JsonObject || o instanceof Collection ||
o.getClass().isArray() || o instanceof Map) {
V8Object v = runtime.executeObjectScript("(" +
createJsonBuilder().toJson(o).toString() + ")");
Expand All @@ -247,6 +251,11 @@ private V8Array convertArguments(Object[] args, Set<V8Value> newValues) {
V8Object v8o = convertJavaObject(o);
newValues.add(v8o);
result.push(v8o);
} else if (o instanceof VariableWrapper) {
o = new VariableWrapperWrapper((VariableWrapper)o);
V8Object v8o = convertJavaObject(o);
newValues.add(v8o);
result.push(v8o);
} else if (o instanceof V8ScriptRunner || o instanceof LocaleProvider) {
V8Object v8o = convertJavaObject(o);
newValues.add(v8o);
Expand Down Expand Up @@ -334,4 +343,33 @@ public Object getAbbreviations(String name) {
return a.toJson(createJsonBuilder());
}
}

/**
* Wraps around {@link VariableWrapper} and converts
* {@link VariableWrapperParams} objects to JSON objects
* @author Michel Kraemer
*/
private class VariableWrapperWrapper {
private final VariableWrapper wrapper;

public VariableWrapperWrapper(VariableWrapper wrapper) {
this.wrapper = wrapper;
}

/**
* Call the {@link VariableWrapper} with the given parameters
* @param params the context in which an item should be rendered
* @param prePunct the text that precedes the item to render
* @param str the item to render
* @param postPunct the text that follows the item to render
* @return the string to be rendered
*/
@SuppressWarnings("unused")
public String wrap(Object params, String prePunct,
String str, String postPunct) {
Map<String, Object> m = convertObject((V8Object)params);
VariableWrapperParams p = VariableWrapperParams.fromJson(m);
return wrapper.wrap(p, prePunct, str, postPunct);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,17 @@ Sys.prototype.setAbbreviations = function(name) {
};

function makeCsl(style, lang, forceLang, scriptRunner, itemDataProvider,
localeProvider, abbreviationProvider) {
localeProvider, abbreviationProvider, variableWrapper) {
var sys = new Sys();
sys.scriptRunner = scriptRunner;
sys.itemDataProvider = itemDataProvider;
sys.localeProvider = localeProvider;
sys.abbreviationProvider = abbreviationProvider;
if (variableWrapper) {
sys.variableWrapper = function(params, prePunct, str, postPunct) {
return variableWrapper.wrap(params, prePunct, str, postPunct);
};
}
return new CSL.Engine(sys, style, lang, forceLang);
}

Expand Down
29 changes: 29 additions & 0 deletions citeproc-java/src/test/java/de/undercouch/citeproc/CSLTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,35 @@ public void abbreviations() throws Exception {
assertEquals("Johnson and Kernighan, \u201cB.\u201d", a.get(0).getText());
}

/**
* Tests if output can be decorated
* @throws Exception if something goes wrong
*/
@Test
public void variableWrapper() throws Exception {
VariableWrapper wrapper = new VariableWrapper() {
@Override
public String wrap(VariableWrapperParams params, String prePunct,
String str, String postPunct) {
if (params.getContext() == Context.CITATION &&
Arrays.asList(params.getVariableNames()).contains("author")) {
return prePunct + "<strong>" + str + "</strong>" + postPunct;
}
return prePunct + str + postPunct;
}
};

CSL citeproc = new CSL(new ListItemDataProvider(items),
new DefaultLocaleProvider(), new DefaultAbbreviationProvider(),
wrapper, "chicago-note-bibliography", "en-US", false);

List<Citation> a = citeproc.makeCitation(items[0].getId());
assertEquals(0, a.get(0).getIndex());
assertEquals("<strong>Johnson and Kernighan</strong>, "
+ "\u201cThe Programming Language B.\u201d",
a.get(0).getText());
}

/**
* Tests if citation items can be registered unsorted
* @throws Exception if something goes wrong
Expand Down
4 changes: 4 additions & 0 deletions citeproc-java/templates/Builder.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@

import java.util.Map;

<% for (i in additionalImports) { %>
import ${i};
<% } %>

/**
* Builder for {@link $name}
* @author Michel Kraemer
Expand Down
10 changes: 10 additions & 0 deletions citeproc-java/templates/Context.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Context",
"pkg": "de.undercouch.citeproc",
"description": "A context in which rendering happens",

"types": [
"citation",
"bibliography"
]
}
4 changes: 4 additions & 0 deletions citeproc-java/templates/Object.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@
import de.undercouch.citeproc.helper.json.JsonObject;
<% } %>

<% for (i in additionalImports) { %>
import ${i};
<% } %>

/**
* $description
* @author Michel Kraemer
Expand Down
52 changes: 52 additions & 0 deletions citeproc-java/templates/VariableWrapperParams.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
{
"name": "VariableWrapperParams",
"pkg": "de.undercouch.citeproc",
"description": "Parameters for a {@link de.undercouch.citeproc.VariableWrapper}",

"additionalImports": [
"de.undercouch.citeproc.csl.CSLItemData"
],

"props": [
{
"type": "CSLItemData",
"name": "itemData"
},
{
"type": "String[]",
"name": "variableNames"
},
{
"type": "Context",
"name": "context"
},
{
"type": "String",
"name": "xclass"
},
{
"type": "String",
"name": "position"
},
{
"type": "Integer",
"name": "note-number"
},
{
"type": "Integer",
"name": "first-reference-note-number"
},
{
"type": "Integer",
"name": "citation-number"
},
{
"type": "Integer",
"name": "index"
},
{
"type": "String",
"name": "mode"
}
]
}

0 comments on commit e474383

Please sign in to comment.