Permalink
Browse files

Added anonEval to easily inspect a JS object, and callJSFunction:with…

…JSValueArray: to call a js function with raw JSValues
  • Loading branch information...
1 parent 8ac38a6 commit 7adae75d82384e63409276b1db8c9c6fe983c29c @parmanoir committed Oct 11, 2011
@@ -101,24 +101,32 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
- (id)callFunction:(NSString*)name withArguments:(NSArray*)arguments;
- (BOOL)hasFunction:(NSString*)name;
- (BOOL)isSyntaxValid:(NSString*)script;
+- (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)error;
- (BOOL)evalJSFile:(NSString*)path;
- (BOOL)evalJSFile:(NSString*)path toJSValueRef:(JSValueRef*)returnValue;
- (JSValueRef)evalJSString:(NSString*)script;
- (JSValueRef)evalJSString:(NSString*)script withScriptPath:(NSString*)path;
-- (JSValueRef)callJSFunction:(JSValueRef)function withArguments:(NSArray*)arguments;
+- (JSValueRef)callJSFunction:(JSObjectRef)function withArguments:(NSArray*)arguments;
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArguments:arguments, ... NS_REQUIRES_NIL_TERMINATION;
- (JSValueRef)callJSFunctionNamed:(NSString*)functionName withArgumentsArray:(NSArray*)arguments;
- (JSObjectRef)JSFunctionNamed:(NSString*)functionName;
- (BOOL)hasJSFunctionNamed:(NSString*)functionName;
+
+- (JSValueRef)anonEval:(NSString*)script withThis:(JSValueRef)jsThis;
+// Arguments are JSValueRefs wrapped in BoxedJSValue
+- (JSValueRef)callJSFunction:(JSObjectRef)function withJSValueArray:(NSArray*)args;
+
+
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path;
- (NSString*)expandJSMacros:(NSString*)script path:(NSString*)path errors:(NSMutableArray*)array;
-- (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)error;
+
- (BOOL)setObject:(id)object withName:(NSString*)name;
- (BOOL)setObject:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
- (BOOL)setObjectNoRetain:(id)object withName:(NSString*)name attributes:(JSPropertyAttributes)attributes;
- (id)objectWithName:(NSString*)name;
- (BOOL)removeObjectWithName:(NSString*)name;
+
// Get ObjC and raw values from Javascript
- (id)unboxJSValueRef:(JSValueRef)jsValue;
- (BOOL)toBool:(JSValueRef)value;
@@ -309,6 +317,20 @@ typedef struct JSValueRefAndContextRef JSValueRefAndContextRef;
@end
//
+// Boxed value, used for arguments in callJSFunction:withJSValueRefArray:
+//
+@interface BoxedJSValue : NSObject {
+ JSValueRef jsValue;
+}
++ (id)with:(JSValueRef)v;
+- (void)setJSValue:(JSValueRef)v;
+- (JSValueRef)jsValue;
+
+@end
+
+
+
+//
// Helpers
//
id NSStringFromJSValue(JSContextRef ctx, JSValueRef value);
@@ -615,12 +615,13 @@ - (JSValueRef)evalJSString:(NSString*)script
//
// Call a Javascript function by function reference (JSValueRef)
//
-- (JSValueRef)callJSFunction:(JSValueRef)function withArguments:(NSArray*)arguments
+- (JSValueRef)callJSFunction:(JSObjectRef)jsFunction withArguments:(NSArray*)arguments
{
+/*
JSObjectRef jsFunction = JSValueToObject(ctx, function, NULL);
// Return if function is not of function type
if (!jsFunction) return NSLog(@"callJSFunction : value is not a function"), NULL;
-
+*/
// Convert arguments
JSValueRef* jsArguments = NULL;
NSUInteger argumentCount = [arguments count];
@@ -728,6 +729,54 @@ - (BOOL)hasJSFunctionNamed:(NSString*)name
return !![self JSFunctionNamed:name];
}
+
+//
+// Eval an anonymous function with a custom 'this'.
+// Used to easily inspect and manipulate a JSValue
+// Given a javascript date :
+// [jsc anonEval:@"return this.getMilliseconds()" withThis:myObject]
+// Getting an object's keys :
+// [jsc anonEval:@"return Object.keys(this)" withThis:myObject]
+// Getting the length of an array :
+// [jsc anonEval:@"return this.length" withThis:myObject]
+//
+- (JSValueRef)anonEval:(NSString*)script withThis:(JSValueRef)jsThis {
+ JSStringRef scriptJS= JSStringCreateWithUTF8CString([script UTF8String]);
+ JSObjectRef fn = JSObjectMakeFunction(ctx, NULL, 0, NULL, scriptJS, NULL, 1, NULL);
+ JSValueRef result = JSObjectCallAsFunction(ctx, fn, jsThis ? JSValueToObject(ctx, jsThis, NULL) : NULL, 0, NULL, NULL);
+ JSStringRelease(scriptJS);
+ return result;
+}
+
+//
+// Call a Javascript function with raw, non-JSCocoa-boxed JSValueRefs.
+// The JSValueRefs themselves do need to be boxed with 'BoxedJSValue' to be stored in an NSArray
+//
+- (JSValueRef)callJSFunction:(JSObjectRef)function withJSValueArray:(NSArray*)args {
+
+ JSValueRef* jsArguments = nil;
+ NSUInteger argumentCount= [args count];
+ if (argumentCount) {
+ jsArguments = malloc(sizeof(JSValueRef)*argumentCount);
+ for (NSUInteger i=0; i<argumentCount; i++)
+ jsArguments[i] = [[args objectAtIndex:i] jsValue];
+ }
+
+ JSValueRef exception = NULL;
+ JSValueRef returnValue = JSObjectCallAsFunction(ctx, function, NULL, argumentCount, jsArguments, &exception);
+
+ if (jsArguments)
+ free(jsArguments);
+
+ if (exception) {
+ [self callDelegateForException:exception];
+ return NULL;
+ }
+
+ return returnValue;
+}
+
+
//
// Expand macros
//
@@ -798,6 +847,8 @@ - (BOOL)isSyntaxValid:(NSString*)script error:(NSString**)outError
//
- (id)unboxJSValueRef:(JSValueRef)value
{
+ if (!value)
+ return nil;
id object = nil;
[JSCocoaFFIArgument unboxJSValueRef:value toObject:&object inContext:ctx];
return object;
@@ -5033,3 +5084,22 @@ - (id)description {
@end
+
+//
+// Boxed JSValue
+//
+@implementation BoxedJSValue
+
++ (id)with:(JSValueRef)v {
+ id o = [[BoxedJSValue new] autorelease];
+ [o setJSValue:v];
+ return o;
+}
+- (void)setJSValue:(JSValueRef)v {
+ jsValue = v;
+}
+- (JSValueRef)jsValue {
+ return jsValue;
+}
+
+@end
@@ -126,6 +126,7 @@
// Change that as we could be inactive - check that identifier has two dots
// if (app.NSApplicationBundleIdentifier != 'com.inexdo.JSCocoa') throw 'dictionary get failed (3)'
+// log('ID=' + app.NSApplicationBundleIdentifier)
if (app.NSApplicationBundleIdentifier.match(/\./g).length != 2) throw 'dictionary get failed (3)'
// JSCocoaController.log('app=' + app['class'])
@@ -103,6 +103,8 @@ - (void)cycleContext
- (IBAction)_runJSTests:(id)sender {
[self cycleContext];
+
+
[textField setStringValue:@"Running Tests ..."];
// Clean up notifications registered by previously run tests
@@ -230,6 +232,9 @@ - (IBAction)_runJSTests:(id)sender {
[jsc setUseJSLint:YES];
if (![str isEqualToString:[JSCocoa runningArchitecture]]) NSLog(@"!!!!!!!!!!ObjJ syntax with autocall disabled failed");
}
+
+
+
/*
id class = objc_getClass([@"ファイナンス" UTF8String]);
id o = [class new];
@@ -1129,7 +1134,7 @@ + (id)newErrorBlockForJSFunction:(JSValueRefAndContextRef)callbackFunction {
JSValueProtect(mainContext, callbackFunction.value);
void (^theBlock)(NSError *) = ^(NSError *err) {
- [[JSCocoa controllerFromContext:mainContext] callJSFunction:callbackFunction.value withArguments:[NSArray arrayWithObjects:err, nil]];
+ [[JSCocoa controllerFromContext:mainContext] callJSFunction:JSValueToObject(mainContext, callbackFunction.value, NULL) withArguments:[NSArray arrayWithObjects:err, nil]];
};
return [theBlock copy];
Oops, something went wrong.

0 comments on commit 7adae75

Please sign in to comment.