jammit-core 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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