[MacRuby] #744: map on an array delivered by terminal app via scripting bridge gives an immutable error
#744: map on an array delivered by terminal app via scripting bridge gives an immutable error ----------------------------+----------------------------------------------- Reporter: jazzbox@… | Owner: lsansonetti@… Type: defect | Status: new Priority: major | Milestone: MacRuby 0.7 Component: MacRuby | Keywords: ----------------------------+----------------------------------------------- {{{ $ cat term.rb framework 'ScriptingBridge' term = SBApplication.applicationWithBundleIdentifier('com.apple.terminal') p term.windows p term.windows.class.ancestors p [term.windows.first].map { |w| w.name } p term.windows.map { |w| w.name } }}} {{{ $ macruby term.rb [#<TerminalWindow:0x2006a8fe0>] [Array, NSMutableArray, NSArray, Enumerable, NSObject, Kernel] ["Terminal — macruby"] /Users/box/macrubyscripts/term.rb:5:in `<main>': can't modify frozen/immutable array (RuntimeError) }}} MacRuby 0.5 gives no error. -- Ticket URL: <http://www.macruby.org/trac/ticket/744> MacRuby <http://macruby.org/>
#744: map on an array delivered by terminal app via scripting bridge gives an immutable error ----------------------------+----------------------------------------------- Reporter: jazzbox@… | Owner: lsansonetti@… Type: defect | Status: closed Priority: major | Milestone: MacRuby 0.7 Component: MacRuby | Resolution: invalid Keywords: | ----------------------------+----------------------------------------------- Changes (by martinlagardette@…): * status: new => closed * resolution: => invalid Comment: I'm not sure how it worked in MacRuby 0.5. Are you sure it does work? Doesn't work with my copy of 0.5. In fact, it doesn't work in Obj-C either, so I'm not really sure how we can make it work within MacRuby :P {{{ #!text/x-objc #import <Foundation/Foundation.h> #import <ScriptingBridge/ScriptingBridge.h> int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SBApplication *app = [SBApplication applicationWithBundleIdentifier:@"com.apple.terminal"]; SBElementArray *windows = [app windows]; NSLog(@"%@", [windows class]); // This raises "can't add an object that already exists" [windows addObject:@"Window name"]; int i = 0; for (id termWindow in windows) { // Same for that [windows replaceObjectAtIndex:i++ withObject:[termWindow name]]; } [pool drain]; return 0; }}} I'm closing the bug right now, bug feel free to re-open the bug if you have an Obj-C version that modifies the array that I would not have thought of. -- Ticket URL: <http://www.macruby.org/trac/ticket/744#comment:1> MacRuby <http://macruby.org/>
#744: map on an array delivered by terminal app via scripting bridge gives an immutable error ----------------------------+----------------------------------------------- Reporter: jazzbox@… | Owner: lsansonetti@… Type: defect | Status: reopened Priority: major | Milestone: MacRuby 0.7 Component: MacRuby | Resolution: Keywords: | ----------------------------+----------------------------------------------- Changes (by jazzbox@…): * status: closed => reopened * resolution: invalid => Comment: Hi Thibault, I'm sorry, but I cannot agree! Your Obj-C example is a replacement for map! and not for map which should return a new Array and is not allowed to modify the original array! In the following example map works even with an immutable NSArray {{{ a = NSArray.arrayWithArray [1,2,3] p a p a.map { |e| e + 10 } p a # a should be unchanged }}} and gives correctly {{{ [1, 2, 3] [11, 12, 13] [1, 2, 3] }}} If I define my own Array#map my breaking example is working too, see this: {{{ framework 'ScriptingBridge' class NSArray # why does Array not work here? def my_map &block res = [] self.each { |e| res << block.call(e) } res end end term = SBApplication.applicationWithBundleIdentifier('com.apple.terminal') p term.windows p term.windows.class.ancestors p [term.windows.first].map { |w| w.name } p NSArray.arrayWithArray(term.windows).map { |w| w.name } p term.windows.my_map { |w| w.name } }}} And last but not least here is my working Obj-C example (although I don't like Obj-C very much, but hey, that's my first example with blocks) {{{ #import <Foundation/Foundation.h> #import <ScriptingBridge/ScriptingBridge.h> int main (int argc, const char * argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; SBApplication *app = [SBApplication applicationWithBundleIdentifier:@"com.apple.terminal"]; SBElementArray *windows = [app windows]; //NSLog(@"%@", [windows class]); NSLog(@"%@", windows); NSMutableArray *result = [NSMutableArray arrayWithCapacity: [windows count]]; [windows enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { //NSLog(@"%@", [obj name]); [result addObject:[obj name]]; }]; NSLog(@"%@", result); [pool drain]; return 0; } }}} BTW, the original example is still working with my version of MacRuby 0.5! -- Ticket URL: <http://www.macruby.org/trac/ticket/744#comment:2> MacRuby <http://macruby.org/>
#744: map on an array delivered by terminal app via scripting bridge gives an immutable error ----------------------------+----------------------------------------------- Reporter: jazzbox@… | Owner: lsansonetti@… Type: defect | Status: reopened Priority: major | Milestone: Component: MacRuby | Resolution: Keywords: | ----------------------------+----------------------------------------------- Changes (by lsansonetti@…): * milestone: MacRuby 0.7 => Comment: Indeed, I suspect this is a bug in the way we detect mutability in pure NSArrays. Sorry for the premature close. -- Ticket URL: <http://www.macruby.org/trac/ticket/744#comment:3> MacRuby <http://macruby.org/>
#744: map on an array delivered by terminal app via scripting bridge gives an immutable error ----------------------------+----------------------------------------------- Reporter: jazzbox@… | Owner: lsansonetti@… Type: defect | Status: closed Priority: major | Milestone: MacRuby 0.7 Component: MacRuby | Resolution: fixed Keywords: | ----------------------------+----------------------------------------------- Changes (by martinlagardette@…): * status: reopened => closed * resolution: => fixed * milestone: => MacRuby 0.7 Comment: Ok, so the problem was actually how `#map` was implemented on `NSArray`s. It was using a `-mutableCopy` as the array to modify, but apparently this doesn't work with `SBElementArray`s. So I went and modified all the ruby methods on NSArray that would copy + modify an array (`#map`, `#shuffle`, `#uniq`, etc.) to use `[NSMutableArray arrayWithArray:rcv]` instead. This might be a little slower, but at least it works :-)/ For the curious, `[[rcv class] arrayWithArray:rcv]` could have been better, but this doesn't work with `SBEelementArray`s either. Anyway, fixed with r4253 :-) -- Ticket URL: <http://www.macruby.org/trac/ticket/744#comment:4> MacRuby <http://macruby.org/>
participants (1)
-
MacRuby