jammit-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. data/LICENSE +22 -0
  2. data/README +24 -0
  3. data/README.rdoc +17 -0
  4. data/Rakefile +59 -0
  5. data/VERSION +1 -0
  6. data/bin/jammit +13 -0
  7. data/lib/assets.example.yml +14 -0
  8. data/lib/jammit-core.rb +219 -0
  9. data/lib/jammit-core/cli.rb +87 -0
  10. data/lib/jammit-core/command_line.rb +79 -0
  11. data/lib/jammit-core/compressor.rb +214 -0
  12. data/lib/jammit-core/config.rb +82 -0
  13. data/lib/jammit-core/dependencies.rb +23 -0
  14. data/lib/jammit-core/helper.rb +77 -0
  15. data/lib/jammit-core/jst.js +1 -0
  16. data/lib/jammit-core/packager.rb +163 -0
  17. data/lib/jammit-core/routes.rb +16 -0
  18. data/lib/jammit-core/ui.rb +55 -0
  19. data/test/config/assets-broken.yml +16 -0
  20. data/test/config/assets-closure.yml +16 -0
  21. data/test/config/assets-compression-disabled.yml +16 -0
  22. data/test/config/assets-css.yml +6 -0
  23. data/test/config/assets-erb.yml +13 -0
  24. data/test/config/assets-no-java.yml +16 -0
  25. data/test/config/assets.yml +13 -0
  26. data/test/fixtures/jammed/test-closure.js +1 -0
  27. data/test/fixtures/jammed/test-datauri.css +1 -0
  28. data/test/fixtures/jammed/test-line-break.css +8 -0
  29. data/test/fixtures/jammed/test-mhtml.css +17 -0
  30. data/test/fixtures/jammed/test-uncompressed.css +36 -0
  31. data/test/fixtures/jammed/test-uncompressed.js +13 -0
  32. data/test/fixtures/jammed/test.css +1 -0
  33. data/test/fixtures/jammed/test.js +1 -0
  34. data/test/fixtures/jammed/test.jst +6 -0
  35. data/test/fixtures/jammed/test2.jst +6 -0
  36. data/test/fixtures/src/test1.css +11 -0
  37. data/test/fixtures/src/test1.js +8 -0
  38. data/test/fixtures/src/test1.jst +1 -0
  39. data/test/fixtures/src/test2.css +20 -0
  40. data/test/fixtures/src/test2.js +5 -0
  41. data/test/fixtures/src/test2.jst +5 -0
  42. data/test/fixtures/src/test_fonts.css +5 -0
  43. data/test/fixtures/tags/css_includes.html +6 -0
  44. data/test/fixtures/tags/css_individual_includes.html +3 -0
  45. data/test/fixtures/tags/css_plain_includes.html +1 -0
  46. data/test/fixtures/tags/css_print.html +6 -0
  47. data/test/public/embed/DroidSansMono.eot +0 -0
  48. data/test/public/embed/DroidSansMono.ttf +0 -0
  49. data/test/public/embed/asterisk_orange.png +0 -0
  50. data/test/public/embed/asterisk_yellow.png +0 -0
  51. data/test/test_helper.rb +44 -0
  52. data/test/unit/command_line_test.rb +28 -0
  53. data/test/unit/test_closure_compressor.rb +24 -0
  54. data/test/unit/test_compressor.rb +24 -0
  55. data/test/unit/test_configuration.rb +71 -0
  56. data/test/unit/test_in_the_wrong_directory.rb +40 -0
  57. data/test/unit/test_jammit_helpers.rb +44 -0
  58. data/test/unit/test_packager.rb +77 -0
  59. metadata +187 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009 Jeremy Ashkenas, DocumentCloud
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,24 @@
1
+ ==
2
+ _ _ __ __ __ __ ___ _____
3
+ _ | |/_\ | \/ | \/ |_ _|_ _|
4
+ | || / _ \| |\/| | |\/| || | | |
5
+ \__/_/ \_\_| |_|_| |_|___| |_|
6
+
7
+
8
+ Jammit is an industrial strength asset packaging library for Rails,
9
+ providing both the CSS and JavaScript concatenation and compression
10
+ that you'd expect, as well as ahead-of-time gzipping, built-in JavaScript
11
+ template support, and optional Data-URI / MHTML image embedding.
12
+
13
+ Installation:
14
+ gem install jammit
15
+
16
+ For documentation, usage, and examples, see:
17
+ http://documentcloud.github.com/jammit/
18
+
19
+ To suggest a feature or report a bug:
20
+ http://github.com/documentcloud/jammit/issues/
21
+
22
+ For internal source docs, see:
23
+ http://documentcloud.github.com/jammit/doc/
24
+
data/README.rdoc ADDED
@@ -0,0 +1,17 @@
1
+ = jammit-core
2
+
3
+ Description goes here.
4
+
5
+ == Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ == Copyright
16
+
17
+ Copyright (c) 2010 Christocracy. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,59 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "jammit-core"
8
+ gem.summary = %Q{A non-Rails fork of the Jammit asset-packager}
9
+ gem.description = %Q{A non-Rails fork of the Jammit asset-packager for use with any Ruby framework}
10
+ gem.email = "christocracy@gmail.com"
11
+ gem.homepage = "http://github.com/christocracy/jammit-core"
12
+ gem.authors = ["Christocracy"]
13
+ gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
14
+ gem.files = FileList["[A-Z]*", "{bin,generators,lib,test,js}/**/*", 'lib/jeweler/templates/.gitignore']
15
+ gem.add_dependency "yui-compressor"
16
+ gem.add_dependency "closure-compiler"
17
+ gem.add_dependency "extlib"
18
+ gem.add_dependency "json"
19
+
20
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
21
+ end
22
+ Jeweler::GemcutterTasks.new
23
+ rescue LoadError
24
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
25
+ end
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/test_*.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ begin
35
+ require 'rcov/rcovtask'
36
+ Rcov::RcovTask.new do |test|
37
+ test.libs << 'test'
38
+ test.pattern = 'test/**/test_*.rb'
39
+ test.verbose = true
40
+ end
41
+ rescue LoadError
42
+ task :rcov do
43
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
44
+ end
45
+ end
46
+
47
+ task :test => :check_dependencies
48
+
49
+ task :default => :test
50
+
51
+ require 'rake/rdoctask'
52
+ Rake::RDocTask.new do |rdoc|
53
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
54
+
55
+ rdoc.rdoc_dir = 'rdoc'
56
+ rdoc.title = "jammit-core #{version}"
57
+ rdoc.rdoc_files.include('README*')
58
+ rdoc.rdoc_files.include('lib/**/*.rb')
59
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
data/bin/jammit ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ # Check if an older version of extjs-mvc is installed
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
5
+ require 'jammit-core'
6
+ require 'jammit-core/cli'
7
+
8
+ begin
9
+ Jammit::CLI.start
10
+ rescue Jammit::Error => e
11
+ Jammit.ui.error(e.message)
12
+ exit e.status_code
13
+ end
@@ -0,0 +1,14 @@
1
+ output_folder: public
2
+ base_url: base_url
3
+ package_assets: on # (on, off, always)
4
+ embed_assets: on # (on, off, datauri)
5
+ compress_assets: false
6
+ gzip_assets: false
7
+ package_path: packages # (defaults to assets)
8
+ javascript_compressor: closure # (yui, closure)
9
+ compressor_options:
10
+ compilation_level: ADVANCED_OPTIMIZATIONS
11
+
12
+ javascripts:
13
+
14
+ stylesheets:
@@ -0,0 +1,219 @@
1
+ $LOAD_PATH.push File.expand_path(File.dirname(__FILE__))
2
+
3
+ # @Jammit@ is the central namespace for all Jammit classes, and provides access
4
+ # to all of the configuration options.
5
+ module Jammit
6
+
7
+ VERSION = "0.4.3"
8
+
9
+ ROOT = File.expand_path(File.dirname(__FILE__))
10
+
11
+ ASSET_ROOT = File.expand_path(".") unless defined?(ASSET_ROOT)
12
+
13
+ PUBLIC_ROOT = File.join(ASSET_ROOT, 'public')
14
+
15
+ DEFAULT_CONFIG_PATH = File.join(ASSET_ROOT, 'config')
16
+
17
+ DEFAULT_CONFIG_FILENAME = 'assets.yml'
18
+
19
+ DEFAULT_PACKAGE_PATH = "assets"
20
+
21
+ DEFAULT_JST_SCRIPT = File.join(ROOT, 'lib/jammit/jst.js')
22
+
23
+ DEFAULT_JST_COMPILER = "template"
24
+
25
+ DEFAULT_JST_NAMESPACE = "window.JST"
26
+
27
+ AVAILABLE_COMPRESSORS = [:yui, :closure]
28
+
29
+ DEFAULT_COMPRESSOR = :yui
30
+
31
+ SUFFIX = 'all'
32
+ DEBUG_SUFFIX = 'all-debug'
33
+
34
+ autoload :UI, 'jammit-core/ui'
35
+ autoload :Config, 'jammit-core/config'
36
+
37
+ class Error < StandardError
38
+ def self.status_code(code = nil)
39
+ return @code unless code
40
+ @code = code
41
+ end
42
+
43
+ def status_code
44
+ self.class.status_code
45
+ end
46
+ end
47
+
48
+ # Jammit raises @AppNotFound when trying to run outside of an application
49
+ class AppNotFound < Error; status_code(1) ; end
50
+
51
+ # Jammit raises a @PackageNotFound@ exception when a non-existent package is
52
+ # requested by a browser -- rendering a 404.
53
+ class PackageNotFound < Error; status_code(2) ; end
54
+
55
+ # Jammit raises a ConfigurationNotFound exception when you try to load the
56
+ # configuration of an assets.yml file that doesn't exist.
57
+ class ConfigurationNotFound < Error; status_code(3) ; end
58
+
59
+ # Jammit raises AlreadyConfigred if trying to over-write an existing configuration file
60
+ class AlreadyConfigured < Error; status_code(4) ; end
61
+
62
+ # Jammit raises an OutputNotWritable exception if the output directory for
63
+ # cached packages is locked.
64
+ class OutputNotWritable < Error; status_code(4) ; end
65
+
66
+ class << self
67
+ attr_reader :configuration
68
+ attr_writer :ui
69
+ attr_writer :options
70
+
71
+
72
+ def configure
73
+ @configured ||= begin
74
+ ##
75
+ # perform some config here?
76
+ #
77
+ #configure_gem_home_and_path
78
+ true
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Ensure we're running within a rails app unless generating a new app ($ xmvc generate app foo)
84
+ #
85
+ def ensure_in_app
86
+ unless ARGV.empty? || ARGV.first == 'help' || (File.exists?('app') && File.exists?('config') && File.exists?('config/environment.json'))
87
+ raise Jammit::AppNotFound.new("This command must be executed from the root of an extjs-mvc application")
88
+ end
89
+ end
90
+
91
+ def ui
92
+ @ui ||= UI.new
93
+ end
94
+
95
+ def options
96
+ @options
97
+ end
98
+
99
+ def asset_root
100
+ unless @asset_root
101
+ if (options && options[:asset_root])
102
+ @asset_root = options[:asset_root]
103
+ else
104
+ @asset_root = ASSET_ROOT
105
+ end
106
+ end
107
+
108
+ #@asset_root ||= (options && options[:asset_root]) ? options[:asset_root] : ASSET_ROOT
109
+ @asset_root
110
+ end
111
+
112
+ def public_root
113
+ @public_root ||= File.join(asset_root, 'public')
114
+ end
115
+
116
+ def config_path
117
+ @config_path ||= File.join(asset_root, 'config', DEFAULT_CONFIG_FILENAME)
118
+ end
119
+
120
+ def package_path
121
+ @package_path ||= (@options && @options[:package_path]) ? @options[:package_path] : config[:package_path]
122
+ end
123
+
124
+ # Load the complete asset configuration from the specified @config_path@.
125
+
126
+ def config
127
+ unless @config
128
+ # Normalize config
129
+ @config = Jammit::Config.load.to_mash
130
+
131
+ @config[:output_folder] = (@config[:output_folder]) ? File.join(asset_root, @config[:output_folder]) : public_root
132
+ @config[:package_path] = @config[:package_path] || Jammit::DEFAULT_PACKAGE_PATH
133
+ @config[:embed_assets] = @config[:embed_assets] || @config[:embed_images]
134
+ @config[:compress_assets] = !(@config[:compress_assets] == false)
135
+ @config[:gzip_assets] = !(@config[:gzip_assets] == false)
136
+ @config[:mhtml_enabled] = @config[:embed_assets] && @config[:embed_assets] != "datauri"
137
+ @config[:compressor_options] = (@config[:compressor_options] || {}).to_mash
138
+ @config[:css_compressor_options] = (@config[:css_compressor_options] || {}).to_mash
139
+ @config[:javascript_compressor] = get_javascript_compressor(@config[:javascript_compressor].to_sym)
140
+ @config[:package_assets] = get_package_assets(@config[:package_assets])
141
+ @config[:template_function] = get_template_function(@config[:template_function])
142
+ @config[:include_jst_script] = @config[:template_function] == Jammit::DEFAULT_JST_COMPILER
143
+ @config[:template_namespace] = get_template_namespace(@config[:template_namespace])
144
+ @config[:suffix] = SUFFIX unless @config[:suffix]
145
+ @config[:debug_suffix] = DEBUG_SUFFIX unless @config[:debug_suffix]
146
+ end
147
+ @config
148
+ end
149
+
150
+ def config=(config)
151
+ @config = config
152
+ end
153
+
154
+ # The YUI Compressor requires Java > 1.4, and Closure requires Java > 1.6.
155
+ def check_java_version
156
+ java = @config[:compressor_options][:java] || 'java'
157
+ @config[:css_compressor_options][:java] ||= java if @config[:compressor_options][:java]
158
+ version = (`#{java} -version 2>&1`)[/\d+\.\d+/]
159
+ disable_compression if !version ||
160
+ (@config[:javascript_compressor] == :closure && version < '1.6') ||
161
+ (@config[:javascript_compressor] == :yui && version < '1.4')
162
+ end
163
+
164
+ # If we don't have a working Java VM, then disable asset compression and
165
+ # complain loudly.
166
+ def disable_compression
167
+ @config[:compress_assets] = false
168
+ Jammit.ui.warn("Asset compression disabled -- Java unavailable.")
169
+ end
170
+
171
+ # Turn asset packaging on or off, depending on configuration and environment.
172
+ def get_package_assets(value)
173
+ package_env = !defined?(Rails) || !Rails.env.development?
174
+ (value == true || value.nil?) ? package_env : (value == 'always') ? true : false
175
+ end
176
+
177
+ # Assign the JST template function, unless explicitly turned off.
178
+ def get_template_function(value)
179
+ (value == true || value.nil?) ? DEFAULT_JST_COMPILER : value == false ? '' : value
180
+ end
181
+
182
+ # Ensure that the JavaScript compressor is a valid choice.
183
+ def get_javascript_compressor(value)
184
+ Jammit::AVAILABLE_COMPRESSORS.include?(value) ? value : Jammit::DEFAULT_COMPRESSOR
185
+ end
186
+
187
+ # Set the root JS object in which to stash all compiled JST.
188
+ def get_template_namespace(value)
189
+ (value == true || value.nil?) ? Jammit::DEFAULT_JST_NAMESPACE : value.to_s
190
+ end
191
+
192
+ # Force a reload by resetting the Packager and reloading the configuration.
193
+ # In development, this will be called as a before_filter before every request.
194
+ def reload!
195
+ Thread.current[:jammit_packager] = nil
196
+ @config = Config.load(config[:config_path], true)
197
+ end
198
+
199
+ # Keep a global (thread-local) reference to a @Jammit::Packager@, to avoid
200
+ # recomputing asset lists unnecessarily.
201
+ def packager
202
+ Thread.current[:jammit_packager] ||= Packager.new
203
+ end
204
+
205
+ # Generate the base filename for a version of a given package.
206
+ def filename(package, extension, suffix=nil)
207
+ suffix_part = suffix ? "-#{suffix}" : ''
208
+ "#{package}#{suffix_part}.#{extension}"
209
+ end
210
+
211
+ # Generates the server-absolute URL to an asset package.
212
+ def asset_url(package, extension, suffix=nil, mtime=nil)
213
+ timestamp = mtime ? "?#{mtime.to_i}" : ''
214
+ "/#{package_path}/#{filename(package, extension, suffix)}#{timestamp}"
215
+ end
216
+ end
217
+ end
218
+
219
+ require 'jammit-core/dependencies'
@@ -0,0 +1,87 @@
1
+ require 'thor'
2
+ require 'yaml'
3
+
4
+ module Jammit
5
+ class CLI < Thor
6
+ ARGV = ::ARGV.dup
7
+
8
+ desc "init", "Initialize a project for jammit-core"
9
+ def init
10
+ Jammit::Config.dispatch(:create)
11
+ end
12
+
13
+ desc "config", "Manage Jammit configuration file. Use jammit config show, jammit config set <name> <value>"
14
+ def config(cmd, *params)
15
+ Jammit::Config.dispatch(cmd.to_sym, *params)
16
+ end
17
+
18
+ desc "build", "Compile assets"
19
+ def build(package = :all, *params)
20
+ package = package.to_s
21
+ case package
22
+ when "all"
23
+ Jammit.packager.force = true #Jammit.configuration[:force]
24
+ Jammit.packager.precache_all(Jammit.config[:output_folder], Jammit.config[:base_url])
25
+ else
26
+ Jammit.packager.force = true
27
+ Jammit.packager.precache(package, Jammit.config[:output_folder], Jammit.config[:base_url])
28
+ end
29
+ end
30
+
31
+ def initialize(args=ARGV, options={}, config={})
32
+
33
+ Jammit.ui = UI::Shell.new(shell)
34
+ super
35
+
36
+ #@options = {
37
+ # :config_path => Jammit::DEFAULT_CONFIG_PATH,
38
+ # :output_folder => nil,
39
+ # :base_url => nil,
40
+ # :force => false
41
+ #}
42
+
43
+ if options.kind_of? Hash
44
+ Jammit.options = options
45
+ end
46
+
47
+ #Jammit.packager.force = @options[:force]
48
+ #Jammit.packager.precache_all(@options[:output_folder], @options[:base_url])
49
+
50
+ end
51
+
52
+ private
53
+
54
+ # Uses @OptionParser@ to grab the options: *--output*, *--config*, and
55
+ # *--base-url*...
56
+ def parse_options
57
+ #@options = {
58
+ # :config_path => Jammit::DEFAULT_CONFIG_PATH,
59
+ # :output_folder => nil,
60
+ # :base_url => nil,
61
+ # :force => false
62
+ #}
63
+
64
+ #@option_parser = OptionParser.new do |opts|
65
+ # opts.on('-o', '--output PATH', 'output folder for packages (default: "public/assets")') do |output_folder|
66
+ # @options[:output_folder] = output_folder
67
+ # end
68
+ # opts.on('-c', '--config PATH', 'path to assets.yml (default: "config/assets.yml")') do |config_path|
69
+ # @options[:config_path] = config_path
70
+ ## end
71
+ # opts.on('-u', '--base-url URL', 'base URL for MHTML (ex: "http://example.com")') do |base_url|
72
+ # @options[:base_url] = base_url
73
+ # end
74
+ # opts.on('-f', '--force', 'force a rebuild of all assets') do |force|
75
+ # @options[:force] = force
76
+ # end
77
+ # opts.on_tail('-v', '--version', 'display Jammit version') do
78
+ # puts "Jammit version #{Jammit::VERSION}"
79
+ # exit
80
+ # end
81
+ #end
82
+ #@option_parser.banner = BANNER
83
+ #@option_parser.parse!(ARGV)
84
+ end
85
+
86
+ end
87
+ end