bpm 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitmodules +3 -0
- data/Gemfile +0 -13
- data/TODO.md +1 -0
- data/bpm.gemspec +8 -3
- data/lib/bpm/cli/base.rb +22 -20
- data/lib/bpm/generator.rb +3 -3
- data/lib/bpm/libgems_ext/dependency_installer.rb +4 -4
- data/lib/bpm/libgems_ext/installer.rb +1 -1
- data/lib/bpm/package.rb +13 -9
- data/lib/bpm/pipeline/generated_asset.rb +30 -3
- data/lib/bpm/pipeline/transport_processor.rb +20 -12
- data/lib/bpm/pipeline.rb +17 -9
- data/lib/bpm/project.rb +42 -10
- data/lib/bpm/server.rb +5 -0
- data/lib/bpm/version.rb +1 -1
- data/lib/bpm.rb +2 -0
- data/lib/vendored_sprockets.rb +7 -0
- data/spec/cli/add_spec.rb +40 -37
- data/spec/cli/build_spec.rb +5 -5
- data/spec/cli/new_spec.rb +49 -23
- data/spec/cli/push_spec.rb +5 -5
- data/spec/cli/unpack_spec.rb +14 -14
- data/spec/fixtures/{badrake-0.8.7.spd → badrake-0.8.7.bpkg} +0 -0
- data/spec/fixtures/{builder-3.0.0.spd → builder-3.0.0.bpkg} +0 -0
- data/spec/fixtures/{bundler-1.1.pre.spd → bundler-1.1.pre.bpkg} +0 -0
- data/spec/fixtures/{coffee-1.0.1.pre.spd → coffee-1.0.1.pre.bpkg} +0 -0
- data/spec/fixtures/{core-test-0.4.9.spd → core-test-0.4.9.bpkg} +0 -0
- data/spec/fixtures/{custom_generator-1.0.spd → custom_generator-1.0.bpkg} +0 -0
- data/spec/fixtures/custom_name/MyProject.json +4 -0
- data/spec/fixtures/hello_world/css/dummy.css +3 -0
- data/spec/fixtures/{highline-1.6.1.spd → highline-1.6.1.bpkg} +0 -0
- data/spec/fixtures/{ivory-0.0.1.spd → ivory-0.0.1.bpkg} +0 -0
- data/spec/fixtures/{jquery-1.4.3.spd → jquery-1.4.3.bpkg} +0 -0
- data/spec/fixtures/minitest/assets/bpm_packages.js +1 -0
- data/spec/fixtures/minitest/assets/bpm_styles.css +0 -0
- data/spec/fixtures/minitest/assets/minitest/app_package.js +1 -0
- data/spec/fixtures/minitest/lib/main.js +1 -0
- data/spec/fixtures/minitest/minitest.json +22 -0
- data/spec/fixtures/minitest/packages/uglyduck/lib/main.js +1 -0
- data/spec/fixtures/minitest/packages/uglyduck/minifier/main.js +4 -0
- data/spec/fixtures/minitest/packages/uglyduck/package.json +21 -0
- data/spec/fixtures/{optparse-1.0.1.spd → optparse-1.0.1.bpkg} +0 -0
- data/spec/fixtures/{rake-0.8.6.spd → rake-0.8.6.bpkg} +0 -0
- data/spec/fixtures/{rake-0.8.7.spd → rake-0.8.7.bpkg} +0 -0
- data/spec/fixtures/{spade-0.5.0.spd → spade-0.5.0.bpkg} +0 -0
- data/spec/fixtures/transporter/packages/transport/lib/main.js +1 -0
- data/spec/fixtures/transporter/packages/transport/package.json +1 -1
- data/spec/fixtures/transporter/packages/transport/transports/wrapper.js +5 -0
- data/spec/gauntlet_spec.rb +2 -2
- data/spec/package_spec.rb +3 -3
- data/spec/pipeline_spec.rb +175 -54
- data/spec/project_spec.rb +19 -3
- data/spec/support/fake_gem_server.rb +4 -4
- data/templates/init/project.json +3 -1
- data/templates/project/index.html +1 -1
- data/vendor/sprockets/.gitignore +7 -0
- data/vendor/sprockets/.travis.yml +6 -0
- data/vendor/sprockets/Gemfile +8 -0
- data/vendor/sprockets/LICENSE +20 -0
- data/vendor/sprockets/README.md +22 -0
- data/vendor/sprockets/Rakefile +8 -0
- data/vendor/sprockets/lib/sprockets/asset.rb +203 -0
- data/vendor/sprockets/lib/sprockets/asset_attributes.rb +161 -0
- data/vendor/sprockets/lib/sprockets/base.rb +147 -0
- data/vendor/sprockets/lib/sprockets/bundled_asset.rb +222 -0
- data/vendor/sprockets/lib/sprockets/cache/file_store.rb +41 -0
- data/vendor/sprockets/lib/sprockets/caching.rb +121 -0
- data/vendor/sprockets/lib/sprockets/charset_normalizer.rb +41 -0
- data/vendor/sprockets/lib/sprockets/context.rb +191 -0
- data/vendor/sprockets/lib/sprockets/digest.rb +73 -0
- data/vendor/sprockets/lib/sprockets/directive_processor.rb +380 -0
- data/vendor/sprockets/lib/sprockets/eco_template.rb +39 -0
- data/vendor/sprockets/lib/sprockets/ejs_template.rb +38 -0
- data/vendor/sprockets/lib/sprockets/engines.rb +92 -0
- data/vendor/sprockets/lib/sprockets/environment.rb +93 -0
- data/vendor/sprockets/lib/sprockets/errors.rb +17 -0
- data/vendor/sprockets/lib/sprockets/index.rb +80 -0
- data/vendor/sprockets/lib/sprockets/jst_processor.rb +26 -0
- data/vendor/sprockets/lib/sprockets/processing.rb +310 -0
- data/vendor/sprockets/lib/sprockets/processor.rb +32 -0
- data/vendor/sprockets/lib/sprockets/safety_colons.rb +28 -0
- data/vendor/sprockets/lib/sprockets/server.rb +270 -0
- data/vendor/sprockets/lib/sprockets/static_asset.rb +87 -0
- data/vendor/sprockets/lib/sprockets/static_compilation.rb +82 -0
- data/vendor/sprockets/lib/sprockets/trail.rb +122 -0
- data/vendor/sprockets/lib/sprockets/utils.rb +67 -0
- data/vendor/sprockets/lib/sprockets/version.rb +3 -0
- data/vendor/sprockets/lib/sprockets.rb +31 -0
- data/vendor/sprockets/sprockets.gemspec +30 -0
- data/vendor/sprockets/test/fixtures/asset/POW.png +0 -0
- data/vendor/sprockets/test/fixtures/asset/application.js +6 -0
- data/vendor/sprockets/test/fixtures/asset/bar-utf8.css +2 -0
- data/vendor/sprockets/test/fixtures/asset/charset.css +2 -0
- data/vendor/sprockets/test/fixtures/asset/circle/a.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/circle/b.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/circle/c.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/compat.js +4 -0
- data/vendor/sprockets/test/fixtures/asset/constants.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/constants.yml +1 -0
- data/vendor/sprockets/test/fixtures/asset/default_mime_type.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/filename.js.erb +1 -0
- data/vendor/sprockets/test/fixtures/asset/foo-utf8.css +2 -0
- data/vendor/sprockets/test/fixtures/asset/included_header.js +4 -0
- data/vendor/sprockets/test/fixtures/asset/jquery.tmpl.min.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/mismatch.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/multiple.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/multipleengine.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/noengine.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/noformat.coffee +1 -0
- data/vendor/sprockets/test/fixtures/asset/one.css +1 -0
- data/vendor/sprockets/test/fixtures/asset/oneengine.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/project.css +1 -0
- data/vendor/sprockets/test/fixtures/asset/project.js.erb +4 -0
- data/vendor/sprockets/test/fixtures/asset/relative/include.js +4 -0
- data/vendor/sprockets/test/fixtures/asset/relative/require.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/relative/require_outside_path.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/require_self.css +9 -0
- data/vendor/sprockets/test/fixtures/asset/require_self_twice.css +8 -0
- data/vendor/sprockets/test/fixtures/asset/semicolons/bar.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/semicolons/index.js +5 -0
- data/vendor/sprockets/test/fixtures/asset/sprite.css.erb +12 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c/d.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c/e.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/b/c.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/b.css +2 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/b.js.erb +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/d/c.js.coffee +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all/d/e.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require.js +7 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require_directory.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/all_with_require_tree.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/tree/directory/application.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/tree/directory/bar.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/directory/foo.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/tree/application.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/tree/tree/bar.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/tree/foo.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/with_logical_path/a/a.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/with_logical_path/require_tree_with_logical_path.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/a.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/b.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/tree/without_argument/require_tree_without_argument.js +1 -0
- data/vendor/sprockets/test/fixtures/asset/two.css +1 -0
- data/vendor/sprockets/test/fixtures/asset/unicode.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/unknownexts.min.js +2 -0
- data/vendor/sprockets/test/fixtures/asset/users.js.erb.str +4 -0
- data/vendor/sprockets/test/fixtures/context/POW.png +0 -0
- data/vendor/sprockets/test/fixtures/context/application.js.yml +3 -0
- data/vendor/sprockets/test/fixtures/context/bar.js +1 -0
- data/vendor/sprockets/test/fixtures/context/foo.js +2 -0
- data/vendor/sprockets/test/fixtures/context/helpers.css.erb +3 -0
- data/vendor/sprockets/test/fixtures/context/properties.js.erb +7 -0
- data/vendor/sprockets/test/fixtures/context/require_glob.js +1 -0
- data/vendor/sprockets/test/fixtures/context/resolve_content_type.js.erb +4 -0
- data/vendor/sprockets/test/fixtures/context/sprite.css.embed +3 -0
- data/vendor/sprockets/test/fixtures/default/application.js.coffee +4 -0
- data/vendor/sprockets/test/fixtures/default/coffee/foo.coffee +1 -0
- data/vendor/sprockets/test/fixtures/default/coffee/index.js +3 -0
- data/vendor/sprockets/test/fixtures/default/empty +0 -0
- data/vendor/sprockets/test/fixtures/default/gallery.css.erb +3 -0
- data/vendor/sprockets/test/fixtures/default/gallery.js +1 -0
- data/vendor/sprockets/test/fixtures/default/goodbye.jst.eco +1 -0
- data/vendor/sprockets/test/fixtures/default/hello.jst.ejs +1 -0
- data/vendor/sprockets/test/fixtures/default/hello.txt +1 -0
- data/vendor/sprockets/test/fixtures/default/interpolation.js +1 -0
- data/vendor/sprockets/test/fixtures/default/missing_require.js +1 -0
- data/vendor/sprockets/test/fixtures/default/mobile/a.js +1 -0
- data/vendor/sprockets/test/fixtures/default/mobile/b.js +1 -0
- data/vendor/sprockets/test/fixtures/default/mobile/c.css +1 -0
- data/vendor/sprockets/test/fixtures/default/mobile/d.css +1 -0
- data/vendor/sprockets/test/fixtures/default/mobile/index.css +3 -0
- data/vendor/sprockets/test/fixtures/default/mobile/index.js +1 -0
- data/vendor/sprockets/test/fixtures/default/noreturn.js +1 -0
- data/vendor/sprockets/test/fixtures/default/project.js.coffee.erb +2 -0
- data/vendor/sprockets/test/fixtures/directives/code_before_comment +3 -0
- data/vendor/sprockets/test/fixtures/directives/comment_without_directives +6 -0
- data/vendor/sprockets/test/fixtures/directives/directive_word_splitting +6 -0
- data/vendor/sprockets/test/fixtures/directives/directives_after_header +16 -0
- data/vendor/sprockets/test/fixtures/directives/double_slash +9 -0
- data/vendor/sprockets/test/fixtures/directives/hash +8 -0
- data/vendor/sprockets/test/fixtures/directives/no_header +2 -0
- data/vendor/sprockets/test/fixtures/directives/slash_star +10 -0
- data/vendor/sprockets/test/fixtures/directives/slash_star_single +4 -0
- data/vendor/sprockets/test/fixtures/directives/space_between_directive_word +2 -0
- data/vendor/sprockets/test/fixtures/directives/triple_hash +10 -0
- data/vendor/sprockets/test/fixtures/encoding/ascii.js +1 -0
- data/vendor/sprockets/test/fixtures/encoding/ascii_utf8.js +2 -0
- data/vendor/sprockets/test/fixtures/encoding/utf16.js +0 -0
- data/vendor/sprockets/test/fixtures/encoding/utf8.js +1 -0
- data/vendor/sprockets/test/fixtures/encoding/utf8_bom.js +1 -0
- data/vendor/sprockets/test/fixtures/engines/hello.alert +1 -0
- data/vendor/sprockets/test/fixtures/engines/moo.js.str +1 -0
- data/vendor/sprockets/test/fixtures/public/compiled-digest-0aa2105d29558f3eb790d411d7d8fb66.js +3 -0
- data/vendor/sprockets/test/fixtures/public/compiled-digest-1c41eb0cf934a0c76babe875f982f9d1.js +1 -0
- data/vendor/sprockets/test/fixtures/server/app/javascripts/application.js +5 -0
- data/vendor/sprockets/test/fixtures/server/app/javascripts/bar.js +1 -0
- data/vendor/sprockets/test/fixtures/server/app/javascripts/foo.js +1 -0
- data/vendor/sprockets/test/fixtures/server/app/javascripts/hello.txt +2 -0
- data/vendor/sprockets/test/fixtures/server/app/javascripts/tree.js +1 -0
- data/vendor/sprockets/test/fixtures/server/vendor/javascripts/missing_require.js +1 -0
- data/vendor/sprockets/test/fixtures/server/vendor/stylesheets/missing_require.css +1 -0
- data/vendor/sprockets/test/sprockets_test.rb +56 -0
- data/vendor/sprockets/test/test_asset.rb +593 -0
- data/vendor/sprockets/test/test_asset_attributes.rb +86 -0
- data/vendor/sprockets/test/test_caching.rb +62 -0
- data/vendor/sprockets/test/test_context.rb +115 -0
- data/vendor/sprockets/test/test_directive_processor.rb +124 -0
- data/vendor/sprockets/test/test_encoding.rb +65 -0
- data/vendor/sprockets/test/test_engines.rb +73 -0
- data/vendor/sprockets/test/test_environment.rb +610 -0
- data/vendor/sprockets/test/test_server.rb +227 -0
- metadata +258 -54
- data/spec/fixtures/transporter/packages/transport/lib/wrapper.js +0 -5
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'tilt'
|
2
|
+
|
3
|
+
module Sprockets
|
4
|
+
# Some browsers have issues with stylesheets that contain multiple
|
5
|
+
# `@charset` definitions. The issue surfaces while using Sass since
|
6
|
+
# it inserts a `@charset` at the top of each file. Then Sprockets
|
7
|
+
# concatenates them together.
|
8
|
+
#
|
9
|
+
# The `CharsetNormalizer` processor strips out multiple `@charset`
|
10
|
+
# definitions.
|
11
|
+
#
|
12
|
+
# The current implementation is naive. It picks the first `@charset`
|
13
|
+
# it sees and strips the others. This works for most people because
|
14
|
+
# the other definitions are usually `UTF-8`. A more sophisticated
|
15
|
+
# approach would be to re-encode stylesheets with mixed encodings.
|
16
|
+
#
|
17
|
+
# This behavior can be disabled with:
|
18
|
+
#
|
19
|
+
# environment.unregister_bundle_processor 'text/css', Sprockets::CharsetNormalizer
|
20
|
+
#
|
21
|
+
class CharsetNormalizer < Tilt::Template
|
22
|
+
def prepare
|
23
|
+
end
|
24
|
+
|
25
|
+
def evaluate(context, locals, &block)
|
26
|
+
charset = nil
|
27
|
+
|
28
|
+
# Find and strip out any `@charset` definitions
|
29
|
+
filtered_data = data.gsub(/^@charset "([^"]+)";$/) {
|
30
|
+
charset ||= $1; ""
|
31
|
+
}
|
32
|
+
|
33
|
+
if charset
|
34
|
+
# If there was a charset, move it to the top
|
35
|
+
"@charset \"#{charset}\";#{filtered_data}"
|
36
|
+
else
|
37
|
+
data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,191 @@
|
|
1
|
+
require 'sprockets/errors'
|
2
|
+
require 'sprockets/utils'
|
3
|
+
require 'pathname'
|
4
|
+
require 'set'
|
5
|
+
|
6
|
+
module Sprockets
|
7
|
+
# `Context` provides helper methods to all `Tilt` processors. They
|
8
|
+
# are typically accessed by ERB templates. You can mix in custom
|
9
|
+
# helpers by injecting them into `Environment#context_class`. Do not
|
10
|
+
# mix them into `Context` directly.
|
11
|
+
#
|
12
|
+
# environment.instance_eval do
|
13
|
+
# include MyHelper
|
14
|
+
# def asset_url; end
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# <%= asset_url "foo.png" %>
|
18
|
+
#
|
19
|
+
# The `Context` also collects dependencies declared by
|
20
|
+
# assets. See `DirectiveProcessor` for an example of this.
|
21
|
+
class Context
|
22
|
+
attr_reader :environment, :pathname
|
23
|
+
attr_reader :_required_paths, :_dependency_paths
|
24
|
+
attr_writer :__LINE__
|
25
|
+
|
26
|
+
def initialize(environment, logical_path, pathname)
|
27
|
+
@environment = environment
|
28
|
+
@logical_path = logical_path
|
29
|
+
@pathname = pathname
|
30
|
+
@__LINE__ = nil
|
31
|
+
|
32
|
+
@_required_paths = []
|
33
|
+
@_dependency_paths = Set.new([pathname.to_s])
|
34
|
+
end
|
35
|
+
|
36
|
+
# Returns the environment path that contains the file.
|
37
|
+
#
|
38
|
+
# If `app/javascripts` and `app/stylesheets` are in your path, and
|
39
|
+
# current file is `app/javascripts/foo/bar.js`, `root_path` would
|
40
|
+
# return `app/javascripts`.
|
41
|
+
def root_path
|
42
|
+
environment.paths.detect { |path| pathname.to_s[path] }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns logical path without any file extensions.
|
46
|
+
#
|
47
|
+
# 'app/javascripts/application.js'
|
48
|
+
# # => 'application'
|
49
|
+
#
|
50
|
+
def logical_path
|
51
|
+
@logical_path[/^([^.]+)/, 0]
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns content type of file
|
55
|
+
#
|
56
|
+
# 'application/javascript'
|
57
|
+
# 'text/css'
|
58
|
+
#
|
59
|
+
def content_type
|
60
|
+
environment.content_type_of(pathname)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Given a logical path, `resolve` will find and return the fully
|
64
|
+
# expanded path. Relative paths will also be resolved. An optional
|
65
|
+
# `:content_type` restriction can be supplied to restrict the
|
66
|
+
# search.
|
67
|
+
#
|
68
|
+
# resolve("foo.js")
|
69
|
+
# # => "/path/to/app/javascripts/foo.js"
|
70
|
+
#
|
71
|
+
# resolve("./bar.js")
|
72
|
+
# # => "/path/to/app/javascripts/bar.js"
|
73
|
+
#
|
74
|
+
def resolve(path, options = {}, &block)
|
75
|
+
pathname = Pathname.new(path)
|
76
|
+
attributes = environment.attributes_for(pathname)
|
77
|
+
|
78
|
+
if pathname.absolute?
|
79
|
+
pathname
|
80
|
+
|
81
|
+
elsif content_type = options[:content_type]
|
82
|
+
content_type = self.content_type if content_type == :self
|
83
|
+
|
84
|
+
if attributes.format_extension
|
85
|
+
if content_type != attributes.content_type
|
86
|
+
raise ContentTypeMismatch, "#{path} is " +
|
87
|
+
"'#{attributes.content_type}', not '#{content_type}'"
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
resolve(path) do |candidate|
|
92
|
+
if self.content_type == environment.content_type_of(candidate)
|
93
|
+
return candidate
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
raise FileNotFound, "couldn't find file '#{path}'"
|
98
|
+
else
|
99
|
+
environment.resolve(path, :base_path => self.pathname.dirname, &block)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# `depend_on` allows you to state a dependency on a file without
|
104
|
+
# including it.
|
105
|
+
#
|
106
|
+
# This is used for caching purposes. Any changes made to
|
107
|
+
# the dependency file with invalidate the cache of the
|
108
|
+
# source file.
|
109
|
+
def depend_on(path)
|
110
|
+
@_dependency_paths << resolve(path).to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
# Reads `path` and runs processors on the file.
|
114
|
+
#
|
115
|
+
# This allows you to capture the result of an asset and include it
|
116
|
+
# directly in another.
|
117
|
+
#
|
118
|
+
# <%= evaluate "bar.js" %>
|
119
|
+
#
|
120
|
+
def evaluate(path, options = {})
|
121
|
+
start_time = Time.now.to_f
|
122
|
+
pathname = resolve(path)
|
123
|
+
attributes = environment.attributes_for(pathname)
|
124
|
+
processors = options[:processors] || attributes.processors
|
125
|
+
|
126
|
+
if options[:data]
|
127
|
+
result = options[:data]
|
128
|
+
else
|
129
|
+
result = Sprockets::Utils.read_unicode(pathname)
|
130
|
+
end
|
131
|
+
|
132
|
+
processors.each do |processor|
|
133
|
+
begin
|
134
|
+
template = processor.new(pathname.to_s) { result }
|
135
|
+
result = template.render(self, {})
|
136
|
+
rescue Exception => e
|
137
|
+
annotate_exception! e
|
138
|
+
raise
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
elapsed_time = ((Time.now.to_f - start_time) * 1000).to_i
|
143
|
+
logger.info "Compiled #{attributes.pretty_path} (#{elapsed_time}ms) (pid #{Process.pid})"
|
144
|
+
|
145
|
+
result
|
146
|
+
end
|
147
|
+
|
148
|
+
# Tests if target path is able to be safely required into the
|
149
|
+
# current concatenation.
|
150
|
+
def asset_requirable?(path)
|
151
|
+
pathname = resolve(path)
|
152
|
+
content_type = environment.content_type_of(pathname)
|
153
|
+
pathname.file? && (self.content_type.nil? || self.content_type == content_type)
|
154
|
+
end
|
155
|
+
|
156
|
+
# `require_asset` declares `path` as a dependency of the file. The
|
157
|
+
# dependency will be inserted before the file and will only be
|
158
|
+
# included once.
|
159
|
+
#
|
160
|
+
# If ERB processing is enabled, you can use it to dynamically
|
161
|
+
# require assets.
|
162
|
+
#
|
163
|
+
# <%= require_asset "#{framework}.js" %>
|
164
|
+
#
|
165
|
+
def require_asset(path)
|
166
|
+
pathname = resolve(path, :content_type => :self)
|
167
|
+
|
168
|
+
unless @_required_paths.include?(pathname.to_s)
|
169
|
+
@_dependency_paths << pathname.to_s
|
170
|
+
@_required_paths << pathname.to_s
|
171
|
+
end
|
172
|
+
|
173
|
+
pathname
|
174
|
+
end
|
175
|
+
|
176
|
+
private
|
177
|
+
# Annotates exception backtrace with the original template that
|
178
|
+
# the exception was raised in.
|
179
|
+
def annotate_exception!(exception)
|
180
|
+
location = pathname.to_s
|
181
|
+
location << ":#{@__LINE__}" if @__LINE__
|
182
|
+
|
183
|
+
exception.extend(Sprockets::EngineError)
|
184
|
+
exception.sprockets_annotation = " (in #{location})"
|
185
|
+
end
|
186
|
+
|
187
|
+
def logger
|
188
|
+
environment.logger
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Sprockets
|
2
|
+
# `Digest` is an internal mixin whose public methods are exposed on
|
3
|
+
# the `Environment` and `Index` classes.
|
4
|
+
module Digest
|
5
|
+
# Returns a `Digest` implementation class.
|
6
|
+
#
|
7
|
+
# Defaults to `Digest::MD5`.
|
8
|
+
def digest_class
|
9
|
+
@digest_class
|
10
|
+
end
|
11
|
+
|
12
|
+
# Assign a `Digest` implementation class. This maybe any Ruby
|
13
|
+
# `Digest::` implementation such as `Digest::MD5` or
|
14
|
+
# `Digest::SHA1`.
|
15
|
+
#
|
16
|
+
# environment.digest_class = Digest::SHA1
|
17
|
+
#
|
18
|
+
def digest_class=(klass)
|
19
|
+
expire_index!
|
20
|
+
@digest_class = klass
|
21
|
+
end
|
22
|
+
|
23
|
+
# The `Environment#version` is a custom value used for manually
|
24
|
+
# expiring all asset caches.
|
25
|
+
#
|
26
|
+
# Sprockets is able to track most file and directory changes and
|
27
|
+
# will take care of expiring the cache for you. However, its
|
28
|
+
# impossible to know when any custom helpers change that you mix
|
29
|
+
# into the `Context`.
|
30
|
+
#
|
31
|
+
# It would be wise to increment this value anytime you make a
|
32
|
+
# configuration change to the `Environment` object.
|
33
|
+
def version
|
34
|
+
@version
|
35
|
+
end
|
36
|
+
|
37
|
+
# Assign an environment version.
|
38
|
+
#
|
39
|
+
# environment.version = '2.0'
|
40
|
+
#
|
41
|
+
def version=(version)
|
42
|
+
expire_index!
|
43
|
+
@version = version
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns a `Digest` instance for the `Environment`.
|
47
|
+
#
|
48
|
+
# This value serves two purposes. If two `Environment`s have the
|
49
|
+
# same digest value they can be treated as equal. This is more
|
50
|
+
# useful for comparing environment states between processes rather
|
51
|
+
# than in the same. Two equal `Environment`s can share the same
|
52
|
+
# cached assets.
|
53
|
+
#
|
54
|
+
# The value also provides a seed digest for all `Asset`
|
55
|
+
# digests. Any change in the environment digest will affect all of
|
56
|
+
# its assets.
|
57
|
+
def digest
|
58
|
+
# Recompute digest for the first time or again after its been cleared
|
59
|
+
@digest ||= compute_digest
|
60
|
+
|
61
|
+
# Returned a dupped copy so the caller can safely mutate it with `.update`
|
62
|
+
@digest.dup
|
63
|
+
end
|
64
|
+
|
65
|
+
protected
|
66
|
+
def compute_digest
|
67
|
+
# Compute the initial digest using the implementation
|
68
|
+
# class. The Sprockets release version and custom environment
|
69
|
+
# version are mixed in.
|
70
|
+
digest_class.new.update(VERSION).update(version.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,380 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'shellwords'
|
3
|
+
require 'tilt'
|
4
|
+
require 'yaml'
|
5
|
+
|
6
|
+
module Sprockets
|
7
|
+
# The `DirectiveProcessor` is responsible for parsing and evaluating
|
8
|
+
# directive comments in a source file.
|
9
|
+
#
|
10
|
+
# A directive comment starts with a comment prefix, followed by an "=",
|
11
|
+
# then the directive name, then any arguments.
|
12
|
+
#
|
13
|
+
# // JavaScript
|
14
|
+
# //= require "foo"
|
15
|
+
#
|
16
|
+
# # CoffeeScript
|
17
|
+
# #= require "bar"
|
18
|
+
#
|
19
|
+
# /* CSS
|
20
|
+
# *= require "baz"
|
21
|
+
# */
|
22
|
+
#
|
23
|
+
# The Processor is implemented as a `Tilt::Template` and is loosely
|
24
|
+
# coupled to Sprockets. This makes it possible to disable or modify
|
25
|
+
# the processor to do whatever you'd like. You could add your own
|
26
|
+
# custom directives or invent your own directive syntax.
|
27
|
+
#
|
28
|
+
# `Environment#processors` includes `DirectiveProcessor` by default.
|
29
|
+
#
|
30
|
+
# To remove the processor entirely:
|
31
|
+
#
|
32
|
+
# env.unregister_processor('text/css', Sprockets::DirectiveProcessor)
|
33
|
+
# env.unregister_processor('application/javascript', Sprockets::DirectiveProcessor)
|
34
|
+
#
|
35
|
+
# Then inject your own preprocessor:
|
36
|
+
#
|
37
|
+
# env.register_processor('text/css', MyProcessor)
|
38
|
+
#
|
39
|
+
class DirectiveProcessor < Tilt::Template
|
40
|
+
attr_reader :pathname
|
41
|
+
|
42
|
+
def prepare
|
43
|
+
@pathname = Pathname.new(file)
|
44
|
+
|
45
|
+
@directive_parser = Parser.new(data)
|
46
|
+
@included_pathnames = []
|
47
|
+
@compat = false
|
48
|
+
end
|
49
|
+
|
50
|
+
# Implemented for Tilt#render.
|
51
|
+
#
|
52
|
+
# `context` is a `Context` instance with methods that allow you to
|
53
|
+
# access the environment and append to the bundle. See `Context`
|
54
|
+
# for the complete API.
|
55
|
+
def evaluate(context, locals, &block)
|
56
|
+
@context = context
|
57
|
+
|
58
|
+
@result = ""
|
59
|
+
@has_written_body = false
|
60
|
+
|
61
|
+
process_directives
|
62
|
+
process_source
|
63
|
+
|
64
|
+
@result
|
65
|
+
end
|
66
|
+
|
67
|
+
def processed_header
|
68
|
+
@directive_parser.processed_header
|
69
|
+
end
|
70
|
+
|
71
|
+
def processed_body
|
72
|
+
@directive_parser.body
|
73
|
+
end
|
74
|
+
|
75
|
+
def processed_source
|
76
|
+
@directive_parser.processed_source
|
77
|
+
end
|
78
|
+
|
79
|
+
def directives
|
80
|
+
@directive_parser.directives
|
81
|
+
end
|
82
|
+
|
83
|
+
protected
|
84
|
+
class Parser
|
85
|
+
# Directives will only be picked up if they are in the header
|
86
|
+
# of the source file. C style (/* */), JavaScript (//), and
|
87
|
+
# Ruby (#) comments are supported.
|
88
|
+
#
|
89
|
+
# Directives in comments after the first non-whitespace line
|
90
|
+
# of code will not be processed.
|
91
|
+
#
|
92
|
+
HEADER_PATTERN = /
|
93
|
+
\A (
|
94
|
+
(?m:\s*) (
|
95
|
+
(\/\* (?m:.*?) \*\/) |
|
96
|
+
(\#\#\# (?m:.*?) \#\#\#) |
|
97
|
+
(\/\/ .* \n?)+ |
|
98
|
+
(\# .* \n?)+
|
99
|
+
)
|
100
|
+
)+
|
101
|
+
/x
|
102
|
+
|
103
|
+
# Directives are denoted by a `=` followed by the name, then
|
104
|
+
# argument list.
|
105
|
+
#
|
106
|
+
# A few different styles are allowed:
|
107
|
+
#
|
108
|
+
# // =require foo
|
109
|
+
# //= require foo
|
110
|
+
# //= require "foo"
|
111
|
+
#
|
112
|
+
DIRECTIVE_PATTERN = /
|
113
|
+
^ [\W]* = \s* (\w+.*?) (\*\/)? $
|
114
|
+
/x
|
115
|
+
|
116
|
+
attr_reader :source, :header, :body
|
117
|
+
|
118
|
+
def initialize(source)
|
119
|
+
@source = source
|
120
|
+
@header = @source[HEADER_PATTERN, 0] || ""
|
121
|
+
@body = $' || @source
|
122
|
+
|
123
|
+
# Ensure body ends in a new line
|
124
|
+
@body += "\n" if @body != "" && @body !~ /\n\Z/m
|
125
|
+
end
|
126
|
+
|
127
|
+
def header_lines
|
128
|
+
@header_lines ||= header.split("\n")
|
129
|
+
end
|
130
|
+
|
131
|
+
# Returns the header String with any directives stripped.
|
132
|
+
def processed_header
|
133
|
+
header_lines.reject do |line|
|
134
|
+
extract_directive(line)
|
135
|
+
end.join("\n")
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns the source String with any directives stripped.
|
139
|
+
def processed_source
|
140
|
+
@processed_source ||= processed_header + body
|
141
|
+
end
|
142
|
+
|
143
|
+
# Returns an Array of directive structures. Each structure
|
144
|
+
# is an Array with the line number as the first element, the
|
145
|
+
# directive name as the second element, followed by any
|
146
|
+
# arguments.
|
147
|
+
#
|
148
|
+
# [[1, "require", "foo"], [2, "require", "bar"]]
|
149
|
+
#
|
150
|
+
def directives
|
151
|
+
@directives ||= header_lines.each_with_index.map do |line, index|
|
152
|
+
if directive = extract_directive(line)
|
153
|
+
[index + 1, *Shellwords.shellwords(directive)]
|
154
|
+
end
|
155
|
+
end.compact
|
156
|
+
end
|
157
|
+
|
158
|
+
def extract_directive(line)
|
159
|
+
line[DIRECTIVE_PATTERN, 1]
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
attr_reader :included_pathnames
|
164
|
+
attr_reader :context
|
165
|
+
|
166
|
+
# Gathers comment directives in the source and processes them.
|
167
|
+
# Any directive method matching `process_*_directive` will
|
168
|
+
# automatically be available. This makes it easy to extend the
|
169
|
+
# processor.
|
170
|
+
#
|
171
|
+
# To implement a custom directive called `require_glob`, subclass
|
172
|
+
# `Sprockets::DirectiveProcessor`, then add a method called
|
173
|
+
# `process_require_glob_directive`.
|
174
|
+
#
|
175
|
+
# class DirectiveProcessor < Sprockets::DirectiveProcessor
|
176
|
+
# def process_require_glob_directive
|
177
|
+
# Dir["#{pathname.dirname}/#{glob}"].sort.each do |filename|
|
178
|
+
# require(filename)
|
179
|
+
# end
|
180
|
+
# end
|
181
|
+
# end
|
182
|
+
#
|
183
|
+
# Replace the current processor on the environment with your own:
|
184
|
+
#
|
185
|
+
# env.unregister_processor('text/css', Sprockets::DirectiveProcessor)
|
186
|
+
# env.register_processor('text/css', DirectiveProcessor)
|
187
|
+
#
|
188
|
+
def process_directives
|
189
|
+
directives.each do |line_number, name, *args|
|
190
|
+
context.__LINE__ = line_number
|
191
|
+
send("process_#{name}_directive", *args)
|
192
|
+
context.__LINE__ = nil
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def process_source
|
197
|
+
unless @has_written_body || processed_header.empty?
|
198
|
+
@result << processed_header << "\n"
|
199
|
+
end
|
200
|
+
|
201
|
+
included_pathnames.each do |pathname|
|
202
|
+
@result << context.evaluate(pathname)
|
203
|
+
end
|
204
|
+
|
205
|
+
unless @has_written_body
|
206
|
+
@result << processed_body
|
207
|
+
end
|
208
|
+
|
209
|
+
if compat? && constants.any?
|
210
|
+
@result.gsub!(/<%=(.*?)%>/) { constants[$1.strip] }
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# The `require` directive functions similar to Ruby's own `require`.
|
215
|
+
# It provides a way to declare a dependency on a file in your path
|
216
|
+
# and ensures its only loaded once before the source file.
|
217
|
+
#
|
218
|
+
# `require` works with files in the environment path:
|
219
|
+
#
|
220
|
+
# //= require "foo.js"
|
221
|
+
#
|
222
|
+
# Extensions are optional. If your source file is ".js", it
|
223
|
+
# assumes you are requiring another ".js".
|
224
|
+
#
|
225
|
+
# //= require "foo"
|
226
|
+
#
|
227
|
+
# Relative paths work too. Use a leading `./` to denote a relative
|
228
|
+
# path:
|
229
|
+
#
|
230
|
+
# //= require "./bar"
|
231
|
+
#
|
232
|
+
def process_require_directive(path)
|
233
|
+
if @compat
|
234
|
+
if path =~ /<([^>]+)>/
|
235
|
+
path = $1
|
236
|
+
else
|
237
|
+
path = "./#{path}" unless relative?(path)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
context.require_asset(path)
|
242
|
+
end
|
243
|
+
|
244
|
+
# `require_self` causes the body of the current file to be
|
245
|
+
# inserted before any subsequent `require` or `include`
|
246
|
+
# directives. Useful in CSS files, where it's common for the
|
247
|
+
# index file to contain global styles that need to be defined
|
248
|
+
# before other dependencies are loaded.
|
249
|
+
#
|
250
|
+
# /*= require "reset"
|
251
|
+
# *= require_self
|
252
|
+
# *= require_tree .
|
253
|
+
# */
|
254
|
+
#
|
255
|
+
def process_require_self_directive
|
256
|
+
if @has_written_body
|
257
|
+
raise ArgumentError, "require_self can only be called once per source file"
|
258
|
+
end
|
259
|
+
|
260
|
+
context.require_asset(pathname)
|
261
|
+
process_source
|
262
|
+
included_pathnames.clear
|
263
|
+
@has_written_body = true
|
264
|
+
end
|
265
|
+
|
266
|
+
# The `include` directive works similar to `require` but
|
267
|
+
# inserts the contents of the dependency even if it already
|
268
|
+
# has been required.
|
269
|
+
#
|
270
|
+
# //= include "header"
|
271
|
+
#
|
272
|
+
def process_include_directive(path)
|
273
|
+
included_pathnames << context.resolve(path)
|
274
|
+
end
|
275
|
+
|
276
|
+
# `require_directory` requires all the files inside a single
|
277
|
+
# directory. It's similar to `path/*` since it does not follow
|
278
|
+
# nested directories.
|
279
|
+
#
|
280
|
+
# //= require_directory "./javascripts"
|
281
|
+
#
|
282
|
+
def process_require_directory_directive(path = ".")
|
283
|
+
if relative?(path)
|
284
|
+
root = pathname.dirname.join(path).expand_path
|
285
|
+
context.depend_on(root)
|
286
|
+
|
287
|
+
Dir["#{root}/*"].sort.each do |filename|
|
288
|
+
if filename == self.file
|
289
|
+
next
|
290
|
+
elsif context.asset_requirable?(filename)
|
291
|
+
context.require_asset(filename)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
else
|
295
|
+
# The path must be relative and start with a `./`.
|
296
|
+
raise ArgumentError, "require_directory argument must be a relative path"
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# `require_tree` requires all the nested files in a directory.
|
301
|
+
# Its glob equivalent is `path/**/*`.
|
302
|
+
#
|
303
|
+
# //= require_tree "./public"
|
304
|
+
#
|
305
|
+
def process_require_tree_directive(path = ".")
|
306
|
+
if relative?(path)
|
307
|
+
root = pathname.dirname.join(path).expand_path
|
308
|
+
context.depend_on(root)
|
309
|
+
|
310
|
+
Dir["#{root}/**/*"].sort.each do |filename|
|
311
|
+
if filename == self.file
|
312
|
+
next
|
313
|
+
elsif File.directory?(filename)
|
314
|
+
context.depend_on(filename)
|
315
|
+
elsif context.asset_requirable?(filename)
|
316
|
+
context.require_asset(filename)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
else
|
320
|
+
# The path must be relative and start with a `./`.
|
321
|
+
raise ArgumentError, "require_tree argument must be a relative path"
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# Allows you to state a dependency on a file without
|
326
|
+
# including it.
|
327
|
+
#
|
328
|
+
# This is used for caching purposes. Any changes made to
|
329
|
+
# the dependency file with invalidate the cache of the
|
330
|
+
# source file.
|
331
|
+
#
|
332
|
+
# This is useful if you are using ERB and File.read to pull
|
333
|
+
# in contents from another file.
|
334
|
+
#
|
335
|
+
# //= depend_on "foo.png"
|
336
|
+
#
|
337
|
+
def process_depend_on_directive(path)
|
338
|
+
context.depend_on(context.resolve(path))
|
339
|
+
end
|
340
|
+
|
341
|
+
# Enable Sprockets 1.x compat mode.
|
342
|
+
#
|
343
|
+
# Makes it possible to use the same JavaScript source
|
344
|
+
# file in both Sprockets 1 and 2.
|
345
|
+
#
|
346
|
+
# //= compat
|
347
|
+
#
|
348
|
+
def process_compat_directive
|
349
|
+
@compat = true
|
350
|
+
end
|
351
|
+
|
352
|
+
# Checks if Sprockets 1.x compat mode enabled
|
353
|
+
def compat?
|
354
|
+
@compat
|
355
|
+
end
|
356
|
+
|
357
|
+
# Sprockets 1.x allowed for constant interpolation if a
|
358
|
+
# constants.yml was present. This is only available if
|
359
|
+
# compat mode is on.
|
360
|
+
def constants
|
361
|
+
if compat?
|
362
|
+
path = File.join(context.root_path, "constants.yml")
|
363
|
+
File.exist?(path) ? YAML.load_file(path) : {}
|
364
|
+
else
|
365
|
+
{}
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
# `provide` is stubbed out for Sprockets 1.x compat.
|
370
|
+
# Mutating the path when an asset is being built is
|
371
|
+
# not permitted.
|
372
|
+
def process_provide_directive(path)
|
373
|
+
end
|
374
|
+
|
375
|
+
private
|
376
|
+
def relative?(path)
|
377
|
+
path =~ /^\.($|\.?\/)/
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|