How do I subclass Obj-C classes in MacRuby?
Hi All, I've produced an ugly bunch of ruby that talks to OpenDirectory and am trying to clean it up a bit. Currently I'm using pure ruby classes that proxy Obj-C objects held in instance variables, but my goal is to have something structured like this - module OpenDirectory class Node < ODNode def find_user_by_name name ... end end end but I can't work out how to make a Ruby class that subclasses an Obj-C class and overrides the initialiser. With classes that descend from Obj-C classes the ruby "initialize" method doesn't seem to get called (because they're missing descent from the Ruby base Object class?), and all my attempts to override init result in 2010-05-05 15:55:34.237 macruby[2600:903] object 0x200249900 with 0 retain-count passed to CFMakeCollectable. and a segfault. Attached below is a reduced case, if anyone can point out how to get a valid MyNode object it'd be much appreciated. If node is a real ODNode (as in the commented lines) all works correctly. I'm not calling super, since the object has (I believe) already been alloc'd and I'm explicitly calling the designated initializer later in my own init. If I *do* call super in my own init, I just get an additional "object 0x... with 0 retain-count passed to CFMakeCollectable" error. If I use ODNode.nodeWithSession:name:error: in my own init the example below works, but I end up with an ODNode rather than a MyNode so it's missing any methods I'm adding to my own class. (I'm also unsure whether I need to be retaining the session in an instance variable myself or if it's also being retained in the ODNode, but that's another question.) Any pointers very much appreciated... Russell example: framework 'OpenDirectory' # no BridgeSupport for CFOpenDirectory.framework... :( Users = "dsRecTypeStandard:Users" RecordName = "dsAttrTypeStandard:RecordName" MatchEqualTo = 0x2001 RealName = "dsAttrTypeStandard:RealName" # some account name to search for me = "russm" class MyNode < ODNode def init @session = ODSession.defaultSession STDERR.puts "===== pre CFMakeCollectable error" self.initWithSession @session, name:"/Local/Default", error:nil STDERR.puts "===== post CFMakeCollectable error" self end end node = MyNode.new #session = ODSession.defaultSession #node = ODNode.nodeWithSession session, name:"/Local/Default", error:nil query = ODQuery.queryWithNode node, forRecordTypes: Users, attribute: RecordName, matchType: MatchEqualTo, queryValues: me, returnAttributes: RealName, maximumResults:0, error:nil STDERR.puts "===== pre segfault" results = query.resultsAllowingPartial false, error:nil STDERR.puts "===== post segfault" result_attributes = results[0].recordDetailsForAttributes nil, error:nil puts result_attributes.inspect
Hi! I believe the problem is that you were overriding the wrong init method. Here is what I changed to your code to make it work: class MyNode < ODNode def initWithSession(session, name:name, error:err) if super @session = session self end end end session = ODSession.defaultSession node = MyNode.nodeWithSession session, name: "/Local/Default", error: nil I override initWithSession:name:error instead of init, and created a "MyNode" object the exact same way I would have created an ODNode :-) The results were, I believe, what you would expect: $> macruby od.rb {"dsAttrTypeStandard:AppleMetaNodeLocation"=>["/Local/Default"], ...} Hope that helps! -- Thibault Martin-Lagardette On May 4, 2010, at 23:37, russell muetzelfeldt wrote:
Hi All,
I've produced an ugly bunch of ruby that talks to OpenDirectory and am trying to clean it up a bit. Currently I'm using pure ruby classes that proxy Obj-C objects held in instance variables, but my goal is to have something structured like this -
module OpenDirectory class Node < ODNode def find_user_by_name name ... end end end
but I can't work out how to make a Ruby class that subclasses an Obj-C class and overrides the initialiser. With classes that descend from Obj-C classes the ruby "initialize" method doesn't seem to get called (because they're missing descent from the Ruby base Object class?), and all my attempts to override init result in
2010-05-05 15:55:34.237 macruby[2600:903] object 0x200249900 with 0 retain-count passed to CFMakeCollectable.
and a segfault.
Attached below is a reduced case, if anyone can point out how to get a valid MyNode object it'd be much appreciated. If node is a real ODNode (as in the commented lines) all works correctly. I'm not calling super, since the object has (I believe) already been alloc'd and I'm explicitly calling the designated initializer later in my own init. If I *do* call super in my own init, I just get an additional "object 0x... with 0 retain-count passed to CFMakeCollectable" error. If I use ODNode.nodeWithSession:name:error: in my own init the example below works, but I end up with an ODNode rather than a MyNode so it's missing any methods I'm adding to my own class.
(I'm also unsure whether I need to be retaining the session in an instance variable myself or if it's also being retained in the ODNode, but that's another question.)
Any pointers very much appreciated...
Russell
example:
framework 'OpenDirectory'
# no BridgeSupport for CFOpenDirectory.framework... :( Users = "dsRecTypeStandard:Users" RecordName = "dsAttrTypeStandard:RecordName" MatchEqualTo = 0x2001 RealName = "dsAttrTypeStandard:RealName"
# some account name to search for me = "russm"
class MyNode < ODNode def init @session = ODSession.defaultSession STDERR.puts "===== pre CFMakeCollectable error" self.initWithSession @session, name:"/Local/Default", error:nil STDERR.puts "===== post CFMakeCollectable error" self end end
node = MyNode.new #session = ODSession.defaultSession #node = ODNode.nodeWithSession session, name:"/Local/Default", error:nil query = ODQuery.queryWithNode node, forRecordTypes: Users, attribute: RecordName, matchType: MatchEqualTo, queryValues: me, returnAttributes: RealName, maximumResults:0, error:nil STDERR.puts "===== pre segfault" results = query.resultsAllowingPartial false, error:nil STDERR.puts "===== post segfault" result_attributes = results[0].recordDetailsForAttributes nil, error:nil puts result_attributes.inspect
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Oh and by the way, you can generate BridgeSupport for CFOpenDirectory yourself if you need: $> gen_bridge_metadata -f /System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework -o CFOpenDirectory.bridgesupport Then all you need to do is place `CFOpenDirectory.bridgesupport' wherever you need, and call from your script: load_bridge_support_file '/path/to/CFOpenDirectory.bridgesupport' And you should have access to `kODMatchEqualTo' etc. -- Thibault Martin-Lagardette On May 4, 2010, at 23:37, russell muetzelfeldt wrote:
# no BridgeSupport for CFOpenDirectory.framework... :( Users = "dsRecTypeStandard:Users" RecordName = "dsAttrTypeStandard:RecordName" MatchEqualTo = 0x2001 RealName = "dsAttrTypeStandard:RealName"
And you should have access to `kODMatchEqualTo' etc.
Which should be available as KODMatchEqualTo and not kODMatchEqualTo (Ruby's constants start by an upper case letter) - Matt On Wed, May 5, 2010 at 12:26 AM, Thibault Martin-Lagardette <thibault.ml@ gmail.com> wrote:
Oh and by the way, you can generate BridgeSupport for CFOpenDirectory yourself if you need:
$> gen_bridge_metadata -f /System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework -o CFOpenDirectory.bridgesupport
Then all you need to do is place `CFOpenDirectory.bridgesupport' wherever you need, and call from your script:
load_bridge_support_file '/path/to/CFOpenDirectory.bridgesupport'
And you should have access to `kODMatchEqualTo' etc.
-- Thibault Martin-Lagardette
On May 4, 2010, at 23:37, russell muetzelfeldt wrote:
# no BridgeSupport for CFOpenDirectory.framework... :( Users = "dsRecTypeStandard:Users" RecordName = "dsAttrTypeStandard:RecordName" MatchEqualTo = 0x2001 RealName = "dsAttrTypeStandard:RealName"
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
participants (3)
-
Matt Aimonetti
-
russell muetzelfeldt
-
Thibault Martin-Lagardette