sprockets 2.12.5 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +296 -0
  3. data/LICENSE +2 -2
  4. data/README.md +235 -262
  5. data/bin/sprockets +1 -0
  6. data/lib/rake/sprocketstask.rb +5 -4
  7. data/lib/sprockets/asset.rb +143 -212
  8. data/lib/sprockets/autoload/closure.rb +7 -0
  9. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  10. data/lib/sprockets/autoload/eco.rb +7 -0
  11. data/lib/sprockets/autoload/ejs.rb +7 -0
  12. data/lib/sprockets/autoload/sass.rb +7 -0
  13. data/lib/sprockets/autoload/uglifier.rb +7 -0
  14. data/lib/sprockets/autoload/yui.rb +7 -0
  15. data/lib/sprockets/autoload.rb +11 -0
  16. data/lib/sprockets/base.rb +56 -393
  17. data/lib/sprockets/bower.rb +58 -0
  18. data/lib/sprockets/bundle.rb +69 -0
  19. data/lib/sprockets/cache/file_store.rb +168 -14
  20. data/lib/sprockets/cache/memory_store.rb +66 -0
  21. data/lib/sprockets/cache/null_store.rb +46 -0
  22. data/lib/sprockets/cache.rb +236 -0
  23. data/lib/sprockets/cached_environment.rb +69 -0
  24. data/lib/sprockets/closure_compressor.rb +35 -10
  25. data/lib/sprockets/coffee_script_processor.rb +25 -0
  26. data/lib/sprockets/coffee_script_template.rb +17 -0
  27. data/lib/sprockets/compressing.rb +44 -23
  28. data/lib/sprockets/configuration.rb +83 -0
  29. data/lib/sprockets/context.rb +86 -144
  30. data/lib/sprockets/dependencies.rb +73 -0
  31. data/lib/sprockets/deprecation.rb +90 -0
  32. data/lib/sprockets/digest_utils.rb +180 -0
  33. data/lib/sprockets/directive_processor.rb +207 -211
  34. data/lib/sprockets/eco_processor.rb +32 -0
  35. data/lib/sprockets/eco_template.rb +9 -30
  36. data/lib/sprockets/ejs_processor.rb +31 -0
  37. data/lib/sprockets/ejs_template.rb +9 -29
  38. data/lib/sprockets/encoding_utils.rb +261 -0
  39. data/lib/sprockets/engines.rb +53 -35
  40. data/lib/sprockets/environment.rb +17 -64
  41. data/lib/sprockets/erb_processor.rb +30 -0
  42. data/lib/sprockets/erb_template.rb +11 -0
  43. data/lib/sprockets/errors.rb +4 -13
  44. data/lib/sprockets/file_reader.rb +15 -0
  45. data/lib/sprockets/http_utils.rb +117 -0
  46. data/lib/sprockets/jst_processor.rb +35 -15
  47. data/lib/sprockets/legacy.rb +330 -0
  48. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  49. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  50. data/lib/sprockets/loader.rb +325 -0
  51. data/lib/sprockets/manifest.rb +202 -127
  52. data/lib/sprockets/manifest_utils.rb +45 -0
  53. data/lib/sprockets/mime.rb +112 -31
  54. data/lib/sprockets/path_dependency_utils.rb +85 -0
  55. data/lib/sprockets/path_digest_utils.rb +47 -0
  56. data/lib/sprockets/path_utils.rb +287 -0
  57. data/lib/sprockets/paths.rb +42 -19
  58. data/lib/sprockets/processing.rb +178 -126
  59. data/lib/sprockets/processor_utils.rb +180 -0
  60. data/lib/sprockets/resolve.rb +211 -0
  61. data/lib/sprockets/sass_cache_store.rb +22 -17
  62. data/lib/sprockets/sass_compressor.rb +39 -15
  63. data/lib/sprockets/sass_functions.rb +2 -70
  64. data/lib/sprockets/sass_importer.rb +2 -30
  65. data/lib/sprockets/sass_processor.rb +292 -0
  66. data/lib/sprockets/sass_template.rb +12 -59
  67. data/lib/sprockets/server.rb +129 -84
  68. data/lib/sprockets/transformers.rb +145 -0
  69. data/lib/sprockets/uglifier_compressor.rb +39 -12
  70. data/lib/sprockets/unloaded_asset.rb +137 -0
  71. data/lib/sprockets/uri_tar.rb +98 -0
  72. data/lib/sprockets/uri_utils.rb +188 -0
  73. data/lib/sprockets/utils/gzip.rb +67 -0
  74. data/lib/sprockets/utils.rb +210 -44
  75. data/lib/sprockets/version.rb +1 -1
  76. data/lib/sprockets/yui_compressor.rb +39 -11
  77. data/lib/sprockets.rb +142 -81
  78. metadata +96 -90
  79. data/lib/sprockets/asset_attributes.rb +0 -137
  80. data/lib/sprockets/bundled_asset.rb +0 -78
  81. data/lib/sprockets/caching.rb +0 -96
  82. data/lib/sprockets/charset_normalizer.rb +0 -41
  83. data/lib/sprockets/index.rb +0 -100
  84. data/lib/sprockets/processed_asset.rb +0 -152
  85. data/lib/sprockets/processor.rb +0 -32
  86. data/lib/sprockets/safety_colons.rb +0 -28
  87. data/lib/sprockets/scss_template.rb +0 -13
  88. data/lib/sprockets/static_asset.rb +0 -60
@@ -0,0 +1,85 @@
1
+ require 'set'
2
+ require 'sprockets/path_utils'
3
+ require 'sprockets/uri_utils'
4
+
5
+ module Sprockets
6
+ # Internal: Related PathUtils helpers that also track all the file system
7
+ # calls they make for caching purposes. All functions return a standard
8
+ # return value and a Set of cache dependency URIs that can be used in the
9
+ # future to see if the returned value should be invalidated from cache.
10
+ #
11
+ # entries_with_dependencies("app/assets/javascripts")
12
+ # # => [
13
+ # # ["application.js", "projects.js", "users.js", ...]
14
+ # # #<Set: {"file-digest:/path/to/app/assets/javascripts"}>
15
+ # # ]
16
+ #
17
+ # The returned dependency set can be passed to resolve_dependencies(deps)
18
+ # to check if the returned result is still fresh. In this case, entry always
19
+ # returns a single path, but multiple calls should accumulate dependencies
20
+ # into a single set thats saved off and checked later.
21
+ #
22
+ # resolve_dependencies(deps)
23
+ # # => "\x01\x02\x03"
24
+ #
25
+ # Later, resolving the same set again will produce a different hash if
26
+ # something on the file system has changed.
27
+ #
28
+ # resolve_dependencies(deps)
29
+ # # => "\x03\x04\x05"
30
+ #
31
+ module PathDependencyUtils
32
+ include PathUtils
33
+ include URIUtils
34
+
35
+ # Internal: List directory entries and return a set of dependencies that
36
+ # would invalid the cached return result.
37
+ #
38
+ # See PathUtils#entries
39
+ #
40
+ # path - String directory path
41
+ #
42
+ # Returns an Array of entry names and a Set of dependency URIs.
43
+ def entries_with_dependencies(path)
44
+ return entries(path), file_digest_dependency_set(path)
45
+ end
46
+
47
+ # Internal: List directory filenames and associated Stats under a
48
+ # directory.
49
+ #
50
+ # See PathUtils#stat_directory
51
+ #
52
+ # dir - A String directory
53
+ #
54
+ # Returns an Array of filenames and a Set of dependency URIs.
55
+ def stat_directory_with_dependencies(dir)
56
+ return stat_directory(dir).to_a, file_digest_dependency_set(dir)
57
+ end
58
+
59
+ # Internal: Returns a set of dependencies for a particular path.
60
+ #
61
+ # path - String directory path
62
+ #
63
+ # Returns a Set of dependency URIs.
64
+ def file_digest_dependency_set(path)
65
+ Set.new([build_file_digest_uri(path)])
66
+ end
67
+
68
+ # Internal: List directory filenames and associated Stats under an entire
69
+ # directory tree.
70
+ #
71
+ # See PathUtils#stat_sorted_tree
72
+ #
73
+ # dir - A String directory
74
+ #
75
+ # Returns an Array of filenames and a Set of dependency URIs.
76
+ def stat_sorted_tree_with_dependencies(dir)
77
+ deps = Set.new([build_file_digest_uri(dir)])
78
+ results = stat_sorted_tree(dir).map do |path, stat|
79
+ deps << build_file_digest_uri(path) if stat.directory?
80
+ [path, stat]
81
+ end
82
+ return results, deps
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,47 @@
1
+ require 'sprockets/digest_utils'
2
+ require 'sprockets/path_utils'
3
+
4
+ module Sprockets
5
+ # Internal: Crossover of path and digest utilities functions.
6
+ module PathDigestUtils
7
+ include DigestUtils, PathUtils
8
+
9
+ # Internal: Compute digest for file stat.
10
+ #
11
+ # path - String filename
12
+ # stat - File::Stat
13
+ #
14
+ # Returns String digest bytes.
15
+ def stat_digest(path, stat)
16
+ if stat.directory?
17
+ # If its a directive, digest the list of filenames
18
+ digest_class.digest(self.entries(path).join(','))
19
+ elsif stat.file?
20
+ # If its a file, digest the contents
21
+ digest_class.file(path.to_s).digest
22
+ else
23
+ raise TypeError, "stat was not a directory or file: #{stat.ftype}"
24
+ end
25
+ end
26
+
27
+ # Internal: Compute digest for path.
28
+ #
29
+ # path - String filename or directory path.
30
+ #
31
+ # Returns String digest bytes or nil.
32
+ def file_digest(path)
33
+ if stat = self.stat(path)
34
+ self.stat_digest(path, stat)
35
+ end
36
+ end
37
+
38
+ # Internal: Compute digest for a set of paths.
39
+ #
40
+ # paths - Array of filename or directory paths.
41
+ #
42
+ # Returns String digest bytes.
43
+ def files_digest(paths)
44
+ self.digest(paths.map { |path| self.file_digest(path) })
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,287 @@
1
+ module Sprockets
2
+ # Internal: File and path related utilities. Mixed into Environment.
3
+ #
4
+ # Probably would be called FileUtils, but that causes namespace annoyances
5
+ # when code actually wants to reference ::FileUtils.
6
+ module PathUtils
7
+ extend self
8
+
9
+ # Public: Like `File.stat`.
10
+ #
11
+ # path - String file or directory path
12
+ #
13
+ # Returns nil if the file does not exist.
14
+ def stat(path)
15
+ if File.exist?(path)
16
+ File.stat(path.to_s)
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ # Public: Like `File.file?`.
23
+ #
24
+ # path - String file path.
25
+ #
26
+ # Returns true path exists and is a file.
27
+ def file?(path)
28
+ if stat = self.stat(path)
29
+ stat.file?
30
+ else
31
+ false
32
+ end
33
+ end
34
+
35
+ # Public: Like `File.directory?`.
36
+ #
37
+ # path - String file path.
38
+ #
39
+ # Returns true path exists and is a directory.
40
+ def directory?(path)
41
+ if stat = self.stat(path)
42
+ stat.directory?
43
+ else
44
+ false
45
+ end
46
+ end
47
+
48
+ # Public: A version of `Dir.entries` that filters out `.` files and `~`
49
+ # swap files.
50
+ #
51
+ # path - String directory path
52
+ #
53
+ # Returns an empty `Array` if the directory does not exist.
54
+ def entries(path)
55
+ if File.directory?(path)
56
+ entries = Dir.entries(path, :encoding => Encoding.default_internal)
57
+ entries.reject! { |entry|
58
+ entry.start_with?(".".freeze) ||
59
+ (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
60
+ entry.end_with?("~".freeze)
61
+ }
62
+ entries.sort!
63
+ else
64
+ []
65
+ end
66
+ end
67
+
68
+ # Public: Check if path is absolute or relative.
69
+ #
70
+ # path - String path.
71
+ #
72
+ # Returns true if path is absolute, otherwise false.
73
+ if File::ALT_SEPARATOR
74
+ require 'pathname'
75
+
76
+ # On Windows, ALT_SEPARATOR is \
77
+ # Delegate to Pathname since the logic gets complex.
78
+ def absolute_path?(path)
79
+ Pathname.new(path).absolute?
80
+ end
81
+ else
82
+ def absolute_path?(path)
83
+ path[0] == File::SEPARATOR
84
+ end
85
+ end
86
+
87
+ if File::ALT_SEPARATOR
88
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}|#{Regexp.quote(File::ALT_SEPARATOR)}"
89
+ else
90
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}"
91
+ end
92
+
93
+ # Public: Check if path is explicitly relative.
94
+ # Starts with "./" or "../".
95
+ #
96
+ # path - String path.
97
+ #
98
+ # Returns true if path is relative, otherwise false.
99
+ def relative_path?(path)
100
+ path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false
101
+ end
102
+
103
+ # Internal: Get relative path for root path and subpath.
104
+ #
105
+ # path - String path
106
+ # subpath - String subpath of path
107
+ #
108
+ # Returns relative String path if subpath is a subpath of path, or nil if
109
+ # subpath is outside of path.
110
+ def split_subpath(path, subpath)
111
+ return "" if path == subpath
112
+ path = File.join(path, '')
113
+ if subpath.start_with?(path)
114
+ subpath[path.length..-1]
115
+ else
116
+ nil
117
+ end
118
+ end
119
+
120
+ # Internal: Detect root path and base for file in a set of paths.
121
+ #
122
+ # paths - Array of String paths
123
+ # filename - String path of file expected to be in one of the paths.
124
+ #
125
+ # Returns [String root, String path]
126
+ def paths_split(paths, filename)
127
+ paths.each do |path|
128
+ if subpath = split_subpath(path, filename)
129
+ return path, subpath
130
+ end
131
+ end
132
+ nil
133
+ end
134
+
135
+ # Internal: Get path's extensions.
136
+ #
137
+ # path - String
138
+ #
139
+ # Returns an Array of String extnames.
140
+ def path_extnames(path)
141
+ File.basename(path).scan(/\.[^.]+/)
142
+ end
143
+
144
+ # Internal: Match path extnames against available extensions.
145
+ #
146
+ # path - String
147
+ # extensions - Hash of String extnames to values
148
+ #
149
+ # Returns [String extname, Object value] or nil nothing matched.
150
+ def match_path_extname(path, extensions)
151
+ basename = File.basename(path)
152
+
153
+ i = basename.index('.'.freeze)
154
+ while i && i < basename.length - 1
155
+ extname = basename[i..-1]
156
+ if value = extensions[extname]
157
+ return extname, value
158
+ end
159
+
160
+ i = basename.index('.'.freeze, i+1)
161
+ end
162
+
163
+ nil
164
+ end
165
+
166
+ # Internal: Returns all parents for path
167
+ #
168
+ # path - String absolute filename or directory
169
+ # root - String path to stop at (default: system root)
170
+ #
171
+ # Returns an Array of String paths.
172
+ def path_parents(path, root = nil)
173
+ root = "#{root}#{File::SEPARATOR}" if root
174
+ parents = []
175
+
176
+ loop do
177
+ parent = File.dirname(path)
178
+ break if parent == path
179
+ break if root && !path.start_with?(root)
180
+ parents << path = parent
181
+ end
182
+
183
+ parents
184
+ end
185
+
186
+ # Internal: Find target basename checking upwards from path.
187
+ #
188
+ # basename - String filename: ".sprocketsrc"
189
+ # path - String path to start search: "app/assets/javascripts/app.js"
190
+ # root - String path to stop at (default: system root)
191
+ #
192
+ # Returns String filename or nil.
193
+ def find_upwards(basename, path, root = nil)
194
+ path_parents(path, root).each do |dir|
195
+ filename = File.join(dir, basename)
196
+ return filename if file?(filename)
197
+ end
198
+ nil
199
+ end
200
+
201
+ # Public: Stat all the files under a directory.
202
+ #
203
+ # dir - A String directory
204
+ #
205
+ # Returns an Enumerator of [path, stat].
206
+ def stat_directory(dir)
207
+ return to_enum(__method__, dir) unless block_given?
208
+
209
+ self.entries(dir).each do |entry|
210
+ path = File.join(dir, entry)
211
+ if stat = self.stat(path)
212
+ yield path, stat
213
+ end
214
+ end
215
+
216
+ nil
217
+ end
218
+
219
+ # Public: Recursive stat all the files under a directory.
220
+ #
221
+ # dir - A String directory
222
+ #
223
+ # Returns an Enumerator of [path, stat].
224
+ def stat_tree(dir, &block)
225
+ return to_enum(__method__, dir) unless block_given?
226
+
227
+ self.stat_directory(dir) do |path, stat|
228
+ yield path, stat
229
+
230
+ if stat.directory?
231
+ stat_tree(path, &block)
232
+ end
233
+ end
234
+
235
+ nil
236
+ end
237
+
238
+ # Public: Recursive stat all the files under a directory in alphabetical
239
+ # order.
240
+ #
241
+ # dir - A String directory
242
+ #
243
+ # Returns an Enumerator of [path, stat].
244
+ def stat_sorted_tree(dir, &block)
245
+ return to_enum(__method__, dir) unless block_given?
246
+
247
+ self.stat_directory(dir).sort_by { |path, stat|
248
+ stat.directory? ? "#{path}/" : path
249
+ }.each do |path, stat|
250
+ yield path, stat
251
+
252
+ if stat.directory?
253
+ stat_sorted_tree(path, &block)
254
+ end
255
+ end
256
+
257
+ nil
258
+ end
259
+
260
+ # Public: Write to a file atomically. Useful for situations where you
261
+ # don't want other processes or threads to see half-written files.
262
+ #
263
+ # Utils.atomic_write('important.file') do |file|
264
+ # file.write('hello')
265
+ # end
266
+ #
267
+ # Returns nothing.
268
+ def atomic_write(filename)
269
+ dirname, basename = File.split(filename)
270
+ basename = [
271
+ basename,
272
+ Thread.current.object_id,
273
+ Process.pid,
274
+ rand(1000000)
275
+ ].join('.')
276
+ tmpname = File.join(dirname, basename)
277
+
278
+ File.open(tmpname, 'wb+') do |f|
279
+ yield f
280
+ end
281
+
282
+ File.rename(tmpname, filename)
283
+ ensure
284
+ File.delete(tmpname) if File.exist?(tmpname)
285
+ end
286
+ end
287
+ end
@@ -1,36 +1,53 @@
1
+ require 'sprockets/path_utils'
2
+ require 'sprockets/utils'
3
+
1
4
  module Sprockets
2
5
  module Paths
6
+ include PathUtils, Utils
7
+
3
8
  # Returns `Environment` root.
4
9
  #
5
10
  # All relative paths are expanded with root as its base. To be
6
11
  # useful set this to your applications root directory. (`Rails.root`)
7
12
  def root
8
- @trail.root.dup
13
+ config[:root]
14
+ end
15
+
16
+ # Internal: Change Environment root.
17
+ #
18
+ # Only the initializer should change the root.
19
+ def root=(path)
20
+ self.config = hash_reassoc(config, :root) do
21
+ File.expand_path(path)
22
+ end
9
23
  end
24
+ private :root=
10
25
 
11
26
  # Returns an `Array` of path `String`s.
12
27
  #
13
28
  # These paths will be used for asset logical path lookups.
14
- #
15
- # Note that a copy of the `Array` is returned so mutating will
16
- # have no affect on the environment. See `append_path`,
17
- # `prepend_path`, and `clear_paths`.
18
29
  def paths
19
- @trail.paths.dup
30
+ config[:paths]
20
31
  end
21
32
 
22
33
  # Prepend a `path` to the `paths` list.
23
34
  #
24
35
  # Paths at the end of the `Array` have the least priority.
25
36
  def prepend_path(path)
26
- @trail.prepend_path(path)
37
+ self.config = hash_reassoc(config, :paths) do |paths|
38
+ path = File.expand_path(path, config[:root]).freeze
39
+ paths.unshift(path)
40
+ end
27
41
  end
28
42
 
29
43
  # Append a `path` to the `paths` list.
30
44
  #
31
45
  # Paths at the beginning of the `Array` have a higher priority.
32
46
  def append_path(path)
33
- @trail.append_path(path)
47
+ self.config = hash_reassoc(config, :paths) do |paths|
48
+ path = File.expand_path(path, config[:root]).freeze
49
+ paths.push(path)
50
+ end
34
51
  end
35
52
 
36
53
  # Clear all paths and start fresh.
@@ -39,20 +56,26 @@ module Sprockets
39
56
  # completely wipe the paths list and reappend them in the order
40
57
  # you want.
41
58
  def clear_paths
42
- @trail.paths.dup.each { |path| @trail.remove_path(path) }
59
+ self.config = hash_reassoc(config, :paths) do |paths|
60
+ paths.clear
61
+ end
43
62
  end
44
63
 
45
- # Returns an `Array` of extensions.
64
+ # Public: Iterate over every file under all load paths.
46
65
  #
47
- # These extensions maybe omitted from logical path searches.
48
- #
49
- # # => [".js", ".css", ".coffee", ".sass", ...]
50
- #
51
- def extensions
52
- @trail.extensions.dup
53
- end
66
+ # Returns Enumerator if no block is given.
67
+ def each_file
68
+ return to_enum(__method__) unless block_given?
54
69
 
55
- protected
56
- attr_reader :trail
70
+ paths.each do |root|
71
+ stat_tree(root).each do |filename, stat|
72
+ if stat.file?
73
+ yield filename
74
+ end
75
+ end
76
+ end
77
+
78
+ nil
79
+ end
57
80
  end
58
81
  end