[MacRuby-devel] Loading bundled bundles; #require or #framework?

Nick Ludlam nick at recoil.org
Tue Jul 20 10:36:38 PDT 2010


On 19 Jul 2010, at 22:00, Laurent Sansonetti wrote:

> Hi Nick,
> 
> On Jul 18, 2010, at 11:34 AM, Nick Ludlam wrote:
> 
>> Hi all,
>> sorry for the tongue-twister message subject, but I'm having a difficult time figuring out how #require works, within the context of loading custom Bundles at startup.
>> 
>> I've been following http://www.macruby.org/recipes/create-an-objective-c-bundle.html and have successfully created an obj-c wrapper around a c++ library in order to read id3 tags from mp3 files.
>> 
>> My obj-c class is called 'TagLibBundle' and I've implemented the following init method as specified:
>> 
>> void Init_TagLibBundle(void) { }
> 
> This Init method is only required if you use #require. #require tries to locate and call this function based on the basename of the path given to it. C extensions use this function to create classes and methods. In your case, since the wrapper is all in Objective-C, nothing has to be initialized, so the init function can remain empty.

Thanks Laurent,
So in my case, do I even need to implement this method? If I understand correctly, the Init_*() method is used in standard Ruby C extensions, and you would usually call rb_define_module(), rb_define_method() etc. in order to make your Ruby class definitions.

By using NSBundle.bundleWithPath, I'm effectively not using any native Ruby, as they are direct Foundation calls.  Is the definition of Init_TagLibBundle() only there to satisfy what the #require method demands?

>> So far, so good. I've added the bundle to a MacRuby project, and it's copied into the Frameworks/ folder in the app bundle during the build. I am able to load the bundle with the following statement:
>> 
>> bundle_path = NSBundle.mainBundle.privateFrameworksPath
>> NSBundle.bundleWithPath(bundle_path + "/TagLibBundle.bundle").loadAndReturnError(nil)
> 
> That should work. If you use NSBundle to load the bundle, then you don't need the Init function as discussed above. Otherwise, you can keep the Init function and you may be able to use #require here. 

I couldn't get #require to work, but that might be to do with the name of the bundle being 'TagLibBundle.bundle', rather than just 'TagLibBundle'. I need to investigate.

> I am not sure if the Frameworks directory inside your app bundle is the right place for a bundle (even though it might not matter).

Yes, I'm not sure where it should live, but I don't think it breaks anything having non-Framework objects in 'Frameworks'. I'd be interested to hear if there's a consensus amongst MacRubyists here as to what is best practice.

>> I can also load the bundle with:
>> 
>> bundle_path = NSBundle.mainBundle.privateFrameworksPath
>> framework(bundle_path + '/TagLibBundle.bundle')
> 
> This can work too but #framework is supposed to be used against frameworks, not simple bundles. #framework does quite a bit more of logic (like, trying to locate a BridgeSupport file), so it may not be a good idea to use it to load non-framework dynamic libraries (such as simple dylibs or bundles).

Ok that's good to know, thanks.

>> So I have two questions:
>> 
>> Can I add the privateFrameWorksPath to the #framework search path, like you would with $:.unshift(path), and get rid of the absolute path?
> 
> I would recommend using NSBundle or require to load it and calculate the path at runtime like you do already.
> 
>> And is the tutorial incorrect in using #require to load the bundle, where it should be #framework? Or have I got something wrong with my setup?
> 
> I think the tutorial is good, but it could probably be improved with a discussion around the Init function (why it's needed, etc.).

Yes completely, the tutorial got me all the way to working code, which is great. I was just unsure of some of the more specific details.

I want to write up this process of getting id3 tags visible in MacRuby, as the pure native gem has problems working with 0.6, and this seemed to be the best route for distribution packaging. I'm hoping this will help others in showing how you can easily bridge the compiled world with the interpreted world.

Nick




More information about the MacRuby-devel mailing list