ControlTower in MacRuby
Hello, I apologize for the repost, but I have not found help anywhere else... My goal is to run a ControlTower instance (1) in MacRuby within a Cocoa app, i.e. using -[MacRuby evaluateFileAtPath:] First question: Is this possible at all? Second question: I understand that my control script is the body to: app = Rack::Builder.new { ... config ... }.to_app but I have not figured out how to make an .rb file that will run a control tower instance. Any help is appreciated! Alex 1) http://svn.macosforge.org/repository/ruby/ControlTower/
On 21 Jul 2010, at 15:31, Alexander von Below wrote:
Hello,
I apologize for the repost, but I have not found help anywhere else...
My goal is to run a ControlTower instance (1) in MacRuby within a Cocoa app, i.e. using -[MacRuby evaluateFileAtPath:]
First question: Is this possible at all?
Second question:
I understand that my control script is the body to:
app = Rack::Builder.new { ... config ... }.to_app
but I have not figured out how to make an .rb file that will run a control tower instance.
Any help is appreciated!
Hi Alexander, I've got a MacRuby app happily running very happily with Control Tower. First I cloned the code from github, and built and installed the macgem package. Then I also installed rack with sudo macgem install rack in order to get some of Rack's built in server functionality. Then a short script would look like: require 'rubygems' require 'control_tower' require 'rack/utils' server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false } app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app @s = ControlTower::Server.new(app, server_options) if @s puts 'Starting control tower webserver' @s.start else puts "ERROR: Couldnt build server" end This would run a server on port 3001, and expose the files found in your ~/Sites/ directory as top level files eg. ~/Sites/index.html becomes http://localhost:3001/index.html Of course you'd need to replace 'nick' with your user homedir name. Nick
Yeah it was a quickly contrived example. I'm actually doing this in my code: map "/resources" do run Rack::File.new(NSBundle.mainBundle.bundlePath + "/Contents/Resources") end On 21 Jul 2010, at 20:22, Matt Aimonetti wrote:
"/Users/nick/Sites/" = File.expand_path("~/Sites")
Sent from my iPhone
On Jul 21, 2010, at 11:44, Nick Ludlam <nick@recoil.org> wrote:
"/Users/nick/Sites/"
MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
I don't suppose you'd care to contribute an example? This is clearly helpful! - Jordan On Jul 21, 2010, at 11:44 AM, Nick Ludlam wrote:
On 21 Jul 2010, at 15:31, Alexander von Below wrote:
Hello,
I apologize for the repost, but I have not found help anywhere else...
My goal is to run a ControlTower instance (1) in MacRuby within a Cocoa app, i.e. using -[MacRuby evaluateFileAtPath:]
First question: Is this possible at all?
Second question:
I understand that my control script is the body to:
app = Rack::Builder.new { ... config ... }.to_app
but I have not figured out how to make an .rb file that will run a control tower instance.
Any help is appreciated!
Hi Alexander, I've got a MacRuby app happily running very happily with Control Tower. First I cloned the code from github, and built and installed the macgem package. Then I also installed rack with
sudo macgem install rack
in order to get some of Rack's built in server functionality. Then a short script would look like:
require 'rubygems' require 'control_tower' require 'rack/utils'
server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false }
app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app
@s = ControlTower::Server.new(app, server_options) if @s puts 'Starting control tower webserver' @s.start else puts "ERROR: Couldnt build server" end
This would run a server on port 3001, and expose the files found in your ~/Sites/ directory as top level files
eg. ~/Sites/index.html becomes http://localhost:3001/index.html
Of course you'd need to replace 'nick' with your user homedir name.
Nick
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
On 21 Jul 2010, at 21:00, Jordan K. Hubbard wrote:
I don't suppose you'd care to contribute an example? This is clearly helpful!
I'm actually in the middle of writing up a tutorial/article of my experiences in wrapping C/C++ code with simple Obj-C classes, and making it into a loadable bundle. In my case, it has been in relation to taking TagLib, a C++ id3 tag library, and exposing that functionality in Ruby. As a follow-up, I can write up how you can make use of the TagLib bundle, and create simple podcast RSS feeds from them using Control Tower. I could contribute pure code, but I think it's nicer to have a real-world example to work with, and a bit of methodology. Does this sound sensible? Nick
On Jul 21, 2010, at 1:57 PM, Nick Ludlam wrote:
On 21 Jul 2010, at 21:00, Jordan K. Hubbard wrote:
I don't suppose you'd care to contribute an example? This is clearly helpful!
I'm actually in the middle of writing up a tutorial/article of my experiences in wrapping C/C++ code with simple Obj-C classes, and making it into a loadable bundle. In my case, it has been in relation to taking TagLib, a C++ id3 tag library, and exposing that functionality in Ruby.
As a follow-up, I can write up how you can make use of the TagLib bundle, and create simple podcast RSS feeds from them using Control Tower. I could contribute pure code, but I think it's nicer to have a real-world example to work with, and a bit of methodology. Does this sound sensible?
Very much so! If you do it as a blog post, we can link to it in the docs section. If you contribute it as a project (under the Ruby license), we can check it into the repo as sample code - your choice! Thanks, - Jordan
Or we could even put it in the tutorials or recipes sections of the website http://www.macruby.org/documentation.html if you are ok with that. - Matt On Wed, Jul 21, 2010 at 2:24 PM, Jordan K. Hubbard <jkh@apple.com> wrote:
On Jul 21, 2010, at 1:57 PM, Nick Ludlam wrote:
On 21 Jul 2010, at 21:00, Jordan K. Hubbard wrote:
I don't suppose you'd care to contribute an example? This is clearly helpful!
I'm actually in the middle of writing up a tutorial/article of my experiences in wrapping C/C++ code with simple Obj-C classes, and making it into a loadable bundle. In my case, it has been in relation to taking TagLib, a C++ id3 tag library, and exposing that functionality in Ruby.
As a follow-up, I can write up how you can make use of the TagLib bundle, and create simple podcast RSS feeds from them using Control Tower. I could contribute pure code, but I think it's nicer to have a real-world example to work with, and a bit of methodology. Does this sound sensible?
Very much so! If you do it as a blog post, we can link to it in the docs section. If you contribute it as a project (under the Ruby license), we can check it into the repo as sample code - your choice!
Thanks,
- Jordan
_______________________________________________ MacRuby-devel mailing list MacRuby-devel@lists.macosforge.org http://lists.macosforge.org/mailman/listinfo.cgi/macruby-devel
Apologies for being so late to reply... On Jul 21, 2010, at 11:44 AM, Nick Ludlam wrote:
On 21 Jul 2010, at 15:31, Alexander von Below wrote:
Hi Alexander, I've got a MacRuby app happily running very happily with Control Tower. First I cloned the code from github, and built and installed the macgem package. Then I also installed rack with
sudo macgem install rack
ControlTower currently has a version of rack that is vendored into the gem. Currently it's the same as rack v1.2.1, but with one particularly annoying bug fixed (unrelated to Ruby vs. MacRuby). Originally we made rack a gem dependency, but we decided that vendoring might work better for now, since there may still be MacRuby specific bugs lurking. There's also the possibility that we could optimize parts of rack for MacRuby, though there's nothing like that in there now. I'll do my best to keep the vendored version up to date with the latest rack release. tl;dr -- You shouldn't have to install rack to use ControlTower, but there's not any harm if you do.
in order to get some of Rack's built in server functionality. Then a short script would look like:
require 'rubygems' require 'control_tower' require 'rack/utils'
server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false }
app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app
@s = ControlTower::Server.new(app, server_options) if @s puts 'Starting control tower webserver' @s.start else puts "ERROR: Couldnt build server" end
This will work...however... There are two ways to use a Rack based server to run a web app (this is true for more than just ControlTower): 1. Use a rack-up file (e.g. config.ru) and pass it as an argument to the server start script (or, in the case of thin, if you're running a Rails app thin is nice enough to go find the file for you). The contents of this file are then eval'd in the context of Rack::Builder.new 2. Programmatically, create the app (as above) using Rack::Builder.new and pass it into one of the rack handlers. If you look at the standard rack distribution, you'll see that there are handlers for all of the common rack servers. Eventually, we should submit a pull request for rack to include our handler, but for the time being ours is located in the control_tower gem. So, the example above would look like: ----- require 'rubygems' require 'control_tower' require 'rack/utils' require 'rack/handler/control_tower' server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false } app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app Rack::Handler::ControlTower.run(app, server_options) do |s| puts "ERROR: Couldnt build server" unless s end ----- The reason to use the handler, instead of calling Server.new directly (even though, that's pretty much all the handler does), is that this is part of the rack-protocol, and guaranteed not to change. At some point in the future, we might add some more complicated logic around how to start a server, at which point your code that directly calls Server.new might break. Cheers, Josh
On 28 Jul 2010, at 20:03, Joshua Ballanco wrote:
Apologies for being so late to reply...
On Jul 21, 2010, at 11:44 AM, Nick Ludlam wrote:
On 21 Jul 2010, at 15:31, Alexander von Below wrote:
Hi Alexander, I've got a MacRuby app happily running very happily with Control Tower. First I cloned the code from github, and built and installed the macgem package. Then I also installed rack with
sudo macgem install rack
ControlTower currently has a version of rack that is vendored into the gem. Currently it's the same as rack v1.2.1, but with one particularly annoying bug fixed (unrelated to Ruby vs. MacRuby). Originally we made rack a gem dependency, but we decided that vendoring might work better for now, since there may still be MacRuby specific bugs lurking. There's also the possibility that we could optimize parts of rack for MacRuby, though there's nothing like that in there now. I'll do my best to keep the vendored version up to date with the latest rack release.
tl;dr -- You shouldn't have to install rack to use ControlTower, but there's not any harm if you do.
Hi Joshua, Thanks for pointing that out. For some reason I had missed CT coming with Rack, so had assumed otherwise. I've just tested omitting that in my code and it works like a charm.
in order to get some of Rack's built in server functionality. Then a short script would look like:
require 'rubygems' require 'control_tower' require 'rack/utils'
server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false }
app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app
@s = ControlTower::Server.new(app, server_options) if @s puts 'Starting control tower webserver' @s.start else puts "ERROR: Couldnt build server" end
This will work...however...
There are two ways to use a Rack based server to run a web app (this is true for more than just ControlTower):
1. Use a rack-up file (e.g. config.ru) and pass it as an argument to the server start script (or, in the case of thin, if you're running a Rails app thin is nice enough to go find the file for you). The contents of this file are then eval'd in the context of Rack::Builder.new
2. Programmatically, create the app (as above) using Rack::Builder.new and pass it into one of the rack handlers. If you look at the standard rack distribution, you'll see that there are handlers for all of the common rack servers. Eventually, we should submit a pull request for rack to include our handler, but for the time being ours is located in the control_tower gem. So, the example above would look like:
----- require 'rubygems' require 'control_tower' require 'rack/utils' require 'rack/handler/control_tower'
server_options = { :port => 3001, :host => '0.0.0.0', :concurrent => false }
app = Rack::Builder.new do map "/" do run Rack::File.new("/Users/nick/Sites/") end end.to_app
Rack::Handler::ControlTower.run(app, server_options) do |s| puts "ERROR: Couldnt build server" unless s end -----
The reason to use the handler, instead of calling Server.new directly (even though, that's pretty much all the handler does), is that this is part of the rack-protocol, and guaranteed not to change. At some point in the future, we might add some more complicated logic around how to start a server, at which point your code that directly calls Server.new might break.
Great, I have amended my code to reflect the correct API. Incidentally I have had great success in getting concurrency working with MacRuby HEAD (0.7) for serving up my XML feeds and the raw files. I also notice you're explicitly requiring 'rack/handler/control_tower.rb'. Is that going to remain the case too? Or could this be folded into the main require 'control_tower' call, if you're going to indicate that this is good practice. Lastly, I just wanted to check with you on threading. I'm wrapping that whole sequence above in a simple method, and using the following to spin it out from the main thread: @webserverThread = NSThread.alloc.initWithTarget self, selector:'startServerThread', object:nil @webserverThread.start But I found myself needing to create an autorelease pool (as I would with writing obj-c) at the beginning of #startServerThread otherwise I saw some really funky corruption and crashes. Now I'm a little fuzzy on how GC works, so is this a necessary requirement when spawning new threads within a GC run environment? Nick
participants (5)
-
Alexander von Below
-
Jordan K. Hubbard
-
Joshua Ballanco
-
Matt Aimonetti
-
Nick Ludlam