turbo-sprockets-rails3-envaware 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +117 -0
  4. data/Rakefile +28 -0
  5. data/lib/sprockets/asset_with_dependencies.rb +134 -0
  6. data/lib/sprockets/static_non_digest_generator.rb +106 -0
  7. data/lib/sprockets/unprocessed_asset.rb +39 -0
  8. data/lib/turbo-sprockets-rails3.rb +15 -0
  9. data/lib/turbo-sprockets/helpers.rb +9 -0
  10. data/lib/turbo-sprockets/railtie.rb +26 -0
  11. data/lib/turbo-sprockets/sprockets_overrides/asset.rb +31 -0
  12. data/lib/turbo-sprockets/sprockets_overrides/base.rb +38 -0
  13. data/lib/turbo-sprockets/sprockets_overrides/bundled_asset.rb +33 -0
  14. data/lib/turbo-sprockets/sprockets_overrides/environment.rb +21 -0
  15. data/lib/turbo-sprockets/sprockets_overrides/index.rb +30 -0
  16. data/lib/turbo-sprockets/sprockets_overrides/processed_asset.rb +29 -0
  17. data/lib/turbo-sprockets/sprockets_overrides/static_compiler.rb +94 -0
  18. data/lib/turbo-sprockets/tasks/assets.rake +204 -0
  19. data/lib/turbo-sprockets/version.rb +3 -0
  20. data/test/abstract_unit.rb +143 -0
  21. data/test/assets_debugging_test.rb +65 -0
  22. data/test/assets_test.rb +542 -0
  23. data/test/fixtures/alternate/stylesheets/style.css +1 -0
  24. data/test/fixtures/app/fonts/dir/font.ttf +0 -0
  25. data/test/fixtures/app/fonts/font.ttf +0 -0
  26. data/test/fixtures/app/images/logo.png +0 -0
  27. data/test/fixtures/app/javascripts/application.js +1 -0
  28. data/test/fixtures/app/javascripts/dir/xmlhr.js +0 -0
  29. data/test/fixtures/app/javascripts/extra.js +0 -0
  30. data/test/fixtures/app/javascripts/foo.min.js +0 -0
  31. data/test/fixtures/app/javascripts/xmlhr.js +0 -0
  32. data/test/fixtures/app/stylesheets/application.css +1 -0
  33. data/test/fixtures/app/stylesheets/dir/style.css +0 -0
  34. data/test/fixtures/app/stylesheets/extra.css +0 -0
  35. data/test/fixtures/app/stylesheets/style.css +0 -0
  36. data/test/fixtures/app/stylesheets/style.ext +0 -0
  37. data/test/fixtures/app/stylesheets/style.min.css +0 -0
  38. data/test/sprockets_helper_test.rb +363 -0
  39. data/test/sprockets_helper_with_routes_test.rb +57 -0
  40. data/test/sprockets_helpers_abstract_unit.rb +358 -0
  41. metadata +139 -0
@@ -0,0 +1,15 @@
1
+ require 'sprockets/railtie'
2
+
3
+ module Sprockets
4
+ # Assets
5
+ autoload :UnprocessedAsset, "sprockets/unprocessed_asset"
6
+ autoload :AssetWithDependencies, "sprockets/asset_with_dependencies"
7
+ end
8
+
9
+ require 'sprockets'
10
+ Dir[File.expand_path('../turbo-sprockets/sprockets_overrides/*.rb', __FILE__)].each do |f|
11
+ require f
12
+ end
13
+
14
+ require 'turbo-sprockets/helpers'
15
+ require 'turbo-sprockets/railtie'
@@ -0,0 +1,9 @@
1
+ module TurboSprockets
2
+ def self.get_source_manifest_path(manifest_dir, filename="sources_manifest.yml")
3
+ "#{manifest_dir}/#{get_source_manifest_filename(filename)}"
4
+ end
5
+
6
+ def self.get_source_manifest_filename(filename="sources_manifest.yml")
7
+ ENV['RAILS_ENV'] ? "#{ENV['RAILS_ENV'].downcase}_#{filename}" : filename
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ require "action_controller/railtie"
2
+
3
+ module Sprockets
4
+ autoload :StaticNonDigestGenerator, "sprockets/static_non_digest_generator"
5
+ end
6
+
7
+ module TurboSprockets
8
+ class Railtie < ::Rails::Railtie
9
+ rake_tasks do
10
+ load "turbo-sprockets/tasks/assets.rake"
11
+ end
12
+
13
+ initializer "turbo-sprockets.environment", :after => "sprockets.environment", :group => :all do |app|
14
+ config = app.config
15
+
16
+ manifest_dir = config.assets.manifest || File.join(Rails.public_path, config.assets.prefix)
17
+ digests_manifest = File.join(manifest_dir, "manifest.yml")
18
+ sources_manifest = File.join(TurboSprockets.get_source_manifest_path(manifest_dir))
19
+ config.assets.digests = (File.exist?(digests_manifest) && YAML.load_file(digests_manifest)) || {}
20
+ config.assets.source_digests = (File.exist?(sources_manifest) && YAML.load_file(sources_manifest)) || {}
21
+
22
+ # Clear digests if loading previous manifest format
23
+ config.assets.digests = {} if config.assets.digests[:digest_files]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ require 'sprockets/asset'
2
+
3
+ module Sprockets
4
+ Asset.class_eval do
5
+ # Internal initializer to load `Asset` from serialized `Hash`.
6
+ def self.from_hash(environment, hash)
7
+ return unless hash.is_a?(Hash)
8
+
9
+ klass = case hash['class']
10
+ when 'BundledAsset'
11
+ BundledAsset
12
+ when 'ProcessedAsset'
13
+ ProcessedAsset
14
+ when 'UnprocessedAsset'
15
+ UnprocessedAsset
16
+ when 'StaticAsset'
17
+ StaticAsset
18
+ else
19
+ nil
20
+ end
21
+
22
+ if klass
23
+ asset = klass.allocate
24
+ asset.init_with(environment, hash)
25
+ asset
26
+ end
27
+ rescue UnserializeError
28
+ nil
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ require 'sprockets/base'
2
+
3
+ module Sprockets
4
+ Base.class_eval do
5
+ protected
6
+
7
+ def build_asset(logical_path, pathname, options)
8
+ pathname = Pathname.new(pathname)
9
+
10
+ # If there are any processors to run on the pathname, use
11
+ # `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.
12
+ if attributes_for(pathname).processors.any?
13
+ if options[:bundle] == false
14
+ circular_call_protection(pathname.to_s) do
15
+ if options[:process] == false
16
+ UnprocessedAsset.new(index, logical_path, pathname)
17
+ else
18
+ ProcessedAsset.new(index, logical_path, pathname)
19
+ end
20
+ end
21
+ else
22
+ BundledAsset.new(index, logical_path, pathname, options)
23
+ end
24
+ else
25
+ StaticAsset.new(index, logical_path, pathname)
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def cache_key_for(path, options)
32
+ options[:process] = true unless options.key?(:process)
33
+ key = "#{path}:#{options[:bundle] ? '1' : '0'}"
34
+ key << ":0" unless options[:process]
35
+ key
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,33 @@
1
+ require 'sprockets/bundled_asset'
2
+
3
+ module Sprockets
4
+ BundledAsset.class_eval do
5
+
6
+ # Adds :process options
7
+
8
+ def initialize(environment, logical_path, pathname, options = {})
9
+ super(environment, logical_path, pathname)
10
+ @process = options.fetch(:process, true)
11
+
12
+ @processed_asset = environment.find_asset(pathname, :bundle => false, :process => @process)
13
+ @required_assets = @processed_asset.required_assets
14
+ @dependency_paths = @processed_asset.dependency_paths
15
+
16
+ @source = ""
17
+
18
+ # Explode Asset into parts and gather the dependency bodies
19
+ to_a.each { |dependency| @source << dependency.to_s }
20
+
21
+ if @process
22
+ # Run bundle processors on concatenated source
23
+ context = environment.context_class.new(environment, logical_path, pathname)
24
+ @source = context.evaluate(pathname, :data => @source,
25
+ :processors => environment.bundle_processors(content_type))
26
+ end
27
+
28
+ @mtime = to_a.map(&:mtime).max
29
+ @length = Rack::Utils.bytesize(source)
30
+ @digest = environment.digest.update(source).hexdigest
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,21 @@
1
+ require 'sprockets/environment'
2
+
3
+ module Sprockets
4
+ Environment.class_eval do
5
+
6
+ # Adds :process options
7
+
8
+ def find_asset(path, options = {})
9
+ options[:bundle] = true unless options.key?(:bundle)
10
+ options[:process] = true unless options.key?(:process)
11
+
12
+ # Ensure in-memory cached assets are still fresh on every lookup
13
+ if (asset = @assets[cache_key_for(path, options)]) && asset.fresh?(self)
14
+ asset
15
+ elsif asset = index.find_asset(path, options)
16
+ # Cache is pushed upstream by Index#find_asset
17
+ asset
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ require 'sprockets/index'
2
+
3
+ module Sprockets
4
+ Index.class_eval do
5
+
6
+ # Adds :process options
7
+
8
+ def find_asset(path, options = {})
9
+ options[:bundle] = true unless options.key?(:bundle)
10
+ options[:process] = true unless options.key?(:process)
11
+
12
+ if asset = @assets[cache_key_for(path, options)]
13
+ asset
14
+ elsif asset = super
15
+ logical_path_cache_key = cache_key_for(path, options)
16
+ full_path_cache_key = cache_key_for(asset.pathname, options)
17
+
18
+ # Cache on Index
19
+ @assets[logical_path_cache_key] = @assets[full_path_cache_key] = asset
20
+
21
+ # Push cache upstream to Environment
22
+ @environment.instance_eval do
23
+ @assets[logical_path_cache_key] = @assets[full_path_cache_key] = asset
24
+ end
25
+
26
+ asset
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,29 @@
1
+ require 'sprockets/processed_asset'
2
+
3
+ module Sprockets
4
+
5
+ # Remove and redefine ProcessedAsset to inherit from AssetWithDependencies
6
+
7
+ remove_const :ProcessedAsset
8
+
9
+ class ProcessedAsset < AssetWithDependencies
10
+ def initialize(environment, logical_path, pathname)
11
+ super
12
+
13
+ start_time = Time.now.to_f
14
+
15
+ context = environment.context_class.new(environment, logical_path, pathname)
16
+ @source = context.evaluate(pathname)
17
+ @length = Rack::Utils.bytesize(source)
18
+ @digest = environment.digest.update(source).hexdigest
19
+
20
+ build_required_assets(environment, context)
21
+ build_dependency_paths(environment, context)
22
+
23
+ @dependency_digest = compute_dependency_digest(environment)
24
+
25
+ elapsed_time = ((Time.now.to_f - start_time) * 1000).to_i
26
+ environment.logger.info "Compiled #{logical_path} (#{elapsed_time}ms) (pid #{Process.pid})"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,94 @@
1
+ begin
2
+ require 'sprockets/static_compiler'
3
+ rescue LoadError
4
+ end
5
+
6
+ # Sprockets::StaticCompiler was only introduced in Rails 3.2.x
7
+ if defined?(Sprockets::StaticCompiler)
8
+ module Sprockets
9
+ StaticCompiler.class_eval do
10
+ def initialize(env, target, paths, options = {})
11
+ @env = env
12
+ @target = target
13
+ @paths = paths
14
+ @digest = options.fetch(:digest, true)
15
+ @manifest = options.fetch(:manifest, true)
16
+ @manifest_path = options.delete(:manifest_path) || target
17
+ @zip_files = options.delete(:zip_files) || /\.(?:css|html|js|svg|txt|xml)$/
18
+
19
+ @current_source_digests = options.fetch(:source_digests, {})
20
+ @current_digests = options.fetch(:digests, {})
21
+
22
+ @digests = {}
23
+ @source_digests = {}
24
+ end
25
+
26
+ def compile
27
+ start_time = Time.now.to_f
28
+
29
+ env.each_logical_path(paths) do |logical_path|
30
+ # Fetch asset without any processing or compression,
31
+ # to calculate a digest of the concatenated source files
32
+ next unless asset = env.find_asset(logical_path, :process => false)
33
+ @source_digests[logical_path] = asset.digest
34
+
35
+ # Recompile if digest has changed or compiled digest file is missing
36
+ current_digest_file = @current_digests[logical_path]
37
+
38
+ if @source_digests[logical_path] != @current_source_digests[logical_path] ||
39
+ !(current_digest_file && File.exists?("#{@target}/#{current_digest_file}"))
40
+
41
+ if asset = env.find_asset(logical_path)
42
+ digest_path = write_asset(asset)
43
+ @digests[asset.logical_path] = digest_path
44
+ @digests[aliased_path_for(asset.logical_path)] = digest_path
45
+ # Update current_digests with new hash, for future assets to reference
46
+ @current_digests[asset.logical_path] = asset.digest_path
47
+ end
48
+ else
49
+ # Set asset file from manifest.yml
50
+ digest_path = @current_digests[logical_path]
51
+ @digests[logical_path] = digest_path
52
+ @digests[aliased_path_for(logical_path)] = digest_path
53
+
54
+ env.logger.debug "Not compiling #{logical_path}, sources digest has not changed " <<
55
+ "(#{@source_digests[logical_path][0...7]})"
56
+ end
57
+ end
58
+
59
+ # Encode all filenames & digests as UTF-8 for Ruby 1.9,
60
+ # otherwise YAML dumps other string encodings as !binary
61
+ if RUBY_VERSION.to_f >= 1.9
62
+ @source_digests = encode_hash_as_utf8 @source_digests
63
+ @digests = encode_hash_as_utf8 @digests
64
+ end
65
+
66
+ if @manifest
67
+ write_manifest(@digests)
68
+ write_sources_manifest(@source_digests)
69
+ end
70
+
71
+ # Store digests in Rails config. (Important if non-digest is run after primary)
72
+ config = ::Rails.application.config
73
+ config.assets.digests = @digests
74
+ config.assets.source_digests = @source_digests
75
+
76
+ elapsed_time = ((Time.now.to_f - start_time) * 1000).to_i
77
+ env.logger.debug "Processed #{'non-' unless @digest}digest assets in #{elapsed_time}ms"
78
+ end
79
+
80
+ def write_sources_manifest(source_digests)
81
+ FileUtils.mkdir_p(@manifest_path)
82
+ File.open(TurboSprockets.get_source_manifest_path(@manifest_path), 'wb') do |f|
83
+ YAML.dump(source_digests, f)
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def encode_hash_as_utf8(hash)
90
+ Hash[*hash.map {|k,v| [k.encode("UTF-8"), v.encode("UTF-8")] }.flatten]
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,204 @@
1
+ require "fileutils"
2
+ require 'shellwords'
3
+
4
+ # Clear all assets tasks from sprockets railtie,
5
+ # but preserve any extra actions added via 'enhance'
6
+ task_enhancements = {}
7
+ Rake::Task.tasks.each do |task|
8
+ if task.name.match '^assets:'
9
+ task_enhancements[task.name] = task.actions[1..-1] if task.actions.size > 1
10
+ task.clear
11
+ end
12
+ end
13
+
14
+ # Replace with our extended assets tasks
15
+ namespace :assets do
16
+ def ruby_rake_task(task, fork = true)
17
+ env = ENV['RAILS_ENV'] || 'production'
18
+ groups = ENV['RAILS_GROUPS'] || 'assets'
19
+ args = [$0, task,"RAILS_ENV=#{env}","RAILS_GROUPS=#{groups}"]
20
+ args << "--trace" if Rake.application.options.trace
21
+ if $0 =~ /rake\.bat\Z/i
22
+ Kernel.exec $0, *args
23
+ else
24
+ fork ? ruby(*args) : Kernel.exec(FileUtils::RUBY, *args)
25
+ end
26
+ end
27
+
28
+ # We are currently running with no explicit bundler group
29
+ # and/or no explicit environment - we have to reinvoke rake to
30
+ # execute this task.
31
+ def invoke_or_reboot_rake_task(task)
32
+ if ENV['RAILS_GROUPS'].to_s.empty? || ENV['RAILS_ENV'].to_s.empty?
33
+ ruby_rake_task task
34
+ else
35
+ Rake::Task[task].invoke
36
+ end
37
+ end
38
+
39
+ # Returns an array of assets recognized by config.assets.digests,
40
+ # including gzipped assets and manifests
41
+ def known_assets
42
+ assets = Rails.application.config.assets.digests.to_a.flatten.map do |asset|
43
+ [asset, "#{asset}.gz"]
44
+ end.flatten
45
+ assets + (%w(manifest.yml) << TurboSprockets.get_source_manifest_filename)
46
+ end
47
+
48
+ desc "Compile all the assets named in config.assets.precompile"
49
+ task :precompile do
50
+ invoke_or_reboot_rake_task "assets:precompile:all"
51
+ end
52
+
53
+ namespace :precompile do
54
+ def internal_precompile(digest=nil)
55
+ unless Rails.application.config.assets.enabled
56
+ warn "Cannot precompile assets if sprockets is disabled. Please set config.assets.enabled to true"
57
+ exit
58
+ end
59
+
60
+ # Ensure that action view is loaded and the appropriate
61
+ # sprockets hooks get executed
62
+ _ = ActionView::Base
63
+
64
+ config = Rails.application.config
65
+ config.assets.compile = true
66
+ config.assets.clean_after_precompile = false if config.assets.clean_after_precompile.nil?
67
+ config.assets.digest = digest unless digest.nil?
68
+ config.assets.digests ||= {}
69
+ config.assets.source_digests ||= {}
70
+ config.assets.handle_expiration = false if config.assets.handle_expiration.nil?
71
+
72
+ env = Rails.application.assets
73
+ target = File.join(::Rails.public_path, config.assets.prefix)
74
+
75
+ # This takes a long time to run if you aren't cleaning expired assets.
76
+ # You must call the assets:clean_expired rake task regularly if this is
77
+ # enabled
78
+ if config.assets.handle_expiration
79
+ # Before first compile, set the mtime of all current assets to current time.
80
+ # This time reflects the last time the assets were being used.
81
+ if digest.nil?
82
+ ::Rails.logger.debug "Updating mtimes for current assets..."
83
+ paths = known_assets.map { |asset| File.join(target, asset) }
84
+ paths.each_slice(100) do |slice|
85
+ # File.utime raises 'Operation not permitted' unless user is owner of file.
86
+ # Non-owners have permission to update mtime to the current time using 'touch'.
87
+ `touch -c #{slice.shelljoin}`
88
+ end
89
+ end
90
+ end
91
+
92
+ # If processing non-digest assets, and compiled digest files are
93
+ # present, then generate non-digest assets from existing assets.
94
+ # It is assumed that `assets:precompile:nondigest` won't be run manually
95
+ # if assets have been previously compiled with digests.
96
+ if !config.assets.digest && config.assets.digests.any?
97
+ generator = Sprockets::StaticNonDigestGenerator.new(env, target, config.assets.precompile,
98
+ :digests => config.assets.digests)
99
+ generator.generate
100
+ else
101
+ compiler = Sprockets::StaticCompiler.new(env, target, config.assets.precompile,
102
+ :digest => config.assets.digest,
103
+ :manifest => digest.nil?,
104
+ :manifest_path => config.assets.manifest,
105
+ :digests => config.assets.digests,
106
+ :source_digests => config.assets.source_digests
107
+ )
108
+ compiler.compile
109
+ end
110
+ end
111
+
112
+ task :all => ["assets:cache:clean"] do
113
+ # Other gems may want to add hooks to run after the 'assets:precompile:***' tasks.
114
+ # Since we aren't running separate rake tasks anymore, we manually invoke the extra actions.
115
+ internal_precompile
116
+ Rake::Task["assets:precompile:primary"].actions[1..-1].each &:call
117
+
118
+ if ::Rails.application.config.assets.digest
119
+ internal_precompile(false)
120
+ Rake::Task["assets:precompile:nondigest"].actions[1..-1].each &:call
121
+ end
122
+ end
123
+
124
+ task :primary => ["assets:cache:clean"] do
125
+ internal_precompile
126
+ end
127
+
128
+ task :nondigest => ["assets:cache:clean"] do
129
+ internal_precompile(false)
130
+ end
131
+ end
132
+
133
+ desc "Remove old assets that aren't referenced by manifest.yml"
134
+ task :clean_expired do
135
+ invoke_or_reboot_rake_task "assets:clean_expired:all"
136
+ end
137
+
138
+ # Remove assets that haven't been deployed since `config.assets.expire_after` (default 1 day).
139
+ # This provides a buffer between deploys, so that older assets can still be requested.
140
+ # The precompile task updates the mtime of the current assets before compiling,
141
+ # which indicates when they were last in use.
142
+ #
143
+ # The current assets are ignored, which is faster than the alternative of
144
+ # setting their mtimes only to check them again.
145
+ namespace :clean_expired do
146
+ task :all => ["assets:environment"] do
147
+ config = ::Rails.application.config
148
+ expire_after = config.assets.expire_after || 1.day
149
+ public_asset_path = File.join(::Rails.public_path, config.assets.prefix)
150
+
151
+ @known_assets = known_assets
152
+
153
+ Dir.glob(File.join(public_asset_path, '**/*')).each do |asset|
154
+ next if File.directory?(asset)
155
+ logical_path = asset.sub("#{public_asset_path}/", '')
156
+
157
+ unless logical_path.in?(@known_assets)
158
+ # Delete asset if not used for more than expire_after seconds
159
+ if File.mtime(asset) < (Time.now - expire_after)
160
+ ::Rails.logger.debug "Removing expired asset: #{logical_path}"
161
+ FileUtils.rm_f asset
162
+ end
163
+ end
164
+ end
165
+ end
166
+ end
167
+
168
+ desc "Remove compiled assets"
169
+ task :clean do
170
+ invoke_or_reboot_rake_task "assets:clean:all"
171
+ end
172
+
173
+ namespace :clean do
174
+ task :all => ["assets:cache:clean"] do
175
+ config = ::Rails.application.config
176
+ public_asset_path = File.join(::Rails.public_path, config.assets.prefix)
177
+ rm_rf public_asset_path, :secure => true
178
+ end
179
+ end
180
+
181
+ namespace :cache do
182
+ task :clean => ["assets:environment"] do
183
+ FileUtils.mkdir_p(File.join(::Rails.root.to_s, *%w(tmp cache assets)))
184
+ ::Rails.application.assets.cache.clear
185
+ end
186
+ end
187
+
188
+ task :environment do
189
+ if ::Rails.application.config.assets.initialize_on_precompile
190
+ Rake::Task["environment"].invoke
191
+ else
192
+ ::Rails.application.initialize!(:assets)
193
+ Sprockets::Bootstrap.new(Rails.application).run
194
+ end
195
+ end
196
+ end
197
+
198
+
199
+ # Append previous task enhancements to new Rake tasks.
200
+ task_enhancements.each do |task_name, actions|
201
+ actions.each do |proc|
202
+ Rake::Task[task_name].enhance &proc
203
+ end
204
+ end