New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Apps in gems #1007
Apps in gems #1007
Conversation
If Padrino is loaded using rubygems, this patch enables Padrino::Mounter to load apps from gems. To allow the reloader what it does, this only searches for the app file, but does not load the application. Applications in gems are expected to be found in `gem-folder/app/app.rb`. Gems named after `ApplicationConstant.underscore` will be found. Optionally, they can be prefixed with `padrino-`.
This allows application objects nested one level into a Module to be autodetected. If a module contain more than one app, the behaviour is undefined.
This generator generates a spare Padrino application that works both as a standalone application and as a mountable Gem in other probjects.
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. |
👍 on namespacing! |
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 |
This change expects that all app names are given in full. No magic detection of apps in modules - this has too many implicit assumptions, like there only being one app in a module.
Also, make all require_paths potential app locations. While this strictly includes 'lib', this means that multiple apps can be packaged in a gem in a sane way.
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? |
This allows the project generator to generate a gemspec fitting the project add some files to assist in gem development.
This avoids accidentally finding the wrong app that comes earlier in the require-path.
Yeah nice I like the idea of just having this as an option flag to make it even easier to generate as a gem. Want to spend some time looking at this a little more and hopefully helping us to write some documentation for it as well closer to the release. |
This adds a Padrino::Module module that orchestrates loading of gems. Padrino::Module implements the most important methods to properly load code from a gem (#dependency_paths and #root) and adds a method `gem!` to flag a module as being loaded from a gem. It also modifies the generators so that now, everything works out of the box.
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. |
Hi everybody,
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
padrino-gen gem my_gem_name
with all the known options and be done.Some limitations apply, which can or cannot be fixed by the framework:
config/
in gems obviously only makes sense for testing the thing or running it standalone.public_path
is currently the mouting apps public path.For API use, for example, this implementation is fully usable.
What do you think? @achiu, @nesquena , @dariocravero ?
Regards,
Florian