public
Created — forked from alloy/associated_objects.m

MacRuby with Objective-C associated objects

  • Download Gist
associated_objects.m
Objective-C
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <MacRuby/MacRuby.h>
 
@interface NSObject (MRAssociatedObjects)
- (id)associatedObjectForSymbol:(NSString *)rubySymbolName;
- (void)setAssociatedObject:(id)value forSymbol:(NSString *)rubySymbolName;
@end
 
@implementation NSObject (MRAssociatedObjects)
 
static VALUE
symbolNameToSymbol(id rubySymbolName)
{
VALUE sym;
ID id_to_s = rb_intern("to_s");
 
if (SYMBOL_P(rubySymbolName)) {
sym = (VALUE)rubySymbolName;
} else if ([rubySymbolName isKindOfClass:[NSString class]]) {
sym = rb_name2sym([rubySymbolName UTF8String]);
} else {
if (rb_respond_to((VALUE)rubySymbolName, id_to_s)) {
VALUE str = rb_funcall((VALUE)rubySymbolName, id_to_s, 0, Qnil);
sym = rb_name2sym(RSTRING_PTR(str));
}
else {
[NSException raise:@"ArgumentError"
format:@"Expected a Symbol or NSString, but got `%@'", rubySymbolName];
}
}
return sym;
}
 
- (id)associatedObjectForSymbol:(id)rubySymbolName
{
return objc_getAssociatedObject(self, (void *)symbolNameToSymbol(rubySymbolName));
}
 
- (void)setAssociatedObject:(id)value forSymbol:(id)rubySymbolName
{
objc_setAssociatedObject(self, (void *)symbolNameToSymbol(rubySymbolName), value, OBJC_ASSOCIATION_RETAIN);
}
 
@end
 
 
// Ruby expects this
void
Init_associated_objects() {}
 
 
@interface TestAssociatedObject : NSObject
@end
@implementation TestAssociatedObject
 
- (void)computeAnswerInObjC
{
if ([[self associatedObjectForSymbol:@"question"] isEqual:@"the answer to everything"]) {
[self setAssociatedObject:[NSNumber numberWithInt:42] forSymbol:@"computed_answer"];
}
}
 
@end
gistfile1.txt
1 2 3 4 5 6
% clang -fobjc-gc -framework Foundation -framework MacRuby -bundle -o associated_objects.bundle associated_objects.m
 
% macruby test.rb
42
/Users/eloy/tmp/associated-objects/test.rb:6:in `[]=:': ArgumentError: Expected a Symbol or NSString, but got `42' (RuntimeError)
from /Users/eloy/tmp/associated-objects/test.rb:13:in `<main>'
test-associated_objects.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
require "associated_objects"
 
class NSObject
alias_method :[], :associatedObjectForSymbol
def []=(symbol, value)
setAssociatedObject(value, forSymbol:symbol)
end
end
 
o = TestAssociatedObject.new
o[:question] = "the answer to everything"
o.computeAnswerInObjC
p o[:computed_answer] # => 42
 
# anything other than a string/symbol makes it go boom
o["string is ok too"] = "yup"
o[42] = "ohnoes" # => test.rb:6:in `[]=:': ArgumentError: Expected a Symbol or NSString, but got `42' (RuntimeError)
p o[42]

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.