diff options
19 files changed, 271 insertions, 9 deletions
@@ -11,6 +11,8 @@ end gem "rack", :git => "git://github.com/rack/rack.git" gem "rack-test", :git => "git://github.com/brynary/rack-test.git" +gem "sprockets", :git => "git://github.com/sstephenson/sprockets.git" + gem "rake", ">= 0.8.7" gem "mocha", ">= 0.9.8" diff --git a/actionpack/lib/abstract_controller/asset_paths.rb b/actionpack/lib/abstract_controller/asset_paths.rb index 9ca2fb742f..ad14cd6d87 100644 --- a/actionpack/lib/abstract_controller/asset_paths.rb +++ b/actionpack/lib/abstract_controller/asset_paths.rb @@ -3,7 +3,7 @@ module AbstractController extend ActiveSupport::Concern included do - config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir + config_accessor :asset_host, :asset_path, :assets_dir, :javascripts_dir, :stylesheets_dir, :use_sprockets end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/railtie.rb b/actionpack/lib/action_controller/railtie.rb index f0c29825ba..0dd13fa9bf 100644 --- a/actionpack/lib/action_controller/railtie.rb +++ b/actionpack/lib/action_controller/railtie.rb @@ -21,6 +21,7 @@ module ActionController paths = app.config.paths options = app.config.action_controller + options.use_sprockets ||= app.config.assets.enabled options.assets_dir ||= paths["public"].first options.javascripts_dir ||= paths["public/javascripts"].first options.stylesheets_dir ||= paths["public/stylesheets"].first diff --git a/actionpack/lib/action_view/helpers.rb b/actionpack/lib/action_view/helpers.rb index d338ce616a..cb1ab64121 100644 --- a/actionpack/lib/action_view/helpers.rb +++ b/actionpack/lib/action_view/helpers.rb @@ -22,6 +22,7 @@ module ActionView #:nodoc: autoload :RecordTagHelper autoload :SanitizeHelper autoload :ScriptaculousHelper + autoload :SprocketsHelper autoload :TagHelper autoload :TextHelper autoload :TranslationHelper @@ -52,6 +53,7 @@ module ActionView #:nodoc: include RecordTagHelper include SanitizeHelper include ScriptaculousHelper + include SprocketsHelper include TagHelper include TextHelper include TranslationHelper diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb index 82bbfcc7d2..ed95f1c018 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb @@ -86,7 +86,11 @@ module ActionView # javascript_path "http://www.railsapplication.com/js/xmlhr" # => http://www.railsapplication.com/js/xmlhr # javascript_path "http://www.railsapplication.com/js/xmlhr.js" # => http://www.railsapplication.com/js/xmlhr.js def javascript_path(source) - asset_paths.compute_public_path(source, 'javascripts', 'js') + if config.use_sprockets + sprockets_javascript_path(source) + else + asset_paths.compute_public_path(source, 'javascripts', 'js') + end end alias_method :path_to_javascript, :javascript_path # aliased to avoid conflicts with a javascript_path named route @@ -173,8 +177,12 @@ module ActionView # # javascript_include_tag :all, :cache => true, :recursive => true def javascript_include_tag(*sources) - @javascript_include ||= JavascriptIncludeTag.new(config, asset_paths) - @javascript_include.include_tag(*sources) + if config.use_sprockets + sprockets_javascript_include_tag(*sources) + else + @javascript_include ||= JavascriptIncludeTag.new(config, asset_paths) + @javascript_include.include_tag(*sources) + end end end diff --git a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb index a48c87b49a..a994afb65e 100644 --- a/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +++ b/actionpack/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb @@ -63,7 +63,11 @@ module ActionView # stylesheet_path "http://www.railsapplication.com/css/style" # => http://www.railsapplication.com/css/style # stylesheet_path "http://www.railsapplication.com/css/style.css" # => http://www.railsapplication.com/css/style.css def stylesheet_path(source) - asset_paths.compute_public_path(source, 'stylesheets', 'css') + if config.use_sprockets + sprockets_stylesheet_path(source) + else + asset_paths.compute_public_path(source, 'stylesheets', 'css') + end end alias_method :path_to_stylesheet, :stylesheet_path # aliased to avoid conflicts with a stylesheet_path named route @@ -136,8 +140,12 @@ module ActionView # stylesheet_link_tag :all, :concat => true # def stylesheet_link_tag(*sources) - @stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths) - @stylesheet_include.include_tag(*sources) + if config.use_sprockets + sprockets_stylesheet_link_tag(*sources) + else + @stylesheet_include ||= StylesheetIncludeTag.new(config, asset_paths) + @stylesheet_include.include_tag(*sources) + end end end diff --git a/actionpack/lib/action_view/helpers/sprockets_helper.rb b/actionpack/lib/action_view/helpers/sprockets_helper.rb new file mode 100644 index 0000000000..408a2030ab --- /dev/null +++ b/actionpack/lib/action_view/helpers/sprockets_helper.rb @@ -0,0 +1,85 @@ +require 'uri' + +module ActionView + module Helpers + module SprocketsHelper + def sprockets_javascript_path(source) + compute_sprockets_path source, 'assets', 'js' + end + + def sprockets_javascript_include_tag(source, options = {}) + options = { + 'type' => "text/javascript", + 'src' => sprockets_javascript_path(source) + }.merge(options.stringify_keys) + + content_tag 'script', "", options + end + + def sprockets_stylesheet_path(source) + compute_sprockets_path source, 'assets', 'css' + end + + def sprockets_stylesheet_link_tag(source, options = {}) + options = { + 'rel' => "stylesheet", + 'type' => "text/css", + 'media' => "screen", + 'href' => sprockets_stylesheet_path(source) + }.merge(options.stringify_keys) + + tag 'link', options + end + + private + def compute_sprockets_path(source, dir, default_ext) + source = source.to_s + + return source if URI.parse(source).host + + # Add /javscripts to relative paths + if source[0] != ?/ + source = "/#{dir}/#{source}" + end + + # Add default extension if there isn't one + if default_ext && File.extname(source).empty? + source = "#{source}.#{default_ext}" + end + + # Fingerprint url + if source =~ /^\/#{dir}\/(.+)/ + source = assets.path($1, config.perform_caching, dir) + end + + host = compute_asset_host(source) + + if controller.respond_to?(:request) && host && URI.parse(host).host + source = "#{controller.request.protocol}#{host}#{source}" + end + + source + end + + def compute_asset_host(source) + if host = config.asset_host + if host.is_a?(Proc) || host.respond_to?(:call) + case host.is_a?(Proc) ? host.arity : host.method(:call).arity + when 2 + request = controller.respond_to?(:request) && controller.request + host.call(source, request) + else + host.call(source) + end + else + (host =~ /%d/) ? host % (source.hash % 4) : host + end + end + end + + def assets + Rails.application.assets + end + end + end +end diff --git a/actionpack/test/fixtures/sprockets/app/javascripts/application.js b/actionpack/test/fixtures/sprockets/app/javascripts/application.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/javascripts/application.js diff --git a/actionpack/test/fixtures/sprockets/app/javascripts/dir/xmlhr.js b/actionpack/test/fixtures/sprockets/app/javascripts/dir/xmlhr.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/javascripts/dir/xmlhr.js diff --git a/actionpack/test/fixtures/sprockets/app/javascripts/xmlhr.js b/actionpack/test/fixtures/sprockets/app/javascripts/xmlhr.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/javascripts/xmlhr.js diff --git a/actionpack/test/fixtures/sprockets/app/stylesheets/application.css b/actionpack/test/fixtures/sprockets/app/stylesheets/application.css new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/stylesheets/application.css diff --git a/actionpack/test/fixtures/sprockets/app/stylesheets/dir/style.css b/actionpack/test/fixtures/sprockets/app/stylesheets/dir/style.css new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/stylesheets/dir/style.css diff --git a/actionpack/test/fixtures/sprockets/app/stylesheets/style.css b/actionpack/test/fixtures/sprockets/app/stylesheets/style.css new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/actionpack/test/fixtures/sprockets/app/stylesheets/style.css diff --git a/actionpack/test/template/sprockets_helper_test.rb b/actionpack/test/template/sprockets_helper_test.rb new file mode 100644 index 0000000000..67aee86d02 --- /dev/null +++ b/actionpack/test/template/sprockets_helper_test.rb @@ -0,0 +1,96 @@ +require 'abstract_unit' +require 'sprockets' + +class SprocketsHelperTest < ActionView::TestCase + tests ActionView::Helpers::SprocketsHelper + + attr_accessor :assets + + def setup + super + + @controller = BasicController.new + + @request = Class.new do + def protocol() 'http://' end + def ssl?() false end + def host_with_port() 'localhost' end + end.new + + @controller.request = @request + + @assets = Sprockets::Environment.new + @assets.paths << FIXTURES.join("sprockets/app/javascripts") + @assets.paths << FIXTURES.join("sprockets/app/stylesheets") + + config.perform_caching = true + end + + def url_for(*args) + "http://www.example.com" + end + + test "javascript path" do + assert_equal "/assets/application-d41d8cd98f00b204e9800998ecf8427e.js", + sprockets_javascript_path(:application) + + assert_equal "/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + sprockets_javascript_path("xmlhr") + assert_equal "/assets/dir/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js", + sprockets_javascript_path("dir/xmlhr.js") + + assert_equal "/dir/xmlhr.js", + sprockets_javascript_path("/dir/xmlhr") + + assert_equal "http://www.railsapplication.com/js/xmlhr", + sprockets_javascript_path("http://www.railsapplication.com/js/xmlhr") + assert_equal "http://www.railsapplication.com/js/xmlhr.js", + sprockets_javascript_path("http://www.railsapplication.com/js/xmlhr.js") + end + + test "javascript include tag" do + assert_equal '<script src="/assets/application-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + sprockets_javascript_include_tag(:application) + + assert_equal '<script src="/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + sprockets_javascript_include_tag("xmlhr") + assert_equal '<script src="/assets/xmlhr-d41d8cd98f00b204e9800998ecf8427e.js" type="text/javascript"></script>', + sprockets_javascript_include_tag("xmlhr.js") + assert_equal '<script src="http://www.railsapplication.com/xmlhr" type="text/javascript"></script>', + sprockets_javascript_include_tag("http://www.railsapplication.com/xmlhr") + end + + test "stylesheet path" do + assert_equal "/assets/application-d41d8cd98f00b204e9800998ecf8427e.css", + sprockets_stylesheet_path(:application) + + assert_equal "/assets/style-d41d8cd98f00b204e9800998ecf8427e.css", + sprockets_stylesheet_path("style") + assert_equal "/assets/dir/style-d41d8cd98f00b204e9800998ecf8427e.css", + sprockets_stylesheet_path("dir/style.css") + assert_equal "/dir/style.css", + sprockets_stylesheet_path("/dir/style.css") + + assert_equal "http://www.railsapplication.com/css/style", + sprockets_stylesheet_path("http://www.railsapplication.com/css/style") + assert_equal "http://www.railsapplication.com/css/style.css", + sprockets_stylesheet_path("http://www.railsapplication.com/css/style.css") + end + + test "stylesheet link tag" do + assert_equal '<link href="/assets/application-d41d8cd98f00b204e9800998ecf8427e.css" media="screen" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag(:application) + + assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="screen" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag("style") + assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="screen" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag("style.css") + + assert_equal '<link href="http://www.railsapplication.com/style.css" media="screen" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag("http://www.railsapplication.com/style.css") + assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="all" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag("style", :media => "all") + assert_equal '<link href="/assets/style-d41d8cd98f00b204e9800998ecf8427e.css" media="print" rel="stylesheet" type="text/css" />', + sprockets_stylesheet_link_tag("style", :media => "print") + end +end diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index 1b834275a7..66a1f88c61 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -137,6 +137,37 @@ module Rails @config ||= Application::Configuration.new(find_root_with_flag("config.ru", Dir.pwd)) end + def assets + @assets ||= build_asset_environment + end + + def build_asset_environment + return unless config.assets.enabled + require 'sprockets' + env = Sprockets::Environment.new(root.to_s) + env.static_root = File.join(root.join("public"), config.assets.prefix) + env + end + + initializer :add_sprockets_paths do |app| + if config.assets.enabled + paths = [ + "app/javascripts", + "app/stylesheets", + "vendor/plugins/*/app/javascripts", + "vendor/plugins/*/app/stylesheets", + "vendor/plugins/*/javascripts", + "vendor/plugins/*/stylesheets" + ] + config.assets.paths + + paths.each do |pattern| + Dir[app.root.join(pattern)].each do |dir| + app.assets.paths << dir + end + end + end + end + protected def default_asset_path diff --git a/railties/lib/rails/application/configuration.rb b/railties/lib/rails/application/configuration.rb index 23b0e765ae..4a042e0033 100644 --- a/railties/lib/rails/application/configuration.rb +++ b/railties/lib/rails/application/configuration.rb @@ -9,7 +9,8 @@ module Rails :filter_parameters, :helpers_paths, :logger, :preload_frameworks, :reload_plugins, :secret_token, :serve_static_assets, :session_options, - :time_zone, :whiny_nils, :force_ssl + :time_zone, :whiny_nils, :force_ssl, + :assets attr_writer :log_level @@ -29,6 +30,12 @@ module Rails @log_level = nil @middleware = app_middleware @generators = app_generators + + @assets = ActiveSupport::OrderedOptions.new + @assets.enabled = false + @assets.paths = [] + @assets.precompile = [] + @assets.prefix = "/assets" end def compiled_asset_path diff --git a/railties/lib/rails/application/finisher.rb b/railties/lib/rails/application/finisher.rb index a45b61c99c..be063e5f25 100644 --- a/railties/lib/rails/application/finisher.rb +++ b/railties/lib/rails/application/finisher.rb @@ -33,6 +33,21 @@ module Rails end end + initializer :add_sprockets_route do |app| + assets = config.assets + if assets.enabled + app.routes.append do + mount app.assets => assets.prefix + end + end + end + + initializer :set_sprockets_logger do |app| + if config.assets.enabled + app.assets.logger = Rails.logger + end + end + initializer :build_middleware_stack do build_middleware_stack end diff --git a/railties/lib/rails/tasks.rb b/railties/lib/rails/tasks.rb index af52014728..4d09b0c2c0 100644 --- a/railties/lib/rails/tasks.rb +++ b/railties/lib/rails/tasks.rb @@ -3,6 +3,7 @@ $VERBOSE = nil # Load Rails rakefile extensions %w( annotations + assets documentation framework log diff --git a/railties/lib/rails/tasks/assets.rake b/railties/lib/rails/tasks/assets.rake new file mode 100644 index 0000000000..396ce728a1 --- /dev/null +++ b/railties/lib/rails/tasks/assets.rake @@ -0,0 +1,6 @@ +namespace :assets do + task :compile => :environment do + assets = Rails.application.config.assets.precompile + Rails.application.assets.precompile(*assets) + end +end |