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-plugin3.0
-
- 1.6
+
+ 1.7truetrueUTF-8
diff --git a/src/main/java/be/klak/rhino/RhinoContext.java b/src/main/java/be/klak/rhino/RhinoContext.java
index d203197..69670cc 100644
--- a/src/main/java/be/klak/rhino/RhinoContext.java
+++ b/src/main/java/be/klak/rhino/RhinoContext.java
@@ -1,6 +1,21 @@
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.apache.commons.io.FilenameUtils;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.ContextFactory;
@@ -77,14 +92,64 @@ 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) {
- evalJS("load('" + 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) {
+ String path = FilenameUtils.separatorsToUnix(fileName);
+ evalJS("load('" + path + "')");
// Main.processFile(this.jsContext, this.jsScope, fileName);
}
@@ -95,14 +160,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 +215,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";