Created
August 8, 2012 02:05
-
-
Save tschaub/3291399 to your computer and use it in GitHub Desktop.
Example of a JavaScript iterator created with Rhino.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Demonstrates how a JavaScript iterator can be created with Rhino. This | |
* simple Range class can be defined as a JavaScript constructor. | |
* | |
* Example use: | |
* | |
* >> // set up Range constructor and prototype | |
* >> defineClass(Packages.com.example.Range) | |
* | |
* >> var range = new Range(3, 5) | |
* >> range.high | |
* 5 | |
* >> range.low | |
* 3 | |
* | |
* >> for (var i in range) { | |
* .. print("got: " + i); | |
* .. } | |
* got: 3 | |
* got: 4 | |
* got: 5 | |
* | |
* >> var range = new Range() | |
* Error: Call constructor with two numbers. (<stdin>#15) | |
* | |
* >> var range = Range() | |
* Error: Call constructor with new keyword. (<stdin>#16) | |
* | |
*/ | |
package com.example; | |
import org.mozilla.javascript.Context; | |
import org.mozilla.javascript.Function; | |
import org.mozilla.javascript.JavaScriptException; | |
import org.mozilla.javascript.NativeIterator; | |
import org.mozilla.javascript.ScriptRuntime; | |
import org.mozilla.javascript.ScriptableObject; | |
import org.mozilla.javascript.annotations.JSConstructor; | |
import org.mozilla.javascript.annotations.JSFunction; | |
import org.mozilla.javascript.annotations.JSGetter; | |
public class Range extends ScriptableObject { | |
/** serialVersionUID */ | |
private static final long serialVersionUID = 2468077032059444220L; | |
/** | |
* Low value of range (inclusive). | |
*/ | |
int low; | |
/** | |
* High value of range (inclusive). | |
*/ | |
int high; | |
/** | |
* Current value. | |
*/ | |
int current; | |
/** | |
* JavaScript prototype constructor. | |
*/ | |
public Range() { | |
} | |
/** | |
* Create a new range with the given integer values. | |
* @param low | |
* @param high | |
*/ | |
private Range(int low, int high) { | |
this.low = low; | |
this.high = high; | |
current = low - 1; | |
} | |
/** | |
* JavaScript constructor for a range. | |
* @param cx | |
* @param args | |
* @param ctorObj | |
* @param inNewExpr | |
* @return | |
*/ | |
@JSConstructor | |
public static Object constructor(Context cx, Object[] args, Function ctorObj, boolean inNewExpr) { | |
if (!inNewExpr) { | |
throw ScriptRuntime.constructError("Error", "Call constructor with new keyword."); | |
} | |
if (args.length != 2) { | |
throw ScriptRuntime.constructError("Error", "Call constructor with two numbers."); | |
} | |
return new Range((int) Context.toNumber(args[0]), (int) Context.toNumber(args[1])); | |
} | |
/** | |
* JavaScript getter for high value. | |
* @return | |
*/ | |
@JSGetter | |
public int getHigh() { | |
return high; | |
} | |
/** | |
* JavaScript getter for low value. | |
* @return | |
*/ | |
@JSGetter | |
public int getLow() { | |
return low; | |
} | |
/** | |
* JavaScript method for accessing the next value in the range. Throws | |
* StopIteration when the range is exhausted. | |
* @return | |
*/ | |
@JSFunction | |
public int next() { | |
++current; | |
if (current > high) { | |
throw new JavaScriptException( | |
NativeIterator.getStopIterationObject(getParentScope()), null, 0); | |
} | |
return current; | |
} | |
/** | |
* Magic method to allow for...in syntax. | |
* @param b | |
* @return | |
*/ | |
@JSFunction | |
public Object __iterator__(boolean b) { | |
return this; | |
} | |
/** | |
* Name for JavaScript constructor. | |
*/ | |
@Override | |
public String getClassName() { | |
return "Range"; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
If you remove the "force construction using new keyword" and attempt to construct it without using "new", the Range does not seem to work correctly. Why?