Permalink
Browse files

Add Padrino::Module to orchestrate loading

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.
  • Loading branch information...
skade committed Jan 21, 2013
1 parent 79822b4 commit 88d575f5404abcfb77c32d9c3df43e46e0399a22
@@ -12,6 +12,7 @@
require 'padrino-core/router'
require 'padrino-core/server'
require 'padrino-core/tasks'
require 'padrino-core/module'
# The Padrino environment (falls back to the rack env or finally develop)
@@ -165,5 +166,32 @@ def clear_middleware!
def use(m, *args, &block)
middleware << [m, args, block]
end
##
# Registers a gem with padrino. This relieves the caller from setting up
# loadpaths by himself and enables Padrino to look up apps in gem folder.
#
# The name given has to be the proper gem name as given in the gemspec.
#
# @param [String] name
# The name of the gem being registered.
#
# @param [Module] main_module
# The main module of the gem.
#
# @returns The root path of the loaded gem
def gem(name, main_module)
_,spec = Gem.loaded_specs.find { |spec_name, spec| spec_name == name }
gems << [main_module, spec]
spec.full_gem_path
end
##
# Returns all currently known padrino gems.
#
# @returns [Module, Gem::Specification]
def gems
@gems ||= []
end
end # self
end # Padrino
@@ -200,7 +200,8 @@ def dependency_paths
"#{root}/config/database.rb", "#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb",
"#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb", "#{root}/config/apps.rb"
]
@_dependency_paths ||= @_dependency_paths_was
gem_paths = Padrino.gems.map { |mod,_| mod.dependency_paths }.flatten!
@_dependency_paths ||= (@_dependency_paths_was + Array(gem_paths))
end
##
@@ -0,0 +1,59 @@
module Padrino
module Module
attr_accessor :root
##
# Register this module as being loaded from a gem. This automatically
# sets the root and therefore the dependency paths correctly.
#
# @param [String] name
# The name of the gem. Has to be the name as stated in the gemspec.
#
# @returns the gems root.
def gem!(name)
self.root = Padrino.gem(name, self)
end
##
# Helper method for file references within a Padrino module.
#
# @param [Array<String>] args
# The directories to join to {Module.root}.
#
# @return [String]
# The absolute path.
#
# @example
# module MyModule
# extend Padrino::Module
# gem! 'my_gem'
# end
# Module.root!
def root(*args)
File.expand_path(File.join(@root, *args))
end
##
# Returns the list of path globs to load as dependencies
# Appends custom dependency patterns to the be loaded for Padrino.
#
# @return [Array<String>]
# The dependency paths.
#
# @example
# module MyModule
# extend Padrino::Module
# gem! 'my_gem'
# end
#
# Module.dependency_paths << "#{MyModule.root}/uploaders/*.rb"
#
def dependency_paths
[
"#{root}/lib/**/*.rb", "#{root}/shared/lib/**/*.rb",
"#{root}/models/**/*.rb", "#{root}/shared/models/**/*.rb"
]
end
end
end
@@ -161,13 +161,12 @@ def locate_app_file
candidates << app_constant.app_file if app_constant.respond_to?(:app_file) && File.exist?(app_constant.app_file.to_s)
candidates << Padrino.first_caller if File.identical?(Padrino.first_caller.to_s, Padrino.called_from.to_s)
candidates << Padrino.mounted_root(name.downcase, "app.rb")
if defined?(Gem)
_,spec = Gem.loaded_specs.find { |spec_name, spec| spec_name.sub(/padrino-/, "") == @gem }
if spec
simple_name = name.split("::").last.downcase
if path = spec.require_paths.grep(%r|#{simple_name}/?$|)
candidates << File.expand_path(File.join(spec.full_gem_path, path, "app.rb"))
end
Padrino.gems.each do |_, spec|
next if @gem && spec.name != @gem
simple_name = name.split("::").last.downcase
if path = spec.require_paths.grep(%r|#{simple_name}/?$|)
candidates << File.expand_path(File.join(spec.full_gem_path, path, "app.rb"))
end
end
candidates << Padrino.root("app", "app.rb")
@@ -1,5 +1,7 @@
require 'app_gem/version'
require 'padrino'
module AppGem
extend Padrino::Module
gem! 'app_gem'
end
@@ -188,6 +188,8 @@ def spec.full_gem_path
Padrino.root("fixtures", "app_gem")
end
require Padrino.root("fixtures", "app_gem", "lib", "app_gem")
Padrino.mount("AppGem::App").to("/from_gem")
mounter = Padrino.mounted_apps[0]
assert_equal AppGem::App, mounter.app_obj
@@ -52,6 +52,17 @@ def self.banner; "padrino-gen project [name] [options]"; end
def setup_project
valid_constant?(options[:app] || name)
@app_name = (options[:app] || name).gsub(/\W/, '_').underscore.camelize
if options.gem?
if !options[:app]
say "An app name must be given when generating a gem", :red
exit
end
if name == options[:app]
say "The app name and project name cannot be the same", :red
exit
end
@app_name = [name.camelcase, @app_name].join('::')
end
self.destination_root = File.join(options[:root], name)
if options[:template] # Run the template to create project
execute_runner(:template, options[:template])
@@ -11,7 +11,7 @@ Gem::Specification.new do |gem|
gem.files = `git ls-files`.split($\)
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
gem.name = <%=name.inspect%>
gem.name = <%=name.underscore.inspect%>
gem.require_paths = ["lib", "app"]
gem.version = <%=name.camelcase%>::VERSION
@@ -1,2 +1,6 @@
require 'padrino-core'
module <%=name.camelcase%>
extend Padrino::Module
gem! <%=name.inspect%>
end
@@ -77,6 +77,7 @@ def teardown
capture_io { generate(:project,'sample_gem', '--gem', "--root=#{@apptmp}") }
assert_file_exists("#{@apptmp}/sample_gem/sample_gem.gemspec")
assert_match_in_file(/^gemspec/,"#{@apptmp}/sample_gem/Gemfile")
assert_match_in_file(/^SampleGem::App/,"#{@apptmp}/sample_gem/app/app.rb")
assert_file_exists("#{@apptmp}/sample_gem/README.md")
end

0 comments on commit 88d575f

Please sign in to comment.