From: David <dba...@gm...> - 2006-01-30 17:47:36
|
Hello. I am looking into using Ruby to manipulate some data in my Cocoa-based application. I found the excellent documentation written by Tom Burks but it is not detailed enough on how to add this functionality to an existing Cocoa app in XCode. What I am looking for is the necessary changes needed to my project to allow my Cocoa app based on XCode 2.2 running on Tiger to call Ruby routines passing in NSArray objects with the minimum amount of changes to my project. I assume I need to at least add the RubyCocoa framework. After doing this and importing "RubyCocoa/RubyCocoa.h" I get an error: /Library/Frameworks/RubyCocoa.framework/Headers/osx_ruby.h:21:20: error: config.h: No such file or directory I also looked at the HybridLangApp sample but it is based on RBApplicationMain instead of NSApplicationMain. Thanks for any assistance. |
From: Tim B. <tim...@gm...> - 2006-01-31 06:46:15
|
Hi David, Thanks for your comments on the documentation. I too have wanted to mix RubyCocoa into an existing application, but I hadn't tried it until this evening, when I successfully converted one of my pure Objective-C Cocoa projects to RubyCocoa. Here's my story: First I added the RubyCocoa framework to the project in Xcode. In my case, I right-clicked on the project name in the Groups & Files panel in Xcode, then selected Add->Existing Frameworks... and navigated to /Library/Frameworks/RubyCocoa.framework. Next I replaced the contents of main.m with the following, taken from the RubyCocoa Xcode templates: --- #import <RubyCocoa/RBRuntime.h> int main(int argc, const char *argv[]) { return RBApplicationMain("rb_main.rb", argc, argv); } --- This is necessary to make sure that Ruby is properly initialized and it also gives you a way to run some Ruby code when your program starts. As far as I know, you *must* replace your main() to use RubyCocoa, but you probably didn't have anything special there anyway -- just a call to NSApplicationMain, which your converted app will make with Ruby. Then I added rb_main.rb to my project using Add->Existing Files... and then finding and selecting one from a template-based RubyCocoa application. For reference, this short file contains the following Ruby code: --- require 'osx/cocoa' def rb_main_init path =3D OSX::NSBundle.mainBundle.resourcePath.to_s rbfiles =3D Dir.entries(path).select {|x| /\.rb\z/ =3D~ x} rbfiles -=3D [ File.basename(__FILE__) ] rbfiles.each do |path| require( File.basename(path) ) OSX::NSLog "require #{File.basename(path)}" end end if $0 =3D=3D __FILE__ then rb_main_init OSX.NSApplicationMain(0, nil) end --- It loads any ruby files in your application's resource directory and then calls NSApplicationMain. Then I built and tested my application. Everything seemed to work just as before, but now my formerly mild-mannered Objective-C program can speak Ruby. From here forward, you can add Ruby files to your application and know that all inline code in them will get executed when rb_main_init loads the files during startup. In my case, I added a console object that I've been writing/debugging that let's me run irb inside a Cocoa app. Accessing my Objective-C objects was a puzzle at first, but I managed to get to my top-level document object (a game) from the NSDocumentController: > game_controller =3D OSX::NSDocumentController.sharedDocumentController > game =3D game_controller.documents.objectAtIndex(0) From there, I could directly call the methods of my object from Ruby: > game.start > game.sendEvent_forPlayer(10, 0) > game.stop I'll test it more in the next few days, but as far as I can tell, the transplant went smoothly. Hope that helps, Tim |
From: Jonathan P. <jp...@dc...> - 2006-01-31 14:02:12
|
On 31 Jan 2006, at 6:46, Tim Burks wrote: >> game_controller = OSX::NSDocumentController.sharedDocumentController >> game = game_controller.documents.objectAtIndex(0) > > From there, I could directly call the methods of my object from Ruby: >> game.start >> game.sendEvent_forPlayer(10, 0) >> game.stop The same should work in the other direction too: assuming you can get a reference in objc to one of your ruby objects, you should be able to call methods on it. e.g.: In ruby: game.setRubyObject(someobj) Then in objc: [rubyObject someMethod: anArgument]; .. assuming you've got an instance variable called 'rubyObject' of type 'id' that has a setter method like: -(void)setRubyObject:(id)obj { [obj retain]; [rubyObject autorelease]; rubyObject = obj; } Another, possibly simpler, solution is to define an ObjC class in Ruby: class Foo < OSX::NSObject # ... def myMethod(arg1) puts arg1 end end Then, in objc: Class fooClass = NSClassFromString(@"Foo"); id fooInstance = [[fooClass alloc] init]; [fooInstance myMethod: @"hello"]; [the above code is untested - I think the idea is right though] I imagine there'll be various compiler warnings since there are no prototypes for the messages being sent to the 'id' variable type. An objc interface declaration should fix that. Cheers, Jonathan |
From: David <dba...@gm...> - 2006-01-31 17:26:32
|
I had came to this solution as well when testing and it does work. I would have thought though that this could be encapsulated into an RBObject class so that you can hide some of this and do some sanity checks as well? There is a initWithRubyObject in RBObject but would it be useful to have a initWithRubyObjectName? I was also thinking that with XCode it should be possible to write a script that will read your ruby files and generate an objc interface file for them each time you build.. that would be cool.. > Another, possibly simpler, solution is to define an ObjC class in > Ruby: > > class Foo < OSX::NSObject > # ... > def myMethod(arg1) > puts arg1 > end > end > > Then, in objc: > > Class fooClass = NSClassFromString(@"Foo"); > id fooInstance = [[fooClass alloc] init]; > [fooInstance myMethod: @"hello"]; > [the above code is untested - I think the idea is right though] > > > > I imagine there'll be various compiler warnings since there are no > prototypes for the messages being sent to the 'id' variable type. > An objc interface declaration should fix that. > > > > Cheers, > > Jonathan > > |
From: Jonathan P. <jp...@dc...> - 2006-01-31 17:40:22
|
On 31 Jan 2006, at 17:26, David wrote: > I had came to this solution as well when testing and it does work. > I would have thought though that this could be encapsulated into an > RBObject class so that you can hide some of this and do some sanity > checks as well? There is a initWithRubyObject in RBObject but > would it be useful to have a initWithRubyObjectName? Can you give an example of how you'd like/expect things to work? I'm not quite clear on it yet. > I was also thinking that with XCode it should be possible to write > a script that will read your ruby files and generate an objc > interface file for them each time you build.. that would be cool.. Certainly possible - although how useful it is depends on how broad your interface is going to be. If there are relatively few entry points into ruby then it's probably easy enough to keep two files up to date (as you would have to do anyway with a plain objc header and implementation). Cheers, Jonathan |
From: David <dba...@gm...> - 2006-02-01 18:51:29
|
From my existing Cocoa app I would like to pass several NSArray's to Ruby, manipulate them in Ruby, serialize the arrays in JSON format, and return that data back to Cocoa. Does this seem like a reasonable task for the RubyCocoa bridge? I see ruby 1.8+ has a to_yaml method for objects but how do I produce JSON format for the arrays? |
From: Jonathan P. <jp...@dc...> - 2006-02-01 22:39:41
|
On 1 Feb 2006, at 18:51, David wrote: > From my existing Cocoa app I would like to pass several NSArray's > to Ruby, manipulate them in Ruby, serialize the arrays in JSON > format, and return that data back to Cocoa. Does this seem like a > reasonable task for the RubyCocoa bridge? > > I see ruby 1.8+ has a to_yaml method for objects but how do I > produce JSON format for the arrays? Assuming you have an NSArray instance my_array in ruby, can you just do: manipulate(my_array.to_a).to_yaml i.e., convert the NSArray to a real ruby Array, do some stuff on it, then convert that array to yaml/json? |
From: David <dba...@gm...> - 2006-01-31 15:33:02
|
Thanks for the explanation.. I also spent some time investigating it =20= last night (probably because I'm stubborn :) ) and was able to come =20 to a similar result. I started an entry on the RubyCocoa Wiki so =20 that it will be easier for anybody in the future to not have to spend =20= time figuring out what to do.. Feel free to edit it or add this info =20= to your documentation.. The easier it is for a newby to get this stuff to work the more =20 people there will be using it. I originally tried getting PyObjc to =20 work and even asked on the mailing list but never got a =20 straightforward answer on how to make the bridge transparent.. =20 especially as transparent as the Ruby-Obj-C bridge appears to be.. :) =20= So now I'm using Ruby instead.. David On Jan 31, 2006, at 12:46 AM, Tim Burks wrote: > Hi David, > > Thanks for your comments on the documentation. > > I too have wanted to mix RubyCocoa into an existing application, but I > hadn't tried it until this evening, when I successfully converted one > of my pure Objective-C Cocoa projects to RubyCocoa. Here's my story: > > First I added the RubyCocoa framework to the project in Xcode. In my > case, I right-clicked on the project name in the Groups & Files panel > in Xcode, then selected Add->Existing Frameworks... and navigated to > /Library/Frameworks/RubyCocoa.framework. > > Next I replaced the contents of main.m with the following, taken from > the RubyCocoa Xcode templates: > --- > #import <RubyCocoa/RBRuntime.h> > > int main(int argc, const char *argv[]) > { > return RBApplicationMain("rb_main.rb", argc, argv); > } > --- > This is necessary to make sure that Ruby is properly initialized and > it also gives you a way to run some Ruby code when your program > starts. As far as I know, you *must* replace your main() to use > RubyCocoa, but you probably didn't have anything special there anyway > -- just a call to NSApplicationMain, which your converted app will > make with Ruby. > > Then I added rb_main.rb to my project using Add->Existing Files... and > then finding and selecting one from a template-based RubyCocoa > application. For reference, this short file contains the following > Ruby code: > --- > require 'osx/cocoa' > > def rb_main_init > path =3D OSX::NSBundle.mainBundle.resourcePath.to_s > rbfiles =3D Dir.entries(path).select {|x| /\.rb\z/ =3D~ x} > rbfiles -=3D [ File.basename(__FILE__) ] > rbfiles.each do |path| > require( File.basename(path) ) > OSX::NSLog "require #{File.basename(path)}" > end > end > > if $0 =3D=3D __FILE__ then > rb_main_init > OSX.NSApplicationMain(0, nil) > end > --- > It loads any ruby files in your application's resource directory and > then calls NSApplicationMain. > > Then I built and tested my application. Everything seemed to work > just as before, but now my formerly mild-mannered Objective-C program > can speak Ruby. > > =46rom here forward, you can add Ruby files to your application and = know > that all inline code in them will get executed when rb_main_init loads > the files during startup. > > In my case, I added a console object that I've been writing/debugging > that let's me run irb inside a Cocoa app. Accessing my Objective-C > objects was a puzzle at first, but I managed to get to my top-level > document object (a game) from the NSDocumentController: >> game_controller =3D = OSX::NSDocumentController.sharedDocumentController >> game =3D game_controller.documents.objectAtIndex(0) > > =46rom there, I could directly call the methods of my object from = Ruby: >> game.start >> game.sendEvent_forPlayer(10, 0) >> game.stop > > I'll test it more in the next few days, but as far as I can tell, the > transplant went smoothly. > > Hope that helps, > > Tim > > > ------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. Do you grep through =20 > log files > for problems? Stop! Download the new AJAX search engine that makes > searching your log files as easy as surfing the web. DOWNLOAD =20 > SPLUNK! > http://sel.as-us.falkag.net/sel?cmd=3Dlnk&kid=103432&bid#0486&dat=121642= > _______________________________________________ > Rubycocoa-talk mailing list > Rub...@li... > https://lists.sourceforge.net/lists/listinfo/rubycocoa-talk |