diff options
author | José Valim <jose.valim@gmail.com> | 2010-09-04 00:31:35 +0200 |
---|---|---|
committer | José Valim <jose.valim@gmail.com> | 2010-09-04 00:31:43 +0200 |
commit | 23a9455962f0362cf242ffa96db7a9e7fdb0804b (patch) | |
tree | c046d1285d078649db6833fa1b73a6c23f7f16ea /railties | |
parent | 63032c1162e96d3380168ca63ac42aa044dbebd6 (diff) | |
parent | c3c1a1e14859e6716970283caeab0c4c3720862e (diff) | |
download | rails-23a9455962f0362cf242ffa96db7a9e7fdb0804b.tar.gz rails-23a9455962f0362cf242ffa96db7a9e7fdb0804b.tar.bz2 rails-23a9455962f0362cf242ffa96db7a9e7fdb0804b.zip |
This commit merges most of the work done by Piotr Sarnacki in his Ruby Summer of Code project.
His work brings several capabilities from app to engines, as routes, middleware stack, asset handling and much more. Please check Rails::Engine documentation for more refenrences.
Merge remote branch 'drogus/engines'
Diffstat (limited to 'railties')
22 files changed, 1189 insertions, 265 deletions
diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 7c41367a84..3663910281 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -94,10 +94,5 @@ module Rails def public_path application && application.paths.public.to_a.first end - - def public_path=(path) - ActiveSupport::Deprecation.warn "Setting Rails.public_path= is deprecated. " << - "Please set paths.public = in config/application.rb instead.", caller - end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 5b26333486..8631a5df3e 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -41,24 +41,6 @@ module Rails autoload :Railties, 'rails/application/railties' class << self - private :new - - def configure(&block) - class_eval(&block) - end - - def instance - if self == Rails::Application - if Rails.application - ActiveSupport::Deprecation.warn "Calling a method in Rails::Application is deprecated, " << - "please call it directly in your application constant #{Rails.application.class.name}.", caller - end - Rails.application - else - @@instance ||= new - end - end - def inherited(base) raise "You cannot have more than one Rails::Application" if Rails.application super @@ -66,19 +48,9 @@ module Rails Rails.application.add_lib_to_load_path! ActiveSupport.run_load_hooks(:before_configuration, base.instance) end - - def respond_to?(*args) - super || instance.respond_to?(*args) - end - - protected - - def method_missing(*args, &block) - instance.send(*args, &block) - end end - delegate :middleware, :to => :config + delegate :default_url_options, :default_url_options=, :to => :routes # This method is called just after an application inherits from Rails::Application, # allowing the developer to load classes in lib and use them during application @@ -108,14 +80,6 @@ module Rails super end - def routes - @routes ||= ActionDispatch::Routing::RouteSet.new - end - - def railties - @railties ||= Railties.new(config) - end - def routes_reloader @routes_reloader ||= ActiveSupport::FileUpdateChecker.new([]){ reload_routes! } end @@ -131,7 +95,9 @@ module Rails end def initialize! + raise "Application has been already initialized." if @initialized run_initializers(self) + @initialized = true self end @@ -156,38 +122,32 @@ module Rails self end - def app - @app ||= begin - config.middleware = config.middleware.merge_into(default_middleware_stack) - config.middleware.build(routes) - end - end alias :build_middleware_stack :app - def call(env) - app.call(env.reverse_merge!(env_defaults)) - end - - def env_defaults - @env_defaults ||= { + def env_config + @env_config ||= super.merge({ "action_dispatch.parameter_filter" => config.filter_parameters, - "action_dispatch.secret_token" => config.secret_token - } + "action_dispatch.secret_token" => config.secret_token, + "action_dispatch.asset_path" => nil + }) end def initializers initializers = Bootstrap.initializers_for(self) - railties.all { |r| initializers += r.initializers } initializers += super initializers += Finisher.initializers_for(self) initializers end + def config + @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) + end + protected def default_middleware_stack ActionDispatch::MiddlewareStack.new.tap do |middleware| - middleware.use ::ActionDispatch::Static, paths.public.to_a.first if config.serve_static_assets + middleware.use ::ActionDispatch::Static, config.static_asset_paths if config.serve_static_assets middleware.use ::Rack::Lock if !config.allow_concurrency middleware.use ::Rack::Runtime middleware.use ::Rails::Rack::Logger diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index 44e26b5713..e39b3bc705 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -6,10 +6,7 @@ module Rails module Bootstrap include Initializable - initializer :load_environment_config do - environment = config.paths.config.environments.to_a.first - require environment if environment - end + initializer :load_environment_hook do end initializer :load_active_support do require 'active_support/dependencies' @@ -73,4 +70,4 @@ module Rails end end end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/application/configurable.rb b/railties/lib/rails/application/configurable.rb deleted file mode 100644 index f598e33965..0000000000 --- a/railties/lib/rails/application/configurable.rb +++ /dev/null @@ -1,19 +0,0 @@ -module Rails - class Application - module Configurable - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - def inherited(base) - raise "You cannot inherit from a Rails::Application child" - end - end - - def config - @config ||= Application::Configuration.new(self.class.find_root_with_flag("config.ru", Dir.pwd)) - end - end - end -end
\ No newline at end of file diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index c3418e0d80..477bbbc1e7 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -1,16 +1,13 @@ -require 'active_support/deprecation' require 'active_support/core_ext/string/encoding' require 'rails/engine/configuration' module Rails class Application class Configuration < ::Rails::Engine::Configuration - include ::Rails::Configuration::Deprecated - attr_accessor :allow_concurrency, :cache_classes, :cache_store, :encoding, :consider_all_requests_local, :dependency_loading, - :filter_parameters, :log_level, :logger, :middleware, - :plugins, :preload_frameworks, :reload_plugins, + :filter_parameters, :log_level, :logger, + :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, :session_options, :time_zone, :whiny_nils @@ -28,6 +25,22 @@ module Rails @middleware = app_middleware end + def asset_path=(value) + action_mailer.asset_path = value if respond_to?(:action_mailer) && action_mailer + action_controller.asset_path = value if respond_to?(:action_controller) && action_controller + super(value) + end + + def asset_host=(value) + action_mailer.asset_host = value if action_mailer + action_controller.asset_host = value if action_controller + super(value) + end + + def compiled_asset_path + "/" + end + def encoding=(value) @encoding = value if "ruby".encoding_aware? @@ -48,19 +61,10 @@ module Rails paths.app.controllers << builtin_controller if builtin_controller paths.config.database "config/database.yml" paths.config.environment "config/environment.rb" - paths.config.environments "config/environments", :glob => "#{Rails.env}.rb" paths.lib.templates "lib/templates" paths.log "log/#{Rails.env}.log" paths.tmp "tmp" paths.tmp.cache "tmp/cache" - paths.vendor "vendor", :load_path => true - paths.vendor.plugins "vendor/plugins" - - if File.exists?("#{root}/test/mocks/#{Rails.env}") - ActiveSupport::Deprecation.warn "\"Rails.root/test/mocks/#{Rails.env}\" won't be added " << - "automatically to load paths anymore in future releases" - paths.mocks_path "test/mocks", :autoload => true, :glob => Rails.env - end paths end diff --git a/railties/lib/rails/application/railties.rb b/railties/lib/rails/application/railties.rb index b3e6693f89..c1d2de571f 100644 --- a/railties/lib/rails/application/railties.rb +++ b/railties/lib/rails/application/railties.rb @@ -1,31 +1,21 @@ -module Rails - class Application - class Railties - # TODO Write tests for this behavior extracted from Application - def initialize(config) - @config = config - end +require 'rails/engine/railties' +module Rails + class Application < Engine + class Railties < Rails::Engine::Railties def all(&block) - @all ||= railties + engines + plugins + @all ||= railties + engines + super @all.each(&block) if block @all end def railties - @railties ||= ::Rails::Railtie.subclasses.map(&:new) + @railties ||= ::Rails::Railtie.subclasses.map(&:instance) end def engines - @engines ||= ::Rails::Engine.subclasses.map(&:new) - end - - def plugins - @plugins ||= begin - plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym } - Plugin.all(plugin_names, @config.paths.vendor.plugins) - end + @engines ||= ::Rails::Engine.subclasses.map(&:instance) end end end -end
\ No newline at end of file +end diff --git a/railties/lib/rails/configuration.rb b/railties/lib/rails/configuration.rb index e5af12b901..8369795e71 100644 --- a/railties/lib/rails/configuration.rb +++ b/railties/lib/rails/configuration.rb @@ -71,86 +71,5 @@ module Rails end end end - - module Deprecated - def frameworks(*args) - raise "config.frameworks in no longer supported. See the generated " \ - "config/boot.rb for steps on how to limit the frameworks that " \ - "will be loaded" - end - alias :frameworks= :frameworks - - def view_path=(value) - ActiveSupport::Deprecation.warn "config.view_path= is deprecated, " << - "please do paths.app.views= instead", caller - paths.app.views = value - end - - def view_path - ActiveSupport::Deprecation.warn "config.view_path is deprecated, " << - "please do paths.app.views instead", caller - paths.app.views.to_a.first - end - - def routes_configuration_file=(value) - ActiveSupport::Deprecation.warn "config.routes_configuration_file= is deprecated, " << - "please do paths.config.routes= instead", caller - paths.config.routes = value - end - - def routes_configuration_file - ActiveSupport::Deprecation.warn "config.routes_configuration_file is deprecated, " << - "please do paths.config.routes instead", caller - paths.config.routes.to_a.first - end - - def database_configuration_file=(value) - ActiveSupport::Deprecation.warn "config.database_configuration_file= is deprecated, " << - "please do paths.config.database= instead", caller - paths.config.database = value - end - - def database_configuration_file - ActiveSupport::Deprecation.warn "config.database_configuration_file is deprecated, " << - "please do paths.config.database instead", caller - paths.config.database.to_a.first - end - - def log_path=(value) - ActiveSupport::Deprecation.warn "config.log_path= is deprecated, " << - "please do paths.log= instead", caller - paths.config.log = value - end - - def log_path - ActiveSupport::Deprecation.warn "config.log_path is deprecated, " << - "please do paths.log instead", caller - paths.config.log.to_a.first - end - - def controller_paths=(value) - ActiveSupport::Deprecation.warn "config.controller_paths= is deprecated, " << - "please do paths.app.controllers= instead", caller - paths.app.controllers = value - end - - def controller_paths - ActiveSupport::Deprecation.warn "config.controller_paths is deprecated, " << - "please do paths.app.controllers instead", caller - paths.app.controllers.to_a.uniq - end - - def cookie_secret=(value) - ActiveSupport::Deprecation.warn "config.cookie_secret= is deprecated, " << - "please use config.secret_token= instead", caller - self.secret_token = value - end - - def cookie_secret - ActiveSupport::Deprecation.warn "config.cookie_secret is deprecated, " << - "please use config.secret_token instead", caller - self.secret_token - end - end end end diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 555bc9dbc8..e10980a6d9 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -2,6 +2,7 @@ require 'rails/railtie' require 'active_support/core_ext/module/delegation' require 'pathname' require 'rbconfig' +require 'rails/engine/railties' module Rails # Rails::Engine allows you to wrap a specific Rails application and share it accross @@ -86,14 +87,172 @@ module Rails # all folders under "app" are automatically added to the load path. So if you have # "app/observers", it's added by default. # + # == Endpoint + # + # Engine can be also a rack application. It can be useful if you have a rack application that + # you would like to wrap with Engine and provide some of the Engine's features. + # + # To do that, use endpoint method: + # module MyEngine + # class Engine < Rails::Engine + # endpoint MyRackApplication + # end + # end + # + # Now you can mount your engine in application's routes just like that: + # + # MyRailsApp::Application.routes.draw do + # mount MyEngine::Engine => "/engine" + # end + # + # == Middleware stack + # + # As Engine can now be rack endpoint, it can also have a middleware stack. The usage is exactly + # the same as in application: + # + # module MyEngine + # class Engine < Rails::Engine + # middleware.use SomeMiddleware + # end + # end + # + # == Routes + # + # If you don't specify endpoint, routes will be used as default endpoint. You can use them + # just like you use application's routes: + # + # # ENGINE/config/routes.rb + # MyEngine::Engine.routes.draw do + # match "/" => "posts#index" + # end + # + # == Mount priority + # + # Note that now there can be more than one router in you application and it's better to avoid + # passing requests through many routers. Consider such situation: + # + # MyRailsApp::Application.routes.draw do + # mount MyEngine::Engine => "/blog" + # match "/blog/omg" => "main#omg" + # end + # + # MyEngine is mounted at "/blog" path and additionaly "/blog/omg" points application's controller. + # In such situation request to "/blog/omg" will go through MyEngine and if there is no such route + # in Engine's routes, it will be dispatched to "main#omg". It's much better to swap that: + # + # MyRailsApp::Application.routes.draw do + # match "/blog/omg" => "main#omg" + # mount MyEngine::Engine => "/blog" + # end + # + # Now, Engine will get only requests that were not handled by application. + # + # == Asset path + # + # When you use engine with its own public directory, you will probably want to copy or symlink it + # to application's public directory. To simplify generating paths for assets, you can set asset_path + # for an Engine: + # + # module MyEngine + # class Engine < Rails::Engine + # config.asset_path = "/my_engine/%s" + # end + # end + # + # With such config, asset paths will be automatically modified inside Engine: + # image_path("foo.jpg") #=> "/my_engine/images/foo.jpg" + # + # == Engine name + # + # There are some places where engine's name is used. + # * routes: when you mount engine with mount(MyEngine::Engine => '/my_engine'), it's used as default :as option + # * migrations: when you copy engine's migrations, they will be decorated with suffix based on engine_name, for example: + # 2010010203121314_create_users.my_engine.rb + # + # Engine name is set by default based on class name. For MyEngine::Engine it will be my_engine_engine. + # You can change it manually it manually using engine_name method: + # + # module MyEngine + # class Engine < Rails::Engine + # engine_name "my_engine" + # end + # end + # + # == Namespaced Engine + # + # Normally, when you create controllers, helpers and models inside engine, they are treated + # as they would be created inside application. One of the cosequences of that is including + # application's helpers and url_helpers inside controller. Sometimes, especially when your + # engine provides its own routes, you don't want that. To isolate engine's stuff from application + # you can use namespace method: + # + # module MyEngine + # class Engine < Rails::Engine + # namespace MyEngine + # end + # end + # + # With such Engine, everything that is inside MyEngine module, will be isolated from application. + # + # Consider such controller: + # + # module MyEngine + # class FooController < ActionController::Base + # end + # end + # + # If engine is marked as namespaced, FooController has access only to helpers from engine and + # url_helpers from MyEngine::Engine.routes. + # + # Additionaly namespaced engine will set its name according to namespace, so in that case: + # MyEngine::Engine.engine_name #=> "my_engine" + # and it will set MyEngine.table_name_prefix to "my_engine_" + # + # == Using Engine's routes outside Engine + # + # Since you can mount engine inside application's routes now, you do not have direct access to engine's + # url_helpers inside application. When you mount Engine in application's routes special helper is + # created to allow doing that. Consider such scenario: + # + # # APP/config/routes.rb + # MyApplication::Application.routes.draw do + # mount MyEngine::Engine => "/my_engine", :as => "my_engine" + # match "/foo" => "foo#index" + # end + # + # Now, you can use my_engine helper: + # + # class FooController < ApplicationController + # def index + # my_engine.root_url #=> /my_engine/ + # end + # end + # + # There is also 'app' helper that gives you access to application's routes inside Engine: + # + # module MyEngine + # class BarController + # app.foo_path #=> /foo + # end + # end + # + # Note that :as option takes engine_name as default, so most of the time you can ommit it. + # + # If you want to generate url to engine's route using polymorphic_url, you can also use that helpers. + # + # Let's say that you want to create a form pointing to one of the engine's routes. All you need to do + # is passing helper as the first element in array with attributes for url: + # + # form_for([my_engine, @user]) + # + # This code will use my_engine.user_path(@user) to generate proper route. + # class Engine < Railtie autoload :Configurable, "rails/engine/configurable" autoload :Configuration, "rails/engine/configuration" class << self - attr_accessor :called_from - - # TODO Remove this. It's deprecated. + attr_accessor :called_from, :namespaced alias :engine_name :railtie_name def inherited(base) @@ -122,9 +281,40 @@ module Rails RbConfig::CONFIG['host_os'] =~ /mswin|mingw/ ? Pathname.new(root).expand_path : Pathname.new(root).realpath end + + def endpoint(endpoint = nil) + @endpoint = endpoint if endpoint + @endpoint + end + + def namespace(mod) + # TODO: extract that into a module + engine_name(generate_railtie_name(mod)) + + _railtie = self + name = engine_name + mod.singleton_class.instance_eval do + define_method(:_railtie) do + _railtie + end + + define_method(:table_name_prefix) do + "#{name}_" + end + end + + self.routes.default_scope = {:module => name} + + self.namespaced = true + end + + def namespaced? + !!namespaced + end end - delegate :paths, :root, :to => :config + delegate :middleware, :root, :paths, :to => :config + delegate :engine_name, :namespaced?, :to => "self.class" def load_tasks super @@ -140,6 +330,47 @@ module Rails end end + def railties + @railties ||= self.class::Railties.new(config) + end + + def app + @app ||= begin + config.middleware = config.middleware.merge_into(default_middleware_stack) + config.middleware.build(endpoint) + end + end + + def endpoint + self.class.endpoint || routes + end + + def call(env) + app.call(env.merge!(env_config)) + end + + def env_config + @env_config ||= { + 'action_dispatch.routes' => routes, + 'action_dispatch.asset_path' => config.asset_path + } + end + + def routes + @routes ||= ActionDispatch::Routing::RouteSet.new + end + + def initializers + initializers = [] + railties.all { |r| initializers += r.initializers } + initializers += super + initializers + end + + def config + @config ||= Engine::Configuration.new(find_root_with_flag("lib")) + end + # Add configured load paths to ruby load paths and remove duplicates. initializer :set_load_path, :before => :bootstrap_hook do _all_load_paths.reverse_each do |path| @@ -196,6 +427,27 @@ module Rails end end + initializer :load_environment_config, :before => :load_environment_hook do + environment = config.paths.config.environments.to_a.first + require environment if environment + end + + initializer :append_asset_paths do + config.asset_path = "/#{engine_name}%s" unless config.asset_path + + public_path = config.paths.public.to_a.first + if config.compiled_asset_path && File.exist?(public_path) + config.static_asset_paths[config.compiled_asset_path] = public_path + end + end + + initializer :prepend_helpers_path do + unless namespaced? + config.helpers_paths = [] unless config.respond_to?(:helpers_paths) + config.helpers_paths = config.paths.app.helpers.to_a + config.helpers_paths + end + end + initializer :load_config_initializers do paths.config.initializers.to_a.sort.each do |initializer| load(initializer) @@ -208,6 +460,24 @@ module Rails end protected + def find_root_with_flag(flag, default=nil) + root_path = self.class.called_from + + while root_path && File.directory?(root_path) && !File.exist?("#{root_path}/#{flag}") + parent = File.dirname(root_path) + root_path = parent != root_path && parent + end + + root = File.exist?("#{root_path}/#{flag}") ? root_path : default + raise "Could not find root path for #{self}" unless root + + Config::CONFIG['host_os'] =~ /mswin|mingw/ ? + Pathname.new(root).expand_path : Pathname.new(root).realpath + end + + def default_middleware_stack + ActionDispatch::MiddlewareStack.new + end def _all_autoload_paths @_all_autoload_paths ||= (config.autoload_paths + config.eager_load_paths + config.autoload_once_paths).uniq diff --git a/railties/lib/rails/engine/configurable.rb b/railties/lib/rails/engine/configurable.rb deleted file mode 100644 index 9a370f0abb..0000000000 --- a/railties/lib/rails/engine/configurable.rb +++ /dev/null @@ -1,25 +0,0 @@ -module Rails - class Engine - module Configurable - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - delegate :middleware, :root, :paths, :to => :config - - def config - @config ||= Engine::Configuration.new(find_root_with_flag("lib")) - end - - def inherited(base) - raise "You cannot inherit from a Rails::Engine child" - end - end - - def config - self.class.config - end - end - end -end
\ No newline at end of file diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index 521ed95447..3ac8911ba8 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -5,10 +5,13 @@ module Rails class Configuration < ::Rails::Railtie::Configuration attr_reader :root attr_writer :eager_load_paths, :autoload_once_paths, :autoload_paths + attr_accessor :middleware, :plugins, :asset_path def initialize(root=nil) super() @root = root + @middleware = Rails::Configuration::MiddlewareStackProxy.new + @helpers_paths = [] end def paths @@ -26,9 +29,14 @@ module Rails paths.config.initializers "config/initializers", :glob => "**/*.rb" paths.config.locales "config/locales", :glob => "*.{rb,yml}" paths.config.routes "config/routes.rb" + paths.config.environments "config/environments", :glob => "#{Rails.env}.rb" paths.public "public" paths.public.javascripts "public/javascripts" paths.public.stylesheets "public/stylesheets" + paths.vendor "vendor", :load_path => true + paths.vendor.plugins "vendor/plugins" + paths.db "db" + paths.db.migrate "db/migrate" paths end end @@ -48,6 +56,10 @@ module Rails def autoload_paths @autoload_paths ||= paths.autoload_paths end + + def compiled_asset_path + asset_path % "" if asset_path + end end end end diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb new file mode 100644 index 0000000000..389a7602c6 --- /dev/null +++ b/railties/lib/rails/engine/railties.rb @@ -0,0 +1,23 @@ +module Rails + class Engine < Railtie + class Railties + # TODO Write tests for this behavior extracted from Application + def initialize(config) + @config = config + end + + def all(&block) + @all ||= plugins + @all.each(&block) if block + @all + end + + def plugins + @plugins ||= begin + plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym } + Plugin.all(plugin_names, @config.paths.vendor.plugins) + end + end + end + end +end diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index 8d5132a5ca..c07ff2f9cf 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -18,6 +18,10 @@ module Rails # root during the boot process. # class Plugin < Engine + def self.global_plugins + @global_plugins ||= [] + end + def self.inherited(base) raise "You cannot inherit from Rails::Plugin" end @@ -28,6 +32,11 @@ module Rails Dir["#{path}/*"].each do |plugin_path| plugin = new(plugin_path) next unless list.include?(plugin.name) || list.include?(:all) + if global_plugins.include?(plugin.name) + warn "WARNING: plugin #{plugin.name} from #{path} was not loaded. Plugin with the same name has been already loaded." + next + end + global_plugins << plugin.name plugins << plugin end end @@ -39,6 +48,10 @@ module Rails attr_reader :name, :path + def railtie_name + name.to_s + end + def load_tasks super load_deprecated_tasks @@ -78,6 +91,8 @@ module Rails ActiveSupport::Deprecation.warn "Use toplevel init.rb; rails/init.rb is deprecated: #{initrb}" end config = app.config + # TODO: think about evaling initrb in context of Engine (currently it's + # always evaled in context of Rails::Application) eval(File.read(initrb), binding, initrb) end end diff --git a/railties/lib/rails/railtie.rb b/railties/lib/rails/railtie.rb index 58b0d851f7..09650789ac 100644 --- a/railties/lib/rails/railtie.rb +++ b/railties/lib/rails/railtie.rb @@ -1,7 +1,6 @@ require 'rails/initializable' require 'rails/configuration' require 'active_support/inflector' -require 'active_support/deprecation' module Rails # Railtie is the core of the Rails Framework and provides several hooks to extend @@ -131,25 +130,19 @@ module Rails ABSTRACT_RAILTIES = %w(Rails::Railtie Rails::Plugin Rails::Engine Rails::Application) class << self + private :new + def subclasses @subclasses ||= [] end def inherited(base) unless base.abstract_railtie? - base.send(:include, self::Configurable) + base.send(:include, Railtie::Configurable) subclasses << base end end - def railtie_name(*) - ActiveSupport::Deprecation.warn "railtie_name is deprecated and has no effect", caller - end - - def log_subscriber(*) - ActiveSupport::Deprecation.warn "log_subscriber is deprecated and has no effect", caller - end - def rake_tasks(&blk) @rake_tasks ||= [] @rake_tasks << blk if blk @@ -171,6 +164,22 @@ module Rails def abstract_railtie? ABSTRACT_RAILTIES.include?(name) end + + def railtie_name(name = nil) + @railtie_name = name.to_s if name + @railtie_name ||= generate_railtie_name(self.name) + end + + protected + def generate_railtie_name(class_or_module) + ActiveSupport::Inflector.underscore(class_or_module).gsub("/", "_") + end + end + + delegate :railtie_name, :to => "self.class" + + def config + @config ||= Railtie::Configuration.new end def eager_load! diff --git a/railties/lib/rails/railtie/configurable.rb b/railties/lib/rails/railtie/configurable.rb index a2eb938c5a..b6d4ed2312 100644 --- a/railties/lib/rails/railtie/configurable.rb +++ b/railties/lib/rails/railtie/configurable.rb @@ -6,17 +6,29 @@ module Rails end module ClassMethods - def config - @config ||= Railtie::Configuration.new - end + delegate :config, :to => :instance def inherited(base) - raise "You cannot inherit from a Rails::Railtie child" + raise "You cannot inherit from a #{self.superclass.name} child" end - end - def config - self.class.config + def instance + @instance ||= new + end + + def respond_to?(*args) + super || instance.respond_to?(*args) + end + + def configure(&block) + class_eval(&block) + end + + protected + + def method_missing(*args, &block) + instance.send(*args, &block) + end end end end diff --git a/railties/lib/rails/railtie/configuration.rb b/railties/lib/rails/railtie/configuration.rb index 4e6f94c534..f09e3940cc 100644 --- a/railties/lib/rails/railtie/configuration.rb +++ b/railties/lib/rails/railtie/configuration.rb @@ -5,6 +5,7 @@ module Rails class Configuration def initialize @@options ||= {} + @@static_asset_paths = ActiveSupport::OrderedHash.new end # This allows you to modify the application's middlewares from Engines. @@ -65,6 +66,13 @@ module Rails super || @@options.key?(name.to_sym) end + # static_asset_paths is a Hash containing asset_paths + # with associated public folders, like: + # { "/" => "/app/public", "/my_engine" => "app/engines/my_engine/public" } + def static_asset_paths + @@static_asset_paths + end + private def method_missing(name, *args, &blk) @@ -78,4 +86,4 @@ module Rails end end end -end
\ No newline at end of file +end diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index d63d25b42e..6bf56f7052 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -26,18 +26,17 @@ module ApplicationTests FileUtils.rm_rf(new_app) if File.directory?(new_app) end - test "Rails::Application.instance is nil until app is initialized" do + test "Rails.application is nil until app is initialized" do require 'rails' - assert_nil Rails::Application.instance + assert_nil Rails.application require "#{app_path}/config/environment" - assert_equal AppTemplate::Application.instance, Rails::Application.instance + assert_equal AppTemplate::Application.instance, Rails.application end - test "Rails::Application responds to all instance methods" do + test "Rails.application responds to all instance methods" do require "#{app_path}/config/environment" - assert_respond_to Rails::Application, :routes_reloader - assert_equal Rails::Application.routes_reloader, Rails.application.routes_reloader - assert_equal Rails::Application.routes_reloader, AppTemplate::Application.routes_reloader + assert_respond_to Rails.application, :routes_reloader + assert_equal Rails.application.routes_reloader, AppTemplate::Application.routes_reloader end test "Rails::Application responds to paths" do @@ -125,22 +124,6 @@ module ApplicationTests assert !ActionController.autoload?(:RecordIdentifier) end - test "runtime error is raised if config.frameworks= is used" do - add_to_config "config.frameworks = []" - - assert_raises RuntimeError do - require "#{app_path}/config/environment" - end - end - - test "runtime error is raised if config.frameworks is used" do - add_to_config "config.frameworks -= []" - - assert_raises RuntimeError do - require "#{app_path}/config/environment" - end - end - test "filter_parameters should be able to set via config.filter_parameters" do add_to_config <<-RUBY config.filter_parameters += [ :foo, 'bar', lambda { |key, value| @@ -277,5 +260,20 @@ module ApplicationTests get "/" assert_not_equal res, last_response.body end + + test "config.asset_path is not passed through env" do + make_basic_app do |app| + app.config.asset_path = "/omg%s" + end + + class ::OmgController < ActionController::Base + def index + render :inline => "<%= image_path('foo.jpg') %>" + end + end + + get "/" + assert_equal "/omg/images/foo.jpg", last_response.body + end end end diff --git a/railties/test/application/initializers/frameworks_test.rb b/railties/test/application/initializers/frameworks_test.rb index 4ff10091b1..6e9ceb6ef7 100644 --- a/railties/test/application/initializers/frameworks_test.rb +++ b/railties/test/application/initializers/frameworks_test.rb @@ -61,6 +61,7 @@ module ApplicationTests require "#{app_path}/config/environment" assert Foo.method_defined?(:foo_path) + assert Foo.method_defined?(:app) assert_equal ["notify"], Foo.action_methods end diff --git a/railties/test/application/loading_test.rb b/railties/test/application/loading_test.rb index ecf7904c39..a2abf642b8 100644 --- a/railties/test/application/loading_test.rb +++ b/railties/test/application/loading_test.rb @@ -42,6 +42,23 @@ class LoadingTest < Test::Unit::TestCase User end + test "load config/environments/environment before Bootstrap initializers" do + app_file "config/environments/development.rb", <<-RUBY + AppTemplate::Application.configure do + config.development_environment_loaded = true + end + RUBY + + add_to_config <<-RUBY + config.before_initialize do + config.loaded = config.development_environment_loaded + end + RUBY + + require "#{app_path}/config/environment" + assert ::AppTemplate::Application.config.loaded + end + def test_descendants_are_cleaned_on_each_request_without_cache_classes add_to_config <<-RUBY config.cache_classes = false @@ -72,6 +89,11 @@ class LoadingTest < Test::Unit::TestCase assert_equal [], ActiveRecord::Base.descendants end + test "initialize_cant_be_called_twice" do + require "#{app_path}/config/environment" + assert_raise(RuntimeError) { ::AppTemplate::Application.initialize! } + end + protected def setup_ar! diff --git a/railties/test/railties/engine_test.rb b/railties/test/railties/engine_test.rb index 7410a10712..0cc729907e 100644 --- a/railties/test/railties/engine_test.rb +++ b/railties/test/railties/engine_test.rb @@ -1,8 +1,23 @@ require "isolation/abstract_unit" require "railties/shared_tests" +require 'stringio' module RailtiesTest class EngineTest < Test::Unit::TestCase + # TODO: it's copied from generators/test_case, maybe make a module with such helpers? + def capture(stream) + begin + stream = stream.to_s + eval "$#{stream} = StringIO.new" + yield + result = eval("$#{stream}").string + ensure + eval("$#{stream} = #{stream.upcase}") + end + + result + end + include ActiveSupport::Testing::Isolation include SharedTests @@ -13,6 +28,7 @@ module RailtiesTest plugin.write "lib/bukkits.rb", <<-RUBY class Bukkits class Engine < ::Rails::Engine + railtie_name "bukkits" end end RUBY @@ -50,5 +66,483 @@ module RailtiesTest assert index < initializers.index { |i| i.name == :build_middleware_stack } end + + + class Upcaser + def initialize(app) + @app = app + end + + def call(env) + response = @app.call(env) + response[2].upcase! + response + end + end + + test "engine is a rack app and can have his own middleware stack" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'Hello World'] } + + config.middleware.use ::RailtiesTest::EngineTest::Upcaser + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + mount(Bukkits::Engine => "/bukkits") + end + RUBY + + boot_rails + + env = Rack::MockRequest.env_for("/bukkits") + response = Rails.application.call(env) + + assert_equal "HELLO WORLD", response[2] + end + + test "it provides routes as default endpoint" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + match "/foo" => lambda { |env| [200, {'Content-Type' => 'text/html'}, 'foo'] } + end + RUBY + + app_file "config/routes.rb", <<-RUBY + Rails.application.routes.draw do + mount(Bukkits::Engine => "/bukkits") + end + RUBY + + boot_rails + + env = Rack::MockRequest.env_for("/bukkits/foo") + response = Rails.application.call(env) + + assert_equal "foo", response[2] + end + + test "engine can load its own plugins" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + @plugin.write "vendor/plugins/yaffle/init.rb", <<-RUBY + config.yaffle_loaded = true + RUBY + + boot_rails + + assert Bukkits::Engine.config.yaffle_loaded + end + + test "engine does not load plugins that already exists in application" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + @plugin.write "vendor/plugins/yaffle/init.rb", <<-RUBY + config.engine_yaffle_loaded = true + RUBY + + app_file "vendor/plugins/yaffle/init.rb", <<-RUBY + config.app_yaffle_loaded = true + RUBY + + warnings = capture(:stderr) { boot_rails } + + assert !warnings.empty? + assert !Bukkits::Engine.config.respond_to?(:engine_yaffle_loaded) + assert Rails.application.config.app_yaffle_loaded + end + + test "it loads its environment file" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + @plugin.write "config/environments/development.rb", <<-RUBY + Bukkits::Engine.configure do + config.environment_loaded = true + end + RUBY + + boot_rails + + assert Bukkits::Engine.config.environment_loaded + end + + test "it passes router in env" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + endpoint lambda { |env| [200, {'Content-Type' => 'text/html'}, 'hello'] } + end + end + RUBY + + boot_rails + + env = Rack::MockRequest.env_for("/") + response = Bukkits::Engine.call(env) + + assert_equal Bukkits::Engine.routes, env['action_dispatch.routes'] + + env = Rack::MockRequest.env_for("/") + response = Rails.application.call(env) + + assert_equal Rails.application.routes, env['action_dispatch.routes'] + end + + test "it allows to set asset_path" do + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + end + end + RUBY + + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + match "/foo" => "foo#index" + end + RUBY + + @plugin.write "app/controllers/foo_controller.rb", <<-RUBY + class FooController < ActionController::Base + def index + render :index + end + end + RUBY + + @plugin.write "app/views/foo/index.html.erb", <<-RUBY + <%= compute_public_path("/foo", "") %> + <%= image_path("foo.png") %> + <%= javascript_include_tag("foo") %> + <%= stylesheet_link_tag("foo") %> + RUBY + + + app_file "app/controllers/bar_controller.rb", <<-RUBY + class BarController < ActionController::Base + def index + render :index + end + end + RUBY + + app_file "app/views/bar/index.html.erb", <<-RUBY + <%= compute_public_path("/foo", "") %> + RUBY + + add_to_config 'config.asset_path = "/omg%s"' + + @plugin.write 'public/touch.txt', <<-RUBY + touch + RUBY + + boot_rails + + # should set asset_path with engine name by default + assert_equal "/bukkits_engine%s", ::Bukkits::Engine.config.asset_path + + ::Bukkits::Engine.config.asset_path = "/bukkits%s" + + env = Rack::MockRequest.env_for("/foo") + response = Bukkits::Engine.call(env) + stripped_body = response[2].body.split("\n").map(&:strip).join("\n") + + expected = "/omg/bukkits/foo\n" + + "/omg/bukkits/images/foo.png\n" + + "<script src=\"/omg/bukkits/javascripts/foo.js\" type=\"text/javascript\"></script>\n" + + "<link href=\"/omg/bukkits/stylesheets/foo.css\" media=\"screen\" rel=\"stylesheet\" type=\"text/css\" />" + assert_equal expected, stripped_body + end + + test "engine's files are served via ActionDispatch::Static" do + add_to_config "config.serve_static_assets = true" + + @plugin.write "lib/bukkits.rb", <<-RUBY + class Bukkits + class Engine < ::Rails::Engine + engine_name :bukkits + end + end + RUBY + + @plugin.write "public/bukkits.html", "/bukkits/bukkits.html" + app_file "public/app.html", "/app.html" + app_file "public/bukkits/file_from_app.html", "/bukkits/file_from_app.html" + + boot_rails + + env = Rack::MockRequest.env_for("/app.html") + response = Rails.application.call(env) + assert_equal response[2].path, File.join(app_path, "public/app.html") + + env = Rack::MockRequest.env_for("/bukkits/bukkits.html") + response = Rails.application.call(env) + assert_equal response[2].path, File.join(@plugin.path, "public/bukkits.html") + + env = Rack::MockRequest.env_for("/bukkits/file_from_app.html") + response = Rails.application.call(env) + assert_equal response[2].path, File.join(app_path, "public/bukkits/file_from_app.html") + end + + test "shared engine should include application's helpers and own helpers" do + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match "/foo" => "bukkits/foo#index", :as => "foo" + match "/foo/show" => "bukkits/foo#show" + match "/foo/bar" => "bukkits/foo#bar" + end + RUBY + + app_file "app/helpers/some_helper.rb", <<-RUBY + module SomeHelper + def something + "Something... Something... Something..." + end + end + RUBY + + @plugin.write "app/helpers/bar_helper.rb", <<-RUBY + module BarHelper + def bar + "It's a bar." + end + end + RUBY + + @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY + class Bukkits::FooController < ActionController::Base + def index + render :inline => "<%= something %>" + end + + def show + render :text => foo_path + end + + def bar + render :inline => "<%= bar %>" + end + end + RUBY + + boot_rails + + env = Rack::MockRequest.env_for("/foo") + response = Rails.application.call(env) + assert_equal "Something... Something... Something...", response[2].body + + env = Rack::MockRequest.env_for("/foo/show") + response = Rails.application.call(env) + assert_equal "/foo", response[2].body + + env = Rack::MockRequest.env_for("/foo/bar") + response = Rails.application.call(env) + assert_equal "It's a bar.", response[2].body + end + + test "isolated engine should include only its own routes and helpers" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + namespace Bukkits + end + end + RUBY + + @plugin.write "app/models/bukkits/post.rb", <<-RUBY + module Bukkits + class Post + extend ActiveModel::Naming + + def to_param + "1" + end + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + match "/bar" => "bar#index", :as => "bar" + mount Bukkits::Engine => "/bukkits", :as => "bukkits" + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + match "/foo" => "foo#index", :as => "foo" + match "/foo/show" => "foo#show" + match "/from_app" => "foo#from_app" + match "/routes_helpers_in_view" => "foo#routes_helpers_in_view" + match "/polymorphic_path_without_namespace" => "foo#polymorphic_path_without_namespace" + resources :posts + end + RUBY + + app_file "app/helpers/some_helper.rb", <<-RUBY + module SomeHelper + def something + "Something... Something... Something..." + end + end + RUBY + + @plugin.write "app/helpers/engine_helper.rb", <<-RUBY + module EngineHelper + def help_the_engine + "Helped." + end + end + RUBY + + @plugin.write "app/controllers/bukkits/foo_controller.rb", <<-RUBY + class Bukkits::FooController < ActionController::Base + def index + render :inline => "<%= help_the_engine %>" + end + + def show + render :text => foo_path + end + + def from_app + render :inline => "<%= (self.respond_to?(:bar_path) || self.respond_to?(:something)) %>" + end + + def routes_helpers_in_view + render :inline => "<%= foo_path %>, <%= app.bar_path %>" + end + + def polymorphic_path_without_namespace + render :text => polymorphic_path(Post.new) + end + end + RUBY + + @plugin.write "app/mailers/bukkits/my_mailer.rb", <<-RUBY + module Bukkits + class MyMailer < ActionMailer::Base + end + end + RUBY + + add_to_config("config.action_dispatch.show_exceptions = false") + + boot_rails + + assert_equal "bukkits_", Bukkits.table_name_prefix + assert_equal "bukkits", Bukkits::Engine.engine_name + assert_equal Bukkits._railtie, Bukkits::Engine + assert ::Bukkits::MyMailer.method_defined?(:foo_path) + assert !::Bukkits::MyMailer.method_defined?(:bar_path) + + env = Rack::MockRequest.env_for("/bukkits/from_app") + response = AppTemplate::Application.call(env) + assert_equal "false", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/foo/show") + response = AppTemplate::Application.call(env) + assert_equal "/bukkits/foo", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/foo") + response = AppTemplate::Application.call(env) + assert_equal "Helped.", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/routes_helpers_in_view") + response = AppTemplate::Application.call(env) + assert_equal "/bukkits/foo, /bar", response[2].body + + env = Rack::MockRequest.env_for("/bukkits/polymorphic_path_without_namespace") + response = AppTemplate::Application.call(env) + assert_equal "/bukkits/posts/1", response[2].body + end + + test "isolated engine should avoid namespace in names if that's possible" do + @plugin.write "lib/bukkits.rb", <<-RUBY + module Bukkits + class Engine < ::Rails::Engine + namespace Bukkits + end + end + RUBY + + @plugin.write "app/models/bukkits/post.rb", <<-RUBY + module Bukkits + class Post + extend ActiveModel::Naming + include ActiveModel::Conversion + attr_accessor :title + + def to_param + "1" + end + + def persisted? + false + end + end + end + RUBY + + app_file "config/routes.rb", <<-RUBY + AppTemplate::Application.routes.draw do + mount Bukkits::Engine => "/bukkits", :as => "bukkits" + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Bukkits::Engine.routes.draw do + resources :posts + end + RUBY + + @plugin.write "app/controllers/bukkits/posts_controller.rb", <<-RUBY + class Bukkits::PostsController < ActionController::Base + def new + end + end + RUBY + + @plugin.write "app/views/bukkits/posts/new.html.erb", <<-RUBY + <%= form_for(Bukkits::Post.new) do |f| %> + <%= f.text_field :title %> + <% end %> + RUBY + + add_to_config("config.action_dispatch.show_exceptions = false") + + boot_rails + + env = Rack::MockRequest.env_for("/bukkits/posts/new") + response = AppTemplate::Application.call(env) + assert response[2].body =~ /name="post\[title\]"/ + end end end diff --git a/railties/test/railties/mounted_engine_test.rb b/railties/test/railties/mounted_engine_test.rb new file mode 100644 index 0000000000..36dd01198f --- /dev/null +++ b/railties/test/railties/mounted_engine_test.rb @@ -0,0 +1,174 @@ +require 'isolation/abstract_unit' + +module ApplicationTests + class ApplicationRoutingTest < Test::Unit::TestCase + require 'rack/test' + include Rack::Test::Methods + include ActiveSupport::Testing::Isolation + + def setup + build_app + + add_to_config("config.action_dispatch.show_exceptions = false") + + @plugin = engine "blog" + + app_file 'config/routes.rb', <<-RUBY + AppTemplate::Application.routes.draw do |map| + match "/engine_route" => "application_generating#engine_route" + match "/engine_route_in_view" => "application_generating#engine_route_in_view" + match "/url_for_engine_route" => "application_generating#url_for_engine_route" + match "/polymorphic_route" => "application_generating#polymorphic_route" + scope "/:user", :user => "anonymous" do + mount Blog::Engine => "/blog" + end + root :to => 'main#index' + end + RUBY + + @plugin.write "app/models/blog/post.rb", <<-RUBY + module Blog + class Post + extend ActiveModel::Naming + + def id + 44 + end + + def to_param + id.to_s + end + + def new_record? + false + end + end + end + RUBY + + @plugin.write "lib/blog.rb", <<-RUBY + module Blog + class Engine < ::Rails::Engine + namespace(Blog) + end + end + RUBY + + @plugin.write "config/routes.rb", <<-RUBY + Blog::Engine.routes.draw do + resources :posts + match '/generate_application_route', :to => 'posts#generate_application_route' + match '/application_route_in_view', :to => 'posts#application_route_in_view' + end + RUBY + + @plugin.write "app/controllers/blog/posts_controller.rb", <<-RUBY + module Blog + class PostsController < ActionController::Base + def index + render :text => blog.post_path(1) + end + + def generate_application_route + path = app.url_for(:controller => "/main", + :action => "index", + :only_path => true) + render :text => path + end + + def application_route_in_view + render :inline => "<%= app.root_path %>" + end + end + end + RUBY + + app_file "app/controllers/application_generating_controller.rb", <<-RUBY + class ApplicationGeneratingController < ActionController::Base + def engine_route + render :text => blog.posts_path + end + + def engine_route_in_view + render :inline => "<%= blog.posts_path %>" + end + + def url_for_engine_route + render :text => blog.url_for(:controller => "blog/posts", :action => "index", :user => "john", :only_path => true) + end + + def polymorphic_route + render :text => polymorphic_url([blog, Blog::Post.new]) + end + end + RUBY + + boot_rails + end + + def app + @app ||= begin + require "#{app_path}/config/environment" + Rails.application + end + end + + def reset_script_name! + Rails.application.routes.default_url_options = {} + end + + def script_name(script_name) + Rails.application.routes.default_url_options = {:script_name => script_name} + end + + test "routes generation in engine and application" do + # test generating engine's route from engine + get "/john/blog/posts" + assert_equal "/john/blog/posts/1", last_response.body + + # test generating engine's route from engine with default_url_options + script_name "/foo" + get "/john/blog/posts", {}, 'SCRIPT_NAME' => "/foo" + assert_equal "/foo/john/blog/posts/1", last_response.body + reset_script_name! + + # test generating engine's route from application + get "/engine_route" + assert_equal "/anonymous/blog/posts", last_response.body + + get "/engine_route_in_view" + assert_equal "/anonymous/blog/posts", last_response.body + + get "/url_for_engine_route" + assert_equal "/john/blog/posts", last_response.body + + # test generating engine's route from application with default_url_options + script_name "/foo" + get "/engine_route", {}, 'SCRIPT_NAME' => "/foo" + assert_equal "/foo/anonymous/blog/posts", last_response.body + + script_name "/foo" + get "/url_for_engine_route", {}, 'SCRIPT_NAME' => "/foo" + assert_equal "/foo/john/blog/posts", last_response.body + reset_script_name! + + # test generating application's route from engine + get "/someone/blog/generate_application_route" + assert_equal "/", last_response.body + + get "/somone/blog/application_route_in_view" + assert_equal "/", last_response.body + + # test generating application's route from engine with default_url_options + script_name "/foo" + get "/someone/blog/generate_application_route", {}, 'SCRIPT_NAME' => '/foo' + assert_equal "/foo/", last_response.body + reset_script_name! + + # test polymorphic routes + get "/polymorphic_route" + assert_equal "http://example.org/anonymous/blog/posts/44", last_response.body + end + end +end + diff --git a/railties/test/railties/railtie_test.rb b/railties/test/railties/railtie_test.rb index 6715003d3d..406d5d764f 100644 --- a/railties/test/railties/railtie_test.rb +++ b/railties/test/railties/railtie_test.rb @@ -19,6 +19,22 @@ module RailtiesTest assert !Rails::Railtie.respond_to?(:config) end + test "Railtie provides railtie_name" do + begin + class ::Foo < Rails::Railtie ; end + assert_equal "foo", ::Foo.railtie_name + ensure + Object.send(:remove_const, :"Foo") + end + end + + test "railtie_name can be set manualy" do + class Foo < Rails::Railtie + railtie_name "bar" + end + assert_equal "bar", Foo.railtie_name + end + test "cannot inherit from a railtie" do class Foo < Rails::Railtie ; end assert_raise RuntimeError do diff --git a/railties/test/railties/shared_tests.rb b/railties/test/railties/shared_tests.rb index ce7c55c11c..6aae17c237 100644 --- a/railties/test/railties/shared_tests.rb +++ b/railties/test/railties/shared_tests.rb @@ -10,6 +10,55 @@ module RailtiesTest @app ||= Rails.application end + def test_copying_migrations + @plugin.write "db/migrate/1_create_users.rb", <<-RUBY + class CreateUsers < ActiveRecord::Migration + end + RUBY + + @plugin.write "db/migrate/2_add_last_name_to_users.rb", <<-RUBY + class AddLastNameToUsers < ActiveRecord::Migration + end + RUBY + + app_file "db/migrate/1_create_sessions.rb", <<-RUBY + class CreateSessions < ActiveRecord::Migration + end + RUBY + + yaffle = plugin "acts_as_yaffle", "::LEVEL = config.log_level" do |plugin| + plugin.write "lib/acts_as_yaffle.rb", "class ActsAsYaffle; end" + end + + yaffle.write "db/migrate/1_create_yaffles.rb", <<-RUBY + class CreateYaffles < ActiveRecord::Migration + end + RUBY + + add_to_config "ActiveRecord::Base.timestamped_migrations = false" + + Dir.chdir(app_path) do + output = `rake db:copy_migrations FROM=bukkits` + + assert File.exists?("#{app_path}/db/migrate/2_create_users.bukkits.rb") + assert File.exists?("#{app_path}/db/migrate/3_add_last_name_to_users.bukkits.rb") + assert_match /2_create_users/, output + assert_match /3_add_last_name_to_users/, output + assert_equal 3, Dir["#{app_path}/db/migrate/*.rb"].length + + output = `rake db:copy_migrations` + + assert File.exists?("#{app_path}/db/migrate/4_create_yaffles.acts_as_yaffle.rb") + assert_match /4_create_yaffles/, output + + migrations_count = Dir["#{app_path}/db/migrate/*.rb"].length + output = `rake db:copy_migrations` + + assert_equal migrations_count, Dir["#{app_path}/db/migrate/*.rb"].length + assert_match /No migrations were copied/, output + end + end + def test_puts_its_lib_directory_on_load_path boot_rails require "another" |