Join GitHub today
Apps in gems #1007
I took the liberty of finally coming up with a system to wrap apps in gems. Its an often requested feature.
The basic version turned out easier than expected - its basically just a spare Padrino app that can be run both from the gems repository as well as loaded from other Padrino locations. It only contains backwards-compatible changes to the mounter.
It comes with a generator for quickly generating valid Padrino app gems - just run
Some limitations apply, which can or cannot be fixed by the framework:
For API use, for example, this implementation is fully usable.
I think this is just brilliant @skade!!!! Thanks sooo much!!
I'm definitely seen myself reusing APIs!! Imagine the power this brings!.. We can come up with a set of common API gems and bundle them as their own gem-mountable-apps. Amazing!!
As for sprockets and the like, I'd be inclined to use Grunt for the job -yes, I know, it's not Ruby but it I've found it does the job way better and we can then take advantage of Bower and the like. The asset pipeline will kick ass then! This isn't strictly related to the problem you're describing but it's something I've applied in some projects and it just works very well! See a custom version of an asset serving thing here it doesn't make loads of sense without the Gruntfile though. I'll explain better soon.
thanks @skade, looks like a great idea and a great start to it! I also noticed you did nested apps in modules. I feel like it would be better just to default it and have the apps generate it namespaced for you per #741 ? This saves us the trouble of having the mounter handle the discovery. I'll try to get that feature out ASAP finally so we have something more concrete to play with.
Actually, this patch only adds a special behaviour that allows Mounters to find one app in a given module.
The reason for the namespacing is actually bit non-obvious and not related to the wish to namespace apps in general. I used the gem template from bundler as a reference, which generates a module named like the gem and puts an additional VERSION constant in it. The problem is that if the app name would match the gem, we would "half-load" the app constant when bundler loads the gem. This is a situation I want to avoid at all costs. Using
Interesting detail: the branch only fails on Travis because of timeout problems. https://travis-ci.org/padrino/padrino-framework/jobs/4108983
I added a few changes that:
Given how full-circle this feature has come, generating a project as gemable by default and skipping on the whole gem generator thing is actually an option. Any opinions on this?
referenced this pull request
Jan 14, 2013
I made a few fancy additions. The gems main file now has to contain:
require 'padrino-core' module MyGem # this can actually be anything extend Padrino::Module gem! 'my_gem' # this has to be the proper gem name and is actuall an alias for Padrino.gem('my_gem', MyGem) end
After that, we have the following:
This allows us to detect apps in gems without looking at all gems (inefficient and implicit) and gives us the gem name without black magic.
First of all, I found rails detection of engine gems always very strange. AFAIK, it analyses the call stack on load of the Engine class and tries to implicitely detect the name of the gem or similar magic. This approach gives the user direct control when the registration to the core system happens and makes it possible to implement
Also, in contrast to previous versions, gems now have a sensible set of dependencies that mirrors the normal ones.
Okay, I am done with this feature in the current state, so this can be merged.
Some notes about the future:
Travis failed to check out the repos for the jruby test.
@skade I think the gemified apps feature is great. However I'm still not keen on having the mounter do any of the work behind the scene to assist with the mounting. I do like however the ability to extract out the
Padrino.mount("MyGem::Project", :app_file => MyGem.root('lib/app.rb')).to('/gallery') Padrino.mount("MyGem::Project2", :app_file => MyGem.root('lib/project_2.rb')).to('/gallery2')
What do you think about that?
@achiu It depends on what you define as "behind your back". Nothing is mounted without you telling the mounter to do so - the only thing it currently sets up and additional root where it can find additional apps. As we expect those apps to be namespaced, name clashes are ruled out. IMHO, its not more or less behind my back then it currently is.
In the current form, the mounter will only find apps in gems if the gem has registered to do so (by calling
Your code should work already.
I removed the code that auto-detects gems by name somewhere in the middle of the implementation.