[Rubycocoa-devel 1278] Re: BUG: Direct override and inherited methods

Back to archive index

Laurent Sansonetti lsans****@apple*****
Thu Dec 20 07:38:00 JST 2007


Applied to trunk. Thanks a lot for the patch :-)

Laurent

On Dec 15, 2007, at 3:02 AM, Dave Vasilevsky wrote:

> Hi,
>
> I've been overriding methods of Objective-C classes with ruby methods,
> and encountered some weird behavior. It turns out that RubyCocoa isn't
> checking whether the method being overridden belongs to the class at
> hand. If the method actually is inherited, RubyCocoa ends up changing
> not only this class, but some of its ancestors as well.
>
> The solution is to detect whether or not the method is inherited. If
> it is, don't do a direct override, instead add a method with the new
> behavior. Patch with test case follows.
>
> Cheers,
> Dave
>
>
> Index: framework/src/objc/OverrideMixin.m
> ===================================================================
> --- framework/src/objc/OverrideMixin.m	(revision 2158)
> +++ framework/src/objc/OverrideMixin.m	(working copy)
> @@ -390,8 +390,28 @@
>     OVMIX_LOG("Already registered Ruby method by selector '%s' types
> '%s', skipping...", (char *)method, me_types);
>     return;
>   }
> +
> +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
> +  if (direct_override) {
> +    // It's only ok to use setImplementation if this method is in  
> our own
> +    // class--otherwise it will change the behavior of our ancestors.
> +    Method *meth_list, *iter;
> +    BOOL ok = NO;
> +    unsigned int count = 0;
> +
> +    // Search our class' methods
> +    iter = meth_list = class_copyMethodList(klass, &count);
> +    for (; iter && count; ++iter, --count) {
> +      if (sel_isEqual(method_getName(*iter), me_name)) {
> +        ok = YES;
> +        break;
> +      }
> +    }
> +    if (!ok)
> +      direct_override = NO;
> +    free(meth_list);
> +  }
>
> -#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_4
>   if (direct_override)
>     method_setImplementation(me, imp);
>   else
> Index: tests/tc_ovmix.rb
> ===================================================================
> --- tests/tc_ovmix.rb	(revision 2158)
> +++ tests/tc_ovmix.rb	(working copy)
> @@ -101,6 +101,12 @@
>   end
> end
>
> +class OSX::DirectOverrideChild
> +  def overrideMe
> +    'bar'
> +  end
> +end
> +
> class OSX::NSObject
>   def self.mySuperClassMethod
>     'bar'
> @@ -145,6 +151,22 @@
>     OSX::DirectOverride.checkOverridenMethods
>   end
>
> +  def test_direct_inheritance
> +    assert(OSX::DirectOverrideParent.ancestors.include? 
> (OSX::NSObject))
> +    p = OSX::DirectOverrideParent.alloc.init
> +    assert_kind_of(OSX::NSString, p.performSelector('overrideMe'))
> +    assert_equal('foo', p.performSelector('overrideMe').to_s)
> +    p.checkOverride('foo')
> +
> +    assert(OSX::DirectOverrideChild.ancestors.include? 
> (OSX::NSObject))
> +    assert(OSX::DirectOverrideChild.ancestors.include?(
> +      OSX::DirectOverrideParent))
> +    c = OSX::DirectOverrideChild.alloc.init
> +    assert_kind_of(OSX::NSString, c.performSelector('overrideMe'))
> +    assert_equal('bar', c.performSelector('overrideMe').to_s)
> +    c.checkOverride('bar')
> +  end
> +
>   def test_super_method
>     o = OSX::NSString.stringWithCString('blah')
>     assert_equal('foo', o.mySuperMethod.to_s)
> Index: tests/objc_test.m
> ===================================================================
> --- tests/objc_test.m	(revision 2158)
> +++ tests/objc_test.m	(working copy)
> @@ -393,6 +393,37 @@
>
> @end
>
> +
> +// This needs to be separate from DirectOverride since the test  
> might damage
> +// this class.
> + at interface DirectOverrideParent : NSObject
> + at end
> +
> + at implementation DirectOverrideParent
> +
> +- (id)overrideMe
> +{
> +  return @"foo";
> +}
> +
> +- (void)checkOverride:(NSString *)want
> +{
> +  id obj = [self overrideMe];
> +
> +  if (![obj isEqualToString:want])
> +    [NSException raise:@"DirectOverrideInheritance"
> +      format:@"assertion overrideMe failed, got %@", obj];
> +}
> +
> + at end
> +
> + at interface DirectOverrideChild : DirectOverrideParent
> + at end
> +
> + at implementation DirectOverrideChild
> + at end
> +
> +
> #import <AddressBook/ABPeoplePickerC.h>
>
> @interface TestFourCharCode : NSObject
>
> _______________________________________________
> Rubycocoa-devel mailing list
> Rubyc****@lists*****
> http://lists.sourceforge.jp/mailman/listinfo/rubycocoa-devel




More information about the Rubycocoa-devel mailing list
Back to archive index