Subversion Repositories pub

Compare Revisions

No changes between revisions

Ignore whitespace Rev 67 → Rev 68

/pluggablejs/trunk/build.num
1,3 → 1,3
#Build Number for ANT. Do not edit!
#Wed Jul 02 21:19:34 CEST 2008
build.number=34
#Sat Jul 05 15:58:10 CEST 2008
build.number=36
/pluggablejs/trunk/build.xml
9,7 → 9,7
<property name="release" location="release"/>
<property name="depends" location="lib"/>
 
<property name="version" value="1.1.0"/>
<property name="version" value="1.1.1"/>
<property name="jarbasename" value="pluggablejs-${version}build" /><!-- followed by build.number, can't resolve yet -->
 
<target name="init">
/pluggablejs/trunk/debian/changelog
1,3 → 1,9
pluggablejs (1.1.1build36-upstream.0) experimental; urgency=low
 
* New release.
 
-- Toni Corvera <outlyer@gmail.com> Sat, 05 Jul 2008 15:58:16 +0200
 
pluggablejs (1.1.0build33-upstream.0) experimental; urgency=low
 
* New release.
/pluggablejs/trunk/ChangeLog
1,4 → 1,22
1.1.1build36: 2008-07-05
* Re-fixed including from within jar
* General bugfixes
+ Released
 
1.1.1build35: not a release
* Fixed loading of plugins from within jar
* Fixed including (lang.include()) files from within jar
* Added code injection to Sandbox while executing (SandboxAccessor's can
benefit from this)
* Made PluginProperties public again, otherwise it couldn't be modified
from JS
* Made PluginReader public
* Simplified plugin's properties retrieval (plugin identification over
the first line)
 
 
1.1.1build34: not a release
* Bumped revision number
* Renamed the $net object to $net_outlyer to be less intrusive
* Interactive shell prints the result of each line (optionally and on by default)
* Cleaner use of internal variables, there's no longer a need to
5,7 → 23,7
reserve any variable name / namespace beyond $net_outlyer
* lang.array() family of methods to create Java arrays
* lang.var_dump() to help in debugging
* lang.for_each()
* (optional) lang.for_each() as alternative to "for each"
 
1.1.0build33: 2008-07-01
* Sandbox can be created with no associated file (only boilerPlate code
18,6 → 36,7
* More opaque hierarchies where appropriate
* Output.print()
* PluginObject.features as a Set instead of a List
+ Released
 
1.1.0build32: not a release
* Removed the deprecated versions of Sandbox.createDelayedImplementation()
33,3 → 52,4
 
1.0build29: 2008-06-29
* Initial public pre-release
+ Released
/pluggablejs/trunk/src/net/outlyer/plugins/Shell.java
62,11 → 62,12
try {
// undocumented features: when
// $net_outlyer.runtime.internal.shell,autoEOL is true an extra println() is
// $net_outlyer.runtime.internal.shell.autoEOL is true an extra println() is
// issued after each eval
// and when
// $net_outlyer.runtime.internal.shell.inspect is true the result
// of each line is automatically printed
// arrayDump is used internally to print JavaScript arrays
rhino.eval(getInternalObjectFieldName("shell")+" = { " +
" autoEOL: false, inspect: true, arrayDump: null };");
jsArray = rhino.eval("new Array()");
74,8 → 75,8
// Define the arrayDump internal function
rhino.eval(arrayDumpFn+
" = function(arr) {\n" +
" var s = new String();" +
" s += '[';\n" +
" if (0==arr.length) { java.lang.System.out.println('[]'); return; }\n"+
" var s = new String('[');" +
" for (var i=0;i<arr.length;++i) {\n" +
" s += arr[i]+',';\n" +
" }\n" +
155,7 → 156,7
pe.exportObject("ui", new GUI());
pe.exportObject("gui", new GUI());
pe.exportObject("cui", new UI()); // cui stands for Console UI
pe.exportObject("lang", new LanguageExtensions());
pe.exportObject("lang", new RedundantLanguageExtensions());
final PluginObject po = new PluginObject();
pe.setPluginObject(po);
 
/pluggablejs/trunk/src/net/outlyer/plugins/PluginProperties.java
30,7 → 30,15
* Common properties of the plugin object. All of them
* take sane defaults.
*/
class PluginProperties extends SandboxAccessorImpl {
// Can't be package-protected or its fields won't be modifiable from
// js code!
// This limitation appears to apply only to fields, not methods
public class PluginProperties extends SandboxAccessorImpl {
 
// This class isn't meant to be used outside of this package, but must be
// public (see comment above)
PluginProperties(){}
/**
* pluggablejs Api Version against which this plugin was written.
* Default: 1
58,4 → 66,9
* @deprecated The use of this field is yet to be defined
*/
public Object properties; // FIXME: To be defined
 
@Override public String toString() {
return String.format("PluginProperties{ name=%s, type=%s, apiVersion=%d }",
name, type, apiVersion);
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/Internal.java
26,7 → 26,7
 
// $Id$
 
import java.util.Map;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
 
67,14 → 67,18
private static String mapName = "$_";
static String getInternalInitialisation() {
// Commented-out is the the closer-to-Java version
return String.format("= {\n" +
" %2$s: new java.util.HashMap(),\n" +
// " %2$s: new java.util.HashMap(),\n" +
" %2$s: {},\n" +
" set: function(n,v) {\n"+
" %1$s.put(n,v);\n" +
// " %1$s.put(n,v);\n" +
" %1$s[n] = v;\n" +
" return v;\n" +
" },\n" +
" get: function(n) {\n" +
" return %1$s.get(n);\n" +
// " return %1$s.get(n);\n" +
" return %1$s[n];\n" +
" }\n"+
"};",
getInternalObjectFieldName(mapName),
81,16 → 85,38
mapName);
}
 
static void setInternalValue(final ScriptEngine engine,
static void setInternalValue(final ScriptEngine e,
final String name,
final Object value) throws ScriptException {
final Map map = (Map) engine.eval(getInternalObjectFieldName(mapName));
map.put(name, value);
assert null != e;
assert null != name;
// final Map map = (Map) e.eval(getInternalObjectFieldName(mapName));
// map.put(name, value);
try {
assert e instanceof Invocable;
final Invocable ie = (Invocable) e;
ie.invokeMethod(e.eval(getInternalObjectName()), "set", name, value);
}
catch (final NoSuchMethodException x) {
throw new ScriptException("Internal error while storing " +
"internal variable: "+x.getMessage());
}
}
 
static Object getInternalValue(final ScriptEngine e,
final String name) throws ScriptException {
final Map map = (Map) e.eval(getInternalObjectFieldName(mapName));
return map.get(name);
assert null != e;
assert null != name;
// final Map map = (Map) e.eval(getInternalObjectFieldName(mapName));
// return map.get(name);
try {
assert e instanceof Invocable;
final Invocable ie = (Invocable) e;
return ie.invokeMethod(e.eval(getInternalObjectName()), name);
}
catch (final NoSuchMethodException x) {
throw new ScriptException("Internal error while accessing " +
"internal variable: "+x.getMessage());
}
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/utils/LanguageExtensions.java
28,7 → 28,6
 
import java.lang.reflect.Array;
import java.util.Arrays;
import net.outlyer.plugins.Functor;
import net.outlyer.plugins.SandboxAccessor;
 
/**
39,8 → 38,16
public class LanguageExtensions extends LanguageExtensions_V1
implements SandboxAccessor {
 
public static final int revision = 2;
public final int interfaceRevision;
 
public LanguageExtensions() {
this(2);
}
protected LanguageExtensions(int revision) {
interfaceRevision = revision;
}
 
// The array() family is mostly redundant since rhino translates
// automatically as required from JavaScript arrays to Java arrays
// but there are some edge-cases in which they might be desirable
49,7 → 56,7
* Create an array of the same class as the provided object.
* @param tplt Template for the array, must be non-null and non-Void
* @param size Size of the array to create (can be 0)
* @since {@link #revision} 2
* @since {@link #interfaceRevision} 2
*/
public <T> T[] array(final T tplt, int size) {
if (null == tplt || Void.class == tplt.getClass()) {
62,7 → 69,7
* Create an array of the provided class.
* @param c Class of the array elements, must be non-null and different from Void.class
* @param size Size of the array (can be 0)
* @since {@link #revision} 2
* @since {@link #interfaceRevision} 2
*/
public <T> T[] array(final Class<T> c, int size) {
return (T[]) Array.newInstance(c, size);
76,7 → 83,7
* <code>initValues.length</code> instead) (i.e., use 0 to
* get the same size as initValues)
* @param initValues Initial values to put in the array
* @since {@link #revision} 2
* @since {@link #interfaceRevision} 2
*/
public <T> T[] array(final T[] initValues, int size) {
if (null == initValues) {
95,7 → 102,7
/**
* Shorthand form, allows getting a Java array from a JavaScript array.
* @param initValues
* @since {@link #revision} 2
* @since {@link #interfaceRevision} 2
*/
public <T> T[] array(final T[] initValues) {
return array(initValues, initValues.length);
162,36 → 169,4
}
return sb.toString();
}
 
/**
* Apply a function to each element of an iterable collection.
* @see #for_each(Object[], Functor)
* @param c Collection to which to apply
* @param f Function to apply
* @since {@link #revision} 2
*/
public <T> void for_each(final Iterable<T> c, final Functor<Object, T> f) {
for (final T elem : c) {
f.apply(elem);
}
}
/**
* Apply a function to each element of an array
* A JavaScript function can be used transparently as a functor, e.g.:
* <br />
* <code>var arr = lang.array(new Array(1, 2, 3));<br />
* lang.for_each(arr, function(x) { err.println("Element: "+x); });</code>>
* Will produce:
* <pre>Element: 1<br />Element: 2<br />Element: 3</pre>
* @param a Array to which to apply
* @param f Function to apply
* @since {@link #revision} 2
*/
public <T> void for_each(final T[] a, final Functor<Object, T> f) {
if (null == a || null == f) {
return; // FIXME: Error handling
}
for_each(Arrays.asList(a), f);
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/utils/RedundantLanguageExtensions.java
0,0 → 1,80
package net.outlyer.plugins.utils;
 
/*
* Copyright (c) 2008, Toni Corvera. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
// $Id$
 
import java.util.Arrays;
import net.outlyer.plugins.Functor;
 
/**
* Language extensions provided already by JavaScript.
* Versions here provide alternative syntax or semantics to the builtin
* versions, based on other languages.
* <br />
* In general {@link LanguageExtensions} will be preferable over this class.
* @since {@link net.outlyer.plugins.API#REVISION} 1
* @since {@link #interfaceRevision} 2
*/
public class RedundantLanguageExtensions extends LanguageExtensions {
 
public RedundantLanguageExtensions() {
super(2);
}
 
/**
* Apply a function to each element of an iterable collection.
* Note JavaScript 1.6 DOES have a "for each" loop
* ({@link http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Statements:for_each...in})
* @see #for_each(Object[], Functor)
* @param c Collection to which to apply
* @param f Function to apply
* @since {@link #interfaceRevision} 2
*/
public <T> void for_each(final Iterable<T> c, final Functor<Object, T> f) {
for (final T elem : c) {
f.apply(elem);
}
}
/**
* Apply a function to each element of an array
* A JavaScript function can be used transparently as a functor, e.g.:
* <br />
* <code>var arr = lang.array(new Array(1, 2, 3));<br />
* lang.for_each(arr, function(x) { err.println("Element: "+x); });</code>>
* Will produce:
* <pre>Element: 1<br />Element: 2<br />Element: 3</pre>
* @param a Array to which to apply
* @param f Function to apply
* @since {@link #interfaceRevision} 2
*/
public <T> void for_each(final T[] a, final Functor<Object, T> f) {
if (null == a || null == f) {
return; // FIXME: Error handling
}
for_each(Arrays.asList(a), f);
}
}
Property changes:
Added: svn:keyword
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk/src/net/outlyer/plugins/utils/LanguageExtensions_V1.java
1,11 → 1,5
package net.outlyer.plugins.utils;
 
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import javax.script.ScriptException;
import net.outlyer.plugins.SandboxAccessorImpl;
 
/*
* Copyright (c) 2008, Toni Corvera. All rights reserved.
*
32,6 → 26,16
 
// $Id$
 
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.script.ScriptException;
import net.outlyer.plugins.PluginException;
import net.outlyer.plugins.PluginReader;
import net.outlyer.plugins.Sandbox;
import net.outlyer.plugins.SandboxAccessorImpl;
 
/**
* Initial version of LanguageExtensions.
* @see LanguageExtensions
61,19 → 65,53
* Load an external file
* @deprecated Not yet stabilised
*/
public Object include(final String fileName) { // TODO: Support jar URIs
public Object include(final String path) { // TODO: Support jar URIs
try {
return getSandbox().getCurrentEngine().eval(new FileReader(new File(fileName)));
if (path.startsWith("file:/") || path.startsWith("jar:file:/")) {
return include(new URI(path));
}
final File f = new File(path);
if (f.isAbsolute()) {
return include(f.toURI());
}
// Get a reasonable path
final Sandbox s = getSandbox();
final URI callerUri = s.loadedFrom();
// This isn't very elegant but works (in most cases?)...
final String c = callerUri.toString();
final int idx = callerUri.toString().lastIndexOf('/');
final URI reqUri = new URI(c.substring(0, idx)+"/"+path).normalize();
return include(reqUri);
}
catch (final FileNotFoundException e) {
catch (final URISyntaxException e) {
e.printStackTrace();
}
return null;
}
 
public Object include(final URI uri) {
if (null == uri) {
// TODO: Handle better
return null;
}
if (null == uri.getScheme() ||
(!"file".equals(uri.getScheme()) && !"jar".equals(uri.getScheme()))) {
throw new IllegalArgumentException("Only file and jar-contained files can be included");
}
 
try {
return getSandbox().inject(new PluginReader(uri));
}
catch (final IOException e) {
// FIXME: Handle better
System.err.println("Failed to read " + fileName);
System.err.println("Failed to read " + uri);
}
catch (final ScriptException e) {
catch (final PluginException e) {
// FIXME: Handle better
System.err.println("Exception: " + e.getMessage());
}
return null;
}
 
}
/pluggablejs/trunk/src/net/outlyer/plugins/SandboxImpl.java
30,6 → 30,7
// http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/
 
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Method;
import java.net.URI;
import java.util.Collection;
162,7 → 163,6
if (null != prependText) {
rhino.eval(prependText);
}
if (null != pluginUri) {
result = rhino.eval(new PluginReader(pluginUri));
}
228,7 → 228,7
preCode.append("};\n");
 
final ScriptEngine rhino = execute(preCode.toString(), null, null).rhino;
 
try {
final StringBuilder retriever = new StringBuilder();
retriever.append("new ")
358,4 → 358,27
public ScriptEngine getCurrentEngine() {
return currentEngine;
}
 
/**
* {@inheritDoc}
*/
public Object inject(final Reader code) throws IllegalStateException, PluginException {
synchronized (currentEngine) { // Probably not needed
if (null == currentEngine) {
throw new IllegalStateException("Can only inject code while a sandbox is executing");
}
try {
return currentEngine.eval(code);
}
catch (final ScriptException e) {
throw new PluginException("Failed to inject code: " + e.getMessage(), e);
}
}
}
 
@Override public String toString() {
return "Sandbox("+getClass().getSimpleName()+")["+loadedFrom()+"]";
}
}
/pluggablejs/trunk/src/net/outlyer/plugins/PluginReader.java
36,13 → 36,16
import java.net.URI;
 
/**
* java.io.Reader for plugins, tries to abstract the plugin location (file or jar)
* java.io.Reader for plugins, tries to abstract the plugin location (file or jar).
* Generally users of the library may only need such functionality in case
* some needs be fed to an existing sandbox (e.g.
* {@link net.outlyer.plugins.utils.LanguageExtensions_v1#include}).
*/
class PluginReader extends Reader {
public class PluginReader extends Reader {
 
private final Reader readerImpl;
 
PluginReader(final URI uri) throws IOException {
public PluginReader(final URI uri) throws IOException {
super();
assert null != uri;
 
/pluggablejs/trunk/src/net/outlyer/plugins/PluginLocator.java
81,7 → 81,6
void add(final String fileName, final PluginProperties pp, final Sandbox sbox) {
byName.put(pp.name, sbox);
byFilename.put(fileName, sbox);
if (byType.get(pp.type) == null) {
byType.put(pp.type, new LinkedList<Sandbox>());
}
299,7 → 298,7
/**
* Scan over a directory inside a jar file
* @param jarUri Directory to scan
* @return LIst of plugins in directory <code>jarUri</code>
* @return List of plugins in directory <code>jarUri</code>
*/
private void scan(final URI jarUri) {
assert jarUri.getScheme().equals("jar");
321,12 → 320,11
if (url.startsWith(root) && !je.isDirectory()) {
// Accepted URI
 
try {
final URI pluginUri = new URI("jar:"+jarFile+"!"+url);
 
final Sandbox sb = environment.createSandbox(pluginUri);
final PluginProperties pp = PluginEnvironment.fetchPluginProperties(jarUri);
final PluginProperties pp = PluginEnvironment.fetchPluginProperties(pluginUri);
// JarEntry's getName() returns the full path
final String fileName = new File(je.getName()).getName();
if (pp.name == null) {
/pluggablejs/trunk/src/net/outlyer/plugins/PluginEnvironment.java
280,7 → 280,7
 
try {
// Define a Plugin object with a field named type
rhino.eval("var plugin={ type: null, apiVersion: null };");
rhino.eval("var plugin={ type: null, apiVersion: null, name: null };");
}
catch (ScriptException e) {
assert false;
301,18 → 301,15
script.getLineNumber() <= linesToCheckForSupport) {
try {
rhino.eval(line);
// Note that undefined doesn't convert to null!
// XXX: Note that undefined doesn't convert to null, is this safe?
if (null == type) {
rhino.eval("$_1_$ = (undefined===plugin.type)?null:plugin.type;");
type = rhino.get("$_1_$");
type = rhino.eval("plugin.type;");
}
if (null == apiVersion) {
rhino.eval("$_1_$ = (undefined===plugin.apiVersion)?null:plugin.apiVersion;");
apiVersion = rhino.get("$_1_$");
apiVersion = rhino.eval("plugin.apiVersion;");
}
if (null == name) {
rhino.eval("$_1_$ = (undefined===plugin.name)?null:plugin.name;");
name = rhino.get("$_1_$");
name = rhino.eval("plugin.name;");
}
}
catch (final ScriptException e) {
338,7 → 335,6
apiVersion = 0;
}
// name can be null
final PluginProperties pp = new PluginProperties();
try {
pp.apiVersion = Double.valueOf(apiVersion.toString()).intValue();
/pluggablejs/trunk/src/net/outlyer/plugins/Sandbox.java
34,7 → 34,7
* Public methods provided by the sandbox.
*/
// Note that all methods defined directly in this interface imply a call to {@link #execute}.
public interface Sandbox extends RuntimeHooks, SandboxProperties {
public interface Sandbox extends RuntimeHooks, SandboxProperties, Sandbox_R1 {
/**
* Creates an implementation of an interface from a JS object
* containing the interface's methods.
47,7 → 47,9
* @see #createDelayedImplementation(Class,Map)
* @see #execute()
*/
<T> T createDelayedImplementation(final Class<T> interfaceClass, final String objectName) throws PluginExecutionException;
<T> T createDelayedImplementation(final Class<T> interfaceClass,
final String objectName)
throws PluginExecutionException;
 
/**
* Creates an implementation of an interface from inline JS code.
87,7 → 89,7
<T> T createDelayedImplementation(final Class<T> interfaceClass,
final Map<Method, String> methodToCodeMap)
throws PluginExecutionException;
 
/**
* Run the script
*/
94,6 → 96,14
void execute() throws PluginExecutionException;
 
/**
* Obtains a reference to the engine currently in use, if any.
* If called during an execution it will return the current engine, from calling
* outside will return null.
* @return Current ScriptEngine
*/
ScriptEngine getCurrentEngine();
 
/**
* Obtains object containing the plugin object
* <br />
* <b>Note</b>: Implies a call to {@link #execute()}.
101,12 → 111,4
* @return Plugin object associated to this sandbox
*/
BasePluginObject getPluginObject() throws PluginExecutionException;
 
/**
* Obtains a reference to the engine currently in use, if any.
* If called during an execution it will return the current engine, from calling
* outside will return null.
* @return Current ScriptEngine
*/
ScriptEngine getCurrentEngine();
}
/pluggablejs/trunk/src/net/outlyer/plugins/Sandbox_R1.java
0,0 → 1,45
package net.outlyer.plugins;
 
/*
* Copyright (c) 2008, Toni Corvera. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
 
// $Id$
 
import java.io.Reader;
 
/**
* Methods added to {@link Sandbox} in the first revision.
* @since {@link net.outlyer.plugins.API#REVISION} 1
*/
interface Sandbox_R1 {
/**
* Adds code to the code currently executing.
* @param code Source of code to add
* @return Evaluation result
* @throws java.lang.IllegalStateException If not currently running
* @throws net.outlyer.plugins.PluginException If the code failed to be injected
* @since {@link net.outlyer.plugins.API#REVISION} 1
*/
public Object inject(final Reader code) throws IllegalStateException, PluginException;
}
Property changes:
Added: svn:keywords
+Rev Id Date
\ No newline at end of property
/pluggablejs/trunk
Property changes:
Modified: svn:mergeinfo
Merged /pluggablejs/branches/1.1.1build36:r67