Created
November 17, 2009 20:34
-
-
Save jballanc/237245 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/spec/macruby/core/array_spec.rb b/spec/macruby/core/array_spec.rb | |
index 9bc6b7c..4dbbf69 100644 | |
--- a/spec/macruby/core/array_spec.rb | |
+++ b/spec/macruby/core/array_spec.rb | |
@@ -79,3 +79,49 @@ describe "An NSArray object" do | |
end | |
=end | |
end | |
+ | |
+describe "Objective-C Array methods" do | |
+ before :each do | |
+ @a = [1,2,3,4] | |
+ end | |
+ | |
+ it "should be able to be aliased to other selectors" do | |
+ class << @a | |
+ alias :foo :count | |
+ end | |
+ | |
+ @a.foo.should == @a.count | |
+ end | |
+ | |
+ it "should be able to be aliased by pure Ruby methods" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ alias :count :foo | |
+ end | |
+ | |
+ @a.count.should == 42 | |
+ end | |
+ | |
+ it "should be commutative when aliased" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ def do_alias | |
+ alias :old_count :count | |
+ alias :count :foo | |
+ end | |
+ def undo_alias | |
+ alias :count :old_count | |
+ end | |
+ end | |
+ | |
+ @a.count.should == 4 | |
+ @a.do_alias | |
+ @a.count.should == 42 | |
+ @a.undo_alias | |
+ @a.count.should == 4 | |
+ end | |
+end | |
diff --git a/spec/macruby/core/hash_spec.rb b/spec/macruby/core/hash_spec.rb | |
index 7e5a27b..c6d3c9a 100644 | |
--- a/spec/macruby/core/hash_spec.rb | |
+++ b/spec/macruby/core/hash_spec.rb | |
@@ -77,3 +77,49 @@ describe "An NSDictionary object" do | |
lambda { a[42] = 123 }.should raise_error(RuntimeError) | |
end | |
end | |
+ | |
+describe "Objective-C Hash methods" do | |
+ before :each do | |
+ @a = {:a => 1, :b => 2, :c => 3} | |
+ end | |
+ | |
+ it "should be able to be aliased to other selectors" do | |
+ class << @a | |
+ alias :foo :count | |
+ end | |
+ | |
+ @a.foo.should == @a.count | |
+ end | |
+ | |
+ it "should be able to be aliased by pure Ruby methods" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ alias :count :foo | |
+ end | |
+ | |
+ @a.count.should == 42 | |
+ end | |
+ | |
+ it "should be commutative when aliased" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ def do_alias | |
+ alias :old_count :count | |
+ alias :count :foo | |
+ end | |
+ def undo_alias | |
+ alias :count :old_count | |
+ end | |
+ end | |
+ | |
+ @a.count.should == 4 | |
+ @a.do_alias | |
+ @a.count.should == 42 | |
+ @a.undo_alias | |
+ @a.count.should == 4 | |
+ end | |
+end | |
diff --git a/spec/macruby/core/string_spec.rb b/spec/macruby/core/string_spec.rb | |
index 3703b3d..436842a 100644 | |
--- a/spec/macruby/core/string_spec.rb | |
+++ b/spec/macruby/core/string_spec.rb | |
@@ -81,3 +81,49 @@ describe "An NSString object" do | |
#lambda { a << 'foo' }.should raise_error(RuntimeError) | |
end | |
end | |
+ | |
+describe "Objective-C String methods" do | |
+ before :each do | |
+ @a = "test" | |
+ end | |
+ | |
+ it "should be able to be aliased to other selectors" do | |
+ class << @a | |
+ alias :foo :length | |
+ end | |
+ | |
+ @a.foo.should == @a.length | |
+ end | |
+ | |
+ it "should be able to be aliased by pure Ruby methods" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ alias :length :foo | |
+ end | |
+ | |
+ @a.length.should == 42 | |
+ end | |
+ | |
+ it "should be commutative when aliased" do | |
+ class << @a | |
+ def foo | |
+ return 42 | |
+ end | |
+ def do_alias | |
+ alias :old_length :length | |
+ alias :length :foo | |
+ end | |
+ def undo_alias | |
+ alias :length :old_length | |
+ end | |
+ end | |
+ | |
+ @a.length.should == 4 | |
+ @a.do_alias | |
+ @a.length.should == 42 | |
+ @a.undo_alias | |
+ @a.length.should == 4 | |
+ end | |
+end | |
diff --git a/spec/macruby/language/objc_method_spec.rb b/spec/macruby/language/objc_method_spec.rb | |
index b4dc337..e0dd066 100644 | |
--- a/spec/macruby/language/objc_method_spec.rb | |
+++ b/spec/macruby/language/objc_method_spec.rb | |
@@ -408,6 +408,49 @@ describe "A pure Objective-C method" do | |
end | |
@o.methodAcceptingSEL('foo:arg1:arg2:', target:o) | |
end | |
+ | |
+ it "can have another method aliased to it" do | |
+ class << @o | |
+ alias :test_method :methodReturningSelf | |
+ end | |
+ | |
+ @o.should.respond_to(:test_method) | |
+ @o.test_method.should == @o | |
+ @o.test_method.object_id.should == @o.object_id | |
+ end | |
+ | |
+ it "can be aliased to a pure Ruby method" do | |
+ class << @o | |
+ def foo | |
+ return 42 | |
+ end | |
+ alias :methodReturningSelf :foo | |
+ end | |
+ | |
+ @o.should.respond_to(:methodReturningSelf) | |
+ @o.methodReturningSelf.should == 42 | |
+ end | |
+ | |
+ it "should be commutative when aliased" do | |
+ class << @o | |
+ def foo | |
+ return 42 | |
+ end | |
+ def do_alias | |
+ alias :old_methodReturningSelf :methodReturningSelf | |
+ alias :methodReturningSelf :foo | |
+ end | |
+ def undo_alias | |
+ alias :methodReturningSelf :old_methodReturningSelf | |
+ end | |
+ end | |
+ | |
+ @o.methodReturningSelf.should == @o | |
+ @o.do_alias | |
+ @o.methodReturningSelf.should == 42 | |
+ @o.undo_alias | |
+ @o.methodReturningSelf.should == @o | |
+ end | |
end | |
describe "A pure MacRuby method" do | |
diff --git a/vm.cpp b/vm.cpp | |
index 7610df8..e5a53dd 100644 | |
--- a/vm.cpp | |
+++ b/vm.cpp | |
@@ -1419,11 +1419,6 @@ rb_vm_alias_method(Class klass, Method method, ID name, bool noargs) | |
const char *types = method_getTypeEncoding(method); | |
rb_vm_method_node_t *node = GET_CORE()->method_node_get(method); | |
- if (node == NULL) { | |
- rb_raise(rb_eArgError, | |
- "only pure Ruby methods can be aliased (`%s' is not)", | |
- sel_getName(method_getName(method))); | |
- } | |
const char *name_str = rb_id2name(name); | |
SEL sel; | |
@@ -1436,8 +1431,27 @@ rb_vm_alias_method(Class klass, Method method, ID name, bool noargs) | |
sel = sel_registerName(tmp); | |
} | |
- GET_CORE()->add_method(klass, sel, imp, node->ruby_imp, | |
- node->arity, node->flags, types); | |
+ if (node == NULL) { | |
+ Method method_to_replace = class_getInstanceMethod(klass, sel); | |
+ rb_vm_method_node_t *node_to_replace = GET_CORE()->method_node_get(method_to_replace); | |
+ if ((klass == (Class)rb_cCFString || klass == (Class)rb_cCFHash) | |
+ && node_to_replace != NULL) { | |
+ //Doesn't work: | |
+ //GET_CORE()->remove_method(klass, sel); | |
+ // | |
+ //This, apparently, doesn't work either... | |
+ //GET_CORE()->add_method(klass, sel, imp, imp, | |
+ // arity, 0, types); | |
+ // | |
+ //This...sorta...works... | |
+ GET_CORE()->nuke_method(method_to_replace); | |
+ } | |
+ class_replaceMethod(klass, sel, imp, types); | |
+ } | |
+ else { | |
+ GET_CORE()->add_method(klass, sel, imp, node->ruby_imp, | |
+ node->arity, node->flags, types); | |
+ } | |
} | |
extern "C" | |
@@ -1458,6 +1472,15 @@ rb_vm_alias2(VALUE outer, ID name, ID def, unsigned char dynamic_class) | |
const char *def_str = rb_id2name(def); | |
SEL sel = sel_registerName(def_str); | |
+ | |
+ // String and Hash aliases should be defined on the Core Foundation classes | |
+ if (klass == (Class)rb_cNSMutableString) { | |
+ klass = (Class)rb_cCFString; | |
+ } | |
+ if (klass == (Class)rb_cNSMutableHash) { | |
+ klass = (Class)rb_cCFHash; | |
+ } | |
+ | |
Method def_method1 = class_getInstanceMethod(klass, sel); | |
Method def_method2 = NULL; | |
if (def_str[strlen(def_str) - 1] != ':') { | |
@@ -2402,6 +2425,16 @@ RoxorCore::undef_method(Class klass, SEL sel) | |
} | |
} | |
+void | |
+RoxorCore::nuke_method(Method m) | |
+{ | |
+ invalidate_method_cache(method_getName(m)); | |
+ std::map<Method, rb_vm_method_node_t *>::iterator iter = ruby_methods.find(m); | |
+ assert(iter != ruby_methods.end()); | |
+ free(iter->second); | |
+ ruby_methods.erase(iter); | |
+} | |
+ | |
extern "C" | |
void | |
rb_vm_undef_method(Class klass, ID name, bool must_exist) | |
diff --git a/vm.h b/vm.h | |
index cb5abd0..614cbd1 100644 | |
--- a/vm.h | |
+++ b/vm.h | |
@@ -750,6 +750,7 @@ class RoxorCore { | |
rb_vm_method_node_t *node, const char *types); | |
void undef_method(Class klass, SEL sel); | |
void remove_method(Class klass, SEL sel); | |
+ void nuke_method(Method m); | |
bool resolve_methods(std::map<Class, rb_vm_method_source_t *> *map, | |
Class klass, SEL sel); | |
bool copy_method(Class klass, Method m); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
> macirb ⚡(alias_fix) | |
irb(main):001:0> class String | |
irb(main):002:1> def foo | |
irb(main):003:2> puts "Hi" | |
irb(main):004:2> end | |
irb(main):005:1> def do_alias | |
irb(main):006:2> alias :old :length | |
irb(main):007:2> alias :length :foo | |
irb(main):008:2> end | |
irb(main):009:1> def undo_alias | |
irb(main):010:2> alias :length :old | |
irb(main):011:2> end | |
irb(main):012:1> end | |
=> nil | |
irb(main):013:0> a = "test" | |
=> "test" | |
irb(main):014:0> a.foo | |
Hi | |
=> nil | |
irb(main):015:0> a.length | |
=> 4 | |
irb(main):016:0> a.do_alias | |
=> nil | |
irb(main):017:0> a.foo | |
Hi | |
=> nil | |
irb(main):018:0> a.length | |
Hi | |
=> nil | |
irb(main):019:0> a.undo_alias | |
=> nil | |
irb(main):020:0> a.foo | |
Hi | |
=> nil | |
irb(main):021:0> a.length | |
=> 4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment