ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Reilly <peter.kitt.rei...@gmail.com>
Subject Re: Rhino global.load() in script context
Date Tue, 24 Aug 2010 08:30:05 GMT
That is pretty awesome!.

Peter

On Tue, Aug 24, 2010 at 1:53 AM, Jacob Beard <jbeard4@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"<jbeard4@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<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
>>>
>>>
>>
>>
>
> ---------------------------------------------------------------------
> 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