Skip to content

Instantly share code, notes, and snippets.

@Watson1978
Forked from alloy/associated_objects.m
Created October 11, 2011 02:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Watson1978/1277155 to your computer and use it in GitHub Desktop.
Save Watson1978/1277155 to your computer and use it in GitHub Desktop.
MacRuby with Objective-C associated objects
#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
% 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>'
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]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment