ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Greg Roodt <gro...@gmail.com>
Subject Re: Rhino global.load() in script context
Date Mon, 23 Aug 2010 17:56:01 GMT
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
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message