You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@ant.apache.org by Jacob Beard <jb...@cs.mcgill.ca> on 2010/08/21 18:18:53 UTC

Rhino global.load() in script context

Hi,

My Ant script currently generates JavaScript modules, and I also have 
JavaScript modules for unit testing the generated JavaScript. What I'd 
like to do is use a Rhino script element to load the generated 
JavaScript and the unit test modules, and run one on the other. In order 
to do this, I thought I would use Rhino's global.load() function, 
passing in paths as needed, but it looks like load() is not available in 
the global object when running in the Ant script context. Alternatively, 
it seems it would be possible to use Rhino (loadfile task) or Java API's 
to read the contents of the files and then eval them, but unfortunately 
the unit test module has dependencies on other modules, and the module 
loader relies on the existence of load() when running under Rhino. I'm 
wondering, is it possible to gain access to load() in the Ant script 
context?

Thanks,

Jake

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Peter Reilly <pe...@gmail.com>.
That is pretty awesome!.

Peter

On Tue, Aug 24, 2010 at 1:53 AM, Jacob Beard <jb...@cs.mcgill.ca> wrote:
> And here is what it looks like now:
>
> https://svn.apache.org/repos/asf/commons/sandbox/gsoc/2010/scxml-js/trunk/build.xml
>
> Most interesting parts are target run-unit-tests-with-rhino target and macro
> run-unit-tests-with-selenium-macro. I'm pretty happy with this result, as it
> has allowed me to integrate javac compilation with testing of my JavaScript
> modules, and to reuse code from my original build script written in
> JavaScript.
>
> Jake
>
> On 10-08-23 01:56 PM, Greg Roodt wrote:
>>
>> No problem. I had fun discovering how to make it work. I like the macro
>> idea
>> btw.
>>
>> Cheers
>> Greg
>>
>> On 22 Aug 2010 14:03, "Jacob Beard"<jb...@cs.mcgill.ca>  wrote:
>>
>>>
>>> Hi Greg,
>>>
>>> I'll bring it up on the developer's list.
>>>
>>> I've created a macro that sets up the rhino environment, so right now
>>> this seems like a good enough solution for me:
>>>
>>> <macrodef name="rhinoscript">
>>>
>>> <text name="text"/>
>>>
>>> <sequential>
>>>
>>> <script language="javascript" manager="bsf">
>>>
>>> <classpath>
>>>
>>> <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>
>>> <fileset dir="../../../lib/build-java/" includes="*.jar"></fileset>
>>>
>>> </classpath><![CDATA[
>>>
>>> importPackage(java.lang, java.util, java.io);
>>>
>>> //System.out.println("Hello from JavaScript!!");
>>>
>>> //create shell, execute something and grab global
>>>
>>> var shell = org.mozilla.javascript.tools.shell.Main;
>>>
>>> var args = ["-e","var a='STRING';"];
>>>
>>> shell.exec(args);
>>>
>>> var shellGlobal = shell.global;
>>>
>>> //grab functions from shell global and place in current global
>>>
>>> var load=shellGlobal.load;
>>>
>>> var print=shellGlobal.print;
>>>
>>> var defineClass=shellGlobal.defineClass;
>>>
>>> var deserialize=shellGlobal.deserialize;
>>>
>>> var doctest=shellGlobal.doctest;
>>>
>>> var gc=shellGlobal.gc;
>>>
>>> var help=shellGlobal.help;
>>>
>>> var loadClass=shellGlobal.loadClass;
>>>
>>> var quit=shellGlobal.quit;
>>>
>>> var readFile=shellGlobal.readFile;
>>>
>>> var readUrl=shellGlobal.readUrl;
>>>
>>> var runCommand=shellGlobal.runCommand;
>>>
>>> var seal=shellGlobal.seal;
>>>
>>> var serialize=shellGlobal.serialize;
>>>
>>> var spawn=shellGlobal.spawn;
>>>
>>> var sync=shellGlobal.sync;
>>>
>>> var toint32=shellGlobal.toint32;
>>>
>>> var version=shellGlobal.version;
>>>
>>> var environment=shellGlobal.environment;
>>>
>>>
>>>
>>> @{text}
>>>
>>> ]]></script>
>>>
>>> </sequential>
>>>
>>> </macrodef>
>>>
>>>
>>>
>>> <target name="hello">
>>>
>>> <rhinoscript>
>>>
>>> print("Hello World!")
>>>
>>> </rhinoscript>
>>>
>>> </target>
>>>
>>>
>>> Thanks again for your help with this,
>>>
>>> Jake
>>>
>>> On 10-08-22 04:12 AM, Greg Roodt wrote:
>>>
>>>>
>>>> Hi
>>>>
>>>> Glad it worked.
>>>>
>>>> I agree with you. I think it would be much easier and more useful if
>>>>
>>
>> these
>>
>>>>
>>>> functions from the Rhino shell were made available. It is not something
>>>>
>>
>> that
>>
>>>>
>>>> the<script />  task is going out of its way to remove though, the
>>>> problem
>>>>
>>
>> is
>>
>>>>
>>>> actually Rhino/javascript itself (not a problem, more a strictness). The
>>>> javascript language spec does not specify these functions, therefore
>>>> they
>>>> are not made available in the interpreter and JSR 223.
>>>>
>>>> All that the<script />  task essentially does is the following:
>>>> 1. Determine which script engine to use.
>>>> 2. Fire up the script engine.
>>>> 3. Inject Ant objects (project, tasks etc.) into the Context of the
>>>>
>>
>> script.
>>
>>>>
>>>> This is to help make it possible to use scripting languages to write Ant
>>>> scripts, remember this task is not meant to be a general purpose script
>>>> runner, but a way to make it simpler to script Ant tasks.
>>>>
>>>> The Rhino Shell then confuses people, by providing all these wonderful
>>>> functions that arent available in a standard embedded context which is a
>>>>
>>
>> bit
>>
>>>>
>>>> frustrating. Other languages like python do indeed have much more useful
>>>> things baked directly into the language which makes them easier to use.
>>>>
>>>> I think you should bring this up on the dev list and see what they
>>>> think.
>>>>
>>
>> It
>>
>>>>
>>>> might be that the Global stuff can be made available which will then
>>>> make
>>>> javascript and the<script />  tag much more powerful. Or they might
>>>>
>>
>> suggest
>>
>>>>
>>>> creating a new Ant task<rhinoshell />  or something.
>>>>
>>>> Cheers
>>>> Greg
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Sat, Aug 21, 2010 at 11:44 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>>
>>
>> wrote:
>>
>>>>
>>>>
>>>>>
>>>>> Hi Greg,
>>>>>
>>>>> Thanks a lot for this! This does exactly what I want.
>>>>>
>>>>> I had actually just about given up, as I realized that the load
>>>>> function
>>>>>
>>
>> I
>>
>>>>>
>>>>> was attempting to define would have the shortcoming of essentially
>>>>>
>>
>> capturing
>>
>>>>>
>>>>> any local variables eval'ed within it. This mean that while dojo worked
>>>>> because it was declared in the global scope, RequireJS would not load
>>>>> because its top-level argument ("require") was declared using var.
>>>>>
>>>>> I'm mentioning this now only because it's amusing, but to work around
>>>>>
>>
>> this,
>>
>>>>>
>>>>> I tried imagining a way to exit the load function to eval the string to
>>>>>
>>
>> be
>>
>>>>>
>>>>> loaded, thus allowing local variables declared within the string to be
>>>>> declared in the global scope; then returning from the global scope to
>>>>>
>>
>> the
>>
>>>>>
>>>>> call site of the load function. The only way I could think to do this
>>>>>
>>
>> was
>>
>>>>>
>>>>> with continuations. Converting to the continuation-passing style was
>>>>> not
>>>>>
>>
>> an
>>
>>>>>
>>>>> option, because passing in a callback to load would break the API.
>>>>> Fortunately, Rhino exposes a native Continuation. After some playing
>>>>>
>>
>> around,
>>
>>>>>
>>>>> I found that this code had the desired effect:
>>>>>
>>>>> /*
>>>>>
>>>>> this file is to test a technique for creating a load function in Rhino
>>>>>
>>>>> */
>>>>>
>>>>> (function(){
>>>>>
>>>>> myLoadLocal = function(str){
>>>>>
>>>>> eval(str);
>>>>>
>>>>> }
>>>>>
>>>>> function call_with_current_continuation() {
>>>>>
>>>>> var kont = new Continuation();
>>>>>
>>>>> return kont;
>>>>>
>>>>> }
>>>>>
>>>>> var evalString = null, afterEval = null;
>>>>>
>>>>> var beforeEval = call_with_current_continuation();
>>>>>
>>>>> if(evalString){
>>>>>
>>>>> eval(evalString);
>>>>>
>>>>> evalString=null;
>>>>>
>>>>> afterEval(null);
>>>>>
>>>>> }
>>>>>
>>>>> myLoadContinuation = function(str){
>>>>>
>>>>> evalString = str;
>>>>>
>>>>> afterEval = call_with_current_continuation();
>>>>>
>>>>> if(afterEval instanceof Continuation){
>>>>>
>>>>> beforeEval(beforeEval);
>>>>>
>>>>> }else{
>>>>>
>>>>> return;
>>>>>
>>>>> }
>>>>>
>>>>> }
>>>>>
>>>>> myLoadLocal("var foo=1;");
>>>>>
>>>>> print(typeof foo); //should be undefined
>>>>>
>>>>> myLoadContinuation("var bar=2;");
>>>>>
>>>>> print(typeof bar); //should be number
>>>>>
>>>>> print(bar); //should be 2
>>>>>
>>>>> //see if it works again
>>>>>
>>>>> myLoadContinuation("var bat=3;");
>>>>>
>>>>> print(typeof bat); //should be number
>>>>>
>>>>> print(bat); //should be 3
>>>>>
>>>>> })()
>>>>>
>>>>>
>>>>> I think there's probably a more elegant way to use continuations to do
>>>>> this, but this was the first thing I got working. One caveat to this,
>>>>> however, is that Continuations in Rhino only work when run in
>>>>>
>>
>> interpreted
>>
>>>>>
>>>>> mode, without optimizations (-opt -1). Otherwise it fails with the
>>>>>
>>
>> following
>>
>>>>>
>>>>> error:
>>>>>
>>>>> js: Direct call is not supported
>>>>>
>>>>> When I brought this back into the Ant script context, it failed with
>>>>>
>>
>> this
>>
>>>>>
>>>>> error as well, so it appears that this technique would not work in Ant
>>>>>
>>
>> for
>>
>>>>>
>>>>> this reason.
>>>>>
>>>>>
>>>>> I wonder if its worth discussing whether removing the global functions
>>>>> normally found in Rhino is a desirable behaviour for Ant. Other
>>>>>
>>
>> scripting
>>
>>>>>
>>>>> languages include facilities for importing code as part of their core
>>>>>
>>
>> syntax
>>
>>>>>
>>>>> (e.g. Jython's import statement), so this cannot be easily removed for
>>>>>
>>
>> them,
>>
>>>>>
>>>>> but for Rhino, the load function is simply part of the global object,
>>>>>
>>
>> and
>>
>>>>>
>>>>> can be easily removed from the embedding context. But I'm not sure if
>>>>>
>>
>> this
>>
>>>>>
>>>>> is actually a good thing to do. Certainly it reduces the utility of the
>>>>>
>>
>> Ant
>>
>>>>>
>>>>> script context, and increases its verbosity for situations where
>>>>>
>>
>> external
>>
>>>>>
>>>>> scripts must be loaded via a module loader, such as Dojo or RequireJS.
>>>>>
>>
>> Do
>>
>>>>>
>>>>> you think this is something that would be worth bringing up on the
>>>>> developer's list? Would it be useful to file a bug report or feature
>>>>> request?
>>>>>
>>>>> Let me know what you think. Thanks,
>>>>>
>>>>> Jake
>>>>>
>>>>>
>>>>>
>>>>> On 10-08-21 05:37 PM, Greg Roodt wrote:
>>>>>
>>>>>
>>>>>
>>>>>>
>>>>>> This might work for you:
>>>>>>
>>>>>> <project default="hello" name="helloworld" basedir=".">
>>>>>> <target name="hello">
>>>>>> <script language="javascript" manager="bsf">
>>>>>> <classpath>
>>>>>> <fileset dir="rhino-lib" includes="*.jar"></fileset>
>>>>>> </classpath><![CDATA[
>>>>>> importPackage(java.lang, java.util, java.io);
>>>>>> System.out.println("Hello from JavaScript!!");
>>>>>> //create shell, execute something and grab global
>>>>>> var shell = org.mozilla.javascript.tools.shell.Main;
>>>>>> var args = ["-e","var a='STRING';"];
>>>>>> shell.exec(args);
>>>>>> var shellGlobal = shell.global;
>>>>>>
>>>>>> //grab functions from shell global and place in current global
>>>>>> var load=shellGlobal.load;
>>>>>> var print=shellGlobal.print;
>>>>>> var defineClass=shellGlobal.defineClass;
>>>>>> var deserialize=shellGlobal.deserialize;
>>>>>> var doctest=shellGlobal.doctest;
>>>>>> var gc=shellGlobal.gc;
>>>>>> var help=shellGlobal.help;
>>>>>> var loadClass=shellGlobal.loadClass;
>>>>>> var quit=shellGlobal.quit;
>>>>>> var readFile=shellGlobal.readFile;
>>>>>> var readUrl=shellGlobal.readUrl;
>>>>>> var runCommand=shellGlobal.runCommand;
>>>>>> var seal=shellGlobal.seal;
>>>>>> var serialize=shellGlobal.serialize;
>>>>>> var spawn=shellGlobal.spawn;
>>>>>> var sync=shellGlobal.sync;
>>>>>> var toint32=shellGlobal.toint32;
>>>>>> var version=shellGlobal.version;
>>>>>> var environment=shellGlobal.environment;
>>>>>>
>>>>>> //test your bad self
>>>>>> load("test.js");
>>>>>>
>>>>>> ]]></script>
>>>>>> </target>
>>>>>> </project>
>>>>>>
>>>>>> test.js:
>>>>>> var a = function() {
>>>>>> print("test");
>>>>>> help();
>>>>>> var scriptContents = readFile("test.js");
>>>>>> print(scriptContents);
>>>>>> var ver = version();
>>>>>> print("version:"+ver);
>>>>>> print(this);
>>>>>> for(var prop in this){
>>>>>> print(prop);
>>>>>> }
>>>>>> }
>>>>>> a();
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>>>> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> Hi Greg,
>>>>>>>
>>>>>>> Thanks for your response. Replies below:
>>>>>>>
>>>>>>>
>>>>>>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> I believe load() is part of Rhino Shell. I think all that the<script
>>>>>>>>
>>
>> />
>>
>>>>>>>>
>>>>>>>> task runs when using JavaScript is the interpreter. It would only
>>>>>>>>
>>
>> have
>>
>>>>>>>>
>>>>>>>> the
>>>>>>>> pure Javascript standard language features (and a few bits and
>>>>>>>> pieces
>>>>>>>>
>>
>> to
>>
>>>>>>>>
>>>>>>>> interact with Java and the execution context).
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> load() is normally exposed as part of the global object when running
>>>>>>> Rhino,
>>>>>>> in the shell or the interpreter. All the js module loaders that
>>>>>>>
>>
>> support
>>
>>>>>>>
>>>>>>> Rhino that I've encountered, including RequireJS and dojo, make use
>>>>>>> of
>>>>>>> load() to load JavaScript modules.
>>>>>>>
>>>>>>> It might be easier to run the shell for each test? Like so:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> java org.mozilla.javascript.tools.shell.Main [options]
>>>>>>>> script-filename-or-url [script-arguments]
>>>>>>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>>>>>>
>>>>>>>> Or like John Resig does with env.js:
>>>>>>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> I'm using that technique for other parts of my code, but it would be
>>>>>>>
>>
>> much
>>
>>>>>>>
>>>>>>> easier to simply hook into Ant's ResourceSet data structures for this
>>>>>>> part,
>>>>>>> as it's possible to register a number of unit tests with dojo before
>>>>>>> running
>>>>>>> them.
>>>>>>>
>>>>>>>
>>>>>>> Or maybe, define your own global load() function inside the<script />
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> tag?
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> That's what I'm working on. This seems to work, but I still need to
>>>>>>>
>>
>> test
>>
>>>>>>>
>>>>>>> it
>>>>>>> with the dojo module loader:
>>>>>>>
>>>>>>> <script language="javascript" manager="bsf">
>>>>>>>
>>>>>>> <classpath>
>>>>>>>
>>>>>>> <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>>>>>
>>>>>>> <fileset dir="../../../lib/build-java/"
>>>>>>> includes="*.jar"></fileset>
>>>>>>>
>>>>>>> </classpath><![CDATA[
>>>>>>>
>>>>>>> //define load in global scope
>>>>>>>
>>>>>>> function readFile(path){
>>>>>>>
>>>>>>> stream = new java.io.FileInputStream(new
>>>>>>> java.io.File(path));
>>>>>>>
>>>>>>> fc = stream.getChannel();
>>>>>>>
>>>>>>> bb =
>>>>>>> fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>>>>>>> 0, fc.size());
>>>>>>>
>>>>>>> return
>>>>>>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>>>>>>
>>>>>>> }
>>>>>>>
>>>>>>> load = function(path){
>>>>>>>
>>>>>>> eval(String(readFile(path)))
>>>>>>>
>>>>>>> }
>>>>>>>
>>>>>>> echo = helloworld.createTask("echo");
>>>>>>>
>>>>>>> var contents = readFile('hello.js')
>>>>>>>
>>>>>>> echo.setMessage(contents);
>>>>>>>
>>>>>>> echo.perform();
>>>>>>>
>>>>>>> load('hello.js')
>>>>>>>
>>>>>>> echo.perform();
>>>>>>>
>>>>>>> ]]></script>
>>>>>>>
>>>>>>> hello.js:
>>>>>>>
>>>>>>> echo.setMessage("hello world!");
>>>>>>>
>>>>>>>
>>>>>>> Outputs:
>>>>>>>
>>>>>>> hello:
>>>>>>>
>>>>>>> [echo] echo.setMessage("hello world!");
>>>>>>>
>>>>>>> [echo] hello world!
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>>
>>>>>>> Jake
>>>>>>>
>>>>>>> ---------------------------------------------------------------------
>>>>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>> For additional commands, e-mail: user-help@ant.apache.org
>>>
>>>
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Jacob Beard <jb...@cs.mcgill.ca>.
And here is what it looks like now:

https://svn.apache.org/repos/asf/commons/sandbox/gsoc/2010/scxml-js/trunk/build.xml

Most interesting parts are target run-unit-tests-with-rhino target and 
macro run-unit-tests-with-selenium-macro. I'm pretty happy with this 
result, as it has allowed me to integrate javac compilation with testing 
of my JavaScript modules, and to reuse code from my original build 
script written in JavaScript.

Jake

On 10-08-23 01:56 PM, Greg Roodt wrote:
> No problem. I had fun discovering how to make it work. I like the macro idea
> btw.
>
> Cheers
> Greg
>
> On 22 Aug 2010 14:03, "Jacob Beard"<jb...@cs.mcgill.ca>  wrote:
>    
>> Hi Greg,
>>
>> I'll bring it up on the developer's list.
>>
>> I've created a macro that sets up the rhino environment, so right now
>> this seems like a good enough solution for me:
>>
>> <macrodef name="rhinoscript">
>>
>> <text name="text"/>
>>
>> <sequential>
>>
>> <script language="javascript" manager="bsf">
>>
>> <classpath>
>>
>> <fileset dir="../../../lib/java/" includes="js.jar"/>
>>
>> <fileset dir="../../../lib/build-java/" includes="*.jar"></fileset>
>>
>> </classpath><![CDATA[
>>
>> importPackage(java.lang, java.util, java.io);
>>
>> //System.out.println("Hello from JavaScript!!");
>>
>> //create shell, execute something and grab global
>>
>> var shell = org.mozilla.javascript.tools.shell.Main;
>>
>> var args = ["-e","var a='STRING';"];
>>
>> shell.exec(args);
>>
>> var shellGlobal = shell.global;
>>
>> //grab functions from shell global and place in current global
>>
>> var load=shellGlobal.load;
>>
>> var print=shellGlobal.print;
>>
>> var defineClass=shellGlobal.defineClass;
>>
>> var deserialize=shellGlobal.deserialize;
>>
>> var doctest=shellGlobal.doctest;
>>
>> var gc=shellGlobal.gc;
>>
>> var help=shellGlobal.help;
>>
>> var loadClass=shellGlobal.loadClass;
>>
>> var quit=shellGlobal.quit;
>>
>> var readFile=shellGlobal.readFile;
>>
>> var readUrl=shellGlobal.readUrl;
>>
>> var runCommand=shellGlobal.runCommand;
>>
>> var seal=shellGlobal.seal;
>>
>> var serialize=shellGlobal.serialize;
>>
>> var spawn=shellGlobal.spawn;
>>
>> var sync=shellGlobal.sync;
>>
>> var toint32=shellGlobal.toint32;
>>
>> var version=shellGlobal.version;
>>
>> var environment=shellGlobal.environment;
>>
>>
>>
>> @{text}
>>
>> ]]></script>
>>
>> </sequential>
>>
>> </macrodef>
>>
>>
>>
>> <target name="hello">
>>
>> <rhinoscript>
>>
>> print("Hello World!")
>>
>> </rhinoscript>
>>
>> </target>
>>
>>
>> Thanks again for your help with this,
>>
>> Jake
>>
>> On 10-08-22 04:12 AM, Greg Roodt wrote:
>>      
>>> Hi
>>>
>>> Glad it worked.
>>>
>>> I agree with you. I think it would be much easier and more useful if
>>>        
> these
>    
>>> functions from the Rhino shell were made available. It is not something
>>>        
> that
>    
>>> the<script />  task is going out of its way to remove though, the problem
>>>        
> is
>    
>>> actually Rhino/javascript itself (not a problem, more a strictness). The
>>> javascript language spec does not specify these functions, therefore they
>>> are not made available in the interpreter and JSR 223.
>>>
>>> All that the<script />  task essentially does is the following:
>>> 1. Determine which script engine to use.
>>> 2. Fire up the script engine.
>>> 3. Inject Ant objects (project, tasks etc.) into the Context of the
>>>        
> script.
>    
>>> This is to help make it possible to use scripting languages to write Ant
>>> scripts, remember this task is not meant to be a general purpose script
>>> runner, but a way to make it simpler to script Ant tasks.
>>>
>>> The Rhino Shell then confuses people, by providing all these wonderful
>>> functions that arent available in a standard embedded context which is a
>>>        
> bit
>    
>>> frustrating. Other languages like python do indeed have much more useful
>>> things baked directly into the language which makes them easier to use.
>>>
>>> I think you should bring this up on the dev list and see what they think.
>>>        
> It
>    
>>> might be that the Global stuff can be made available which will then make
>>> javascript and the<script />  tag much more powerful. Or they might
>>>        
> suggest
>    
>>> creating a new Ant task<rhinoshell />  or something.
>>>
>>> Cheers
>>> Greg
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>>
>>> On Sat, Aug 21, 2010 at 11:44 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>        
> wrote:
>    
>>>
>>>        
>>>> Hi Greg,
>>>>
>>>> Thanks a lot for this! This does exactly what I want.
>>>>
>>>> I had actually just about given up, as I realized that the load function
>>>>          
> I
>    
>>>> was attempting to define would have the shortcoming of essentially
>>>>          
> capturing
>    
>>>> any local variables eval'ed within it. This mean that while dojo worked
>>>> because it was declared in the global scope, RequireJS would not load
>>>> because its top-level argument ("require") was declared using var.
>>>>
>>>> I'm mentioning this now only because it's amusing, but to work around
>>>>          
> this,
>    
>>>> I tried imagining a way to exit the load function to eval the string to
>>>>          
> be
>    
>>>> loaded, thus allowing local variables declared within the string to be
>>>> declared in the global scope; then returning from the global scope to
>>>>          
> the
>    
>>>> call site of the load function. The only way I could think to do this
>>>>          
> was
>    
>>>> with continuations. Converting to the continuation-passing style was not
>>>>          
> an
>    
>>>> option, because passing in a callback to load would break the API.
>>>> Fortunately, Rhino exposes a native Continuation. After some playing
>>>>          
> around,
>    
>>>> I found that this code had the desired effect:
>>>>
>>>> /*
>>>>
>>>> this file is to test a technique for creating a load function in Rhino
>>>>
>>>> */
>>>>
>>>> (function(){
>>>>
>>>> myLoadLocal = function(str){
>>>>
>>>> eval(str);
>>>>
>>>> }
>>>>
>>>> function call_with_current_continuation() {
>>>>
>>>> var kont = new Continuation();
>>>>
>>>> return kont;
>>>>
>>>> }
>>>>
>>>> var evalString = null, afterEval = null;
>>>>
>>>> var beforeEval = call_with_current_continuation();
>>>>
>>>> if(evalString){
>>>>
>>>> eval(evalString);
>>>>
>>>> evalString=null;
>>>>
>>>> afterEval(null);
>>>>
>>>> }
>>>>
>>>> myLoadContinuation = function(str){
>>>>
>>>> evalString = str;
>>>>
>>>> afterEval = call_with_current_continuation();
>>>>
>>>> if(afterEval instanceof Continuation){
>>>>
>>>> beforeEval(beforeEval);
>>>>
>>>> }else{
>>>>
>>>> return;
>>>>
>>>> }
>>>>
>>>> }
>>>>
>>>> myLoadLocal("var foo=1;");
>>>>
>>>> print(typeof foo); //should be undefined
>>>>
>>>> myLoadContinuation("var bar=2;");
>>>>
>>>> print(typeof bar); //should be number
>>>>
>>>> print(bar); //should be 2
>>>>
>>>> //see if it works again
>>>>
>>>> myLoadContinuation("var bat=3;");
>>>>
>>>> print(typeof bat); //should be number
>>>>
>>>> print(bat); //should be 3
>>>>
>>>> })()
>>>>
>>>>
>>>> I think there's probably a more elegant way to use continuations to do
>>>> this, but this was the first thing I got working. One caveat to this,
>>>> however, is that Continuations in Rhino only work when run in
>>>>          
> interpreted
>    
>>>> mode, without optimizations (-opt -1). Otherwise it fails with the
>>>>          
> following
>    
>>>> error:
>>>>
>>>> js: Direct call is not supported
>>>>
>>>> When I brought this back into the Ant script context, it failed with
>>>>          
> this
>    
>>>> error as well, so it appears that this technique would not work in Ant
>>>>          
> for
>    
>>>> this reason.
>>>>
>>>>
>>>> I wonder if its worth discussing whether removing the global functions
>>>> normally found in Rhino is a desirable behaviour for Ant. Other
>>>>          
> scripting
>    
>>>> languages include facilities for importing code as part of their core
>>>>          
> syntax
>    
>>>> (e.g. Jython's import statement), so this cannot be easily removed for
>>>>          
> them,
>    
>>>> but for Rhino, the load function is simply part of the global object,
>>>>          
> and
>    
>>>> can be easily removed from the embedding context. But I'm not sure if
>>>>          
> this
>    
>>>> is actually a good thing to do. Certainly it reduces the utility of the
>>>>          
> Ant
>    
>>>> script context, and increases its verbosity for situations where
>>>>          
> external
>    
>>>> scripts must be loaded via a module loader, such as Dojo or RequireJS.
>>>>          
> Do
>    
>>>> you think this is something that would be worth bringing up on the
>>>> developer's list? Would it be useful to file a bug report or feature
>>>> request?
>>>>
>>>> Let me know what you think. Thanks,
>>>>
>>>> Jake
>>>>
>>>>
>>>>
>>>> On 10-08-21 05:37 PM, Greg Roodt wrote:
>>>>
>>>>
>>>>          
>>>>> This might work for you:
>>>>>
>>>>> <project default="hello" name="helloworld" basedir=".">
>>>>> <target name="hello">
>>>>> <script language="javascript" manager="bsf">
>>>>> <classpath>
>>>>> <fileset dir="rhino-lib" includes="*.jar"></fileset>
>>>>> </classpath><![CDATA[
>>>>> importPackage(java.lang, java.util, java.io);
>>>>> System.out.println("Hello from JavaScript!!");
>>>>> //create shell, execute something and grab global
>>>>> var shell = org.mozilla.javascript.tools.shell.Main;
>>>>> var args = ["-e","var a='STRING';"];
>>>>> shell.exec(args);
>>>>> var shellGlobal = shell.global;
>>>>>
>>>>> //grab functions from shell global and place in current global
>>>>> var load=shellGlobal.load;
>>>>> var print=shellGlobal.print;
>>>>> var defineClass=shellGlobal.defineClass;
>>>>> var deserialize=shellGlobal.deserialize;
>>>>> var doctest=shellGlobal.doctest;
>>>>> var gc=shellGlobal.gc;
>>>>> var help=shellGlobal.help;
>>>>> var loadClass=shellGlobal.loadClass;
>>>>> var quit=shellGlobal.quit;
>>>>> var readFile=shellGlobal.readFile;
>>>>> var readUrl=shellGlobal.readUrl;
>>>>> var runCommand=shellGlobal.runCommand;
>>>>> var seal=shellGlobal.seal;
>>>>> var serialize=shellGlobal.serialize;
>>>>> var spawn=shellGlobal.spawn;
>>>>> var sync=shellGlobal.sync;
>>>>> var toint32=shellGlobal.toint32;
>>>>> var version=shellGlobal.version;
>>>>> var environment=shellGlobal.environment;
>>>>>
>>>>> //test your bad self
>>>>> load("test.js");
>>>>>
>>>>> ]]></script>
>>>>> </target>
>>>>> </project>
>>>>>
>>>>> test.js:
>>>>> var a = function() {
>>>>> print("test");
>>>>> help();
>>>>> var scriptContents = readFile("test.js");
>>>>> print(scriptContents);
>>>>> var ver = version();
>>>>> print("version:"+ver);
>>>>> print(this);
>>>>> for(var prop in this){
>>>>> print(prop);
>>>>> }
>>>>> }
>>>>> a();
>>>>>
>>>>>
>>>>>
>>>>> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>>> wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>            
>>>>>> Hi Greg,
>>>>>>
>>>>>> Thanks for your response. Replies below:
>>>>>>
>>>>>>
>>>>>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>              
>>>>>>> I believe load() is part of Rhino Shell. I think all that the<script
>>>>>>>                
> />
>    
>>>>>>> task runs when using JavaScript is the interpreter. It would only
>>>>>>>                
> have
>    
>>>>>>> the
>>>>>>> pure Javascript standard language features (and a few bits and pieces
>>>>>>>                
> to
>    
>>>>>>> interact with Java and the execution context).
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>                
>>>>>> load() is normally exposed as part of the global object when running
>>>>>> Rhino,
>>>>>> in the shell or the interpreter. All the js module loaders that
>>>>>>              
> support
>    
>>>>>> Rhino that I've encountered, including RequireJS and dojo, make use of
>>>>>> load() to load JavaScript modules.
>>>>>>
>>>>>> It might be easier to run the shell for each test? Like so:
>>>>>>
>>>>>>
>>>>>>
>>>>>>              
>>>>>>> java org.mozilla.javascript.tools.shell.Main [options]
>>>>>>> script-filename-or-url [script-arguments]
>>>>>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>>>>>
>>>>>>> Or like John Resig does with env.js:
>>>>>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>                
>>>>>> I'm using that technique for other parts of my code, but it would be
>>>>>>              
> much
>    
>>>>>> easier to simply hook into Ant's ResourceSet data structures for this
>>>>>> part,
>>>>>> as it's possible to register a number of unit tests with dojo before
>>>>>> running
>>>>>> them.
>>>>>>
>>>>>>
>>>>>> Or maybe, define your own global load() function inside the<script />
>>>>>>
>>>>>>
>>>>>>
>>>>>>              
>>>>>>> tag?
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>                
>>>>>> That's what I'm working on. This seems to work, but I still need to
>>>>>>              
> test
>    
>>>>>> it
>>>>>> with the dojo module loader:
>>>>>>
>>>>>> <script language="javascript" manager="bsf">
>>>>>>
>>>>>> <classpath>
>>>>>>
>>>>>> <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>>>>
>>>>>> <fileset dir="../../../lib/build-java/"
>>>>>> includes="*.jar"></fileset>
>>>>>>
>>>>>> </classpath><![CDATA[
>>>>>>
>>>>>> //define load in global scope
>>>>>>
>>>>>> function readFile(path){
>>>>>>
>>>>>> stream = new java.io.FileInputStream(new
>>>>>> java.io.File(path));
>>>>>>
>>>>>> fc = stream.getChannel();
>>>>>>
>>>>>> bb =
>>>>>> fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>>>>>> 0, fc.size());
>>>>>>
>>>>>> return
>>>>>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>>>>>
>>>>>> }
>>>>>>
>>>>>> load = function(path){
>>>>>>
>>>>>> eval(String(readFile(path)))
>>>>>>
>>>>>> }
>>>>>>
>>>>>> echo = helloworld.createTask("echo");
>>>>>>
>>>>>> var contents = readFile('hello.js')
>>>>>>
>>>>>> echo.setMessage(contents);
>>>>>>
>>>>>> echo.perform();
>>>>>>
>>>>>> load('hello.js')
>>>>>>
>>>>>> echo.perform();
>>>>>>
>>>>>> ]]></script>
>>>>>>
>>>>>> hello.js:
>>>>>>
>>>>>> echo.setMessage("hello world!");
>>>>>>
>>>>>>
>>>>>> Outputs:
>>>>>>
>>>>>> hello:
>>>>>>
>>>>>> [echo] echo.setMessage("hello world!");
>>>>>>
>>>>>> [echo] hello world!
>>>>>>
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>>
>>>>>> Jake
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>              
>>>>>
>>>>>            
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>
>>>>
>>>>
>>>>          
>>>        
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>> For additional commands, e-mail: user-help@ant.apache.org
>>
>>      
>    

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Greg Roodt <gr...@gmail.com>.
No problem. I had fun discovering how to make it work. I like the macro idea
btw.

Cheers
Greg

On 22 Aug 2010 14:03, "Jacob Beard" <jb...@cs.mcgill.ca> wrote:
> Hi Greg,
>
> I'll bring it up on the developer's list.
>
> I've created a macro that sets up the rhino environment, so right now
> this seems like a good enough solution for me:
>
> <macrodef name="rhinoscript">
>
> <text name="text"/>
>
> <sequential>
>
> <script language="javascript" manager="bsf">
>
> <classpath>
>
> <fileset dir="../../../lib/java/" includes="js.jar"/>
>
> <fileset dir="../../../lib/build-java/" includes="*.jar"></fileset>
>
> </classpath><![CDATA[
>
> importPackage(java.lang, java.util, java.io);
>
> //System.out.println("Hello from JavaScript!!");
>
> //create shell, execute something and grab global
>
> var shell = org.mozilla.javascript.tools.shell.Main;
>
> var args = ["-e","var a='STRING';"];
>
> shell.exec(args);
>
> var shellGlobal = shell.global;
>
> //grab functions from shell global and place in current global
>
> var load=shellGlobal.load;
>
> var print=shellGlobal.print;
>
> var defineClass=shellGlobal.defineClass;
>
> var deserialize=shellGlobal.deserialize;
>
> var doctest=shellGlobal.doctest;
>
> var gc=shellGlobal.gc;
>
> var help=shellGlobal.help;
>
> var loadClass=shellGlobal.loadClass;
>
> var quit=shellGlobal.quit;
>
> var readFile=shellGlobal.readFile;
>
> var readUrl=shellGlobal.readUrl;
>
> var runCommand=shellGlobal.runCommand;
>
> var seal=shellGlobal.seal;
>
> var serialize=shellGlobal.serialize;
>
> var spawn=shellGlobal.spawn;
>
> var sync=shellGlobal.sync;
>
> var toint32=shellGlobal.toint32;
>
> var version=shellGlobal.version;
>
> var environment=shellGlobal.environment;
>
>
>
> @{text}
>
> ]]></script>
>
> </sequential>
>
> </macrodef>
>
>
>
> <target name="hello">
>
> <rhinoscript>
>
> print("Hello World!")
>
> </rhinoscript>
>
> </target>
>
>
> Thanks again for your help with this,
>
> Jake
>
> On 10-08-22 04:12 AM, Greg Roodt wrote:
>> Hi
>>
>> Glad it worked.
>>
>> I agree with you. I think it would be much easier and more useful if
these
>> functions from the Rhino shell were made available. It is not something
that
>> the<script /> task is going out of its way to remove though, the problem
is
>> actually Rhino/javascript itself (not a problem, more a strictness). The
>> javascript language spec does not specify these functions, therefore they
>> are not made available in the interpreter and JSR 223.
>>
>> All that the<script /> task essentially does is the following:
>> 1. Determine which script engine to use.
>> 2. Fire up the script engine.
>> 3. Inject Ant objects (project, tasks etc.) into the Context of the
script.
>> This is to help make it possible to use scripting languages to write Ant
>> scripts, remember this task is not meant to be a general purpose script
>> runner, but a way to make it simpler to script Ant tasks.
>>
>> The Rhino Shell then confuses people, by providing all these wonderful
>> functions that arent available in a standard embedded context which is a
bit
>> frustrating. Other languages like python do indeed have much more useful
>> things baked directly into the language which makes them easier to use.
>>
>> I think you should bring this up on the dev list and see what they think.
It
>> might be that the Global stuff can be made available which will then make
>> javascript and the<script /> tag much more powerful. Or they might
suggest
>> creating a new Ant task<rhinoshell /> or something.
>>
>> Cheers
>> Greg
>>
>>
>>
>>
>>
>>
>>
>>
>> On Sat, Aug 21, 2010 at 11:44 PM, Jacob Beard<jb...@cs.mcgill.ca>
wrote:
>>
>>
>>> Hi Greg,
>>>
>>> Thanks a lot for this! This does exactly what I want.
>>>
>>> I had actually just about given up, as I realized that the load function
I
>>> was attempting to define would have the shortcoming of essentially
capturing
>>> any local variables eval'ed within it. This mean that while dojo worked
>>> because it was declared in the global scope, RequireJS would not load
>>> because its top-level argument ("require") was declared using var.
>>>
>>> I'm mentioning this now only because it's amusing, but to work around
this,
>>> I tried imagining a way to exit the load function to eval the string to
be
>>> loaded, thus allowing local variables declared within the string to be
>>> declared in the global scope; then returning from the global scope to
the
>>> call site of the load function. The only way I could think to do this
was
>>> with continuations. Converting to the continuation-passing style was not
an
>>> option, because passing in a callback to load would break the API.
>>> Fortunately, Rhino exposes a native Continuation. After some playing
around,
>>> I found that this code had the desired effect:
>>>
>>> /*
>>>
>>> this file is to test a technique for creating a load function in Rhino
>>>
>>> */
>>>
>>> (function(){
>>>
>>> myLoadLocal = function(str){
>>>
>>> eval(str);
>>>
>>> }
>>>
>>> function call_with_current_continuation() {
>>>
>>> var kont = new Continuation();
>>>
>>> return kont;
>>>
>>> }
>>>
>>> var evalString = null, afterEval = null;
>>>
>>> var beforeEval = call_with_current_continuation();
>>>
>>> if(evalString){
>>>
>>> eval(evalString);
>>>
>>> evalString=null;
>>>
>>> afterEval(null);
>>>
>>> }
>>>
>>> myLoadContinuation = function(str){
>>>
>>> evalString = str;
>>>
>>> afterEval = call_with_current_continuation();
>>>
>>> if(afterEval instanceof Continuation){
>>>
>>> beforeEval(beforeEval);
>>>
>>> }else{
>>>
>>> return;
>>>
>>> }
>>>
>>> }
>>>
>>> myLoadLocal("var foo=1;");
>>>
>>> print(typeof foo); //should be undefined
>>>
>>> myLoadContinuation("var bar=2;");
>>>
>>> print(typeof bar); //should be number
>>>
>>> print(bar); //should be 2
>>>
>>> //see if it works again
>>>
>>> myLoadContinuation("var bat=3;");
>>>
>>> print(typeof bat); //should be number
>>>
>>> print(bat); //should be 3
>>>
>>> })()
>>>
>>>
>>> I think there's probably a more elegant way to use continuations to do
>>> this, but this was the first thing I got working. One caveat to this,
>>> however, is that Continuations in Rhino only work when run in
interpreted
>>> mode, without optimizations (-opt -1). Otherwise it fails with the
following
>>> error:
>>>
>>> js: Direct call is not supported
>>>
>>> When I brought this back into the Ant script context, it failed with
this
>>> error as well, so it appears that this technique would not work in Ant
for
>>> this reason.
>>>
>>>
>>> I wonder if its worth discussing whether removing the global functions
>>> normally found in Rhino is a desirable behaviour for Ant. Other
scripting
>>> languages include facilities for importing code as part of their core
syntax
>>> (e.g. Jython's import statement), so this cannot be easily removed for
them,
>>> but for Rhino, the load function is simply part of the global object,
and
>>> can be easily removed from the embedding context. But I'm not sure if
this
>>> is actually a good thing to do. Certainly it reduces the utility of the
Ant
>>> script context, and increases its verbosity for situations where
external
>>> scripts must be loaded via a module loader, such as Dojo or RequireJS.
Do
>>> you think this is something that would be worth bringing up on the
>>> developer's list? Would it be useful to file a bug report or feature
>>> request?
>>>
>>> Let me know what you think. Thanks,
>>>
>>> Jake
>>>
>>>
>>>
>>> On 10-08-21 05:37 PM, Greg Roodt wrote:
>>>
>>>
>>>> This might work for you:
>>>>
>>>> <project default="hello" name="helloworld" basedir=".">
>>>> <target name="hello">
>>>> <script language="javascript" manager="bsf">
>>>> <classpath>
>>>> <fileset dir="rhino-lib" includes="*.jar"></fileset>
>>>> </classpath><![CDATA[
>>>> importPackage(java.lang, java.util, java.io);
>>>> System.out.println("Hello from JavaScript!!");
>>>> //create shell, execute something and grab global
>>>> var shell = org.mozilla.javascript.tools.shell.Main;
>>>> var args = ["-e","var a='STRING';"];
>>>> shell.exec(args);
>>>> var shellGlobal = shell.global;
>>>>
>>>> //grab functions from shell global and place in current global
>>>> var load=shellGlobal.load;
>>>> var print=shellGlobal.print;
>>>> var defineClass=shellGlobal.defineClass;
>>>> var deserialize=shellGlobal.deserialize;
>>>> var doctest=shellGlobal.doctest;
>>>> var gc=shellGlobal.gc;
>>>> var help=shellGlobal.help;
>>>> var loadClass=shellGlobal.loadClass;
>>>> var quit=shellGlobal.quit;
>>>> var readFile=shellGlobal.readFile;
>>>> var readUrl=shellGlobal.readUrl;
>>>> var runCommand=shellGlobal.runCommand;
>>>> var seal=shellGlobal.seal;
>>>> var serialize=shellGlobal.serialize;
>>>> var spawn=shellGlobal.spawn;
>>>> var sync=shellGlobal.sync;
>>>> var toint32=shellGlobal.toint32;
>>>> var version=shellGlobal.version;
>>>> var environment=shellGlobal.environment;
>>>>
>>>> //test your bad self
>>>> load("test.js");
>>>>
>>>> ]]></script>
>>>> </target>
>>>> </project>
>>>>
>>>> test.js:
>>>> var a = function() {
>>>> print("test");
>>>> help();
>>>> var scriptContents = readFile("test.js");
>>>> print(scriptContents);
>>>> var ver = version();
>>>> print("version:"+ver);
>>>> print(this);
>>>> for(var prop in this){
>>>> print(prop);
>>>> }
>>>> }
>>>> a();
>>>>
>>>>
>>>>
>>>> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>> wrote:
>>>>
>>>>
>>>>
>>>>
>>>>> Hi Greg,
>>>>>
>>>>> Thanks for your response. Replies below:
>>>>>
>>>>>
>>>>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> I believe load() is part of Rhino Shell. I think all that the<script
/>
>>>>>> task runs when using JavaScript is the interpreter. It would only
have
>>>>>> the
>>>>>> pure Javascript standard language features (and a few bits and pieces
to
>>>>>> interact with Java and the execution context).
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> load() is normally exposed as part of the global object when running
>>>>> Rhino,
>>>>> in the shell or the interpreter. All the js module loaders that
support
>>>>> Rhino that I've encountered, including RequireJS and dojo, make use of
>>>>> load() to load JavaScript modules.
>>>>>
>>>>> It might be easier to run the shell for each test? Like so:
>>>>>
>>>>>
>>>>>
>>>>>> java org.mozilla.javascript.tools.shell.Main [options]
>>>>>> script-filename-or-url [script-arguments]
>>>>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>>>>
>>>>>> Or like John Resig does with env.js:
>>>>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> I'm using that technique for other parts of my code, but it would be
much
>>>>> easier to simply hook into Ant's ResourceSet data structures for this
>>>>> part,
>>>>> as it's possible to register a number of unit tests with dojo before
>>>>> running
>>>>> them.
>>>>>
>>>>>
>>>>> Or maybe, define your own global load() function inside the<script />
>>>>>
>>>>>
>>>>>
>>>>>> tag?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> That's what I'm working on. This seems to work, but I still need to
test
>>>>> it
>>>>> with the dojo module loader:
>>>>>
>>>>> <script language="javascript" manager="bsf">
>>>>>
>>>>> <classpath>
>>>>>
>>>>> <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>>>
>>>>> <fileset dir="../../../lib/build-java/"
>>>>> includes="*.jar"></fileset>
>>>>>
>>>>> </classpath><![CDATA[
>>>>>
>>>>> //define load in global scope
>>>>>
>>>>> function readFile(path){
>>>>>
>>>>> stream = new java.io.FileInputStream(new
>>>>> java.io.File(path));
>>>>>
>>>>> fc = stream.getChannel();
>>>>>
>>>>> bb =
>>>>> fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>>>>> 0, fc.size());
>>>>>
>>>>> return
>>>>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>>>>
>>>>> }
>>>>>
>>>>> load = function(path){
>>>>>
>>>>> eval(String(readFile(path)))
>>>>>
>>>>> }
>>>>>
>>>>> echo = helloworld.createTask("echo");
>>>>>
>>>>> var contents = readFile('hello.js')
>>>>>
>>>>> echo.setMessage(contents);
>>>>>
>>>>> echo.perform();
>>>>>
>>>>> load('hello.js')
>>>>>
>>>>> echo.perform();
>>>>>
>>>>> ]]></script>
>>>>>
>>>>> hello.js:
>>>>>
>>>>> echo.setMessage("hello world!");
>>>>>
>>>>>
>>>>> Outputs:
>>>>>
>>>>> hello:
>>>>>
>>>>> [echo] echo.setMessage("hello world!");
>>>>>
>>>>> [echo] hello world!
>>>>>
>>>>>
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Jake
>>>>>
>>>>> ---------------------------------------------------------------------
>>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>> For additional commands, e-mail: user-help@ant.apache.org
>>>
>>>
>>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
>

Re: Rhino global.load() in script context

Posted by Jacob Beard <jb...@cs.mcgill.ca>.
Hi Greg,

I'll bring it up on the developer's list.

I've created a macro that sets up the rhino environment, so right now 
this seems like a good enough solution for me:

     <macrodef name="rhinoscript">

         <text name="text"/>

         <sequential>

             <script language="javascript" manager="bsf">

                 <classpath>

                 <fileset dir="../../../lib/java/" includes="js.jar"/>

                 <fileset dir="../../../lib/build-java/" includes="*.jar"></fileset>

                 </classpath><![CDATA[

                     importPackage(java.lang, java.util, java.io);

                     //System.out.println("Hello from JavaScript!!");

                     //create shell, execute something and grab global

                     var shell = org.mozilla.javascript.tools.shell.Main;

                     var args = ["-e","var a='STRING';"];

                     shell.exec(args);

                     var shellGlobal = shell.global;

                     //grab functions from shell global and place in current global

                     var load=shellGlobal.load;

                     var print=shellGlobal.print;

                     var defineClass=shellGlobal.defineClass;

                     var deserialize=shellGlobal.deserialize;

                     var doctest=shellGlobal.doctest;

                     var gc=shellGlobal.gc;

                     var help=shellGlobal.help;

                     var loadClass=shellGlobal.loadClass;

                     var quit=shellGlobal.quit;

                     var readFile=shellGlobal.readFile;

                     var readUrl=shellGlobal.readUrl;

                     var runCommand=shellGlobal.runCommand;

                     var seal=shellGlobal.seal;

                     var serialize=shellGlobal.serialize;

                     var spawn=shellGlobal.spawn;

                     var sync=shellGlobal.sync;

                     var toint32=shellGlobal.toint32;

                     var version=shellGlobal.version;

                     var environment=shellGlobal.environment;

     

                     @{text}

             ]]></script>

         </sequential>

     </macrodef>

     

     <target name="hello">

         <rhinoscript>

             print("Hello World!")

         </rhinoscript>

     </target>


Thanks again for your help with this,

Jake

On 10-08-22 04:12 AM, Greg Roodt wrote:
> Hi
>
> Glad it worked.
>
> I agree with you. I think it would be much easier and more useful if these
> functions from the Rhino shell were made available. It is not something that
> the<script />  task is going out of its way to remove though, the problem is
> actually Rhino/javascript itself (not a problem, more a strictness). The
> javascript language spec does not specify these functions, therefore they
> are not made available in the interpreter and JSR 223.
>
> All that the<script />  task essentially does is the following:
> 1. Determine which script engine to use.
> 2. Fire up the script engine.
> 3. Inject Ant objects (project, tasks etc.) into the Context of the script.
> This is to help make it possible to use scripting languages to write Ant
> scripts, remember this task is not meant to be a general purpose script
> runner, but a way to make it simpler to script Ant tasks.
>
> The Rhino Shell then confuses people, by providing all these wonderful
> functions that arent available in a standard embedded context which is a bit
> frustrating. Other languages like python do indeed have much more useful
> things baked directly into the language which makes them easier to use.
>
> I think you should bring this up on the dev list and see what they think. It
> might be that the Global stuff can be made available which will then make
> javascript and the<script />  tag much more powerful. Or they might suggest
> creating a new Ant task<rhinoshell />  or something.
>
> Cheers
> Greg
>
>
>
>
>
>
>
>
> On Sat, Aug 21, 2010 at 11:44 PM, Jacob Beard<jb...@cs.mcgill.ca>  wrote:
>
>    
>> Hi Greg,
>>
>> Thanks a lot for this! This does exactly what I want.
>>
>> I had actually just about given up, as I realized that the load function I
>> was attempting to define would have the shortcoming of essentially capturing
>> any local variables eval'ed within it. This mean that while dojo worked
>> because it was declared in the global scope, RequireJS would not load
>> because its top-level argument ("require") was declared using var.
>>
>> I'm mentioning this now only because it's amusing, but to work around this,
>> I tried imagining a way to exit the load function to eval the string to be
>> loaded, thus allowing local variables declared within the string to be
>> declared in the global scope; then returning from the global scope to the
>> call site of the load function. The only way I could think to do this was
>> with continuations. Converting to the continuation-passing style was not an
>> option, because passing in a callback to load would break the API.
>> Fortunately, Rhino exposes a native Continuation. After some playing around,
>> I found that this code had the desired effect:
>>
>> /*
>>
>>     this file is to test a technique for creating a load function in Rhino
>>
>> */
>>
>> (function(){
>>
>>     myLoadLocal = function(str){
>>
>>         eval(str);
>>
>>     }
>>
>>     function call_with_current_continuation() {
>>
>>         var kont = new Continuation();
>>
>>         return kont;
>>
>>     }
>>
>>     var evalString = null, afterEval = null;
>>
>>     var beforeEval = call_with_current_continuation();
>>
>>     if(evalString){
>>
>>         eval(evalString);
>>
>>         evalString=null;
>>
>>         afterEval(null);
>>
>>     }
>>
>>     myLoadContinuation = function(str){
>>
>>         evalString = str;
>>
>>         afterEval = call_with_current_continuation();
>>
>>         if(afterEval instanceof Continuation){
>>
>>             beforeEval(beforeEval);
>>
>>         }else{
>>
>>             return;
>>
>>         }
>>
>>     }
>>
>>     myLoadLocal("var foo=1;");
>>
>>     print(typeof foo);    //should be undefined
>>
>>     myLoadContinuation("var bar=2;");
>>
>>     print(typeof bar);    //should be number
>>
>>     print(bar);        //should be 2
>>
>>     //see if it works again
>>
>>     myLoadContinuation("var bat=3;");
>>
>>     print(typeof bat);    //should be number
>>
>>     print(bat);        //should be 3
>>
>> })()
>>
>>
>> I think there's probably a more elegant way to use continuations to do
>> this, but this was the first thing I got working. One caveat to this,
>> however, is that Continuations in Rhino only work when run in interpreted
>> mode, without optimizations (-opt -1). Otherwise it fails with the following
>> error:
>>
>> js: Direct call is not supported
>>
>> When I brought this back into the Ant script context, it failed with this
>> error as well, so it appears that this technique would not work in Ant for
>> this reason.
>>
>>
>> I wonder if its worth discussing whether removing the global functions
>> normally found in Rhino is a desirable behaviour for Ant. Other scripting
>> languages include facilities for importing code as part of their core syntax
>> (e.g. Jython's import statement), so this cannot be easily removed for them,
>> but for Rhino, the load function is simply part of the global object, and
>> can be easily removed from the embedding context. But I'm not sure if this
>> is actually a good thing to do. Certainly it reduces the utility of the Ant
>> script context, and increases its verbosity for situations where external
>> scripts must be loaded via a module loader, such as Dojo or RequireJS. Do
>> you think this is something that would be worth bringing up on the
>> developer's list? Would it be useful to file a bug report or feature
>> request?
>>
>> Let me know what you think. Thanks,
>>
>> Jake
>>
>>
>>
>> On 10-08-21 05:37 PM, Greg Roodt wrote:
>>
>>      
>>> This might work for you:
>>>
>>>      <project default="hello" name="helloworld" basedir=".">
>>>         <target name="hello">
>>>             <script language="javascript" manager="bsf">
>>>             <classpath>
>>>                 <fileset dir="rhino-lib" includes="*.jar"></fileset>
>>>             </classpath><![CDATA[
>>>             importPackage(java.lang, java.util, java.io);
>>>             System.out.println("Hello from JavaScript!!");
>>>             //create shell, execute something and grab global
>>>             var shell = org.mozilla.javascript.tools.shell.Main;
>>>             var args = ["-e","var a='STRING';"];
>>>              shell.exec(args);
>>>             var shellGlobal = shell.global;
>>>
>>>             //grab functions from shell global and place in current global
>>>             var load=shellGlobal.load;
>>>             var print=shellGlobal.print;
>>>             var defineClass=shellGlobal.defineClass;
>>>             var deserialize=shellGlobal.deserialize;
>>>             var doctest=shellGlobal.doctest;
>>>             var gc=shellGlobal.gc;
>>>             var help=shellGlobal.help;
>>>             var loadClass=shellGlobal.loadClass;
>>>             var quit=shellGlobal.quit;
>>>             var readFile=shellGlobal.readFile;
>>>             var readUrl=shellGlobal.readUrl;
>>>             var runCommand=shellGlobal.runCommand;
>>>             var seal=shellGlobal.seal;
>>>             var serialize=shellGlobal.serialize;
>>>             var spawn=shellGlobal.spawn;
>>>             var sync=shellGlobal.sync;
>>>             var toint32=shellGlobal.toint32;
>>>             var version=shellGlobal.version;
>>>             var environment=shellGlobal.environment;
>>>
>>>             //test your bad self
>>>             load("test.js");
>>>
>>>             ]]></script>
>>>         </target>
>>>      </project>
>>>
>>> test.js:
>>> var a = function() {
>>> print("test");
>>> help();
>>> var scriptContents = readFile("test.js");
>>> print(scriptContents);
>>> var ver = version();
>>> print("version:"+ver);
>>> print(this);
>>> for(var prop in this){
>>> print(prop);
>>> }
>>> }
>>> a();
>>>
>>>
>>>
>>> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>>   wrote:
>>>
>>>
>>>
>>>        
>>>> Hi Greg,
>>>>
>>>> Thanks for your response. Replies below:
>>>>
>>>>
>>>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>>>
>>>>
>>>>
>>>>          
>>>>> I believe load() is part of Rhino Shell. I think all that the<script />
>>>>> task runs when using JavaScript is the interpreter. It would only have
>>>>> the
>>>>> pure Javascript standard language features (and a few bits and pieces to
>>>>> interact with Java and the execution context).
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>            
>>>> load() is normally exposed as part of the global object when running
>>>> Rhino,
>>>> in the shell or the interpreter. All the js module loaders that support
>>>> Rhino that I've encountered, including RequireJS and dojo, make use of
>>>> load() to load JavaScript modules.
>>>>
>>>>   It might be easier to run the shell for each test? Like so:
>>>>
>>>>
>>>>          
>>>>> java org.mozilla.javascript.tools.shell.Main [options]
>>>>> script-filename-or-url [script-arguments]
>>>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>>>
>>>>> Or like John Resig does with env.js:
>>>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>            
>>>> I'm using that technique for other parts of my code, but it would be much
>>>> easier to simply hook into Ant's ResourceSet data structures for this
>>>> part,
>>>> as it's possible to register a number of unit tests with dojo before
>>>> running
>>>> them.
>>>>
>>>>
>>>>   Or maybe, define your own global load() function inside the<script />
>>>>
>>>>
>>>>          
>>>>>   tag?
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>            
>>>> That's what I'm working on. This seems to work, but I still need to test
>>>> it
>>>> with the dojo module loader:
>>>>
>>>>         <script language="javascript" manager="bsf">
>>>>
>>>>             <classpath>
>>>>
>>>>                 <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>>
>>>>                 <fileset dir="../../../lib/build-java/"
>>>> includes="*.jar"></fileset>
>>>>
>>>>             </classpath><![CDATA[
>>>>
>>>>             //define load in global scope
>>>>
>>>>             function readFile(path){
>>>>
>>>>                 stream = new java.io.FileInputStream(new
>>>> java.io.File(path));
>>>>
>>>>                 fc = stream.getChannel();
>>>>
>>>>                 bb =
>>>> fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>>>> 0, fc.size());
>>>>
>>>>                 return
>>>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>>>
>>>>             }
>>>>
>>>>             load = function(path){
>>>>
>>>>                 eval(String(readFile(path)))
>>>>
>>>>             }
>>>>
>>>>             echo = helloworld.createTask("echo");
>>>>
>>>>             var contents = readFile('hello.js')
>>>>
>>>>             echo.setMessage(contents);
>>>>
>>>>             echo.perform();
>>>>
>>>>             load('hello.js')
>>>>
>>>>             echo.perform();
>>>>
>>>>         ]]></script>
>>>>
>>>> hello.js:
>>>>
>>>> echo.setMessage("hello world!");
>>>>
>>>>
>>>> Outputs:
>>>>
>>>> hello:
>>>>
>>>>      [echo] echo.setMessage("hello world!");
>>>>
>>>>      [echo] hello world!
>>>>
>>>>
>>>>
>>>> Thanks,
>>>>
>>>> Jake
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>>> For additional commands, e-mail: user-help@ant.apache.org
>>>>
>>>>
>>>>
>>>>
>>>>          
>>>
>>>        
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>> For additional commands, e-mail: user-help@ant.apache.org
>>
>>
>>      
>    

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Greg Roodt <gr...@gmail.com>.
Hi

Glad it worked.

I agree with you. I think it would be much easier and more useful if these
functions from the Rhino shell were made available. It is not something that
the <script /> task is going out of its way to remove though, the problem is
actually Rhino/javascript itself (not a problem, more a strictness). The
javascript language spec does not specify these functions, therefore they
are not made available in the interpreter and JSR 223.

All that the <script /> task essentially does is the following:
1. Determine which script engine to use.
2. Fire up the script engine.
3. Inject Ant objects (project, tasks etc.) into the Context of the script.
This is to help make it possible to use scripting languages to write Ant
scripts, remember this task is not meant to be a general purpose script
runner, but a way to make it simpler to script Ant tasks.

The Rhino Shell then confuses people, by providing all these wonderful
functions that arent available in a standard embedded context which is a bit
frustrating. Other languages like python do indeed have much more useful
things baked directly into the language which makes them easier to use.

I think you should bring this up on the dev list and see what they think. It
might be that the Global stuff can be made available which will then make
javascript and the <script /> tag much more powerful. Or they might suggest
creating a new Ant task <rhinoshell /> or something.

Cheers
Greg








On Sat, Aug 21, 2010 at 11:44 PM, Jacob Beard <jb...@cs.mcgill.ca> wrote:

> Hi Greg,
>
> Thanks a lot for this! This does exactly what I want.
>
> I had actually just about given up, as I realized that the load function I
> was attempting to define would have the shortcoming of essentially capturing
> any local variables eval'ed within it. This mean that while dojo worked
> because it was declared in the global scope, RequireJS would not load
> because its top-level argument ("require") was declared using var.
>
> I'm mentioning this now only because it's amusing, but to work around this,
> I tried imagining a way to exit the load function to eval the string to be
> loaded, thus allowing local variables declared within the string to be
> declared in the global scope; then returning from the global scope to the
> call site of the load function. The only way I could think to do this was
> with continuations. Converting to the continuation-passing style was not an
> option, because passing in a callback to load would break the API.
> Fortunately, Rhino exposes a native Continuation. After some playing around,
> I found that this code had the desired effect:
>
> /*
>
>    this file is to test a technique for creating a load function in Rhino
>
> */
>
> (function(){
>
>    myLoadLocal = function(str){
>
>        eval(str);
>
>    }
>
>    function call_with_current_continuation() {
>
>        var kont = new Continuation();
>
>        return kont;
>
>    }
>
>    var evalString = null, afterEval = null;
>
>    var beforeEval = call_with_current_continuation();
>
>    if(evalString){
>
>        eval(evalString);
>
>        evalString=null;
>
>        afterEval(null);
>
>    }
>
>    myLoadContinuation = function(str){
>
>        evalString = str;
>
>        afterEval = call_with_current_continuation();
>
>        if(afterEval instanceof Continuation){
>
>            beforeEval(beforeEval);
>
>        }else{
>
>            return;
>
>        }
>
>    }
>
>    myLoadLocal("var foo=1;");
>
>    print(typeof foo);    //should be undefined
>
>    myLoadContinuation("var bar=2;");
>
>    print(typeof bar);    //should be number
>
>    print(bar);        //should be 2
>
>    //see if it works again
>
>    myLoadContinuation("var bat=3;");
>
>    print(typeof bat);    //should be number
>
>    print(bat);        //should be 3
>
> })()
>
>
> I think there's probably a more elegant way to use continuations to do
> this, but this was the first thing I got working. One caveat to this,
> however, is that Continuations in Rhino only work when run in interpreted
> mode, without optimizations (-opt -1). Otherwise it fails with the following
> error:
>
> js: Direct call is not supported
>
> When I brought this back into the Ant script context, it failed with this
> error as well, so it appears that this technique would not work in Ant for
> this reason.
>
>
> I wonder if its worth discussing whether removing the global functions
> normally found in Rhino is a desirable behaviour for Ant. Other scripting
> languages include facilities for importing code as part of their core syntax
> (e.g. Jython's import statement), so this cannot be easily removed for them,
> but for Rhino, the load function is simply part of the global object, and
> can be easily removed from the embedding context. But I'm not sure if this
> is actually a good thing to do. Certainly it reduces the utility of the Ant
> script context, and increases its verbosity for situations where external
> scripts must be loaded via a module loader, such as Dojo or RequireJS. Do
> you think this is something that would be worth bringing up on the
> developer's list? Would it be useful to file a bug report or feature
> request?
>
> Let me know what you think. Thanks,
>
> Jake
>
>
>
> On 10-08-21 05:37 PM, Greg Roodt wrote:
>
>> This might work for you:
>>
>>     <project default="hello" name="helloworld" basedir=".">
>>        <target name="hello">
>>            <script language="javascript" manager="bsf">
>>            <classpath>
>>                <fileset dir="rhino-lib" includes="*.jar"></fileset>
>>            </classpath><![CDATA[
>>            importPackage(java.lang, java.util, java.io);
>>            System.out.println("Hello from JavaScript!!");
>>            //create shell, execute something and grab global
>>            var shell = org.mozilla.javascript.tools.shell.Main;
>>            var args = ["-e","var a='STRING';"];
>>             shell.exec(args);
>>            var shellGlobal = shell.global;
>>
>>            //grab functions from shell global and place in current global
>>            var load=shellGlobal.load;
>>            var print=shellGlobal.print;
>>            var defineClass=shellGlobal.defineClass;
>>            var deserialize=shellGlobal.deserialize;
>>            var doctest=shellGlobal.doctest;
>>            var gc=shellGlobal.gc;
>>            var help=shellGlobal.help;
>>            var loadClass=shellGlobal.loadClass;
>>            var quit=shellGlobal.quit;
>>            var readFile=shellGlobal.readFile;
>>            var readUrl=shellGlobal.readUrl;
>>            var runCommand=shellGlobal.runCommand;
>>            var seal=shellGlobal.seal;
>>            var serialize=shellGlobal.serialize;
>>            var spawn=shellGlobal.spawn;
>>            var sync=shellGlobal.sync;
>>            var toint32=shellGlobal.toint32;
>>            var version=shellGlobal.version;
>>            var environment=shellGlobal.environment;
>>
>>            //test your bad self
>>            load("test.js");
>>
>>            ]]></script>
>>        </target>
>>     </project>
>>
>> test.js:
>> var a = function() {
>> print("test");
>> help();
>> var scriptContents = readFile("test.js");
>> print(scriptContents);
>> var ver = version();
>> print("version:"+ver);
>> print(this);
>> for(var prop in this){
>> print(prop);
>> }
>> }
>> a();
>>
>>
>>
>> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>
>>  wrote:
>>
>>
>>
>>> Hi Greg,
>>>
>>> Thanks for your response. Replies below:
>>>
>>>
>>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>>
>>>
>>>
>>>> I believe load() is part of Rhino Shell. I think all that the<script />
>>>> task runs when using JavaScript is the interpreter. It would only have
>>>> the
>>>> pure Javascript standard language features (and a few bits and pieces to
>>>> interact with Java and the execution context).
>>>>
>>>>
>>>>
>>>>
>>> load() is normally exposed as part of the global object when running
>>> Rhino,
>>> in the shell or the interpreter. All the js module loaders that support
>>> Rhino that I've encountered, including RequireJS and dojo, make use of
>>> load() to load JavaScript modules.
>>>
>>>  It might be easier to run the shell for each test? Like so:
>>>
>>>
>>>> java org.mozilla.javascript.tools.shell.Main [options]
>>>> script-filename-or-url [script-arguments]
>>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>>
>>>> Or like John Resig does with env.js:
>>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>>
>>>>
>>>>
>>>>
>>> I'm using that technique for other parts of my code, but it would be much
>>> easier to simply hook into Ant's ResourceSet data structures for this
>>> part,
>>> as it's possible to register a number of unit tests with dojo before
>>> running
>>> them.
>>>
>>>
>>>  Or maybe, define your own global load() function inside the<script />
>>>
>>>
>>>>  tag?
>>>>
>>>>
>>>>
>>>>
>>> That's what I'm working on. This seems to work, but I still need to test
>>> it
>>> with the dojo module loader:
>>>
>>>        <script language="javascript" manager="bsf">
>>>
>>>            <classpath>
>>>
>>>                <fileset dir="../../../lib/java/" includes="js.jar"/>
>>>
>>>                <fileset dir="../../../lib/build-java/"
>>> includes="*.jar"></fileset>
>>>
>>>            </classpath><![CDATA[
>>>
>>>            //define load in global scope
>>>
>>>            function readFile(path){
>>>
>>>                stream = new java.io.FileInputStream(new
>>> java.io.File(path));
>>>
>>>                fc = stream.getChannel();
>>>
>>>                bb =
>>> fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>>> 0, fc.size());
>>>
>>>                return
>>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>>
>>>            }
>>>
>>>            load = function(path){
>>>
>>>                eval(String(readFile(path)))
>>>
>>>            }
>>>
>>>            echo = helloworld.createTask("echo");
>>>
>>>            var contents = readFile('hello.js')
>>>
>>>            echo.setMessage(contents);
>>>
>>>            echo.perform();
>>>
>>>            load('hello.js')
>>>
>>>            echo.perform();
>>>
>>>        ]]></script>
>>>
>>> hello.js:
>>>
>>> echo.setMessage("hello world!");
>>>
>>>
>>> Outputs:
>>>
>>> hello:
>>>
>>>     [echo] echo.setMessage("hello world!");
>>>
>>>     [echo] hello world!
>>>
>>>
>>>
>>> Thanks,
>>>
>>> Jake
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>>> For additional commands, e-mail: user-help@ant.apache.org
>>>
>>>
>>>
>>>
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
>
>

Re: Rhino global.load() in script context

Posted by Jacob Beard <jb...@cs.mcgill.ca>.
Hi Greg,

Thanks a lot for this! This does exactly what I want.

I had actually just about given up, as I realized that the load function 
I was attempting to define would have the shortcoming of essentially 
capturing any local variables eval'ed within it. This mean that while 
dojo worked because it was declared in the global scope, RequireJS would 
not load because its top-level argument ("require") was declared using var.

I'm mentioning this now only because it's amusing, but to work around 
this, I tried imagining a way to exit the load function to eval the 
string to be loaded, thus allowing local variables declared within the 
string to be declared in the global scope; then returning from the 
global scope to the call site of the load function. The only way I could 
think to do this was with continuations. Converting to the 
continuation-passing style was not an option, because passing in a 
callback to load would break the API. Fortunately, Rhino exposes a 
native Continuation. After some playing around, I found that this code 
had the desired effect:

/*

     this file is to test a technique for creating a load function in Rhino

*/

(function(){

     myLoadLocal = function(str){

         eval(str);

     }

     function call_with_current_continuation() {

         var kont = new Continuation();

         return kont;

     }

     var evalString = null, afterEval = null;

     var beforeEval = call_with_current_continuation();

     if(evalString){

         eval(evalString);

         evalString=null;

         afterEval(null);

     }

     myLoadContinuation = function(str){

         evalString = str;

         afterEval = call_with_current_continuation();

         if(afterEval instanceof Continuation){

             beforeEval(beforeEval);

         }else{

             return;

         }

     }

     myLoadLocal("var foo=1;");

     print(typeof foo);    //should be undefined

     myLoadContinuation("var bar=2;");

     print(typeof bar);    //should be number

     print(bar);        //should be 2

     //see if it works again

     myLoadContinuation("var bat=3;");

     print(typeof bat);    //should be number

     print(bat);        //should be 3

})()


I think there's probably a more elegant way to use continuations to do 
this, but this was the first thing I got working. One caveat to this, 
however, is that Continuations in Rhino only work when run in 
interpreted mode, without optimizations (-opt -1). Otherwise it fails 
with the following error:

js: Direct call is not supported

When I brought this back into the Ant script context, it failed with 
this error as well, so it appears that this technique would not work in 
Ant for this reason.


I wonder if its worth discussing whether removing the global functions 
normally found in Rhino is a desirable behaviour for Ant. Other 
scripting languages include facilities for importing code as part of 
their core syntax (e.g. Jython's import statement), so this cannot be 
easily removed for them, but for Rhino, the load function is simply part 
of the global object, and can be easily removed from the embedding 
context. But I'm not sure if this is actually a good thing to do. 
Certainly it reduces the utility of the Ant script context, and 
increases its verbosity for situations where external scripts must be 
loaded via a module loader, such as Dojo or RequireJS. Do you think this 
is something that would be worth bringing up on the developer's list? 
Would it be useful to file a bug report or feature request?

Let me know what you think. Thanks,

Jake


On 10-08-21 05:37 PM, Greg Roodt wrote:
> This might work for you:
>
>      <project default="hello" name="helloworld" basedir=".">
>         <target name="hello">
>             <script language="javascript" manager="bsf">
>             <classpath>
>                 <fileset dir="rhino-lib" includes="*.jar"></fileset>
>             </classpath><![CDATA[
>             importPackage(java.lang, java.util, java.io);
>             System.out.println("Hello from JavaScript!!");
>             //create shell, execute something and grab global
>             var shell = org.mozilla.javascript.tools.shell.Main;
>             var args = ["-e","var a='STRING';"];
>              shell.exec(args);
>             var shellGlobal = shell.global;
>
>             //grab functions from shell global and place in current global
>             var load=shellGlobal.load;
>             var print=shellGlobal.print;
>             var defineClass=shellGlobal.defineClass;
>             var deserialize=shellGlobal.deserialize;
>             var doctest=shellGlobal.doctest;
>             var gc=shellGlobal.gc;
>             var help=shellGlobal.help;
>             var loadClass=shellGlobal.loadClass;
>             var quit=shellGlobal.quit;
>             var readFile=shellGlobal.readFile;
>             var readUrl=shellGlobal.readUrl;
>             var runCommand=shellGlobal.runCommand;
>             var seal=shellGlobal.seal;
>             var serialize=shellGlobal.serialize;
>             var spawn=shellGlobal.spawn;
>             var sync=shellGlobal.sync;
>             var toint32=shellGlobal.toint32;
>             var version=shellGlobal.version;
>             var environment=shellGlobal.environment;
>
>             //test your bad self
>             load("test.js");
>
>             ]]></script>
>         </target>
>      </project>
>
> test.js:
> var a = function() {
> print("test");
> help();
> var scriptContents = readFile("test.js");
> print(scriptContents);
> var ver = version();
> print("version:"+ver);
> print(this);
> for(var prop in this){
> print(prop);
> }
> }
> a();
>
>
>
> On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard<jb...@cs.mcgill.ca>  wrote:
>
>    
>> Hi Greg,
>>
>> Thanks for your response. Replies below:
>>
>>
>> On 10-08-21 01:41 PM, Greg Roodt wrote:
>>
>>      
>>> I believe load() is part of Rhino Shell. I think all that the<script />
>>> task runs when using JavaScript is the interpreter. It would only have the
>>> pure Javascript standard language features (and a few bits and pieces to
>>> interact with Java and the execution context).
>>>
>>>
>>>        
>> load() is normally exposed as part of the global object when running Rhino,
>> in the shell or the interpreter. All the js module loaders that support
>> Rhino that I've encountered, including RequireJS and dojo, make use of
>> load() to load JavaScript modules.
>>
>>   It might be easier to run the shell for each test? Like so:
>>      
>>> java org.mozilla.javascript.tools.shell.Main [options]
>>> script-filename-or-url [script-arguments]
>>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>>
>>> Or like John Resig does with env.js:
>>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>>
>>>
>>>        
>> I'm using that technique for other parts of my code, but it would be much
>> easier to simply hook into Ant's ResourceSet data structures for this part,
>> as it's possible to register a number of unit tests with dojo before running
>> them.
>>
>>
>>   Or maybe, define your own global load() function inside the<script />
>>      
>>>   tag?
>>>
>>>
>>>        
>> That's what I'm working on. This seems to work, but I still need to test it
>> with the dojo module loader:
>>
>>         <script language="javascript" manager="bsf">
>>
>>             <classpath>
>>
>>                 <fileset dir="../../../lib/java/" includes="js.jar"/>
>>
>>                 <fileset dir="../../../lib/build-java/"
>> includes="*.jar"></fileset>
>>
>>             </classpath><![CDATA[
>>
>>             //define load in global scope
>>
>>             function readFile(path){
>>
>>                 stream = new java.io.FileInputStream(new
>> java.io.File(path));
>>
>>                 fc = stream.getChannel();
>>
>>                 bb = fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
>> 0, fc.size());
>>
>>                 return
>> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>>
>>             }
>>
>>             load = function(path){
>>
>>                 eval(String(readFile(path)))
>>
>>             }
>>
>>             echo = helloworld.createTask("echo");
>>
>>             var contents = readFile('hello.js')
>>
>>             echo.setMessage(contents);
>>
>>             echo.perform();
>>
>>             load('hello.js')
>>
>>             echo.perform();
>>
>>         ]]></script>
>>
>> hello.js:
>>
>> echo.setMessage("hello world!");
>>
>>
>> Outputs:
>>
>> hello:
>>
>>      [echo] echo.setMessage("hello world!");
>>
>>      [echo] hello world!
>>
>>
>>
>> Thanks,
>>
>> Jake
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
>> For additional commands, e-mail: user-help@ant.apache.org
>>
>>
>>      
>    

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Greg Roodt <gr...@gmail.com>.
This might work for you:

    <project default="hello" name="helloworld" basedir=".">
       <target name="hello">
           <script language="javascript" manager="bsf">
           <classpath>
               <fileset dir="rhino-lib" includes="*.jar"></fileset>
           </classpath><![CDATA[
           importPackage(java.lang, java.util, java.io);
           System.out.println("Hello from JavaScript!!");
           //create shell, execute something and grab global
           var shell = org.mozilla.javascript.tools.shell.Main;
           var args = ["-e","var a='STRING';"];
            shell.exec(args);
           var shellGlobal = shell.global;

           //grab functions from shell global and place in current global
           var load=shellGlobal.load;
           var print=shellGlobal.print;
           var defineClass=shellGlobal.defineClass;
           var deserialize=shellGlobal.deserialize;
           var doctest=shellGlobal.doctest;
           var gc=shellGlobal.gc;
           var help=shellGlobal.help;
           var loadClass=shellGlobal.loadClass;
           var quit=shellGlobal.quit;
           var readFile=shellGlobal.readFile;
           var readUrl=shellGlobal.readUrl;
           var runCommand=shellGlobal.runCommand;
           var seal=shellGlobal.seal;
           var serialize=shellGlobal.serialize;
           var spawn=shellGlobal.spawn;
           var sync=shellGlobal.sync;
           var toint32=shellGlobal.toint32;
           var version=shellGlobal.version;
           var environment=shellGlobal.environment;

           //test your bad self
           load("test.js");

           ]]></script>
       </target>
    </project>

test.js:
var a = function() {
print("test");
help();
var scriptContents = readFile("test.js");
print(scriptContents);
var ver = version();
print("version:"+ver);
print(this);
for(var prop in this){
print(prop);
}
}
a();



On Sat, Aug 21, 2010 at 7:03 PM, Jacob Beard <jb...@cs.mcgill.ca> wrote:

> Hi Greg,
>
> Thanks for your response. Replies below:
>
>
> On 10-08-21 01:41 PM, Greg Roodt wrote:
>
>> I believe load() is part of Rhino Shell. I think all that the<script />
>> task runs when using JavaScript is the interpreter. It would only have the
>> pure Javascript standard language features (and a few bits and pieces to
>> interact with Java and the execution context).
>>
>>
> load() is normally exposed as part of the global object when running Rhino,
> in the shell or the interpreter. All the js module loaders that support
> Rhino that I've encountered, including RequireJS and dojo, make use of
> load() to load JavaScript modules.
>
>  It might be easier to run the shell for each test? Like so:
>> java org.mozilla.javascript.tools.shell.Main [options]
>> script-filename-or-url [script-arguments]
>> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>>
>> Or like John Resig does with env.js:
>> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>>
>>
> I'm using that technique for other parts of my code, but it would be much
> easier to simply hook into Ant's ResourceSet data structures for this part,
> as it's possible to register a number of unit tests with dojo before running
> them.
>
>
>  Or maybe, define your own global load() function inside the<script />
>>  tag?
>>
>>
> That's what I'm working on. This seems to work, but I still need to test it
> with the dojo module loader:
>
>        <script language="javascript" manager="bsf">
>
>            <classpath>
>
>                <fileset dir="../../../lib/java/" includes="js.jar"/>
>
>                <fileset dir="../../../lib/build-java/"
> includes="*.jar"></fileset>
>
>            </classpath><![CDATA[
>
>            //define load in global scope
>
>            function readFile(path){
>
>                stream = new java.io.FileInputStream(new
> java.io.File(path));
>
>                fc = stream.getChannel();
>
>                bb = fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY,
> 0, fc.size());
>
>                return
> java.nio.charset.Charset.defaultCharset().decode(bb).toString();
>
>            }
>
>            load = function(path){
>
>                eval(String(readFile(path)))
>
>            }
>
>            echo = helloworld.createTask("echo");
>
>            var contents = readFile('hello.js')
>
>            echo.setMessage(contents);
>
>            echo.perform();
>
>            load('hello.js')
>
>            echo.perform();
>
>        ]]></script>
>
> hello.js:
>
> echo.setMessage("hello world!");
>
>
> Outputs:
>
> hello:
>
>     [echo] echo.setMessage("hello world!");
>
>     [echo] hello world!
>
>
>
> Thanks,
>
> Jake
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
>
>

Re: Rhino global.load() in script context

Posted by Jacob Beard <jb...@cs.mcgill.ca>.
Hi Greg,

Thanks for your response. Replies below:

On 10-08-21 01:41 PM, Greg Roodt wrote:
> I believe load() is part of Rhino Shell. I think all that the<script />
> task runs when using JavaScript is the interpreter. It would only have the
> pure Javascript standard language features (and a few bits and pieces to
> interact with Java and the execution context).
>    
load() is normally exposed as part of the global object when running 
Rhino, in the shell or the interpreter. All the js module loaders that 
support Rhino that I've encountered, including RequireJS and dojo, make 
use of load() to load JavaScript modules.
> It might be easier to run the shell for each test? Like so:
> java org.mozilla.javascript.tools.shell.Main [options]
> script-filename-or-url [script-arguments]
> https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell
>
> Or like John Resig does with env.js:
> http://ejohn.org/blog/bringing-the-browser-to-the-server/
>    
I'm using that technique for other parts of my code, but it would be 
much easier to simply hook into Ant's ResourceSet data structures for 
this part, as it's possible to register a number of unit tests with dojo 
before running them.

> Or maybe, define your own global load() function inside the<script />  tag?
>    
That's what I'm working on. This seems to work, but I still need to test 
it with the dojo module loader:

         <script language="javascript" manager="bsf">

             <classpath>

                 <fileset dir="../../../lib/java/" includes="js.jar"/>

                 <fileset dir="../../../lib/build-java/" includes="*.jar"></fileset>

             </classpath><![CDATA[

             //define load in global scope

             function readFile(path){

                 stream = new java.io.FileInputStream(new java.io.File(path));

                 fc = stream.getChannel();

                 bb = fc.map(java.nio.channels.FileChannel.MapMode.READ_ONLY, 0, fc.size());

                 return java.nio.charset.Charset.defaultCharset().decode(bb).toString();

             }

             load = function(path){

                 eval(String(readFile(path)))

             }

             echo = helloworld.createTask("echo");

             var contents = readFile('hello.js')

             echo.setMessage(contents);

             echo.perform();

             load('hello.js')

             echo.perform();

         ]]></script>     


hello.js:

echo.setMessage("hello world!");


Outputs:

hello:

      [echo] echo.setMessage("hello world!");

      [echo] hello world!


Thanks,

Jake

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Re: Rhino global.load() in script context

Posted by Greg Roodt <gr...@gmail.com>.
I believe load() is part of Rhino Shell. I think all that the <script />
task runs when using JavaScript is the interpreter. It would only have the
pure Javascript standard language features (and a few bits and pieces to
interact with Java and the execution context).

It might be easier to run the shell for each test? Like so:
java org.mozilla.javascript.tools.shell.Main [options]
script-filename-or-url [script-arguments]
https://developer.mozilla.org/en/Rhino_Shell#Invoking_the_Shell

Or like John Resig does with env.js:
http://ejohn.org/blog/bringing-the-browser-to-the-server/

Or maybe, define your own global load() function inside the <script /> tag?





On Sat, Aug 21, 2010 at 5:18 PM, Jacob Beard <jb...@cs.mcgill.ca> wrote:

> Hi,
>
> My Ant script currently generates JavaScript modules, and I also have
> JavaScript modules for unit testing the generated JavaScript. What I'd like
> to do is use a Rhino script element to load the generated JavaScript and the
> unit test modules, and run one on the other. In order to do this, I thought
> I would use Rhino's global.load() function, passing in paths as needed, but
> it looks like load() is not available in the global object when running in
> the Ant script context. Alternatively, it seems it would be possible to use
> Rhino (loadfile task) or Java API's to read the contents of the files and
> then eval them, but unfortunately the unit test module has dependencies on
> other modules, and the module loader relies on the existence of load() when
> running under Rhino. I'm wondering, is it possible to gain access to load()
> in the Ant script context?
>
> Thanks,
>
> Jake
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
> For additional commands, e-mail: user-help@ant.apache.org
>
>