[macruby-changes] [662] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Thu Oct 9 18:41:33 PDT 2008
Revision: 662
http://trac.macosforge.org/projects/ruby/changeset/662
Author: lsansonetti at apple.com
Date: 2008-10-09 18:41:32 -0700 (Thu, 09 Oct 2008)
Log Message:
-----------
introducing -[NSObject performRubySelector:] methods
Modified Paths:
--------------
MacRuby/trunk/include/ruby/objc.h
MacRuby/trunk/objc.m
Modified: MacRuby/trunk/include/ruby/objc.h
===================================================================
--- MacRuby/trunk/include/ruby/objc.h 2008-10-09 21:40:45 UTC (rev 661)
+++ MacRuby/trunk/include/ruby/objc.h 2008-10-10 01:41:32 UTC (rev 662)
@@ -2,11 +2,47 @@
@interface MacRuby : NSObject
+/* Get a singleton reference to the MacRuby runtime, initializing it before if
+ * needed. The same instance is re-used after.
+ */
+ (MacRuby *)sharedRuntime;
+
+/* Connect and attach a MacRuby runtime to the given process and return a
+ * reference to it. This is done using mach_inject.
+ */
+ (MacRuby *)runtimeAttachedToProcessIdentifier:(pid_t)pid;
+/* Evaluate a Ruby expression in the given file and return a reference to the
+ * result.
+ */
- (id)evaluateFileAtPath:(NSString *)path;
+
+/* Evaluate a Ruby expression in the given URL and return a reference to the
+ * result. Currently only file:// URLs are supported.
+ */
- (id)evaluateFileAtURL:(NSURL *)URL;
+
+/* Evaluate a Ruby expression in the given string and return a reference to the
+ * result.
+ */
- (id)evaluateString:(NSString *)expression;
@end
+
+ at interface NSObject (MacRubyAdditions)
+
+/* Perform the given selector and return a reference to the result. */
+- (id)performRubySelector:(SEL)sel;
+
+/* Perform the given selector, passing the given arguments and return a
+ * reference to the result. The argv argument should be a C array whose size
+ * is the value of the argc argument.
+ */
+- (id)performRubySelector:(SEL)sel withArguments:(id *)argv count:(int)argc;
+
+/* Perform the given selector, passing the given arguments and return a
+ * reference to the result. The arguments should be a NULL-terminated list.
+ */
+- (id)performRubySelector:(SEL)sel withArguments:(id)firstArgument, ...;
+
+ at end
Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m 2008-10-09 21:40:45 UTC (rev 661)
+++ MacRuby/trunk/objc.m 2008-10-10 01:41:32 UTC (rev 662)
@@ -1516,6 +1516,10 @@
void *userdata;
};
+VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id,
+ ID oid, int argc, const VALUE *argv, const NODE *body,
+ int nosuper);
+
static VALUE
rb_ruby_to_objc_closure_handler_main(void *ctx)
{
@@ -1570,10 +1574,6 @@
DLOG("RCALL", "%c[<%s %p> %s] node=%p", class_isMetaClass((Class)klass) ? '+' : '-', class_getName((Class)klass), (void *)rrcv, (char *)sel, body);
- VALUE rb_vm_call(rb_thread_t * th, VALUE klass, VALUE recv, VALUE id,
- ID oid, int argc, const VALUE *argv, const NODE *body,
- int nosuper);
-
ret = rb_vm_call(GET_THREAD(), klass, rrcv, mid, Qnil,
argc, argv, node, 0);
@@ -3338,16 +3338,10 @@
return nil;
}
-static VALUE
-evaluateString_safe(VALUE expression)
+static void
+rb_raise_ruby_exc_in_objc(VALUE ex)
{
- return rb_eval_string([(NSString *)expression UTF8String]);
-}
-
-static VALUE
-evaluateString_rescue(VALUE expression)
-{
- VALUE ex, ex_name, ex_message, ex_backtrace;
+ VALUE ex_name, ex_message, ex_backtrace;
NSException *ocex;
static ID name_id = 0;
static ID message_id = 0;
@@ -3355,35 +3349,42 @@
if (name_id == 0) {
name_id = rb_intern("name");
- }
- if (message_id == 0) {
message_id = rb_intern("message");
- }
- if (backtrace_id == 0) {
backtrace_id = rb_intern("backtrace");
}
- ex = rb_errinfo();
ex_name = rb_funcall(CLASS_OF(ex), name_id, 0);
ex_message = rb_funcall(ex, message_id, 0);
ex_backtrace = rb_funcall(ex, backtrace_id, 0);
- ocex = [NSException exceptionWithName:(id)ex_name reason:(id)ex_message userInfo:
- [NSDictionary dictionaryWithObjectsAndKeys:(id)ex, @"object",
- (id)ex_backtrace, @"backtrace",
- NULL]];
+ ocex = [NSException exceptionWithName:(id)ex_name reason:(id)ex_message
+ userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ (id)ex, @"object",
+ (id)ex_backtrace, @"backtrace",
+ NULL]];
[ocex raise];
+}
- return Qnil;
+static VALUE
+evaluateString_safe(VALUE expression)
+{
+ return rb_eval_string([(NSString *)expression UTF8String]);
}
+static VALUE
+evaluateString_rescue(void)
+{
+ rb_raise_ruby_exc_in_objc(rb_errinfo());
+ return Qnil; /* not reached */
+}
+
- (id)evaluateString:(NSString *)expression
{
VALUE ret;
ret = rb_rescue2(evaluateString_safe, (VALUE)expression,
- evaluateString_rescue, (VALUE)expression,
+ evaluateString_rescue, Qnil,
rb_eException, (VALUE)0);
return RB2OC(ret);
}
@@ -3402,3 +3403,136 @@
}
@end
+
+ at implementation NSObject (MacRubyAdditions)
+
+- (id)performRubySelector:(SEL)sel
+{
+ return [self performRubySelector:sel withArguments:NULL];
+}
+
+struct performRuby_context
+{
+ VALUE rcv;
+ ID mid;
+ int argc;
+ VALUE *argv;
+ NODE *node;
+};
+
+static VALUE
+performRuby_safe(VALUE arg)
+{
+ struct performRuby_context *ud = (struct performRuby_context *)arg;
+ return rb_vm_call(GET_THREAD(), *(VALUE *)ud->rcv, ud->rcv, ud->mid, Qnil,
+ ud->argc, ud->argv, ud->node, 0);
+}
+
+static VALUE
+performRuby_rescue(VALUE arg)
+{
+ if (arg != 0) {
+ ruby_current_thread = (rb_thread_t *)arg;
+ }
+ rb_raise_ruby_exc_in_objc(rb_errinfo());
+ return Qnil; /* not reached */
+}
+
+- (id)performRubySelector:(SEL)sel withArguments:(id *)argv count:(int)argc
+{
+ const bool need_protection = GET_THREAD()->thread_id != pthread_self();
+ NODE *node;
+ IMP imp;
+ VALUE *rargs, ret;
+ ID mid;
+
+ imp = NULL;
+ node = rb_objc_method_node2(*(VALUE *)self, sel, &imp);
+ if (node == NULL) {
+ if (imp != NULL) {
+ [NSException raise:NSInvalidArgumentException format:
+ @"-[%@ %s] is not a pure Ruby method", self, (char *)sel];
+ }
+ else {
+ [NSException raise:NSInvalidArgumentException format:
+ @"receiver %@ does not respond to %s", (char *)sel];
+ }
+ }
+
+ if (argc == 0) {
+ rargs = NULL;
+ }
+ else {
+ int i;
+ rargs = (VALUE *)alloca(sizeof(VALUE) * argc);
+ for (i = 0; i < argc; i++) {
+ rargs[i] = OC2RB(argv[i]);
+ }
+ }
+
+ rb_thread_t *rb_thread_wrap_existing_native_thread(rb_thread_id_t id);
+ void native_mutex_unlock(pthread_mutex_t *lock);
+ void native_mutex_lock(pthread_mutex_t *lock);
+ rb_thread_t *th, *old = NULL;
+
+ if (need_protection) {
+ th = rb_thread_wrap_existing_native_thread(pthread_self());
+ native_mutex_lock(&GET_THREAD()->vm->global_interpreter_lock);
+ old = ruby_current_thread;
+ ruby_current_thread = th;
+ }
+
+ mid = rb_intern((char *)sel);
+
+ struct performRuby_context ud;
+ ud.rcv = (VALUE)self;
+ ud.mid = mid;
+ ud.argc = argc;
+ ud.argv = rargs;
+ ud.node = node->nd_body;
+
+ ret = rb_rescue2(performRuby_safe, (VALUE)&ud,
+ performRuby_rescue, (VALUE)old,
+ rb_eException, (VALUE)0);
+
+ if (need_protection) {
+ native_mutex_unlock(&GET_THREAD()->vm->global_interpreter_lock);
+ ruby_current_thread = old;
+ }
+
+ return RB2OC(ret);
+}
+
+- (id)performRubySelector:(SEL)sel withArguments:firstArg, ...
+{
+ va_list args;
+ int argc;
+ id *argv;
+
+ if (firstArg != nil) {
+ int i;
+
+ argc = 1;
+ va_start(args, firstArg);
+ while (va_arg(args, id)) {
+ argc++;
+ }
+ va_end(args);
+ argv = alloca(sizeof(id) * argc);
+ va_start(args, firstArg);
+ argv[0] = firstArg;
+ for (i = 1; i < argc; i++) {
+ argv[i] = va_arg(args, id);
+ }
+ va_end(args);
+ }
+ else {
+ argc = 0;
+ argv = NULL;
+ }
+
+ return [self performRubySelector:sel withArguments:argv count:argc];
+}
+
+ at end
+
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/macruby-changes/attachments/20081009/a55e8bc8/attachment-0001.html
More information about the macruby-changes
mailing list