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!\""); - * + ** * 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 1: + * {@code + * ScriptingContainer container = new ScriptingContainer(); + * container.runScriptlet("puts \"Hello World!\""); + * } * Produces: - * Hello World!+ * Hello World! + *
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. * + ** * 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 2: + * {@code + * ScriptingContainer container = new ScriptingContainer(); + * container.put("x", 12345); + * container.runScriptlet("puts x.to_s(2)"); + * } * Produces: - * 11000000111001+ * 11000000111001 + *
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")); - * + ** * 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 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 + *
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)); - * + ** * 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)); + } + }+ * 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. + *