ktheory-juicer 1.0.0.ktheory1
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/History.txt +30 -0
- data/Manifest.txt +58 -0
- data/Rakefile +96 -0
- data/Readme.rdoc +312 -0
- data/VERSION +1 -0
- data/bin/juicer +8 -0
- data/lib/juicer.rb +70 -0
- data/lib/juicer/asset/path.rb +275 -0
- data/lib/juicer/asset/path_resolver.rb +79 -0
- data/lib/juicer/binary.rb +171 -0
- data/lib/juicer/cache_buster.rb +130 -0
- data/lib/juicer/chainable.rb +106 -0
- data/lib/juicer/cli.rb +56 -0
- data/lib/juicer/command/install.rb +61 -0
- data/lib/juicer/command/list.rb +57 -0
- data/lib/juicer/command/merge.rb +205 -0
- data/lib/juicer/command/util.rb +32 -0
- data/lib/juicer/command/verify.rb +60 -0
- data/lib/juicer/css_cache_buster.rb +80 -0
- data/lib/juicer/datafy/datafy.rb +20 -0
- data/lib/juicer/dependency_resolver/css_dependency_resolver.rb +29 -0
- data/lib/juicer/dependency_resolver/dependency_resolver.rb +101 -0
- data/lib/juicer/dependency_resolver/javascript_dependency_resolver.rb +23 -0
- data/lib/juicer/ext/logger.rb +5 -0
- data/lib/juicer/ext/string.rb +47 -0
- data/lib/juicer/ext/symbol.rb +15 -0
- data/lib/juicer/image_embed.rb +136 -0
- data/lib/juicer/install/base.rb +186 -0
- data/lib/juicer/install/closure_compiler_installer.rb +69 -0
- data/lib/juicer/install/jslint_installer.rb +51 -0
- data/lib/juicer/install/rhino_installer.rb +53 -0
- data/lib/juicer/install/yui_compressor_installer.rb +67 -0
- data/lib/juicer/jslint.rb +90 -0
- data/lib/juicer/merger/base.rb +74 -0
- data/lib/juicer/merger/javascript_merger.rb +29 -0
- data/lib/juicer/merger/stylesheet_merger.rb +110 -0
- data/lib/juicer/minifyer/closure_compiler.rb +90 -0
- data/lib/juicer/minifyer/java_base.rb +77 -0
- data/lib/juicer/minifyer/yui_compressor.rb +96 -0
- data/test/bin/jslint-1.0.js +523 -0
- data/test/bin/jslint.js +523 -0
- data/test/bin/rhino1_7R1.zip +0 -0
- data/test/bin/rhino1_7R2-RC1.jar +0 -0
- data/test/bin/rhino1_7R2-RC1.zip +0 -0
- data/test/bin/yuicompressor +0 -0
- data/test/bin/yuicompressor-2.3.5.zip +0 -0
- data/test/bin/yuicompressor-2.4.2.jar +0 -0
- data/test/bin/yuicompressor-2.4.2.zip +0 -0
- data/test/data/Changelog.txt +10 -0
- data/test/data/a.css +3 -0
- data/test/data/a.js +5 -0
- data/test/data/a1.css +5 -0
- data/test/data/b.css +1 -0
- data/test/data/b.js +5 -0
- data/test/data/b1.css +5 -0
- data/test/data/c1.css +3 -0
- data/test/data/css/2.gif +1 -0
- data/test/data/css/test.css +11 -0
- data/test/data/css/test2.css +1 -0
- data/test/data/d1.css +3 -0
- data/test/data/images/1.png +1 -0
- data/test/data/my_app.js +2 -0
- data/test/data/not-ok.js +2 -0
- data/test/data/ok.js +3 -0
- data/test/data/path_test.css +5 -0
- data/test/data/path_test2.css +14 -0
- data/test/data/pkg/module/moda.js +2 -0
- data/test/data/pkg/module/modb.js +3 -0
- data/test/data/pkg/pkg.js +1 -0
- data/test/test_helper.rb +169 -0
- data/test/unit/juicer/asset/path_resolver_test.rb +76 -0
- data/test/unit/juicer/asset/path_test.rb +370 -0
- data/test/unit/juicer/cache_buster_test.rb +104 -0
- data/test/unit/juicer/chainable_test.rb +94 -0
- data/test/unit/juicer/command/install_test.rb +58 -0
- data/test/unit/juicer/command/list_test.rb +81 -0
- data/test/unit/juicer/command/merge_test.rb +162 -0
- data/test/unit/juicer/command/util_test.rb +58 -0
- data/test/unit/juicer/command/verify_test.rb +48 -0
- data/test/unit/juicer/css_cache_buster_test.rb +71 -0
- data/test/unit/juicer/datafy_test.rb +37 -0
- data/test/unit/juicer/dependency_resolver/css_dependency_resolver_test.rb +36 -0
- data/test/unit/juicer/dependency_resolver/javascript_dependency_resolver_test.rb +50 -0
- data/test/unit/juicer/ext/string_test.rb +59 -0
- data/test/unit/juicer/ext/symbol_test.rb +27 -0
- data/test/unit/juicer/image_embed_test.rb +271 -0
- data/test/unit/juicer/install/installer_base_test.rb +214 -0
- data/test/unit/juicer/install/jslint_installer_test.rb +54 -0
- data/test/unit/juicer/install/rhino_installer_test.rb +57 -0
- data/test/unit/juicer/install/yui_compressor_test.rb +56 -0
- data/test/unit/juicer/jslint_test.rb +60 -0
- data/test/unit/juicer/merger/base_test.rb +122 -0
- data/test/unit/juicer/merger/javascript_merger_test.rb +74 -0
- data/test/unit/juicer/merger/stylesheet_merger_test.rb +180 -0
- data/test/unit/juicer/minifyer/closure_compressor_test.rb +107 -0
- data/test/unit/juicer/minifyer/yui_compressor_test.rb +116 -0
- data/test/unit/juicer_test.rb +1 -0
- metadata +265 -0
@@ -0,0 +1,186 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'fileutils'
|
4
|
+
require "juicer"
|
5
|
+
|
6
|
+
module Juicer
|
7
|
+
module Install
|
8
|
+
#
|
9
|
+
# Installer skeleton. Provides basic functionality like figuring out where
|
10
|
+
# to install, create base directories, remove unneeded directories and more
|
11
|
+
# housekeeping.
|
12
|
+
#
|
13
|
+
class Base
|
14
|
+
attr_reader :install_dir
|
15
|
+
|
16
|
+
#
|
17
|
+
# Create new installer
|
18
|
+
#
|
19
|
+
def initialize(install_dir = Juicer.home)
|
20
|
+
@install_dir = install_dir
|
21
|
+
@path = nil
|
22
|
+
@bin_path = nil
|
23
|
+
@name = nil
|
24
|
+
@dependencies = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
#
|
28
|
+
# Returns the latest available version number. Must be implemented in
|
29
|
+
# subclasses. Raises an exception when called directly.
|
30
|
+
#
|
31
|
+
def latest
|
32
|
+
raise NotImplementedError.new("Implement in subclasses")
|
33
|
+
end
|
34
|
+
|
35
|
+
# Returns the path relative to installation path this installer will
|
36
|
+
# install to
|
37
|
+
def path
|
38
|
+
return @path if @path
|
39
|
+
@path = "lib/" + self.class.to_s.split("::").pop.sub(/Installer$/, "").underscore
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the path to search for binaries from
|
43
|
+
#
|
44
|
+
def bin_path
|
45
|
+
return @bin_path if @bin_path
|
46
|
+
@bin_path = File.join(path, "bin")
|
47
|
+
end
|
48
|
+
|
49
|
+
#
|
50
|
+
# Returns name of component. Default implementation returns class name
|
51
|
+
# with "Installer" removed
|
52
|
+
#
|
53
|
+
def name
|
54
|
+
return @name if @name
|
55
|
+
@name = File.basename(path).split("_").inject("") { |str, word| (str + " #{word.capitalize}").strip }
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Checks if the component is currently installed.
|
60
|
+
#
|
61
|
+
# If no version is provided the most recent version is assumed.
|
62
|
+
#
|
63
|
+
def installed?(version = nil)
|
64
|
+
installed = File.exists?(File.join(@install_dir, path, "#{version || latest}"))
|
65
|
+
deps = @dependencies.length == 0 || dependencies.all? { |d, v| d.installed?(v) }
|
66
|
+
installed && deps
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Install the component. Creates basic directory structure.
|
71
|
+
#
|
72
|
+
def install(version = nil)
|
73
|
+
raise "#{name} #{version} is already installed in #{File.join(@install_dir, path)}" if installed?(version)
|
74
|
+
version ||= latest
|
75
|
+
log "Installing #{name} #{version} in #{File.join(@install_dir, path)}"
|
76
|
+
|
77
|
+
if @dependencies.length > 0
|
78
|
+
log "Installing dependencies"
|
79
|
+
dependencies { |dependency, ver| dependency.install(ver) unless dependency.installed?(ver) }
|
80
|
+
end
|
81
|
+
|
82
|
+
# Create directories
|
83
|
+
FileUtils.mkdir_p(File.join(@install_dir, path, "bin"))
|
84
|
+
FileUtils.mkdir_p(File.join(@install_dir, path, version))
|
85
|
+
|
86
|
+
# Return resolved version for subclass to use
|
87
|
+
version
|
88
|
+
end
|
89
|
+
|
90
|
+
#
|
91
|
+
# Uninstalls the given version of the component.
|
92
|
+
#
|
93
|
+
# If no version is provided the most recent version is assumed.
|
94
|
+
#
|
95
|
+
# If there are no more files left in INSTALLATION_PATH/<path>, the
|
96
|
+
# whole directory is removed.
|
97
|
+
#
|
98
|
+
# This method takes a block and can be used from subclasses like so:
|
99
|
+
#
|
100
|
+
# def self.uninstall(install_dir = nil, version = nil)
|
101
|
+
# super do |home_dir, version|
|
102
|
+
# # Custom uninstall logic
|
103
|
+
# end
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
#
|
107
|
+
def uninstall(version = nil)
|
108
|
+
version ||= self.latest
|
109
|
+
install_dir = File.join(@install_dir, path, version)
|
110
|
+
raise "#{name} #{version} is not installed" if !File.exists?(install_dir)
|
111
|
+
|
112
|
+
FileUtils.rm_rf(install_dir)
|
113
|
+
|
114
|
+
yield(File.join(@install_dir, path), version) if block_given?
|
115
|
+
|
116
|
+
files = Dir.glob(File.join(@install_dir, path, "**", "*")).find_all { |f| File.file?(f) }
|
117
|
+
FileUtils.rm_rf(File.join(@install_dir, path)) if files.length == 0
|
118
|
+
end
|
119
|
+
|
120
|
+
#
|
121
|
+
# Download a file to Juicer temporary directory. The file will be kept
|
122
|
+
# until #purge is called to wipe it. If the installer receives a request
|
123
|
+
# to download the same file again, the disk cache will be used unless the
|
124
|
+
# force argument is true (default false)
|
125
|
+
#
|
126
|
+
def download(url, force = false)
|
127
|
+
filename = File.join(@install_dir, "download", path.sub("lib/", ""), File.basename(url))
|
128
|
+
return filename if File.exists?(filename) && !force
|
129
|
+
FileUtils.mkdir_p(File.dirname(filename))
|
130
|
+
File.delete(filename) if File.exists?(filename) && force
|
131
|
+
|
132
|
+
log "Downloading #{url}"
|
133
|
+
File.open(filename, "wb") do |file|
|
134
|
+
webpage = open(url)
|
135
|
+
file.write(webpage.read)
|
136
|
+
webpage.close
|
137
|
+
end
|
138
|
+
|
139
|
+
filename
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Display a message to the user through Juicer::LOGGER
|
144
|
+
#
|
145
|
+
def log(str)
|
146
|
+
Juicer::LOGGER.info str
|
147
|
+
end
|
148
|
+
|
149
|
+
#
|
150
|
+
# Add a dependency. Dependency should be a Juicer::Install::Base installer
|
151
|
+
# class (not instance) OR a symbol/string like :rhino/"rhino" (which will
|
152
|
+
# be expanded unto Juicer::Install::RhinoInstaller). Version is optional
|
153
|
+
# and defaults to latest and greatest.
|
154
|
+
#
|
155
|
+
def dependency(dependency, version = nil)
|
156
|
+
dependency = Juicer::Install.get(dependency) if [String, Symbol].include?(dependency.class)
|
157
|
+
|
158
|
+
@dependencies[dependency.to_s + (version || "")] = [dependency, version]
|
159
|
+
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# Yields depencies one at a time: class and version and returns an array
|
163
|
+
# of arrays: [dependency, version] where dependency is an instance and
|
164
|
+
# version a string.
|
165
|
+
#
|
166
|
+
def dependencies(&block)
|
167
|
+
@dependencies.collect do |name, dependency|
|
168
|
+
version = dependency[1]
|
169
|
+
dependency = dependency[0].new(@install_dir)
|
170
|
+
block.call(dependency, version) if block
|
171
|
+
[dependency, version]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# Returns the installer. Accepts installer classes (which are returned
|
178
|
+
# directly), strings or symbols. Strings and symbols may be on the form
|
179
|
+
# :my_module which is expanded to Juicer::Install::MyModuleInstaller
|
180
|
+
#
|
181
|
+
def self.get(nameOrClass)
|
182
|
+
return nameOrClass if nameOrClass.is_a? Class
|
183
|
+
(nameOrClass.to_s + "_installer").classify(Juicer::Install)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require "juicer"
|
2
|
+
require "juicer/install/base"
|
3
|
+
require "zip/zip"
|
4
|
+
|
5
|
+
module Juicer
|
6
|
+
module Install
|
7
|
+
#
|
8
|
+
# Install and uninstall routines for the Google Closure Compiler.
|
9
|
+
# Installation downloads the Closure Compiler distribution, unzips it and
|
10
|
+
# storesthe jar file on disk along with the README.
|
11
|
+
#
|
12
|
+
class ClosureCompilerInstaller < Base
|
13
|
+
def initialize(install_dir = Juicer.home)
|
14
|
+
super(install_dir)
|
15
|
+
@latest = nil
|
16
|
+
@website = "http://code.google.com/p/closure-compiler/downloads/list"
|
17
|
+
@download_link = "http://closure-compiler.googlecode.com/files/compiler-%s.zip"
|
18
|
+
end
|
19
|
+
|
20
|
+
#
|
21
|
+
# Install the Closure Compiler. Downloads the distribution and keeps the jar
|
22
|
+
# file inside PATH/closure_compiler/bin and the README in
|
23
|
+
# PATH/closere_compiler/yyyymmdd/ where yyyymmdd is the version, most recent if
|
24
|
+
# not specified otherwise.
|
25
|
+
#
|
26
|
+
# Path defaults to environment variable $JUICER_HOME or default Juicer
|
27
|
+
# home
|
28
|
+
#
|
29
|
+
def install(version = nil)
|
30
|
+
version = super(version)
|
31
|
+
base = "closure-compiler-#{version}"
|
32
|
+
filename = download(@download_link % version)
|
33
|
+
target = File.join(@install_dir, path)
|
34
|
+
|
35
|
+
Zip::ZipFile.open(filename) do |file|
|
36
|
+
file.extract("README", File.join(target, version, "README"))
|
37
|
+
file.extract("compiler.jar", File.join(target, "bin", "#{base}.jar"))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Uninstalls the given version of Closure Compiler. If no location is
|
43
|
+
# provided the environment variable $JUICER_HOME or Juicers default home
|
44
|
+
# directory is used.
|
45
|
+
#
|
46
|
+
# If no version is provided the most recent version is assumed.
|
47
|
+
#
|
48
|
+
# If there are no more files left in INSTALLATION_PATH/closure_compiler, the
|
49
|
+
# whole directory is removed.
|
50
|
+
#
|
51
|
+
def uninstall(version = nil)
|
52
|
+
super(version) do |dir, version|
|
53
|
+
File.delete(File.join(dir, "bin/closure-compiler-#{version}.jar"))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Check which version is the most recent
|
59
|
+
#
|
60
|
+
def latest
|
61
|
+
return @latest if @latest
|
62
|
+
webpage = Nokogiri::HTML(open(@website))
|
63
|
+
@latest = (webpage / "//table[@id='resultstable']//td/a[contains(@href, 'compiler')]").map{|link|
|
64
|
+
link.get_attribute('href')[/\d{8}/].to_i
|
65
|
+
}.sort.last.to_s
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require "juicer"
|
2
|
+
require "juicer/install/base"
|
3
|
+
require "zip/zip"
|
4
|
+
|
5
|
+
module Juicer
|
6
|
+
module Install
|
7
|
+
#
|
8
|
+
# Install and uninstall routines for the JSLint library by Douglas Crockford.
|
9
|
+
# Installation downloads the jslintfull.js and rhino.js files and stores
|
10
|
+
# them in the Juicer installation directory.
|
11
|
+
#
|
12
|
+
class JSLintInstaller < Base
|
13
|
+
attr_reader :latest
|
14
|
+
|
15
|
+
def initialize(install_dir = Juicer.home)
|
16
|
+
super(install_dir)
|
17
|
+
@latest = "1.0"
|
18
|
+
@website = "http://www.jslint.com/"
|
19
|
+
@path = "lib/jslint"
|
20
|
+
@name = "JsLint"
|
21
|
+
dependency :rhino
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Install JSLint. Downloads the two js files and stores them in the
|
26
|
+
# installation directory.
|
27
|
+
#
|
28
|
+
def install(version = nil)
|
29
|
+
version = super(version)
|
30
|
+
filename = download(File.join(@website, "rhino/jslint.js"))
|
31
|
+
FileUtils.copy(filename, File.join(@install_dir, path, "bin", "jslint-#{version}.js"))
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
# Uninstalls JSLint
|
36
|
+
#
|
37
|
+
def uninstall(version = nil)
|
38
|
+
super(version) do |dir, version|
|
39
|
+
File.delete(File.join(dir, "bin", "jslint-#{version}.js"))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# This class makes it possible to do Juicer.install("jslint") instead of
|
46
|
+
# Juicer.install("j_s_lint"). Sugar, sugar...
|
47
|
+
#
|
48
|
+
class JslintInstaller < JSLintInstaller
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "juicer"
|
2
|
+
require "juicer/install/base"
|
3
|
+
require "zip/zip"
|
4
|
+
|
5
|
+
module Juicer
|
6
|
+
module Install
|
7
|
+
#
|
8
|
+
# Install and uninstall routines for the Mozilla Rhino jar.
|
9
|
+
#
|
10
|
+
class RhinoInstaller < Base
|
11
|
+
attr_reader :latest
|
12
|
+
|
13
|
+
def initialize(install_dir = Juicer.home)
|
14
|
+
super(install_dir)
|
15
|
+
@latest = "1_7R2-RC1"
|
16
|
+
@website = "http://ftp.mozilla.org/pub/mozilla.org/js/"
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Install Rhino. Downloads the jar file and stores it in the installation
|
21
|
+
# directory along with the License text.
|
22
|
+
#
|
23
|
+
def install(version = nil)
|
24
|
+
version = super((version || latest).gsub(/\./, "_"))
|
25
|
+
base = "rhino#{version}"
|
26
|
+
filename = download(File.join(@website, "#{base}.zip"))
|
27
|
+
target = File.join(@install_dir, path)
|
28
|
+
|
29
|
+
Zip::ZipFile.open(filename) do |file|
|
30
|
+
FileUtils.mkdir_p(File.join(target, version))
|
31
|
+
|
32
|
+
begin
|
33
|
+
file.extract("#{base.sub(/-RC\d/, "")}/LICENSE.txt", File.join(target, version, "LICENSE.txt"))
|
34
|
+
rescue Exception
|
35
|
+
# Fail silently, some releases don't carry the license
|
36
|
+
end
|
37
|
+
|
38
|
+
file.extract("#{base.sub(/-RC\d/, "")}/js.jar", File.join(target, "bin", "#{base}.jar"))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
#
|
43
|
+
# Uninstalls Rhino
|
44
|
+
#
|
45
|
+
def uninstall(version = nil)
|
46
|
+
super((version || latest).gsub(/\./, "_")) do |dir, version|
|
47
|
+
base = "rhino#{version}"
|
48
|
+
File.delete(File.join(dir, "bin/", "#{base}.jar"))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "juicer"
|
2
|
+
require "juicer/install/base"
|
3
|
+
require "zip/zip"
|
4
|
+
|
5
|
+
module Juicer
|
6
|
+
module Install
|
7
|
+
#
|
8
|
+
# Install and uninstall routines for the YUI Compressor.
|
9
|
+
# Installation downloads the YUI Compressor distribution, unzips it and
|
10
|
+
# storesthe jar file on disk along with the license.
|
11
|
+
#
|
12
|
+
class YuiCompressorInstaller < Base
|
13
|
+
def initialize(install_dir = Juicer.home)
|
14
|
+
super(install_dir)
|
15
|
+
@latest = nil
|
16
|
+
@website = "http://yuilibrary.com/downloads/"
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Install the Yui Compressor. Downloads the distribution and keeps the jar
|
21
|
+
# file inside PATH/yui_compressor/bin and the README and CHANGELOG in
|
22
|
+
# PATH/yui_compressor/x.y.z/ where x.y.z is the version, most recent if
|
23
|
+
# not specified otherwise.
|
24
|
+
#
|
25
|
+
# Path defaults to environment variable $JUICER_HOME or default Juicer
|
26
|
+
# home
|
27
|
+
#
|
28
|
+
def install(version = nil)
|
29
|
+
version = super(version)
|
30
|
+
base = "yuicompressor-#{version}"
|
31
|
+
filename = download(File.join(@website, "yuicompressor", "#{base}.zip"))
|
32
|
+
target = File.join(@install_dir, path)
|
33
|
+
|
34
|
+
Zip::ZipFile.open(filename) do |file|
|
35
|
+
file.extract("#{base}/doc/README", File.join(target, version, "README"))
|
36
|
+
file.extract("#{base}/doc/CHANGELOG", File.join(target, version, "CHANGELOG"))
|
37
|
+
file.extract("#{base}/build/#{base}.jar", File.join(target, "bin", "#{base}.jar"))
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# Uninstalls the given version of YUI Compressor. If no location is
|
43
|
+
# provided the environment variable $JUICER_HOME or Juicers default home
|
44
|
+
# directory is used.
|
45
|
+
#
|
46
|
+
# If no version is provided the most recent version is assumed.
|
47
|
+
#
|
48
|
+
# If there are no more files left in INSTALLATION_PATH/yui_compressor, the
|
49
|
+
# whole directory is removed.
|
50
|
+
#
|
51
|
+
def uninstall(version = nil)
|
52
|
+
super(version) do |dir, version|
|
53
|
+
File.delete(File.join(dir, "bin/yuicompressor-#{version}.jar"))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Check which version is the most recent
|
59
|
+
#
|
60
|
+
def latest
|
61
|
+
return @latest if @latest
|
62
|
+
webpage = Nokogiri::HTML(open(@website))
|
63
|
+
@latest = (webpage / "//h2[@id='yuicompressor']/../../../..//a")[0].get_attribute("href").match(/(\d\.\d\.\d)/)[1]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "juicer/binary"
|
2
|
+
|
3
|
+
module Juicer
|
4
|
+
#
|
5
|
+
# A Ruby API to Douglas Crockfords genious JsLint program
|
6
|
+
# http://www.jslint.com/
|
7
|
+
#
|
8
|
+
# JsLint parses JavaScript code and identifies (potential) problems.
|
9
|
+
# Effectively, JsLint defines a subset of JavaScript which is safe to use, and
|
10
|
+
# among other things make code minification a substantially less dangerous
|
11
|
+
# task.
|
12
|
+
#
|
13
|
+
class JsLint
|
14
|
+
include Juicer::Binary
|
15
|
+
|
16
|
+
def initialize(options = {})
|
17
|
+
super(options[:java] || "java")
|
18
|
+
path << options[:bin_path] if options[:bin_path]
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Checks if a files has problems. Also includes experimental support for CSS
|
23
|
+
# files. CSS files should begin with the line @charset "UTF-8";
|
24
|
+
#
|
25
|
+
# Returns a Juicer::JsLint::Report object
|
26
|
+
#
|
27
|
+
def check(file)
|
28
|
+
rhino_jar = rhino
|
29
|
+
js_file = locate_lib
|
30
|
+
|
31
|
+
raise FileNotFoundError.new("Unable to locate Rhino jar '#{rhino_jar}'") if !rhino_jar || !File.exists?(rhino_jar)
|
32
|
+
raise FileNotFoundError.new("Unable to locate JsLint '#{js_file}'") if !js_file || !File.exists?(js_file)
|
33
|
+
raise FileNotFoundError.new("Unable to locate input file '#{file}'") unless File.exists?(file)
|
34
|
+
|
35
|
+
lines = execute(%Q{-jar "#{rhino}" "#{locate_lib}" "#{file}"}).split("\n")
|
36
|
+
return Report.new if lines.length == 1 && lines[0] =~ /jslint: No problems/
|
37
|
+
|
38
|
+
report = Report.new
|
39
|
+
lines = lines.reject { |line| !line || "#{line}".strip == "" }
|
40
|
+
report.add_error(lines.shift, lines.shift) while lines.length > 0
|
41
|
+
|
42
|
+
return report
|
43
|
+
end
|
44
|
+
|
45
|
+
def rhino
|
46
|
+
files = locate("**/rhino*.jar", "RHINO_HOME")
|
47
|
+
!files || files.empty? ? nil : files.sort.last
|
48
|
+
end
|
49
|
+
|
50
|
+
def locate_lib
|
51
|
+
files = locate("**/jslint-*.js", "JSLINT_HOME")
|
52
|
+
!files || files.empty? ? nil : files.sort.last
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# Represents the results of a JsLint run
|
57
|
+
#
|
58
|
+
class Report
|
59
|
+
attr_accessor :errors
|
60
|
+
|
61
|
+
def initialize(errors = [])
|
62
|
+
@errors = errors
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_error(message, code)
|
66
|
+
@errors << JsLint::Error.new(message, code)
|
67
|
+
end
|
68
|
+
|
69
|
+
def ok?
|
70
|
+
@errors.nil? || @errors.length == 0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# A JsLint error
|
76
|
+
#
|
77
|
+
class Error
|
78
|
+
attr_accessor :message, :code
|
79
|
+
|
80
|
+
def initialize(message, code)
|
81
|
+
@message = message
|
82
|
+
@code = code
|
83
|
+
end
|
84
|
+
|
85
|
+
def to_s
|
86
|
+
"#@message\n#@code"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|