From d649bf158be130515566aed987f83d36ac9b0ae8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 6 Oct 2010 17:18:59 +0200 Subject: Provide a cleaner syntax for paths configuration that does not rely on method_missing. --- railties/lib/rails.rb | 2 +- railties/lib/rails/application.rb | 2 +- railties/lib/rails/application/bootstrap.rb | 2 +- railties/lib/rails/application/configuration.rb | 18 +-- railties/lib/rails/application/finisher.rb | 2 +- railties/lib/rails/engine.rb | 59 ++++----- railties/lib/rails/engine/configuration.rb | 43 ++++--- railties/lib/rails/engine/railties.rb | 2 +- railties/lib/rails/paths.rb | 152 ++++++++++++++++-------- railties/lib/rails/plugin.rb | 4 +- railties/lib/rails/tasks/railties.rake | 2 +- 11 files changed, 173 insertions(+), 115 deletions(-) (limited to 'railties/lib') diff --git a/railties/lib/rails.rb b/railties/lib/rails.rb index 3663910281..cca0891835 100644 --- a/railties/lib/rails.rb +++ b/railties/lib/rails.rb @@ -92,7 +92,7 @@ module Rails end def public_path - application && application.paths.public.to_a.first + application && application.paths["public"].first end end end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 075e3c5692..5559f49fbd 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -72,7 +72,7 @@ module Rails end def require_environment! #:nodoc: - environment = paths.config.environment.to_a.first + environment = paths["config/environment"].existent.first require environment if environment end diff --git a/railties/lib/rails/application/bootstrap.rb b/railties/lib/rails/application/bootstrap.rb index e39b3bc705..213aa0768a 100644 --- a/railties/lib/rails/application/bootstrap.rb +++ b/railties/lib/rails/application/bootstrap.rb @@ -23,7 +23,7 @@ module Rails # Initialize the logger early in the stack in case we need to log some deprecation. initializer :initialize_logger do Rails.logger ||= config.logger || begin - path = config.paths.log.to_a.first + path = config.paths["log"].first logger = ActiveSupport::BufferedLogger.new(path) logger.level = ActiveSupport::BufferedLogger.const_get(config.log_level.to_s.upcase) logger.auto_flushing = false if Rails.env.production? diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index f902c3ded2..3505388479 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -9,7 +9,7 @@ module Rails :filter_parameters, :log_level, :logger, :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, :session_options, - :time_zone, :whiny_nils + :time_zone, :whiny_nils, :helpers_paths def initialize(*) super @@ -17,6 +17,7 @@ module Rails @allow_concurrency = false @consider_all_requests_local = false @filter_parameters = [] + @helpers_paths = [] @dependency_loading = true @serve_static_assets = true @session_store = :cookie_store @@ -60,13 +61,12 @@ module Rails def paths @paths ||= begin paths = super - paths.config.database "config/database.yml" - paths.config.environment "config/environment.rb" - paths.lib.templates "lib/templates" - paths.log "log/#{Rails.env}.log" - paths.tmp "tmp" - paths.tmp.cache "tmp/cache" - + paths.add "config/database", :with => "config/database.yml" + paths.add "config/environment", :with => "config/environment.rb" + paths.add "lib/templates" + paths.add "log", :with => "log/#{Rails.env}.log" + paths.add "tmp" + paths.add "tmp/cache" paths end end @@ -88,7 +88,7 @@ module Rails # YAML::load. def database_configuration require 'erb' - YAML::load(ERB.new(IO.read(paths.config.database.to_a.first)).result) + YAML::load(ERB.new(IO.read(paths["config/database"].first)).result) end def cache_store diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index b95df467c7..e3342be7ee 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -4,7 +4,7 @@ module Rails include Initializable initializer :add_generator_templates do - config.generators.templates.unshift(*paths.lib.templates.to_a) + config.generators.templates.unshift(*paths["lib/templates"].existent) end initializer :ensure_autoload_once_paths_as_subset do diff --git a/railties/lib/rails/engine.rb b/railties/lib/rails/engine.rb index 3981e8dfd5..bd3e612153 100644 --- a/railties/lib/rails/engine.rb +++ b/railties/lib/rails/engine.rb @@ -90,17 +90,17 @@ module Rails # The available paths in an Engine are: # # class MyEngine < Rails::Engine - # paths.app = "app" - # paths.app.controllers = "app/controllers" - # paths.app.helpers = "app/helpers" - # paths.app.models = "app/models" - # paths.app.views = "app/views" - # paths.lib = "lib" - # paths.lib.tasks = "lib/tasks" - # paths.config = "config" - # paths.config.initializers = "config/initializers" - # paths.config.locales = "config/locales" - # paths.config.routes = "config/routes.rb" + # paths["app"] #=> ["app"] + # paths["app/controllers"] #=> ["app/controllers"] + # paths["app/helpers"] #=> ["app/helpers"] + # paths["app/models"] #=> ["app/models"] + # paths["app/views"] #=> ["app/views"] + # paths["lib"] #=> ["lib"] + # paths["lib/tasks"] #=> ["lib/tasks"] + # paths["config"] #=> ["config"] + # paths["config/initializers"] #=> ["config/initializers"] + # paths["config/locales"] #=> ["config/locales"] + # paths["config/routes"] #=> ["config/routes.rb"] # end # # Your Application class adds a couple more paths to this set. And as in your Application, @@ -276,11 +276,11 @@ module Rails # end # end # - # There is also 'app' helper that gives you access to application's routes inside Engine: + # There is also 'main_app' helper that gives you access to application's routes inside Engine: # # module MyEngine # class BarController - # app.foo_path #=> /foo + # main_app.foo_path #=> /foo # end # end # @@ -381,7 +381,7 @@ module Rails def load_tasks super - config.paths.lib.tasks.to_a.sort.each { |ext| load(ext) } + paths["lib/tasks"].existent.sort.each { |ext| load(ext) } end def eager_load! @@ -441,7 +441,7 @@ module Rails # # Blog::Engine.load_seed def load_seed - seed_file = config.paths.db.seeds.to_a.first + seed_file = paths["db/seeds"].existent.first load(seed_file) if File.exist?(seed_file) end @@ -469,20 +469,22 @@ module Rails end initializer :add_routing_paths do |app| - app.routes_reloader.blocks[routes] = routes_draw_block - paths.config.routes.to_a.each do |route| - app.routes_reloader.paths.unshift(route) if File.exists?(route) + paths = self.paths["config/routes"].existent + + if routes? || paths.any? + app.routes_reloader.blocks[routes] = routes_draw_block + app.routes_reloader.paths.unshift(*paths) end end # I18n load paths are a special case since the ones added # later have higher priority. initializer :add_locales do - config.i18n.railties_load_path.concat(paths.config.locales.to_a) + config.i18n.railties_load_path.concat(paths["config/locales"].existent) end initializer :add_view_paths do - views = paths.app.views.to_a + views = paths["app/views"].existent unless views.empty? ActiveSupport.on_load(:action_controller){ prepend_view_path(views) } ActiveSupport.on_load(:action_mailer){ prepend_view_path(views) } @@ -490,28 +492,27 @@ module Rails end initializer :load_environment_config, :before => :load_environment_hook do - environment = config.paths.config.environments.to_a.first + environment = paths["config/environments"].existent.first require environment if environment end initializer :append_asset_paths do config.asset_path ||= "/#{engine_name}%s" - public_path = config.paths.public.to_a.first + public_path = paths["public"].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 + initializer :prepend_helpers_path do |app| + if !namespaced? || (app == self) + app.config.helpers_paths.unshift(*paths["app/helpers"].existent) end end initializer :load_config_initializers do - paths.config.initializers.to_a.sort.each do |initializer| + config.paths["config/initializers"].existent.sort.each do |initializer| load(initializer) end end @@ -524,6 +525,10 @@ module Rails protected attr_accessor :routes_draw_block + def routes? + defined?(@routes) + end + def find_root_with_flag(flag, default=nil) root_path = self.class.called_from diff --git a/railties/lib/rails/engine/configuration.rb b/railties/lib/rails/engine/configuration.rb index b69c0e1c53..7a07dcad7d 100644 --- a/railties/lib/rails/engine/configuration.rb +++ b/railties/lib/rails/engine/configuration.rb @@ -10,7 +10,6 @@ module Rails def initialize(root=nil) super() @root = root - @helpers_paths = [] end # Returns the middleware stack for the engine. @@ -39,27 +38,27 @@ module Rails def paths @paths ||= begin paths = Rails::Paths::Root.new(@root) - paths.app "app", :eager_load => true, :glob => "*" - paths.app.controllers "app/controllers", :eager_load => true - paths.app.helpers "app/helpers", :eager_load => true - paths.app.models "app/models", :eager_load => true - paths.app.mailers "app/mailers", :eager_load => true - paths.app.views "app/views" - paths.lib "lib", :load_path => true - paths.lib.tasks "lib/tasks", :glob => "**/*.rake" - paths.config "config" - 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.db.seeds "db/seeds.rb" + paths.add "app", :eager_load => true, :glob => "*" + paths.add "app/controllers", :eager_load => true + paths.add "app/helpers", :eager_load => true + paths.add "app/models", :eager_load => true + paths.add "app/mailers", :eager_load => true + paths.add "app/views" + paths.add "lib", :load_path => true + paths.add "lib/tasks", :glob => "**/*.rake" + paths.add "config" + paths.add "config/environments", :glob => "#{Rails.env}.rb" + paths.add "config/initializers", :glob => "**/*.rb" + paths.add "config/locales", :glob => "*.{rb,yml}" + paths.add "config/routes", :with => "config/routes.rb" + paths.add "db" + paths.add "db/migrate" + paths.add "db/seeds", :with => "db/seeds.rb" + paths.add "public" + paths.add "public/javascripts" + paths.add "public/stylesheets" + paths.add "vendor", :load_path => true + paths.add "vendor/plugins" paths end end diff --git a/railties/lib/rails/engine/railties.rb b/railties/lib/rails/engine/railties.rb index 389a7602c6..e91bdbf1e5 100644 --- a/railties/lib/rails/engine/railties.rb +++ b/railties/lib/rails/engine/railties.rb @@ -15,7 +15,7 @@ module Rails def plugins @plugins ||= begin plugin_names = (@config.plugins || [:all]).map { |p| p.to_sym } - Plugin.all(plugin_names, @config.paths.vendor.plugins) + Plugin.all(plugin_names, @config.paths["vendor/plugins"].existent) end end end diff --git a/railties/lib/rails/paths.rb b/railties/lib/rails/paths.rb index d303212f52..1729e8707e 100644 --- a/railties/lib/rails/paths.rb +++ b/railties/lib/rails/paths.rb @@ -2,15 +2,17 @@ require 'set' module Rails module Paths - module PathParent - attr_reader :children - + module PathParent #:nodoc: def method_missing(id, *args) - name = id.to_s + match = id.to_s.match(/^(.*)=$/) + full = [@current, $1 || id].compact.join("/") + + ActiveSupport::Deprecation.warn 'config.paths.app.controller API is deprecated in ' << + 'favor of config.paths["app/controller"] API.' - if name =~ /^(.*)=$/ || args.any? - @children[$1 || name] = Path.new(@root, *args) - elsif path = @children[name] + if match || args.any? + @root[full] = Path.new(@root, full, *args) + elsif path = @root[full] path else super @@ -18,22 +20,72 @@ module Rails end end - class Root + # This object is an extended hash that behaves as root of the Rails::Paths system. + # It allows you to collect information about how you want to structure your application + # paths by a Hash like API. It requires you to give a physical path on initialization. + # + # root = Root.new + # root.add "app/controllers", :eager_load => true + # + # The command above creates a new root object and add "app/controllers" as a path. + # This means we can get a Path object back like below: + # + # path = root["app/controllers"] + # path.eager_load? #=> true + # path.is_a?(Rails::Paths::Path) #=> true + # + # The Path object is simply an array and allows you to easily add extra paths: + # + # path.is_a?(Array) #=> true + # path.inspect #=> ["app/controllers"] + # + # path << "lib/controllers" + # path.inspect #=> ["app/controllers", "lib/controllers"] + # + # Notice that when you add a path using #add, the path object created already + # contains te path with the same path value given to #add. In some situations, + # you may not want this behavior, so you can give :with as option. + # + # root.add "config/routes", :with => "config/routes.rb" + # root["config/routes"].inspect #=> ["config/routes.rb"] + # + # #add also accepts the following options as argument: eager_load, autoload, + # autoload_once and glob. + # + # Finally, the Path object also provides a few helpers: + # + # root = Root.new + # root.path = "/rails" + # root.add "app/controllers" + # + # root["app/controllers"].expanded #=> ["/rails/app/controllers"] + # root["app/controllers"].existent #=> ["/rails/app/controllers"] + # + # Check the Path documentation for more information. + class Root < ::Hash include PathParent - attr_accessor :path def initialize(path) raise if path.is_a?(Array) - @children = {} + @current = nil @path = path @root = self - @all_paths = [] + super() + end + + def []=(path, value) + value = Path.new(self, path, value) unless value.is_a?(Path) + super(path, value) + end + + def add(path, options={}) + with = options[:with] || path + self[path] = Path.new(self, path, with, options) end def all_paths - @all_paths.uniq! - @all_paths + values.tap { |v| v.uniq! } end def autoload_once @@ -52,68 +104,54 @@ module Rails filter_by(:load_path?) end - def push(*) - raise "Application root can only have one physical path" - end - - alias unshift push - alias << push - alias concat push - protected def filter_by(constraint) all = [] all_paths.each do |path| if path.send(constraint) - paths = path.paths - paths -= path.children.values.map { |p| p.send(constraint) ? [] : p.paths }.flatten + paths = path.existent + paths -= path.children.map { |p| p.send(constraint) ? [] : p.existent }.flatten all.concat(paths) end end all.uniq! - all.reject! { |p| !File.exists?(p) } all end end - class Path - include PathParent, Enumerable + class Path < Array + include PathParent attr_reader :path attr_accessor :glob - def initialize(root, *paths) - options = paths.last.is_a?(::Hash) ? paths.pop : {} - @children = {} + def initialize(root, current, *paths) + options = paths.last.is_a?(::Hash) ? paths.pop : {} + super(paths.flatten) + + @current = current @root = root - @paths = paths.flatten @glob = options[:glob] autoload_once! if options[:autoload_once] eager_load! if options[:eager_load] autoload! if options[:autoload] load_path! if options[:load_path] - - @root.all_paths << self - end - - def each - to_a.each { |p| yield p } end - def push(path) - @paths.push path + def children + keys = @root.keys.select { |k| k.include?(@current) } + keys.delete(@current) + @root.values_at(*keys.sort) end - alias << push - - def unshift(path) - @paths.unshift path + def first + expanded.first end - def concat(paths) - @paths.concat paths + def last + expanded.last end %w(autoload_once eager_load autoload load_path).each do |m| @@ -132,20 +170,36 @@ module Rails RUBY end - def paths + # Expands all paths against the root and return all unique values. + def expanded raise "You need to set a path root" unless @root.path + result = [] - result = @paths.map do |p| + each do |p| path = File.expand_path(p, @root.path) - @glob ? Dir[File.join(path, @glob)] : path + + if @glob + result.concat Dir[File.join(path, @glob)] + else + result << path + end end - result.flatten! result.uniq! result end - alias to_a paths + # Returns all expanded paths but only if they exist in the filesystem. + def existent + expanded.select { |f| File.exists?(f) } + end + + def paths + ActiveSupport::Deprecation.warn "paths is deprecated. Please call expand instead." + expanded + end + + alias to_a expanded end end end \ No newline at end of file diff --git a/railties/lib/rails/plugin.rb b/railties/lib/rails/plugin.rb index 5614624673..76fa76598c 100644 --- a/railties/lib/rails/plugin.rb +++ b/railties/lib/rails/plugin.rb @@ -62,13 +62,13 @@ module Rails end initializer :handle_lib_autoload, :before => :set_load_path do |app| - paths = if app.config.reload_plugins + autoload = if app.config.reload_plugins config.autoload_paths else config.autoload_once_paths end - paths.concat config.paths.lib.to_a + autoload.concat paths["lib"].existent end initializer :load_init_rb, :before => :load_config_initializers do |app| diff --git a/railties/lib/rails/tasks/railties.rake b/railties/lib/rails/tasks/railties.rake index 7cf31f84a0..0c1ee0f17a 100644 --- a/railties/lib/rails/tasks/railties.rake +++ b/railties/lib/rails/tasks/railties.rake @@ -2,7 +2,7 @@ namespace :railties do desc "Create symlinks to railties public directories in application's public directory." task :create_symlinks => :environment do paths = Rails.application.config.static_asset_paths.dup - app_public_path = Rails.application.config.paths.public.to_a.first + app_public_path = Rails.application.paths["public"].first paths.each do |mount_path, path| symlink_path = File.join(app_public_path, mount_path) -- cgit v1.2.3