Revision: 118 http://trac.macosforge.org/projects/ruby/changeset/118 Author: lsansonetti@apple.com Date: 2008-03-23 19:19:40 -0700 (Sun, 23 Mar 2008) Log Message: ----------- boxed types are now valid NSValue subclasses Modified Paths: -------------- MacRuby/trunk/objc.m MacRuby/trunk/test-macruby/test_boxed.rb MacRuby/trunk/test-macruby/test_objc.rb Modified: MacRuby/trunk/objc.m =================================================================== --- MacRuby/trunk/objc.m 2008-03-23 04:02:19 UTC (rev 117) +++ MacRuby/trunk/objc.m 2008-03-24 02:19:40 UTC (rev 118) @@ -2498,6 +2498,39 @@ rb_funcall((VALUE)rcv, rb_intern("replace"), 1, newstr); } +static const char * +imp_rb_boxed_objCType(void *rcv, SEL sel) +{ + VALUE klass, type; + + klass = CLASS_OF(rcv); + type = rb_boxed_objc_type(klass); + + return StringValuePtr(type); +} + +static void +imp_rb_boxed_getValue(void *rcv, SEL sel, void *buffer) +{ + bs_element_boxed_t *bs_boxed; + void *data; + bool ok; + + bs_boxed = rb_klass_get_bs_boxed(CLASS_OF(rcv)); + + data = bs_element_boxed_get_data(bs_boxed, (VALUE)rcv, &ok); + if (!ok) + [NSException raise:@"NSException" + format:@"can't get internal data for boxed type `%s'", + RSTRING_PTR(rb_inspect((VALUE)rcv))]; + if (data == NULL) { + *(void **)buffer = NULL; + } + else { + memcpy(buffer, data, bs_boxed->ffi_type->size); + } +} + static inline void rb_objc_install_method(Class klass, SEL sel, IMP imp) { @@ -2545,8 +2578,16 @@ (IMP)imp_rb_string_characterAtIndex); rb_objc_install_method(klass, @selector(getCharacters:range:), (IMP)imp_rb_string_getCharactersRange); - rb_objc_install_method(klass, @selector(replaceCharactersInRange:withString:), + rb_objc_install_method(klass, + @selector(replaceCharactersInRange:withString:), (IMP)imp_rb_string_replaceCharactersInRangeWithString); + + /* Boxed */ + klass = RCLASS_OCID(rb_cBoxed); + rb_objc_override_method(klass, @selector(objCType), + (IMP)imp_rb_boxed_objCType); + rb_objc_override_method(klass, @selector(getValue:), + (IMP)imp_rb_boxed_getValue); } static void * @@ -2780,7 +2821,8 @@ rb_objc_retain( rb_objc_class_magic_cookie = rb_str_new2("rb_objc_class_magic_cookie")); - rb_cBoxed = rb_define_class("Boxed", rb_cObject); + rb_cBoxed = rb_define_class("Boxed", + rb_objc_import_class(objc_getClass("NSValue"))); rb_define_singleton_method(rb_cBoxed, "objc_type", rb_boxed_objc_type, 0); rb_define_singleton_method(rb_cBoxed, "opaque?", rb_boxed_is_opaque, 0); rb_define_singleton_method(rb_cBoxed, "fields", rb_boxed_fields, 0); Modified: MacRuby/trunk/test-macruby/test_boxed.rb =================================================================== --- MacRuby/trunk/test-macruby/test_boxed.rb 2008-03-23 04:02:19 UTC (rev 117) +++ MacRuby/trunk/test-macruby/test_boxed.rb 2008-03-24 02:19:40 UTC (rev 118) @@ -4,9 +4,78 @@ def setup framework 'Foundation' + bundle = '/tmp/_test_bs.bundle' + if !File.exist?(bundle) or File.mtime(bundle) < File.mtime(__FILE__) + s = <<EOS +#import <Foundation/Foundation.h> +@interface NSObject (MacRubyNSPointAdditions) +- (float)x; +- (float)y; +@end +@interface TestBoxed : NSObject +@end +@implementation TestBoxed +- (void)testPoint:(NSPoint)point x:(float)x y:(float)y +{ + if (point.x != x) + [NSException raise:@"NSException" + format:@"point.x (%f) != x (%f)", point.x, x]; + + if (point.y != y) + [NSException raise:@"NSException" + format:@"point.y (%f) != y (%f)", point.y, y]; +} +- (void)testPointAsObject:(id)point x:(float)x y:(float)y +{ + Class boxed; + boxed = NSClassFromString(@"Boxed"); + + if (![point isKindOfClass:boxed]) + [NSException raise:@"NSException" + format:@"point (%@) isn't a boxed type", point]; + + if (![point isKindOfClass:[NSValue class]]) + [NSException raise:@"NSException" + format:@"point (%@) isn't a value type", point]; + +#if 0 // FIXME this cannot be tested yet + if ([point x] != x) + [NSException raise:@"NSException" + format:@"[point x] (%f) != x (%f)", [point x], x]; + + if ([point y] != y) + [NSException raise:@"NSException" + format:@"[point y] (%f) != y (%f)", [point y], y]; +#endif + + if (strcmp([point objCType], @encode(NSPoint)) != 0) + [NSException raise:@"NSException" + format:@"[point objCType] (%s) != @encode(NSPoint) (%s)", + [point objCType], @encode(NSPoint)]; + + NSPoint p; + [point getValue:&p]; + [self testPoint:p x:x y:y]; +} +- (NSPoint)testReturnPointWithX:(float)x y:(float)y +{ + NSPoint p; + p.x = x; + p.y = y; + return p; +} +@end +EOS + File.open('/tmp/_test.m', 'w') { |io| io.write(s) } + system("gcc /tmp/_test.m -bundle -o #{bundle} -framework Foundation -fobjc-gc-only") or exit 1 + end + require 'dl'; DL.dlopen(bundle) end def test_boxed_classes + assert_kind_of(Class, Boxed) + assert_equal(NSValue, Boxed.superclass) + # struct assert(NSRect.ancestors.include?(Boxed)) assert('{_NSRect={_NSPoint=ff}{_NSSize=ff}}', NSRect.objc_type) @@ -80,14 +149,32 @@ end def test_struct_nsstring_marshalling - r = NSRange.new(1.0, 4.0) + r = NSRange.new(1, 4) assert_kind_of(NSString, NSStringFromRange(r)) - # FIXME not passing yet - #assert_equal('{1.0, 4.0}', NSStringFromRange(r)) + assert_equal('{1, 4}', NSStringFromRange(r)) assert_equal(r, NSRangeFromString(NSStringFromRange(r))) rect = NSRect.new(NSPoint.new(42.0, 1042.0), NSSize.new(123, 456)) assert_equal(NSPoint.new(42.0, 1042.0), NSPointFromString(NSStringFromPoint(rect.origin))) end + def test_nspoint_in_objc + p = NSPoint.new(42.0, 99.0) + o = TestBoxed.new + o.testPoint(p, x:42.0, y:99.0) + o.testPointAsObject(p, x:42.0, y:99.0) + assert_equal(p, o.testReturnPointWithX(42.0, y:99.0)) + end + + class MethodReturningBoxed + def foo + NSPoint.new(1, 2) + end + end + def test_objc_call_pure_method_returning_boxed + o = MethodReturningBoxed.new + assert_equal(NSPoint.new(1, 2), o.send(:foo)) + assert_equal(NSPoint.new(1, 2), o.performSelector(:foo)) + end + end Modified: MacRuby/trunk/test-macruby/test_objc.rb =================================================================== --- MacRuby/trunk/test-macruby/test_objc.rb 2008-03-23 04:02:19 UTC (rev 117) +++ MacRuby/trunk/test-macruby/test_objc.rb 2008-03-24 02:19:40 UTC (rev 118) @@ -109,15 +109,4 @@ assert_equal(v, o.test_getObject(dict, forKey:s)) end - class MethodReturningBoxed - def foo - NSPoint.new(1, 2) - end - end - def test_objc_call_pure_method_returning_boxed - o = MethodReturningBoxed.new - assert_equal(NSPoint.new(1, 2), o.send(:foo)) - assert_equal(NSPoint.new(1, 2), o.performSelector(:foo)) - end - end
participants (1)
-
source_changes@macosforge.org