ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jacob Beard <jbea...@cs.mcgill.ca>
Subject Re: Rhino global.load() in script context
Date Sun, 22 Aug 2010 13:02:49 GMT
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<jbeard4@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<jbeard4@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


Mime
View raw message