From fbae33595bb84eb8953586e56dd206c28d9d286e Mon Sep 17 00:00:00 2001 From: stbutler11 Date: Tue, 9 Dec 2014 16:23:22 +0000 Subject: [PATCH] Added in globbing for loading javascript files --- README.md | 4 +- pom.xml | 4 +- src/main/java/be/klak/rhino/RhinoContext.java | 97 +++++++++++++++++-- .../java/be/klak/rhino/RhinoContextTest.java | 17 ++++ src/test/javascript/globLoadTest/glob1.js | 1 + src/test/javascript/globLoadTest/glob2.js | 1 + .../javascript/globLoadTest/notGlobbed.js | 1 + 7 files changed, 112 insertions(+), 13 deletions(-) create mode 100644 src/test/javascript/globLoadTest/glob1.js create mode 100644 src/test/javascript/globLoadTest/glob2.js create mode 100644 src/test/javascript/globLoadTest/notGlobbed.js diff --git a/README.md b/README.md index 0aca039..7ba8a46 100644 --- a/README.md +++ b/README.md @@ -100,8 +100,8 @@ You can still use Firebug to debug when generating a specRunner HTML file (see b * debug: use the built-in Rhino debugger (gives you the chance to set a breakpoint before firing the test suite) * jsRootDir: the javascript install root dir. Jasmine and other should be installed here (see source) * sourcesRootDir: your production JS files root dir. -* specs: one or more spec file to run. Default behavior: use java Class name (replaces Test with Spec, see example) -* sources: one or more JS production file which your spec needs (included before specs, d'uh) +* specs: one or more spec file to run. You may also use the [glob syntax described here](https://docs.oracle.com/javase/7/docs/api/java/nio/file/FileSystem.html#getPathMatcher%28java.lang.String%29).For example to load all javascript files in subdir use subdir/*.js. Default behavior: use java Class name (replaces Test with Spec, see example). +* sources: one or more JS production file which your spec needs (included before specs, d'uh). You can use the same glob syntax as the specs option. * generateSpecRunner: (the HTML output, useful for firefox/firebug debugging etc) * specRunnerSubDir: a subsidiary path to the default runner root directory where generated spec runners will be placed * envJs: load EnvJS support (defaults to true) diff --git a/pom.xml b/pom.xml index a8c786b..d0a320f 100644 --- a/pom.xml +++ b/pom.xml @@ -62,8 +62,8 @@ maven-compiler-plugin 3.0 - 1.6 - 1.6 + 1.7 + 1.7 true true UTF-8 diff --git a/src/main/java/be/klak/rhino/RhinoContext.java b/src/main/java/be/klak/rhino/RhinoContext.java index d203197..9ca3d5d 100644 --- a/src/main/java/be/klak/rhino/RhinoContext.java +++ b/src/main/java/be/klak/rhino/RhinoContext.java @@ -1,6 +1,19 @@ package be.klak.rhino; +import java.io.IOException; import java.net.URL; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.PriorityQueue; import org.mozilla.javascript.Context; import org.mozilla.javascript.ContextFactory; @@ -77,13 +90,62 @@ public class RhinoContext { } } + public void load(String path, String... jsFiles) { - for (String jsFile : jsFiles) { - load(path + jsFile); + try { + List files = getFiles(path, jsFiles); + for (Path file: files) { + load(file.toString()); + } + } catch (IOException e) { + throw new RuntimeException(e); } } - public void load(String fileName) { + private List getFiles(String root, String... globs) throws IOException { + // Use a priority queue as the order of the files may make a difference + final PriorityQueue matchResults = new PriorityQueue<>(); + if (Paths.get(root).toFile().exists()) { + final List pathMatchers = getPathMatchers(root, globs); + Files.walkFileTree(Paths.get(root), new SimpleFileVisitor() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + MatchResult matchResult = match(file, pathMatchers); + if (matchResult != null) { + matchResults.add(matchResult); + }; + return super.visitFile(file, attrs); + } + }); + } + List paths = new ArrayList<>(); + for (MatchResult matchResult : matchResults) { + paths.add(matchResult.path); + } + return paths; + } + + private List getPathMatchers(String root, String[] globs) { + List matchers = new ArrayList<>(); + for (String glob : globs) { + matchers.add(FileSystems.getDefault().getPathMatcher("glob:" + root + glob)); + } + return matchers; + } + + + private MatchResult match(Path file, + List pathMatchers) { + MatchResult matchResult = null; + for (int i = 0; i < pathMatchers.size() && matchResult == null; i++) { + if (pathMatchers.get(i).matches(file)) { + matchResult = new MatchResult(i, file); + } + } + return matchResult; + } + + private void load(String fileName) { evalJS("load('" + fileName + "')"); // Main.processFile(this.jsContext, this.jsScope, fileName); } @@ -95,14 +157,14 @@ public class RhinoContext { * @param resource the resource to resolve from the classpath */ public void loadFromClasspath(final String resource) { - URL rsrcUrl = - Thread.currentThread().getContextClassLoader().getResource(resource); + URL rsrcUrl = + Thread.currentThread().getContextClassLoader().getResource(resource); - if (rsrcUrl == null) { - throw new IllegalArgumentException("resource " + resource + " not found on classpath"); - } + if (rsrcUrl == null) { + throw new IllegalArgumentException("resource " + resource + " not found on classpath"); + } - evalJS(String.format("load('%s')", rsrcUrl.toExternalForm())); + evalJS(String.format("load('%s')", rsrcUrl.toExternalForm())); } // }}} @@ -150,4 +212,21 @@ public class RhinoContext { public void exit() { Context.exit(); } + + private static class MatchResult implements Comparable { + + private final int position; + private final Path path; + + public MatchResult(int position, Path path) { + this.position = position; + this.path = path; + } + + @Override + public int compareTo(MatchResult o) { + return position - o.position; + } + + } } diff --git a/src/test/java/be/klak/rhino/RhinoContextTest.java b/src/test/java/be/klak/rhino/RhinoContextTest.java index 02261c6..c59617a 100644 --- a/src/test/java/be/klak/rhino/RhinoContextTest.java +++ b/src/test/java/be/klak/rhino/RhinoContextTest.java @@ -1,8 +1,10 @@ package be.klak.rhino; import static org.fest.assertions.Assertions.assertThat; +import static org.junit.Assert.fail; import org.junit.Test; +import org.mozilla.javascript.EcmaError; import org.mozilla.javascript.NativeObject; import org.mozilla.javascript.ScriptableObject; @@ -81,6 +83,21 @@ public class RhinoContextTest { assertThat(context.evalJS("loadedTwo")).isEqualTo(true); } + @Test + public void loadGlob() { + RhinoContext context = new RhinoContext(); + context.load("src/test/javascript/", "globLoadTest/g*.js"); + + assertThat(context.evalJS("glob1")).isEqualTo(1.0); + assertThat(context.evalJS("glob2")).isEqualTo(2.0); + try { + context.evalJS("notGlobbed"); + fail("notGlobbed should not have been loaded"); + } catch (EcmaError e) { + // TODO need a better way to detect that it was not loaded + } + } + // {{{ loadsJSFilesFromClasspath @Test public void loadsJSFilesFromClasspath() { diff --git a/src/test/javascript/globLoadTest/glob1.js b/src/test/javascript/globLoadTest/glob1.js new file mode 100644 index 0000000..cdc9f84 --- /dev/null +++ b/src/test/javascript/globLoadTest/glob1.js @@ -0,0 +1 @@ +var glob1 = 1; \ No newline at end of file diff --git a/src/test/javascript/globLoadTest/glob2.js b/src/test/javascript/globLoadTest/glob2.js new file mode 100644 index 0000000..1f0871e --- /dev/null +++ b/src/test/javascript/globLoadTest/glob2.js @@ -0,0 +1 @@ +var glob2 = 2; \ No newline at end of file diff --git a/src/test/javascript/globLoadTest/notGlobbed.js b/src/test/javascript/globLoadTest/notGlobbed.js new file mode 100644 index 0000000..3bf03dc --- /dev/null +++ b/src/test/javascript/globLoadTest/notGlobbed.js @@ -0,0 +1 @@ +var notGlobbed = "Shouldn't be loaded";