How to use custom C struct's?
Hi all, I'm writing an iPhone app. I made the audacious step of trying to test my ObjC model classes using MacRuby. I create and load a dynlib ("bundle") of these classes. So far, so good. However, I have a C struct that I use all over the place: struct MapPoint { int row; int col; }; typedef struct MapPoint MapPoint; Obviously, when I have a method that returns that type, MacRuby doesn't like it. That is, # ruby my_objc_object.mapPoint gives this error: RuntimeError: unrecognized octype `{MapPoint=ii}' The google didn't yield much guidance on this. Before I started a deep-dive on the MacRuby source, and/or the standard ruby way to handle this sort of thing, I thought I would ask a couple of questions: 1) Any easy advice? 2) Is this different in MacRuby than in ruby proper? 3) Any pointers into the MacRuby source that might help me? Thanks, Clay Bridges
Hi, On Aug 5, 2009, at 5:31 PM, Clay Bridges wrote:
The google didn't yield much guidance on this. Before I started a deep-dive on the MacRuby source, and/or the standard ruby way to handle this sort of thing, I thought I would ask a couple of questions:
1) Any easy advice?
Yes, use RubyCocoa
2) Is this different in MacRuby than in ruby proper?
RubyCocoa at least allows you to use BridgeSupport which would allow you to map these. Afaik MacRuby doesn't fully support it yet.
3) Any pointers into the MacRuby source that might help me?
BridgeSupport needs to fully implemented. Keep in mind, MacRuby is not stable yet. HTH, Eloy
When MacRuby's FFI support is more mature, declaring an FFI::Struct subclass like this will be another option. class MapPoint < FFI::Struct layout :row, :int, :col, :Int end You instantiate an FFI::Struct with a pointer. I'm hacking away on a Ruby interface to a C library, and I'm slinging around pointers, structs and unions with ease on MRI 1.8.6, 1.9.1 and JRuby. Best, Jeremy On Wed, Aug 5, 2009 at 8:41 AM, Eloy Duran <eloy.de.enige@gmail.com> wrote:
Hi,
On Aug 5, 2009, at 5:31 PM, Clay Bridges wrote:
The google didn't yield much guidance on this. Before I started a deep-dive on the MacRuby source, and/or the standard ruby way to handle this sort of thing, I thought I would ask a couple of questions:
1) Any easy advice?
Yes, use RubyCocoa
2) Is this different in MacRuby than in ruby proper?
RubyCocoa at least allows you to use BridgeSupport which would allow you to map these. Afaik MacRuby doesn't fully support it yet.
3) Any pointers into the MacRuby source that might help me?
BridgeSupport needs to fully implemented.
Keep in mind, MacRuby is not stable yet.
HTH, Eloy
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Yes, use RubyCocoa
I'm afraid I'm already hooked. ;) If it comes down to it, I've already put a testing-only category wrapper around one method, e.g. #import "Cell.h" @interface Cell (TestUtil) @property (readonly) NSArray* mapPointAsArray; @end @implementation Cell (TestUtil) @dynamic mapPointAsArray; // this method is simply for ruby-side testing - (NSArray*) mapPointAsArray { NSMutableArray* nsma = [[NSMutableArray alloc] initWithCapacity:2]; [nsma addObject:[NSNumber numberWithInt:mapPoint.row]]; [nsma addObject:[NSNumber numberWithInt:mapPoint.col]]; return [nsma autorelease]; } @end Not too much work to do it for the others. Of course, one could argue what I'm really testing here, but the craftsman in me says it's OK. Clay
On Aug 5, 2009, at 8:41 AM, Eloy Duran wrote:
Hi,
On Aug 5, 2009, at 5:31 PM, Clay Bridges wrote:
The google didn't yield much guidance on this. Before I started a deep-dive on the MacRuby source, and/or the standard ruby way to handle this sort of thing, I thought I would ask a couple of questions:
1) Any easy advice?
Yes, use RubyCocoa
2) Is this different in MacRuby than in ruby proper?
RubyCocoa at least allows you to use BridgeSupport which would allow you to map these. Afaik MacRuby doesn't fully support it yet.
3) Any pointers into the MacRuby source that might help me?
BridgeSupport needs to fully implemented.
FYI, BridgeSupport is mostly implemented in MacRuby, at least the part that deals with C structures. The only part that we didn't implement yet is C function pointers, the rest (roughly 90%) is done, and it is faster / more stable than the RubyCocoa code (you will have to believe me, since I wrote both :-)). What Clay needs to do is describe his C structures in a .bridgesupport file. You can read the BridgeSupport(5) man-page for more information. Unfortunately the gen_bridge_metadata(1) cannot generate C structures metadata without a template, and this part is not yet documented. So it may be faster to craft the .bridgesupport file by hand. There are plenty of .bridgesupport files in /System/Library/Frameworks that can be used as an example. Once the file is created, it can loaded from MacRuby using: load_bridge_support_file 'foo.bridgesupport' Laurent
On Aug 5, 2009, at 12:57 PM, Laurent Sansonetti wrote:
On Aug 5, 2009, at 8:41 AM, Eloy Duran wrote:
Hi,
On Aug 5, 2009, at 5:31 PM, Clay Bridges wrote:
The google didn't yield much guidance on this. Before I started a deep-dive on the MacRuby source, and/or the standard ruby way to handle this sort of thing, I thought I would ask a couple of questions:
1) Any easy advice?
Yes, use RubyCocoa
2) Is this different in MacRuby than in ruby proper?
RubyCocoa at least allows you to use BridgeSupport which would allow you to map these. Afaik MacRuby doesn't fully support it yet.
3) Any pointers into the MacRuby source that might help me?
BridgeSupport needs to fully implemented.
FYI, BridgeSupport is mostly implemented in MacRuby, at least the part that deals with C structures. The only part that we didn't implement yet is C function pointers, the rest (roughly 90%) is done, and it is faster / more stable than the RubyCocoa code (you will have to believe me, since I wrote both :-)).
What Clay needs to do is describe his C structures in a .bridgesupport file.
You can read the BridgeSupport(5) man-page for more information. Unfortunately the gen_bridge_metadata(1) cannot generate C structures metadata without a template, and this part is not yet documented. So it may be faster to craft the .bridgesupport file by hand. There are plenty of .bridgesupport files in /System/Library/ Frameworks that can be used as an example.
Once the file is created, it can loaded from MacRuby using:
load_bridge_support_file 'foo.bridgesupport'
Here is an example on how to do this automatically. First, I created a header file with your code. $ cat t.h struct MapPoint { int row; int col; }; typedef struct MapPoint MapPoint; Now, I generate an exceptions template file based on your header file. $ gen_bridge_metadata -F exceptions-template -c '-I.' t.h > exception.xml The exceptions template file contains the name of your struct. The generator uses an exception because we don't want to expose all C structures by default, so it gives the developer a choice. Here we leave it empty, which means MapPoint will be exposed. $ cat exception.xml <?xml version='1.0'?> <!DOCTYPE signatures SYSTEM "file://localhost/System/Library/DTDs/BridgeSupport.dtd "> <signatures version='0.9'> <struct name='MapPoint'/> </signatures> Now, we generate the real .bridgesupport file, passing the exceptions file. $ gen_bridge_metadata -e ./exception.xml -c '-I.' t.h > mappoint.bridgesupport As you can see, it contains a signature for MapPoint. $ cat mappoint.bridgesupport <?xml version='1.0'?> <!DOCTYPE signatures SYSTEM "file://localhost/System/Library/DTDs/BridgeSupport.dtd "> <signatures version='0.9'> <struct name='MapPoint' type='{MapPoint="row"i"col"i}'/> </signatures> And now, you can load it from MacRuby and use it as if it was a real Ruby class. Actually it's a real Ruby class :-) $ macruby -e "load_bridge_support_file('mappoint.bridgesupport'); p MapPoint.new(1, 2)" #<MapPoint row=1 col=2> HTH, Laurent
On Aug 5, 2009, at 1:09 PM, Laurent Sansonetti wrote:
Here is an example on how to do this automatically. [ SNIP ]
Gee, if this were to go up on, say, the wiki for bridgesupport, this sort of explicit advice could help future generations too! Oh what the heck, done. http://bridgesupport.macosforge.org/trac/wiki/Documentation contains a small tutorial based on your example. Feel free to edit more to taste. :) - Jordan
Thank you, Laurent. That was *incredibly* helpful and kind of you, and worked perfectly. Being able to add MapPoint#to_a and MapPoint[row,col] methods was the "oh, ruby, you *are* magic" moment of it all. I was going to try to pay it back by putting it up on a wiki, but Jordan beat me to it. I LOL'd when I saw my lowly MapPoint had made it to the big time. You go, struct! Seriously, gang, as a first contact with the MacRuby community, I couldn't be more impressed. Thanks, Clay
FYI, BridgeSupport is mostly implemented in MacRuby, at least the part that deals with C structures. The only part that we didn't implement yet is C function pointers, the rest (roughly 90%) is done, and it is faster / more stable than the RubyCocoa code (you will have to believe me, since I wrote both :-)).
LOL, I'm a believer :-) @Jordan: Thanks for putting it up on the wiki. Eloy
participants (5)
-
Clay Bridges
-
Eloy Duran
-
Jeremy Voorhis
-
Jordan K. Hubbard
-
Laurent Sansonetti