Skip to content

Commit

Permalink
Added anonEval to easily inspect a JS object, and callJSFunction:with…
Browse files Browse the repository at this point in the history
…JSValueArray: to call a js function with raw JSValues
  • Loading branch information
parmanoir committed Oct 11, 2011
1 parent 8ac38a6 commit 7adae75
Show file tree
Hide file tree
Showing 5 changed files with 18,931 additions and 7,570 deletions.
26 changes: 24 additions & 2 deletions JSCocoa/JSCocoaController.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -308,6 +316,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
//
Expand Down
74 changes: 72 additions & 2 deletions JSCocoa/JSCocoaController.m
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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
//
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
1 change: 1 addition & 0 deletions Tests/16 NSArray NSDictionary easy access.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'])
Expand Down
7 changes: 6 additions & 1 deletion TestsRunner/ApplicationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ - (void)cycleContext
- (IBAction)_runJSTests:(id)sender {
[self cycleContext];



[textField setStringValue:@"Running Tests ..."];

// Clean up notifications registered by previously run tests
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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];
Expand Down
Loading

0 comments on commit 7adae75

Please sign in to comment.