sprocketize 0.1

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.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Mato Ilic
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,45 @@
1
+ # Sprocketize: Command-line utility for the [sprockets](http://getsprockets.com) gem [![Build Status](https://secure.travis-ci.org/matoilic/sprocketize.png)](http://travis-ci.org/matoilic/sprocketize)
2
+
3
+ # Usage #
4
+
5
+ Usage: sprocketize [options] output_directory filename [filename ...]
6
+ -a, --asset-root=DIRECTORY Assets root path.
7
+ -I, --include-dir=DIRECTORY Adds the directory to the Sprockets load path.
8
+ -d, --digest Incorporates a MD5 digest into all filenames.
9
+ -m, --manifest [=DIRECTORY] Writes a manifest for the assets. If no directory is
10
+ specified the manifest will be written to the output directory.
11
+ -g, --gzip Also create a compressed version of all Stylesheets and Javascripts.
12
+ -s, --save Add given parameters to .sprocksrc
13
+ -j [=COMPRESSOR], Compress all Javascript using either closure, yui or uglifier. If no
14
+ compiler is specified closure will be used.
15
+ --compress-javascripts
16
+ -c, --compress-stylesheets Compress all Stylesheets with the YUI CSS compressor.
17
+ -h, --help Show this help message.
18
+ -v, --version Show version.
19
+
20
+ The options can also be set through a local options file in the asset root or through a global file in your
21
+ home directory. `target`, `assets` and `manifest_path` are ignored when set in the global file.
22
+
23
+ #.sprocksrc
24
+ ---
25
+ target: target output directory
26
+ paths:
27
+ - include paths
28
+ assets:
29
+ - all files here will be compiled
30
+ manifest: true or false
31
+ manifest_path: output path for the manifest file
32
+ digest: true or false
33
+ gzip: true or false
34
+ js_compressor: either closure, yui or uglifier
35
+ compress_css: true or false
36
+
37
+ Include paths should always be absolute. Asset paths are always relative to the asset root. The other paths can either
38
+ be absolute or relative. Relative paths are always relative to the asset root.
39
+
40
+ # License #
41
+
42
+ Copyright &copy; 2011 Mato Ilic <<info@matoilic.ch>>
43
+
44
+ Sprockets is distributed under an MIT-style license. See LICENSE for
45
+ details.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'sprocketize'
4
+
5
+ Sprocketize::CLI.new(*ARGV).run
@@ -0,0 +1,7 @@
1
+ require 'sprockets'
2
+
3
+ module Sprocketize
4
+ autoload :CLI, "sprocketize/cli"
5
+ autoload :Compiler, "sprocketize/compiler"
6
+ autoload :VERSION, "sprocketize/version"
7
+ end
@@ -0,0 +1,265 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+ require 'pathname'
4
+ require 'set'
5
+ require 'fileutils'
6
+ require 'yaml'
7
+
8
+ module Sprocketize
9
+ class CLI
10
+ SPROCKETS_FILE = '.sprocksrc'
11
+
12
+ attr_accessor :local_options, :global_options
13
+
14
+ def compile
15
+ env = Sprockets::Environment.new(@root)
16
+ env.js_compressor = expand_js_compressor(@local_options[:js_compressor])
17
+ env.css_compressor = expand_css_compressor(:yui) if @local_options[:compress_css]
18
+ (@paths + (@global_options[:paths] || Set.new)).each {|p| env.append_path(p)}
19
+
20
+ assets = local_options[:assets].map {|a| realpath(a).to_s}
21
+ filter = Proc.new do |asset|
22
+ assets.any? {|a| asset.pathname.to_s.start_with?(a)}
23
+ end
24
+
25
+ options = {
26
+ :manifest => local_options[:manifest] || global_options[:manifest],
27
+ :manifest_path => local_options[:manifest_path],
28
+ :digest => local_options[:digest] || global_options[:digest],
29
+ :gzip => local_options[:gzip] || global_options[:gzip]
30
+ }
31
+
32
+ compiler = Sprocketize::Compiler.new(env, realpath(@local_options[:target], true), [filter], options)
33
+ compiler.compile
34
+ end
35
+
36
+ def initialize(*args)
37
+ @assets = Set.new
38
+ @local_paths = Set.new
39
+ @global_options = load_global_options
40
+ input = parse_input(args)
41
+ @root = input.delete(:root)
42
+ @save = input.delete(:save)
43
+ @local_options = load_local_options(@root)
44
+ @local_options = merge_options(load_local_options(@root), input)
45
+ @local_options.freeze #to preserve exact user input
46
+ end
47
+
48
+ def merge_options(target, source)
49
+ {
50
+ :target => source[:target] || target[:target],
51
+ :paths => (target[:paths] || Set.new).merge((source[:paths] || Set.new)),
52
+ :assets => (target[:assets] || Set.new).merge((source[:assets] || Set.new)),
53
+ :digest => (source[:digest].nil? ? target[:digest] : source[:digest]),
54
+ :manifest => (source[:manifest].nil? ? target[:manifest] : source[:manifest]),
55
+ :manifest_path => (source[:manifest_path] || target[:manifest_path]),
56
+ :gzip => (source[:gzip].nil? ? target[:gzip] : source[:gzip]),
57
+ :js_compressor => source[:js_compressor] || target[:js_compressor],
58
+ :compress_css => source[:compress_css].nil? ? target[:compress_css] : source[:compress_css]
59
+ }
60
+ end
61
+
62
+ def parser
63
+ OptionParser.new do |opts|
64
+ opts.banner = "Usage: sprocketize [options] output_directory filename [filename ...]"
65
+
66
+ opts.on("-a DIRECTORY", "--asset-root=DIRECTORY", "Assets root path.") do |dir|
67
+ exit_if_non_existent(dir)
68
+ @input[:root] = realpath(dir)
69
+ end
70
+
71
+ opts.on("-I DIRECTORY", "--include-dir=DIRECTORY", "Adds the directory to the Sprockets load path.") do |dir|
72
+ exit_if_non_existent(dir)
73
+ @input[:paths] << dir
74
+ end
75
+
76
+ opts.on("-d", "--digest", "Incorporates a MD5 digest into all filenames.") do
77
+ @input[:digest] = true
78
+ end
79
+
80
+ opts.on("-m [DIRECTORY]", "--manifest [=DIRECTORY]", "Writes a manifest for the assets. If no directory is specified the manifest will be written to the output directory.") do |dir|
81
+ @input[:manifest] = true
82
+ @input[:manifest_path] = dir
83
+ end
84
+
85
+ opts.on("-g", "--gzip", "Also create a compressed version of all Stylesheets and Javascripts.") do |dir|
86
+ @input[:gzip] = true
87
+ end
88
+
89
+ opts.on("-s", "--save", "Add given parameters to #{SPROCKETS_FILE}") do |dir|
90
+ @input[:save] = true
91
+ end
92
+
93
+ opts.on("-j [COMPRESSOR]", "--compress-javascripts [=COMPRESSOR]", "Compress all Javascript using either closure, yui or uglifier. If no compiler is specified closure will be used.") do |compressor|
94
+ @input[:js_compressor] = (compressor || 'closure').to_sym
95
+ end
96
+
97
+ opts.on("-c", "--compress-stylesheets", "Compress all Stylesheets with the YUI CSS compressor.") do
98
+ @input[:compress_css] = true
99
+ end
100
+
101
+ opts.on_tail("-h", "--help", "Show this help message.") do
102
+ show_usage
103
+ exit
104
+ end
105
+
106
+ opts.on_tail("-v", "--version", "Show version.") do
107
+ show_version
108
+ exit
109
+ end
110
+ end
111
+ end
112
+
113
+ def puts_error(message)
114
+ puts "\e[31msprocketize: #{message}\e[0m"
115
+ end
116
+
117
+ def run
118
+ if @local_options[:target].to_s.length == 0
119
+ puts_error "no output directory provided"
120
+ show_usage
121
+ elsif @local_options[:assets].length == 0
122
+ puts_error "no assets provided"
123
+ show_usage
124
+ elsif !([:closure, :uglifier, :yui, nil].include?(@local_options[:js_compressor]))
125
+ puts_error "unsupported javascript processor #{@local_options[:js_compressor]}"
126
+ show_usage
127
+ else
128
+ @paths = Set.new
129
+ @local_options[:assets].each do |a|
130
+ a = realpath(a)
131
+ @paths << (a.file? ? a.dirname : a)
132
+ end
133
+ @local_options[:paths].each {|p| @paths << realpath(p)}
134
+
135
+ compile
136
+ save_local_options if @save
137
+ end
138
+ rescue OptionParser::InvalidOption => e
139
+ puts_error e.message
140
+ show_usage
141
+ rescue Sprockets::FileNotFound => e
142
+ puts_error e.message
143
+ end
144
+
145
+ def show_usage
146
+ puts parser
147
+ end
148
+
149
+ def show_version
150
+ puts Sprocketize::VERSION
151
+ end
152
+
153
+ private
154
+
155
+ def exit_if_non_existent(path)
156
+ return if File.exists?(path)
157
+ puts_error "No such file or directory #{path}"
158
+ exit
159
+ end
160
+
161
+ def expand_css_compressor(sym)
162
+ case sym
163
+ when :yui
164
+ load_gem('yui/compressor', 'yui-compressor')
165
+ YUI::CssCompressor.new
166
+ else
167
+ nil
168
+ end
169
+ end
170
+
171
+ def expand_js_compressor(sym)
172
+ case sym
173
+ when :closure
174
+ load_gem('closure-compiler')
175
+ Closure::Compiler.new
176
+ when :uglifier
177
+ load_gem('uglifier')
178
+ Uglifier.new
179
+ when :yui
180
+ load_gem('yui/compressor', 'yui-compressor')
181
+ YUI::JavaScriptCompressor.new
182
+ else
183
+ nil
184
+ end
185
+ end
186
+
187
+ def load_gem(require_path, gem_name = nil)
188
+ begin
189
+ require require_path
190
+ rescue LoadError
191
+ puts_error "required gem #{gem_name || require_path} not installed. please run `gem install #{gem_name || require_path}` to install it."
192
+ exit
193
+ end
194
+ end
195
+
196
+ def load_global_options
197
+ return {} if ENV['HOME'].nil?
198
+ file = Pathname.new(ENV['HOME']).join(SPROCKETS_FILE)
199
+
200
+ load_options(file)
201
+ end
202
+
203
+ def load_local_options(root)
204
+ file = root.join(SPROCKETS_FILE)
205
+
206
+ load_options(file)
207
+ end
208
+
209
+ def load_options(file)
210
+ return {} unless file.exist?
211
+
212
+ raw = YAML.load(File.open(file))
213
+
214
+ options = {}
215
+ raw.each_pair do |key, value|
216
+ options[key.to_sym] = value
217
+ end
218
+
219
+ options[:assets] = options[:assets].to_set if options[:assets].respond_to?(:to_set)
220
+ options[:paths] = options[:paths].to_set if options[:paths].respond_to?(:to_set)
221
+ options[:js_compressor] = options[:js_compressor].to_sym unless options[:js_compressor].nil?
222
+
223
+ options
224
+ end
225
+
226
+ def parse_input(args)
227
+ @input = {
228
+ :root => Pathname.new('.'),
229
+ :paths => Set.new,
230
+ :assets => []
231
+ }
232
+
233
+ parser.order(args) {|a| @input[:assets] << a}
234
+ @input[:target] = @input[:assets].shift
235
+ @input[:assets] = @input[:assets].to_set
236
+
237
+ @input
238
+ end
239
+
240
+ def realpath(path, create = false)
241
+ path = Pathname.new(path)
242
+ path = Pathname.new(@root).join(path) unless path.absolute?
243
+
244
+ FileUtils.mkdir_p(path) if create
245
+
246
+ path.realpath
247
+ end
248
+
249
+ def save_local_options
250
+ File.open(@root.join(SPROCKETS_FILE), 'wb') do |f|
251
+ YAML.dump({
252
+ 'target' => @local_options[:target],
253
+ 'paths' => (@local_options[:paths] || Set.new).to_a.map {|p| p.to_s},
254
+ 'assets' => @local_options[:assets].to_a.map {|a| a.to_s},
255
+ 'manifest' => @local_options[:manifest] || false,
256
+ 'manifest_path' => @local_options[:manifest_path],
257
+ 'digest' => @local_options[:digest] || false,
258
+ 'gzip' => @local_options[:gzip] || false,
259
+ 'js_compressor' => @local_options[:js_compressor],
260
+ 'compress_css' => @local_options[:compress_css] || false
261
+ }, f)
262
+ end
263
+ end
264
+ end
265
+ end
@@ -0,0 +1,61 @@
1
+ require 'fileutils'
2
+
3
+ module Sprocketize
4
+ class Compiler
5
+ attr_accessor :env, :target, :paths
6
+
7
+ def initialize(env, target, paths, options = {})
8
+ @env = env
9
+ @target = target
10
+ @paths = paths
11
+ @gzip = options.key?(:gzip) ? options.delete(:gzip) : false
12
+ @digest = options.key?(:digest) ? options.delete(:digest) : false
13
+ @manifest = options.key?(:manifest) ? options.delete(:manifest) : false
14
+ @manifest_path = options.delete(:manifest_path) || target
15
+ end
16
+
17
+ def compile
18
+ manifest = {}
19
+ env.each_logical_path do |logical_path|
20
+ asset = env.find_asset(logical_path)
21
+ next if asset.nil? || !compile_asset?(asset)
22
+ manifest[logical_path] = write_asset(asset)
23
+ end
24
+ write_manifest(manifest) if @manifest
25
+ end
26
+
27
+ def write_manifest(manifest)
28
+ FileUtils.mkdir_p(@manifest_path)
29
+ File.open("#{@manifest_path}/manifest.yml", 'wb') do |f|
30
+ YAML.dump(manifest, f)
31
+ end
32
+ end
33
+
34
+ def write_asset(asset)
35
+ path_for(asset).tap do |path|
36
+ filename = File.join(target, path)
37
+ FileUtils.mkdir_p File.dirname(filename)
38
+ asset.write_to(filename)
39
+ asset.write_to("#{filename}.gz") if @gzip && filename.to_s =~ /\.(css|js)$/
40
+ end
41
+ end
42
+
43
+ def compile_asset?(asset)
44
+ paths.each do |path|
45
+ case path
46
+ when Regexp
47
+ return true if path.match(asset.pathname.to_s)
48
+ when Proc
49
+ return true if path.call(asset)
50
+ else
51
+ return true if File.fnmatch(path.to_s, asset.pathname.to_s)
52
+ end
53
+ end
54
+ false
55
+ end
56
+
57
+ def path_for(asset)
58
+ @digest ? asset.digest_path : asset.logical_path
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Sprocketize
2
+ VERSION = "0.1"
3
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sprocketize
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Mato Ilic
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-11 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sprockets
16
+ requirement: &70169800278780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 2.1.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70169800278780
25
+ - !ruby/object:Gem::Dependency
26
+ name: rake
27
+ requirement: &70169800278220 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70169800278220
36
+ - !ruby/object:Gem::Dependency
37
+ name: closure-compiler
38
+ requirement: &70169800277620 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70169800277620
47
+ description: Sprocketize provides a command-line utility for the sprockets gem so
48
+ it can be used without rails.
49
+ email:
50
+ - info@matoilic.ch
51
+ executables:
52
+ - sprocketize
53
+ extensions: []
54
+ extra_rdoc_files: []
55
+ files:
56
+ - README.md
57
+ - LICENSE
58
+ - lib/sprocketize/cli.rb
59
+ - lib/sprocketize/compiler.rb
60
+ - lib/sprocketize/version.rb
61
+ - lib/sprocketize.rb
62
+ - bin/sprocketize
63
+ homepage: http://github.com/matoilic/sprocketize
64
+ licenses: []
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ none: false
77
+ requirements:
78
+ - - ! '>='
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubyforge_project:
83
+ rubygems_version: 1.8.12
84
+ signing_key:
85
+ specification_version: 3
86
+ summary: Command-line utility for the Sprockets gem
87
+ test_files: []