sprockets 2.3.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sprockets might be problematic. Click here for more details.

Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +2 -2
  3. data/README.md +332 -115
  4. data/bin/sprockets +8 -0
  5. data/lib/rake/sprocketstask.rb +25 -13
  6. data/lib/sprockets/asset.rb +143 -205
  7. data/lib/sprockets/autoload/closure.rb +7 -0
  8. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  9. data/lib/sprockets/autoload/eco.rb +7 -0
  10. data/lib/sprockets/autoload/ejs.rb +7 -0
  11. data/lib/sprockets/autoload/sass.rb +7 -0
  12. data/lib/sprockets/autoload/uglifier.rb +7 -0
  13. data/lib/sprockets/autoload/yui.rb +7 -0
  14. data/lib/sprockets/autoload.rb +11 -0
  15. data/lib/sprockets/base.rb +49 -257
  16. data/lib/sprockets/bower.rb +58 -0
  17. data/lib/sprockets/bundle.rb +65 -0
  18. data/lib/sprockets/cache/file_store.rb +165 -14
  19. data/lib/sprockets/cache/memory_store.rb +66 -0
  20. data/lib/sprockets/cache/null_store.rb +46 -0
  21. data/lib/sprockets/cache.rb +234 -0
  22. data/lib/sprockets/cached_environment.rb +69 -0
  23. data/lib/sprockets/closure_compressor.rb +53 -0
  24. data/lib/sprockets/coffee_script_processor.rb +25 -0
  25. data/lib/sprockets/coffee_script_template.rb +6 -0
  26. data/lib/sprockets/compressing.rb +74 -0
  27. data/lib/sprockets/configuration.rb +83 -0
  28. data/lib/sprockets/context.rb +125 -131
  29. data/lib/sprockets/dependencies.rb +73 -0
  30. data/lib/sprockets/digest_utils.rb +156 -0
  31. data/lib/sprockets/directive_processor.rb +209 -211
  32. data/lib/sprockets/eco_processor.rb +32 -0
  33. data/lib/sprockets/eco_template.rb +3 -35
  34. data/lib/sprockets/ejs_processor.rb +31 -0
  35. data/lib/sprockets/ejs_template.rb +3 -34
  36. data/lib/sprockets/encoding_utils.rb +258 -0
  37. data/lib/sprockets/engines.rb +45 -38
  38. data/lib/sprockets/environment.rb +17 -67
  39. data/lib/sprockets/erb_processor.rb +30 -0
  40. data/lib/sprockets/erb_template.rb +6 -0
  41. data/lib/sprockets/errors.rb +6 -13
  42. data/lib/sprockets/file_reader.rb +15 -0
  43. data/lib/sprockets/http_utils.rb +115 -0
  44. data/lib/sprockets/jst_processor.rb +35 -19
  45. data/lib/sprockets/legacy.rb +314 -0
  46. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  47. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  48. data/lib/sprockets/loader.rb +176 -0
  49. data/lib/sprockets/manifest.rb +179 -98
  50. data/lib/sprockets/manifest_utils.rb +45 -0
  51. data/lib/sprockets/mime.rb +114 -32
  52. data/lib/sprockets/path_dependency_utils.rb +85 -0
  53. data/lib/sprockets/path_digest_utils.rb +47 -0
  54. data/lib/sprockets/path_utils.rb +282 -0
  55. data/lib/sprockets/paths.rb +81 -0
  56. data/lib/sprockets/processing.rb +157 -189
  57. data/lib/sprockets/processor_utils.rb +103 -0
  58. data/lib/sprockets/resolve.rb +208 -0
  59. data/lib/sprockets/sass_cache_store.rb +19 -15
  60. data/lib/sprockets/sass_compressor.rb +59 -0
  61. data/lib/sprockets/sass_functions.rb +2 -0
  62. data/lib/sprockets/sass_importer.rb +2 -29
  63. data/lib/sprockets/sass_processor.rb +285 -0
  64. data/lib/sprockets/sass_template.rb +4 -44
  65. data/lib/sprockets/server.rb +109 -84
  66. data/lib/sprockets/transformers.rb +145 -0
  67. data/lib/sprockets/uglifier_compressor.rb +63 -0
  68. data/lib/sprockets/uri_utils.rb +190 -0
  69. data/lib/sprockets/utils.rb +193 -44
  70. data/lib/sprockets/version.rb +1 -1
  71. data/lib/sprockets/yui_compressor.rb +65 -0
  72. data/lib/sprockets.rb +144 -53
  73. metadata +248 -238
  74. data/lib/sprockets/asset_attributes.rb +0 -126
  75. data/lib/sprockets/bundled_asset.rb +0 -79
  76. data/lib/sprockets/caching.rb +0 -96
  77. data/lib/sprockets/charset_normalizer.rb +0 -41
  78. data/lib/sprockets/index.rb +0 -99
  79. data/lib/sprockets/processed_asset.rb +0 -152
  80. data/lib/sprockets/processor.rb +0 -32
  81. data/lib/sprockets/safety_colons.rb +0 -28
  82. data/lib/sprockets/scss_template.rb +0 -13
  83. data/lib/sprockets/static_asset.rb +0 -57
  84. data/lib/sprockets/trail.rb +0 -90
@@ -1,48 +1,130 @@
1
- require 'rack/mime'
1
+ require 'sprockets/encoding_utils'
2
+ require 'sprockets/http_utils'
3
+ require 'sprockets/utils'
2
4
 
3
5
  module Sprockets
4
6
  module Mime
5
- # Returns a `Hash` of registered mime types registered on the
6
- # environment and those part of `Rack::Mime`.
7
+ include HTTPUtils, Utils
8
+
9
+ # Public: Mapping of MIME type Strings to properties Hash.
7
10
  #
8
- # If an `ext` is given, it will lookup the mime type for that extension.
9
- def mime_types(ext = nil)
10
- if ext.nil?
11
- Rack::Mime::MIME_TYPES.merge(@mime_types)
12
- else
13
- ext = Sprockets::Utils.normalize_extension(ext)
14
- @mime_types[ext] || Rack::Mime::MIME_TYPES[ext]
15
- end
11
+ # key - MIME Type String
12
+ # value - Hash
13
+ # extensions - Array of extnames
14
+ # charset - Default Encoding or function to detect encoding
15
+ #
16
+ # Returns Hash.
17
+ def mime_types
18
+ config[:mime_types]
16
19
  end
17
20
 
18
- if {}.respond_to?(:key)
19
- def extension_for_mime_type(type)
20
- mime_types.key(type)
21
+ # Internal: Mapping of MIME extension Strings to MIME type Strings.
22
+ #
23
+ # Used for internal fast lookup purposes.
24
+ #
25
+ # Examples:
26
+ #
27
+ # mime_exts['.js'] #=> 'application/javascript'
28
+ #
29
+ # key - MIME extension String
30
+ # value - MIME Type String
31
+ #
32
+ # Returns Hash.
33
+ def mime_exts
34
+ config[:mime_exts]
35
+ end
36
+
37
+ # Public: Register a new mime type.
38
+ #
39
+ # mime_type - String MIME Type
40
+ # options - Hash
41
+ # extensions: Array of String extnames
42
+ # charset: Proc/Method that detects the charset of a file.
43
+ # See EncodingUtils.
44
+ #
45
+ # Returns nothing.
46
+ def register_mime_type(mime_type, options = {})
47
+ # Legacy extension argument, will be removed from 4.x
48
+ if options.is_a?(String)
49
+ options = { extensions: [options] }
21
50
  end
22
- else
23
- def extension_for_mime_type(type)
24
- mime_types.index(type)
51
+
52
+ extnames = Array(options[:extensions]).map { |extname|
53
+ Sprockets::Utils.normalize_extension(extname)
54
+ }
55
+
56
+ charset = options[:charset]
57
+ charset ||= :default if mime_type.start_with?('text/')
58
+ charset = EncodingUtils::CHARSET_DETECT[charset] if charset.is_a?(Symbol)
59
+
60
+ self.computed_config = {}
61
+
62
+ self.config = hash_reassoc(config, :mime_exts) do |mime_exts|
63
+ extnames.each do |extname|
64
+ mime_exts[extname] = mime_type
65
+ end
66
+ mime_exts
67
+ end
68
+
69
+ self.config = hash_reassoc(config, :mime_types) do |mime_types|
70
+ type = { extensions: extnames }
71
+ type[:charset] = charset if charset
72
+ mime_types.merge(mime_type => type)
25
73
  end
26
74
  end
27
75
 
28
- # Register a new mime type.
29
- def register_mime_type(mime_type, ext)
30
- ext = Sprockets::Utils.normalize_extension(ext)
31
- @mime_types[ext] = mime_type
76
+ # Internal: Get detecter function for MIME type.
77
+ #
78
+ # mime_type - String MIME type
79
+ #
80
+ # Returns Proc detector or nil if none is available.
81
+ def mime_type_charset_detecter(mime_type)
82
+ if type = config[:mime_types][mime_type]
83
+ if detect = type[:charset]
84
+ return detect
85
+ end
86
+ end
32
87
  end
33
88
 
34
- if defined? Encoding
35
- # Returns the correct encoding for a given mime type, while falling
36
- # back on the default external encoding, if it exists.
37
- def encoding_for_mime_type(type)
38
- encoding = Encoding::BINARY if type =~ %r{^(image|audio|video)/}
39
- encoding ||= default_external_encoding if respond_to?(:default_external_encoding)
40
- encoding
89
+ # Public: Read file on disk with MIME type specific encoding.
90
+ #
91
+ # filename - String path
92
+ # content_type - String MIME type
93
+ #
94
+ # Returns String file contents transcoded to UTF-8 or in its external
95
+ # encoding.
96
+ def read_file(filename, content_type = nil)
97
+ data = File.binread(filename)
98
+
99
+ if detect = mime_type_charset_detecter(content_type)
100
+ detect.call(data).encode(Encoding::UTF_8, :universal_newline => true)
101
+ else
102
+ data
41
103
  end
42
104
  end
43
- end
44
105
 
45
- # Extend Sprockets module to provide global registry
46
- extend Mime
47
- @mime_types = {}
106
+ private
107
+ def extname_map
108
+ self.computed_config[:_extnames] ||= compute_extname_map
109
+ end
110
+
111
+ def compute_extname_map
112
+ graph = {}
113
+
114
+ ([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
115
+ pipeline_extname = ".#{pipeline}" if pipeline
116
+ ([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type|
117
+ 4.times do |n|
118
+ config[:engines].keys.permutation(n).each do |engine_extnames|
119
+ key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
120
+ type = format_type || config[:engine_mime_types][engine_extnames.first]
121
+ graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline}
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ graph
128
+ end
129
+ end
48
130
  end
@@ -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,282 @@
1
+ require 'fileutils'
2
+
3
+ module Sprockets
4
+ # Internal: File and path related utilities. Mixed into Environment.
5
+ #
6
+ # Probably would be called FileUtils, but that causes namespace annoyances
7
+ # when code actually wants to reference ::FileUtils.
8
+ module PathUtils
9
+ extend self
10
+
11
+ # Public: Like `File.stat`.
12
+ #
13
+ # path - String file or directory path
14
+ #
15
+ # Returns nil if the file does not exist.
16
+ def stat(path)
17
+ if File.exist?(path)
18
+ File.stat(path.to_s)
19
+ else
20
+ nil
21
+ end
22
+ end
23
+
24
+ # Public: Like `File.file?`.
25
+ #
26
+ # path - String file path.
27
+ #
28
+ # Returns true path exists and is a file.
29
+ def file?(path)
30
+ if stat = self.stat(path)
31
+ stat.file?
32
+ else
33
+ false
34
+ end
35
+ end
36
+
37
+ # Public: Like `File.directory?`.
38
+ #
39
+ # path - String file path.
40
+ #
41
+ # Returns true path exists and is a directory.
42
+ def directory?(path)
43
+ if stat = self.stat(path)
44
+ stat.directory?
45
+ else
46
+ false
47
+ end
48
+ end
49
+
50
+ # Public: A version of `Dir.entries` that filters out `.` files and `~`
51
+ # swap files.
52
+ #
53
+ # path - String directory path
54
+ #
55
+ # Returns an empty `Array` if the directory does not exist.
56
+ def entries(path)
57
+ if File.directory?(path)
58
+ Dir.entries(path, :encoding => Encoding.default_internal).reject! { |entry|
59
+ entry =~ /^\.|~$|^\#.*\#$/
60
+ }.sort!
61
+ else
62
+ []
63
+ end
64
+ end
65
+
66
+ # Public: Check if path is absolute or relative.
67
+ #
68
+ # path - String path.
69
+ #
70
+ # Returns true if path is absolute, otherwise false.
71
+ if File::ALT_SEPARATOR
72
+ require 'pathname'
73
+
74
+ # On Windows, ALT_SEPARATOR is \
75
+ # Delegate to Pathname since the logic gets complex.
76
+ def absolute_path?(path)
77
+ Pathname.new(path).absolute?
78
+ end
79
+ else
80
+ def absolute_path?(path)
81
+ path[0] == File::SEPARATOR
82
+ end
83
+ end
84
+
85
+ if File::ALT_SEPARATOR
86
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}|#{Regexp.quote(File::ALT_SEPARATOR)}"
87
+ else
88
+ SEPARATOR_PATTERN = "#{Regexp.quote(File::SEPARATOR)}"
89
+ end
90
+
91
+ # Public: Check if path is explicitly relative.
92
+ # Starts with "./" or "../".
93
+ #
94
+ # path - String path.
95
+ #
96
+ # Returns true if path is relative, otherwise false.
97
+ def relative_path?(path)
98
+ path =~ /^\.\.?($|#{SEPARATOR_PATTERN})/ ? true : false
99
+ end
100
+
101
+ # Internal: Get relative path for root path and subpath.
102
+ #
103
+ # path - String path
104
+ # subpath - String subpath of path
105
+ #
106
+ # Returns relative String path if subpath is a subpath of path, or nil if
107
+ # subpath is outside of path.
108
+ def split_subpath(path, subpath)
109
+ return "" if path == subpath
110
+ path = File.join(path, '')
111
+ if subpath.start_with?(path)
112
+ subpath[path.length..-1]
113
+ else
114
+ nil
115
+ end
116
+ end
117
+
118
+ # Internal: Detect root path and base for file in a set of paths.
119
+ #
120
+ # paths - Array of String paths
121
+ # filename - String path of file expected to be in one of the paths.
122
+ #
123
+ # Returns [String root, String path]
124
+ def paths_split(paths, filename)
125
+ paths.each do |path|
126
+ if subpath = split_subpath(path, filename)
127
+ return path, subpath
128
+ end
129
+ end
130
+ nil
131
+ end
132
+
133
+ # Internal: Get path's extensions.
134
+ #
135
+ # path - String
136
+ #
137
+ # Returns an Array of String extnames.
138
+ def path_extnames(path)
139
+ File.basename(path).scan(/\.[^.]+/)
140
+ end
141
+
142
+ # Internal: Match path extnames against available extensions.
143
+ #
144
+ # path - String
145
+ # extensions - Hash of String extnames to values
146
+ #
147
+ # Returns [String extname, Object value] or nil nothing matched.
148
+ def match_path_extname(path, extensions)
149
+ match, key = nil, ""
150
+ path_extnames(path).reverse_each do |extname|
151
+ key.prepend(extname)
152
+ if value = extensions[key]
153
+ match = [key.dup, value]
154
+ elsif match
155
+ break
156
+ end
157
+ end
158
+ match
159
+ end
160
+
161
+ # Internal: Returns all parents for path
162
+ #
163
+ # path - String absolute filename or directory
164
+ # root - String path to stop at (default: system root)
165
+ #
166
+ # Returns an Array of String paths.
167
+ def path_parents(path, root = nil)
168
+ root = "#{root}#{File::SEPARATOR}" if root
169
+ parents = []
170
+
171
+ loop do
172
+ parent = File.dirname(path)
173
+ break if parent == path
174
+ break if root && !path.start_with?(root)
175
+ parents << path = parent
176
+ end
177
+
178
+ parents
179
+ end
180
+
181
+ # Internal: Find target basename checking upwards from path.
182
+ #
183
+ # basename - String filename: ".sprocketsrc"
184
+ # path - String path to start search: "app/assets/javascripts/app.js"
185
+ # root - String path to stop at (default: system root)
186
+ #
187
+ # Returns String filename or nil.
188
+ def find_upwards(basename, path, root = nil)
189
+ path_parents(path, root).each do |dir|
190
+ filename = File.join(dir, basename)
191
+ return filename if file?(filename)
192
+ end
193
+ nil
194
+ end
195
+
196
+ # Public: Stat all the files under a directory.
197
+ #
198
+ # dir - A String directory
199
+ #
200
+ # Returns an Enumerator of [path, stat].
201
+ def stat_directory(dir)
202
+ return to_enum(__method__, dir) unless block_given?
203
+
204
+ self.entries(dir).each do |entry|
205
+ path = File.join(dir, entry)
206
+ if stat = self.stat(path)
207
+ yield path, stat
208
+ end
209
+ end
210
+
211
+ nil
212
+ end
213
+
214
+ # Public: Recursive stat all the files under a directory.
215
+ #
216
+ # dir - A String directory
217
+ #
218
+ # Returns an Enumerator of [path, stat].
219
+ def stat_tree(dir, &block)
220
+ return to_enum(__method__, dir) unless block_given?
221
+
222
+ self.stat_directory(dir) do |path, stat|
223
+ yield path, stat
224
+
225
+ if stat.directory?
226
+ stat_tree(path, &block)
227
+ end
228
+ end
229
+
230
+ nil
231
+ end
232
+
233
+ # Public: Recursive stat all the files under a directory in alphabetical
234
+ # order.
235
+ #
236
+ # dir - A String directory
237
+ #
238
+ # Returns an Enumerator of [path, stat].
239
+ def stat_sorted_tree(dir, &block)
240
+ return to_enum(__method__, dir) unless block_given?
241
+
242
+ self.stat_directory(dir).sort_by { |path, stat|
243
+ stat.directory? ? "#{path}/" : path
244
+ }.each do |path, stat|
245
+ yield path, stat
246
+
247
+ if stat.directory?
248
+ stat_sorted_tree(path, &block)
249
+ end
250
+ end
251
+
252
+ nil
253
+ end
254
+
255
+ # Public: Write to a file atomically. Useful for situations where you
256
+ # don't want other processes or threads to see half-written files.
257
+ #
258
+ # Utils.atomic_write('important.file') do |file|
259
+ # file.write('hello')
260
+ # end
261
+ #
262
+ # Returns nothing.
263
+ def atomic_write(filename)
264
+ dirname, basename = File.split(filename)
265
+ basename = [
266
+ basename,
267
+ Thread.current.object_id,
268
+ Process.pid,
269
+ rand(1000000)
270
+ ].join('.')
271
+ tmpname = File.join(dirname, basename)
272
+
273
+ File.open(tmpname, 'wb+') do |f|
274
+ yield f
275
+ end
276
+
277
+ FileUtils.mv(tmpname, filename)
278
+ ensure
279
+ FileUtils.rm(tmpname) if File.exist?(tmpname)
280
+ end
281
+ end
282
+ end
@@ -0,0 +1,81 @@
1
+ require 'sprockets/path_utils'
2
+ require 'sprockets/utils'
3
+
4
+ module Sprockets
5
+ module Paths
6
+ include PathUtils, Utils
7
+
8
+ # Returns `Environment` root.
9
+ #
10
+ # All relative paths are expanded with root as its base. To be
11
+ # useful set this to your applications root directory. (`Rails.root`)
12
+ def root
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
23
+ end
24
+ private :root=
25
+
26
+ # Returns an `Array` of path `String`s.
27
+ #
28
+ # These paths will be used for asset logical path lookups.
29
+ def paths
30
+ config[:paths]
31
+ end
32
+
33
+ # Prepend a `path` to the `paths` list.
34
+ #
35
+ # Paths at the end of the `Array` have the least priority.
36
+ def 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
41
+ end
42
+
43
+ # Append a `path` to the `paths` list.
44
+ #
45
+ # Paths at the beginning of the `Array` have a higher priority.
46
+ def 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
51
+ end
52
+
53
+ # Clear all paths and start fresh.
54
+ #
55
+ # There is no mechanism for reordering paths, so its best to
56
+ # completely wipe the paths list and reappend them in the order
57
+ # you want.
58
+ def clear_paths
59
+ self.config = hash_reassoc(config, :paths) do |paths|
60
+ paths.clear
61
+ end
62
+ end
63
+
64
+ # Public: Iterate over every file under all load paths.
65
+ #
66
+ # Returns Enumerator if no block is given.
67
+ def each_file
68
+ return to_enum(__method__) unless block_given?
69
+
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
80
+ end
81
+ end