diff --git a/core/src/main/java/org/jruby/embed/ScriptingContainer.java b/core/src/main/java/org/jruby/embed/ScriptingContainer.java index 5ff4ee09e3d..106ff6ddfb0 100644 --- a/core/src/main/java/org/jruby/embed/ScriptingContainer.java +++ b/core/src/main/java/org/jruby/embed/ScriptingContainer.java @@ -29,16 +29,14 @@ */ package org.jruby.embed; -import java.io.UnsupportedEncodingException; -import org.jruby.embed.internal.LocalContextProvider; import java.io.InputStream; import java.io.PrintStream; import java.io.Reader; import java.io.Writer; -import java.net.URISyntaxException; import java.util.HashMap; import java.util.List; import java.util.Map; + import org.jruby.CompatVersion; import org.jruby.Profile; import org.jruby.Ruby; @@ -53,6 +51,7 @@ import org.jruby.embed.internal.EmbedRubyInterfaceAdapterImpl; import org.jruby.embed.internal.EmbedRubyObjectAdapterImpl; import org.jruby.embed.internal.EmbedRubyRuntimeAdapterImpl; +import org.jruby.embed.internal.LocalContextProvider; import org.jruby.embed.internal.SingleThreadLocalContextProvider; import org.jruby.embed.internal.SingletonLocalContextProvider; import org.jruby.embed.internal.ThreadSafeLocalContextProvider; @@ -80,42 +79,49 @@ * For example, a local context scope, local variable behavior, load paths are * per-container properties. Please see {@link PropertyName} and {@link AttributeName} * for more details. Be aware that the per-container properties should be set prior to - * get Ruby runtime be instantiated; otherwise, default values are applied to. + * get Ruby runtime being instantiated; otherwise, default values are applied to. + * * ScriptingContainer delays Ruby runtime initialization as much as possible to * improve startup time. When values are put into the ScriptingContainer, or runScriptlet - * method gets run Ruby runtime is created internally. However, the default, singleton - * local context scope behave slightly different. If Ruby runtime has been already instantiated - * by another ScriptingContainer, application, etc, the same runtime will be used. + * method gets run the runtime is created internally. However, the default, singleton + * local context scope behave slightly different. If a Ruby runtime has been already + * instantiated by another ScriptingContainer, application, etc, the same runtime + * will be re-used. * * Below are examples. * * The first Example is a very simple Hello World. After initializing a ScriptingContainer, * a Ruby script, puts "Hello World!", runs and produces "Hello World!." - *
Example 1:
- *
- *         ScriptingContainer container = new ScriptingContainer();
- *         container.runScriptlet("puts \"Hello World!\"");
- *
+ * 
+ * Example 1:
+ * {@code
+ *     ScriptingContainer container = new ScriptingContainer();
+ *     container.runScriptlet("puts \"Hello World!\"");
+ * }
  * Produces:
- * Hello World!
+ * Hello World! + *
* * The second example shows how to share variables between Java and Ruby. - * In this example, a local variable "x" is shared. To make this happen, a local variable - * behavior should be transient or persistent. As for JSR223 JRuby engine, set these - * types using System property, org.jruby.embed.localvariable.behavior. If the local - * variable behavior is one of transient or persistent, + * In this example, a local variable {@code "x"} is shared. To make this happen, + * a local variable behavior should be transient or persistent. + * As for JSR223 JRuby engine, set these types using a System property, + * org.jruby.embed.localvariable.behavior. + * If the local variable behavior is one of transient or persistent, * Ruby's local, instance, global variables and constants are available to share * between Java and Ruby. (A class variable sharing does not work on current version) - * Thus, "x" in Java is also "x" in Ruby. - * - *
Example 2:
- *
- *         ScriptingContainer container = new ScriptingContainer();
- *         container.put("x", 12345);
- *         container.runScriptlet("puts x.to_s(2)");
+ * Thus, {@code "x"} in Java is also {@code "x"} in Ruby.
  *
+ * 
+ * Example 2:
+ * {@code
+ *     ScriptingContainer container = new ScriptingContainer();
+ *     container.put("x", 12345);
+ *     container.runScriptlet("puts x.to_s(2)");
+ * }
  * Produces:
- * 11000000111001
+ * 11000000111001 + *
* * The third examples shows how to keep local variables across multiple evaluations. * This feature simulates BSF engine for JRuby. In terms of Ruby semantics, @@ -123,18 +129,19 @@ * this behavior is optional, and users need to specify LocalVariableBehavior.PERSISTENT * when the container is instantiated. * - *
Example 3:
- *
- *         ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
- *         container.runScriptlet("p=9.0");
- *         container.runScriptlet("q = Math.sqrt p");
- *         container.runScriptlet("puts \"square root of #{p} is #{q}\"");
- *         System.out.println("Ruby used values: p = " + container.get("p") +
- *               ", q = " + container.get("q"));
- *
+ * 
+ * Example 3:
+ * {@code
+ *     ScriptingContainer container = new ScriptingContainer(LocalVariableBehavior.PERSISTENT);
+ *     container.runScriptlet("p=9.0");
+ *     container.runScriptlet("q = Math.sqrt p");
+ *     container.runScriptlet("puts \"square root of #{p} is #{q}\"");
+ *     System.out.println("Ruby used values: p = " + container.get("p") + ", q = " + container.get("q"));
+ * }
  * Produces:
  * square root of 9.0 is 3.0
- * Ruby used values: p = 9.0, q = 3.0
+ * Ruby used values: p = 9.0, q = 3.0 + *
* * Also, ScriptingContainer provides better i18n support. For example, * Unicode Escape Sequence can be included in Ruby scripts. @@ -143,28 +150,31 @@ * invoking methods defined by Ruby, and getting an instance of a specified interface * that has been implemented by Ruby. * - *
Example 4:
- *         ScriptingContainer container = new ScriptingContainer();
- *         script =
- *          "def message\n" +
- *              "\"message: #{@message}\"\n" +
- *          "end\n" +
- *          "message";
- *         container.put("@message", "What's up?");
- *         EvalUnit unit = container.parse(script);
- *         IRubyObject ret = unit.run();
- *         System.out.println(JavaEmbedUtils.rubyToJava(ret));
- *         container.put("@message", "Fabulous!");
- *         ret = unit.run();
- *         System.out.println(JavaEmbedUtils.rubyToJava(ret));
- *         container.put("@message", "That's the way you are.");
- *         ret = unit.run();
- *         System.out.println(JavaEmbedUtils.rubyToJava(ret));
- *
+ * 
+ * Example 4:
+ * {@code
+ *     ScriptingContainer container = new ScriptingContainer();
+ *     String script =
+ *       "def message\n" +
+ *         "\"message: #{@message}\"\n" +
+ *       "end\n" +
+ *       "message";
+ *     container.put("@message", "What's up?");
+ *     JavaEmbedUtils.EvalUnit unit = container.parse(script);
+ *     IRubyObject msg = unit.run(); // a RubyString instance
+ *     System.out.println(JavaEmbedUtils.rubyToJava(msg));
+ *     container.put("@message", "Fabulous!");
+ *     msg = unit.run();
+ *     System.out.println(JavaEmbedUtils.rubyToJava(msg));
+ *     container.put("@message", "That's the way you are.");
+ *     msg = unit.run();
+ *     System.out.println(JavaEmbedUtils.rubyToJava(msg));
+ * }
  * Produces:
  *     message: What's up?
  *     message: Fabulous!
- *     message: That's the way you are.
+ * message: That's the way you are. + *
* * See more details at project's * {@see Wiki} diff --git a/core/src/test/java/org/jruby/embed/ScriptingContainerTest.java b/core/src/test/java/org/jruby/embed/ScriptingContainerTest.java index 9f9e9ba4ab3..846b48bce79 100644 --- a/core/src/test/java/org/jruby/embed/ScriptingContainerTest.java +++ b/core/src/test/java/org/jruby/embed/ScriptingContainerTest.java @@ -29,8 +29,6 @@ */ package org.jruby.embed; -import org.jruby.embed.internal.ConcurrentLocalContextProvider; - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -63,6 +61,7 @@ import org.jruby.RubyInstanceConfig.LoadServiceCreator; import org.jruby.ast.Node; import org.jruby.embed.internal.BiVariableMap; +import org.jruby.embed.internal.ConcurrentLocalContextProvider; import org.jruby.embed.internal.LocalContextProvider; import org.jruby.embed.internal.SingleThreadLocalContextProvider; import org.jruby.embed.internal.SingletonLocalContextProvider; @@ -205,7 +204,7 @@ public void testGetProvider() { result = instance.getProvider(); assertTrue(result instanceof SingletonLocalContextProvider); instance = null; - + instance = new ScriptingContainer(LocalContextScope.CONCURRENT); instance.setError(pstream); instance.setOutput(pstream); @@ -227,7 +226,7 @@ public void testGetRuntime() { instance.setOutput(pstream); instance.setWriter(writer); instance.setErrorWriter(writer); - Ruby runtime = JavaEmbedUtils.initialize(new ArrayList()); + Ruby runtime = JavaEmbedUtils.initialize(new ArrayList()); Ruby result = instance.getProvider().getRuntime(); Class expClazz = runtime.getClass(); Class resultClazz = result.getClass(); @@ -267,7 +266,7 @@ public void testGetVarMap() { assertEquals(1.2345, instance.getVarMap().get("parameter")); result.put("@coefficient", 4); assertEquals(4, instance.getVarMap().get("@coefficient")); - + result.clear(); instance = null; } @@ -281,7 +280,7 @@ public void testGetAttributeMap() { ScriptingContainer instance = new ScriptingContainer(LocalContextScope.THREADSAFE); instance.setError(pstream); instance.setOutput(pstream); - + Map result = instance.getAttributeMap(); Object obj = result.get(AttributeName.READER); assertEquals(obj.getClass(), java.io.InputStreamReader.class); @@ -289,7 +288,7 @@ public void testGetAttributeMap() { assertEquals(obj.getClass(), java.io.PrintWriter.class); obj = result.get(AttributeName.ERROR_WRITER); assertEquals(obj.getClass(), java.io.PrintWriter.class); - + result.put(AttributeName.BASE_DIR, "/usr/local/lib"); assertEquals("/usr/local/lib", result.get(AttributeName.BASE_DIR)); @@ -369,7 +368,7 @@ public void testGet() { Object expResult = null; Object result = instance.get(key); assertEquals(expResult, result); - + instance.put("@name", "camellia"); assertEquals("camellia", instance.get("@name")); instance.put("COLOR", "red"); @@ -398,7 +397,7 @@ public void testGet() { instance.setErrorWriter(writer); instance.runScriptlet("ivalue = 200000"); assertEquals(200000L, instance.get("ivalue")); - + instance.getVarMap().clear(); instance = null; } @@ -582,7 +581,7 @@ public void testParse_3args_2() { instance.setWriter(writer); instance.setErrorWriter(writer); EmbedEvalUnit result; - + try { result = instance.parse(type, filename, lines); } catch (Throwable t) { @@ -862,7 +861,7 @@ public void testNewRuntimeAdapter() { instance.setWriter(writer); instance.setErrorWriter(writer); EmbedRubyRuntimeAdapter result = instance.newRuntimeAdapter(); - String script = + String script = "def volume\n"+ " (Math::PI * (@r ** 2.0) * @h)/3.0\n" + "end\n" + @@ -1053,12 +1052,12 @@ public void testCallMethod_4args_3() { instance.setOutput(pstream); instance.setWriter(writer); instance.setErrorWriter(writer); - + // Verify that empty message name returns null Object result = instance.callMethod(null, "", returnType, unit); assertEquals(null, result); - String text = + String text = "songs:\n"+ "- Hey Soul Sister\n" + "- Who Says\n" + @@ -1554,7 +1553,7 @@ public void testGetLoadPaths() { List result = instance.getLoadPaths(); assertTrue(result != null); assertTrue(result.size() > 0); - + instance = null; } @@ -1941,7 +1940,7 @@ public void testSetEnvironment() { instance.setEnvironment(environment); assertEquals(environment, instance.getEnvironment()); - + instance = null; } @@ -1986,7 +1985,7 @@ public void testSetCurrentDirectory() { instance = new ScriptingContainer(); instance.setCurrentDirectory(directory); assertEquals(directory, instance.getCurrentDirectory()); - + instance = new ScriptingContainer(LocalContextScope.CONCURRENT); instance.setError(pstream); instance.setOutput(pstream); @@ -1994,7 +1993,7 @@ public void testSetCurrentDirectory() { instance.setErrorWriter(writer); instance.setCurrentDirectory(directory); assertEquals(directory, instance.getCurrentDirectory()); - + instance = new ScriptingContainer(LocalContextScope.SINGLETHREAD); instance.setError(pstream); instance.setOutput(pstream); @@ -2162,7 +2161,7 @@ public void testSetProfile() { profile = Profile.ALL; instance.setProfile(profile); assertEquals(profile, instance.getProfile()); - + instance = null; } @@ -2244,7 +2243,7 @@ public void testSetArgv() { //instance.setErrorWriter(writer); argv = new String[] {"tree", "woods", "forest"}; instance.setArgv(argv); - String script = + String script = "def print_argv\n" + "all_of_them = \"\"\n" + "ARGV.each { |item| all_of_them += item }\n" + @@ -2636,7 +2635,7 @@ public void testSharingVariableWithCompileMode() { instance.setError(pstream); instance.setOutput(pstream); instance.setErrorWriter(writer); - + instance.put("my_var", "Hullo!"); StringWriter sw = new StringWriter(); @@ -2646,7 +2645,7 @@ public void testSharingVariableWithCompileMode() { assertEquals("Hullo!", sw.toString().trim()); // need to put the lvar again since lvars vanish after eval on a transient setting - instance.put("my_var", "Hullo!"); + instance.put("my_var", "Hullo!"); sw = new StringWriter(); instance.setWriter(sw); instance.setCompileMode(CompileMode.JIT); @@ -2662,7 +2661,7 @@ public void testSharingVariableWithCompileMode() { instance = null; } - + public void testEmbedEvalUnitCompileModes() { org.jruby.embed.ScriptingContainer container = new org.jruby.embed.ScriptingContainer(); container.setCompileMode(CompileMode.OFF); @@ -2711,7 +2710,7 @@ public void testNullToContextClassLoader() { instance = null; } } - + /** * Test of setClassLoader method, of SystemPropertyCatcher. * This method is only used in JSR223 but tested here. Since, JSR223 @@ -2724,13 +2723,13 @@ public void testSystemPropertyCatcherSetClassloader() { ScriptingContainer instance = new ScriptingContainer(LocalContextScope.SINGLETHREAD); org.jruby.embed.util.SystemPropertyCatcher.setClassLoader(instance); assertEquals(instance.getClass().getClassLoader(), instance.getClassLoader()); - + System.setProperty(PropertyName.CLASSLOADER.toString(), "context"); instance = new ScriptingContainer(LocalContextScope.SINGLETHREAD); org.jruby.embed.util.SystemPropertyCatcher.setClassLoader(instance); assertEquals(Thread.currentThread().getContextClassLoader(), instance.getClassLoader()); } - + /** * Test of setClassLoader method, of SystemPropertyCatcher. * This method is only used in JSR223 but tested here. Since, JSR223 @@ -2770,4 +2769,28 @@ public void testContainerScrubsStdioDescriptors() { assertEquals(orig, ChannelDescriptor.getFilenoDescriptorMapReadOnly()); } + + @Test + public void testJavadocExample4() { + ScriptingContainer container = new ScriptingContainer(); + String script = + "def message\n" + + "\"message: #{@message}\"\n" + + "end\n" + + "message"; + container.put("@message", "What's up?"); + JavaEmbedUtils.EvalUnit unit = container.parse(script); + IRubyObject msg = unit.run(); // a RubyString instance + assertEquals("message: What's up?", JavaEmbedUtils.rubyToJava(msg)); + //System.out.println(JavaEmbedUtils.rubyToJava(msg)); + container.put("@message", "Fabulous!"); + msg = unit.run(); + assertEquals("message: Fabulous!", JavaEmbedUtils.rubyToJava(msg)); + //System.out.println(JavaEmbedUtils.rubyToJava(msg)); + container.put("@message", "That's the way you are."); + msg = unit.run(); + assertEquals("message: That's the way you are.", JavaEmbedUtils.rubyToJava(msg)); + //System.out.println(JavaEmbedUtils.rubyToJava(msg)); + } + }