cjohansen-juicer 0.2.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.
- data/.gitignore +2 -0
- data/History.txt +10 -0
- data/Manifest.txt +40 -0
- data/Rakefile +27 -0
- data/Readme.rdoc +108 -0
- data/bin/juicer +7 -0
- data/juicer.gemspec +38 -0
- data/lib/juicer/chainable.rb +105 -0
- data/lib/juicer/cli.rb +51 -0
- data/lib/juicer/command/merge.rb +90 -0
- data/lib/juicer/merger/base.rb +72 -0
- data/lib/juicer/merger/css_dependency_resolver.rb +25 -0
- data/lib/juicer/merger/dependency_resolver.rb +64 -0
- data/lib/juicer/merger/javascript_dependency_resolver.rb +21 -0
- data/lib/juicer/merger/javascript_merger.rb +30 -0
- data/lib/juicer/merger/stylesheet_merger.rb +42 -0
- data/lib/juicer/minifyer/compressor.rb +125 -0
- data/lib/juicer/minifyer/yui_compressor.rb +152 -0
- data/lib/juicer.rb +45 -0
- data/test/juicer/merger/test_base.rb +123 -0
- data/test/juicer/merger/test_css_dependency_resolver.rb +32 -0
- data/test/juicer/merger/test_javascript_dependency_resolver.rb +40 -0
- data/test/juicer/merger/test_javascript_merger.rb +75 -0
- data/test/juicer/merger/test_stylesheet_merger.rb +62 -0
- data/test/juicer/minifyer/test_compressor.rb +36 -0
- data/test/juicer/minifyer/test_yui_compressor.rb +79 -0
- data/test/juicer/test_chainable.rb +87 -0
- data/test/test_helper.rb +277 -0
- data/test/test_juicer.rb +4 -0
- metadata +125 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
['base', 'javascript_dependency_resolver'].each do |lib|
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), lib))
|
4
|
+
end
|
5
|
+
|
6
|
+
module Juicer
|
7
|
+
module Merger
|
8
|
+
# Merge several files into one single output file. Resolves and adds in files from @depend comments
|
9
|
+
class JavaScriptMerger < Base
|
10
|
+
|
11
|
+
# Constructor
|
12
|
+
def initialize(files = [], options = {})
|
13
|
+
@dependency_resolver = JavaScriptDependencyResolver.new
|
14
|
+
super(files, options)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Run file from command line
|
21
|
+
# TODO: Refactor to testable Juicer::Merger::JavaScript::FileMerger.cli method
|
22
|
+
# or similar.
|
23
|
+
#
|
24
|
+
if $0 == __FILE__
|
25
|
+
return puts("Usage: javascript_merger.rb file[...] output") if $*.length < 2
|
26
|
+
|
27
|
+
fm = JavaScriptMerger.new()
|
28
|
+
fm << $*[0..-2]
|
29
|
+
fm.save($*[-1])
|
30
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
['base', 'css_dependency_resolver'].each do |lib|
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), lib))
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
module Juicer
|
9
|
+
module Merger
|
10
|
+
# Merge several files into one single output file. Resolves and adds in files
|
11
|
+
# from @import statements
|
12
|
+
#
|
13
|
+
class StylesheetMerger < Base
|
14
|
+
|
15
|
+
# Constructor
|
16
|
+
#
|
17
|
+
# Options:
|
18
|
+
# * <tt>:web_root</tt> - Path to web root if there is any @import statements
|
19
|
+
# using absolute URLs
|
20
|
+
#
|
21
|
+
def initialize(files = [], options = {})
|
22
|
+
@dependency_resolver = CssDependencyResolver.new(options)
|
23
|
+
super(files, options)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def merge(file)
|
28
|
+
content = super.gsub(/^\s*\@import\s("|')(.*)("|')\;?/, '')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Run file from command line
|
35
|
+
#
|
36
|
+
if $0 == __FILE__
|
37
|
+
return puts("Usage: stylesheet_merger.rb file[...] output") if $*.length < 2
|
38
|
+
|
39
|
+
fm = Juicer::Merger::StylesheetMerger.new()
|
40
|
+
fm << $*[0..-2]
|
41
|
+
fm.save($*[-1])
|
42
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "..", "chainable"))
|
2
|
+
|
3
|
+
module Juicer
|
4
|
+
module Minifyer
|
5
|
+
|
6
|
+
# Juicer::Minifyer::Compressor defines an API for compressing CSS,
|
7
|
+
# JavaScript and others using either a third party compressor library, or by
|
8
|
+
# implementing compression routines in Ruby.
|
9
|
+
#
|
10
|
+
# The Compressor class itself is not able to do anything useful other than
|
11
|
+
# serving as a framework for concrete compressors to implement.
|
12
|
+
#
|
13
|
+
# Author:: Christian Johansen (christian@cjohansen.no)
|
14
|
+
# Copyright:: Copyright (c) 2008-2009 Christian Johansen
|
15
|
+
# License:: MIT
|
16
|
+
#
|
17
|
+
class Compressor
|
18
|
+
include Chainable
|
19
|
+
|
20
|
+
# Initialize compressor with options
|
21
|
+
# options = Hash of options, optional
|
22
|
+
#
|
23
|
+
def initialize(options = {})
|
24
|
+
@options = default_options.merge(options)
|
25
|
+
@opt_set = false
|
26
|
+
end
|
27
|
+
|
28
|
+
# Perform compression, should be implemented in subclasses
|
29
|
+
# file = The file to compress
|
30
|
+
# output = Output file or open output stream. If nil the original file is
|
31
|
+
# overwritten
|
32
|
+
# type = The type of file, js or css. If not provided this is guessed from
|
33
|
+
# the input filename
|
34
|
+
#
|
35
|
+
def save(file, output = nil, type = nil)
|
36
|
+
msg = "Unable to call compress on abstract class Compressor"
|
37
|
+
raise NotImplementedError.new(msg)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return the value of a given option
|
41
|
+
# opt = The option to return value for
|
42
|
+
#
|
43
|
+
def get_opt(opt)
|
44
|
+
@options[opt] || nil
|
45
|
+
end
|
46
|
+
|
47
|
+
# Set an option. Important: you can only set options that are predefined by the
|
48
|
+
# implementing class
|
49
|
+
# opt = The option to set
|
50
|
+
# value = The value of the option
|
51
|
+
#
|
52
|
+
def set_opt(opt, value)
|
53
|
+
if @options.key?(opt)
|
54
|
+
@options[opt] = value
|
55
|
+
@opt_set = true
|
56
|
+
else
|
57
|
+
msg = 'Illegal option, specify one of: ' + @options.keys.join(', ')
|
58
|
+
raise ArgumentError.new(msg)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Performs simple parsing of a string of parameters. All recognized
|
63
|
+
# parameters are set, non-existent arguments raise an ArgumentErrror
|
64
|
+
#
|
65
|
+
def set_opts(options)
|
66
|
+
options = options.split " "
|
67
|
+
option = nil
|
68
|
+
regex = /^--([^=]*)(=(.*))?/
|
69
|
+
|
70
|
+
while word = options.shift
|
71
|
+
if word =~ regex
|
72
|
+
if option
|
73
|
+
set_opt option, true
|
74
|
+
end
|
75
|
+
|
76
|
+
if $3
|
77
|
+
set_opt $1, $3
|
78
|
+
else
|
79
|
+
option = $1
|
80
|
+
end
|
81
|
+
else
|
82
|
+
set_opt option, word
|
83
|
+
option = nil
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# Allows for options to be set and read directly on the object as though they were
|
89
|
+
# standard attributes. compressor.verbose translates to
|
90
|
+
# compressor.get_opt('verbose') and compressor.verbose = true to
|
91
|
+
# compressor.set_opt('verbose', true)
|
92
|
+
def method_missing(m, *args)
|
93
|
+
if @options.key?(m)
|
94
|
+
# Only hit method_missing once per option
|
95
|
+
self.class.send(:define_method, m) do
|
96
|
+
return get_opt(m)
|
97
|
+
end
|
98
|
+
|
99
|
+
return get_opt(m)
|
100
|
+
end
|
101
|
+
|
102
|
+
return super unless m.to_s =~ /=$/
|
103
|
+
|
104
|
+
opt = m.to_s.sub(/=$/, "").to_sym
|
105
|
+
|
106
|
+
if @options.key?(opt)
|
107
|
+
# Only hit method_missing once per option
|
108
|
+
self.class.send(:define_method, m) do
|
109
|
+
return set_opt(opt, args[0])
|
110
|
+
end
|
111
|
+
|
112
|
+
return set_opt(opt, args[0])
|
113
|
+
end
|
114
|
+
|
115
|
+
super
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
# May be overridden in subclasses. Provides default options
|
120
|
+
def default_options
|
121
|
+
{}
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,152 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'tempfile'
|
3
|
+
require File.expand_path(File.join(File.dirname(__FILE__), 'compressor')) unless defined?(Juicer::Minifyer::Compressor)
|
4
|
+
|
5
|
+
module Juicer
|
6
|
+
module Minifyer
|
7
|
+
|
8
|
+
# Provides an interface to the YUI compressor library using
|
9
|
+
# Juicer::Minify::Compressor. The YUI compressor library is implemented
|
10
|
+
# using Java, and as such Java is required when running this code. Also, the
|
11
|
+
# YUI jar file has to be provided.
|
12
|
+
#
|
13
|
+
# The YUI Compressor is invoked using the java binary and the YUI Compressor
|
14
|
+
# jar file.
|
15
|
+
#
|
16
|
+
# Providing the Jar file (usually yuicompressor-x.y.z.jar) can be done in
|
17
|
+
# several ways. The following directories are searched (in preferred order)
|
18
|
+
#
|
19
|
+
# 1. The directory specified by the option :bin_path
|
20
|
+
# 2. The directory specified by the environment variable $YUIC_HOME, if set
|
21
|
+
# 3. Current working directory
|
22
|
+
#
|
23
|
+
# For more information on how the Jar is located, see
|
24
|
+
# +Juicer::Minify::YuiCompressor.locate_jar+
|
25
|
+
#
|
26
|
+
# Author:: Christian Johansen (christian@cjohansen.no)
|
27
|
+
# Copyright:: Copyright (c) 2008-2009 Christian Johansen
|
28
|
+
# License:: MIT
|
29
|
+
#
|
30
|
+
# = Usage example =
|
31
|
+
# yuic = Juicer::Minifyer::YuiCompressor.new({ :bin_path => '/home/user/java/yui/' })
|
32
|
+
# yuic.compress('lib.js', 'lib.compressed.js')
|
33
|
+
#
|
34
|
+
class YuiCompressor < Compressor
|
35
|
+
def initialize(options = {})
|
36
|
+
super
|
37
|
+
@jar = nil
|
38
|
+
@command = nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# Compresses a file using the YUI Compressor. Note that the :bin_path
|
42
|
+
# option needs to be set in order for YuiCompressor to find and use the
|
43
|
+
# YUI jar file. Please refer to the class documentation for how to set
|
44
|
+
# this.
|
45
|
+
#
|
46
|
+
# file = The file to compress
|
47
|
+
# output = A file or stream to save the results to. If not provided the
|
48
|
+
# original file will be overwritten
|
49
|
+
# type = Either :js or :css. If this parameter is not provided, the type
|
50
|
+
# is guessed from the suffix on the input file name
|
51
|
+
def save(file, output = nil, type = nil)
|
52
|
+
type = type.nil? ? file.split('.')[-1].to_sym : type
|
53
|
+
cmd = @command = @command.nil? || @opt_set || type != @type ? command(type) : @command
|
54
|
+
|
55
|
+
output ||= file
|
56
|
+
use_tmp = !output.is_a?(String)
|
57
|
+
output = File.join(Dir::tmpdir, File.basename(file) + '.min.tmp.' + type.to_s) if use_tmp
|
58
|
+
FileUtils.mkdir_p(File.dirname(output))
|
59
|
+
|
60
|
+
cmd += ' -o "' + output + '" "' + file + '"'
|
61
|
+
compressor = IO.popen(cmd, 'r')
|
62
|
+
result = compressor.gets
|
63
|
+
|
64
|
+
if use_tmp # If no output file is provided, YUI compressor will
|
65
|
+
output.puts IO.read(output) # compress to a temp file. This file should be cleared
|
66
|
+
File.delete(output) # out after we fetch its contents.
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
chain_method :save
|
71
|
+
|
72
|
+
private
|
73
|
+
# Constructs the command to use
|
74
|
+
def command(type)
|
75
|
+
@opt_set = false
|
76
|
+
@type = type
|
77
|
+
@jar = locate_jar unless @jar
|
78
|
+
raise 'Unable to locate YUI Compressor Jar' if @jar.nil?
|
79
|
+
cmd = "#{@options[:java]} -jar #{@jar} --type #{@type}"
|
80
|
+
|
81
|
+
@options.each do |k, v|
|
82
|
+
v = '' if v == true
|
83
|
+
v = " #{v}" unless v == '' || v.nil?
|
84
|
+
cmd += " --#{k.to_s.gsub('_', '-')}#{v}" unless v.nil? || [:bin_path, :java].include?(k)
|
85
|
+
end
|
86
|
+
|
87
|
+
return cmd
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns a map of options accepted by YUI Compressor, currently:
|
91
|
+
#
|
92
|
+
# :charset
|
93
|
+
# :line_break
|
94
|
+
# :no_munge (JavaScript only)
|
95
|
+
# :preserve_semi
|
96
|
+
# :preserve_strings
|
97
|
+
#
|
98
|
+
# In addition, some class level options may be set:
|
99
|
+
# :bin_path (defaults to Dir.cwd)
|
100
|
+
# :java (Java command, defaults to 'java')
|
101
|
+
def default_options
|
102
|
+
{ :charset => nil, :line_break => nil, :no_munge => nil,
|
103
|
+
:preserve_semi => nil, :preserve_strings => nil,
|
104
|
+
:bin_path => nil, :java => 'java' }
|
105
|
+
end
|
106
|
+
|
107
|
+
# Locates the Jar file by searching directories.
|
108
|
+
# The following directories are searched (in preferred order)
|
109
|
+
#
|
110
|
+
# 1. The directory specified by the option :bin_path
|
111
|
+
# 2. The directory specified by the environment variable $YUIC_HOME, if set
|
112
|
+
# 3. Current working directory
|
113
|
+
#
|
114
|
+
# If any of these folders contain one or more files named like
|
115
|
+
# yuicompressor.jar or yuicompressor-x.y.z.jar the method will pick the
|
116
|
+
# last file in the list returned by +Dir.glob("#{dir}/yuicompressor*.jar").sort+
|
117
|
+
# This means that higher version numbers will be preferred with the default
|
118
|
+
# naming for the YUI Compressor Jars
|
119
|
+
def locate_jar
|
120
|
+
paths = @options[:bin_path].nil? ? [] : [@options[:bin_path]]
|
121
|
+
jar = nil
|
122
|
+
|
123
|
+
if ENV.key?('YUIC_HOME') && File.exist?(ENV['YUIC_HOME'])
|
124
|
+
paths << ENV['YUIC_HOME']
|
125
|
+
end
|
126
|
+
|
127
|
+
(paths << Dir.pwd).each do |path|
|
128
|
+
files = Dir.glob(File.join(path, 'yuicompressor*.jar'))
|
129
|
+
jar = files.sort.last unless files.empty?
|
130
|
+
break unless jar.nil?
|
131
|
+
end
|
132
|
+
|
133
|
+
jar.nil? ? nil : File.expand_path(jar)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# Run YUI Compressor with command line interface semantics
|
138
|
+
#
|
139
|
+
class Cli
|
140
|
+
def self.run(args)
|
141
|
+
if args.length != 2
|
142
|
+
puts 'Usage: yui_compressor.rb input ouput'
|
143
|
+
else
|
144
|
+
yc = Juicer::Minify::YuiCompressor.new
|
145
|
+
yc.compress(args.shift, args.shift)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
Juicer::Minifyer::Compressor::Cli.run($*) if $0 == __FILE__
|
data/lib/juicer.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
module Juicer
|
2
|
+
|
3
|
+
# :stopdoc:
|
4
|
+
VERSION = '0.2.0'
|
5
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
6
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
7
|
+
# :startdoc:
|
8
|
+
|
9
|
+
# Returns the version string for the library.
|
10
|
+
#
|
11
|
+
def self.version
|
12
|
+
VERSION
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the library path for the module. If any arguments are given,
|
16
|
+
# they will be joined to the end of the libray path using
|
17
|
+
# <tt>File.join</tt>.
|
18
|
+
#
|
19
|
+
def self.libpath( *args )
|
20
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the lpath for the module. If any arguments are given,
|
24
|
+
# they will be joined to the end of the path using
|
25
|
+
# <tt>File.join</tt>.
|
26
|
+
#
|
27
|
+
def self.path( *args )
|
28
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Utility method used to require all files ending in .rb that lie in the
|
32
|
+
# directory below this file that has the same name as the filename passed
|
33
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
34
|
+
# the _filename_ does not have to be equivalent to the directory.
|
35
|
+
#
|
36
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
37
|
+
dir ||= ::File.basename(fname, '.*')
|
38
|
+
search_me = ::File.expand_path(::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
39
|
+
|
40
|
+
Dir.glob(search_me).sort.each { |rb| require rb }
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
Juicer.require_all_libs_relative_to(__FILE__)
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. test_helper])) unless defined?(Juicer)
|
2
|
+
|
3
|
+
class TestMergerBase < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@file_merger = Juicer::Merger::Base.new
|
7
|
+
@file_setup = Juicer::Test::FileSetup.new($DATA_DIR)
|
8
|
+
@file_setup.create!
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
file = path('test_out.css')
|
13
|
+
File.delete(file) if File.exists?(file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_constructor
|
17
|
+
files = ['a.css', 'b.css'].collect { |file| path(file) }
|
18
|
+
file_merger = Juicer::Merger::Base.new files
|
19
|
+
assert_equal 2, file_merger.files.length
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_append_duplicate_files
|
23
|
+
@file_merger.append ['a.css', 'b.css'].collect { |file| path(file) }
|
24
|
+
assert_equal 2, @file_merger.files.length,
|
25
|
+
"b.css should not be included twice even when a.css imports it and it is manually added"
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_append_duplicate
|
29
|
+
@file_merger.append ['a.css', 'b.css'].collect { |file| path(file) }
|
30
|
+
assert_equal 2, @file_merger.files.length
|
31
|
+
|
32
|
+
@file_merger.append path('a.css')
|
33
|
+
assert_equal 2, @file_merger.files.length
|
34
|
+
|
35
|
+
@file_merger.append path('version.txt')
|
36
|
+
assert_equal 3, @file_merger.files.length
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_append_alias
|
40
|
+
@file_merger << ['a.css', 'b.css'].collect { |file| path(file) }
|
41
|
+
assert_equal 2, @file_merger.files.length
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_save_to_stream
|
45
|
+
a_css = path('a.css')
|
46
|
+
a_css_contents = IO.read(a_css) + "\n"
|
47
|
+
ios = StringIO.new
|
48
|
+
@file_merger << a_css
|
49
|
+
@file_merger.save ios
|
50
|
+
assert_equal a_css_contents, ios.string
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_save_to_file
|
54
|
+
a_css = path('a.css')
|
55
|
+
output_file = path('test_out.css')
|
56
|
+
@file_merger << a_css
|
57
|
+
@file_merger.save(output_file)
|
58
|
+
|
59
|
+
assert_equal IO.read(a_css) + "\n", IO.read(output_file)
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_save_merged_to_stream
|
63
|
+
a_css = path('a.css')
|
64
|
+
b_css = path('b.css')
|
65
|
+
ios = StringIO.new
|
66
|
+
|
67
|
+
@file_merger << a_css
|
68
|
+
@file_merger << b_css
|
69
|
+
@file_merger.save(ios)
|
70
|
+
|
71
|
+
assert_equal "#{IO.read(a_css)}\n#{IO.read(b_css)}\n", ios.string
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_save_merged_to_file
|
75
|
+
a_css = path('a.css')
|
76
|
+
b_css = path('b.css')
|
77
|
+
a_contents = IO.read(a_css) + "\n"
|
78
|
+
b_contents = IO.read(b_css) + "\n"
|
79
|
+
output_file = path('test_out.css')
|
80
|
+
|
81
|
+
@file_merger << a_css
|
82
|
+
@file_merger << b_css
|
83
|
+
@file_merger.save(output_file)
|
84
|
+
|
85
|
+
assert_equal "#{IO.read(a_css)}\n#{IO.read(b_css)}\n", IO.read(output_file)
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_resolve_dependencies
|
89
|
+
Juicer::Merger::Base.publicize_methods do
|
90
|
+
@file_merger.dependency_resolver = MockImportResolver.new
|
91
|
+
|
92
|
+
@file_merger.resolve_dependencies('a.css')
|
93
|
+
assert_equal 1, @file_merger.files.length
|
94
|
+
|
95
|
+
@file_merger.resolve_dependencies('a.css')
|
96
|
+
assert_equal 1, @file_merger.files.length
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def test_merge
|
101
|
+
Juicer::Merger::Base.publicize_methods do
|
102
|
+
a_content = <<EOF
|
103
|
+
@import 'b.css';
|
104
|
+
|
105
|
+
/* Dette er a.css */
|
106
|
+
|
107
|
+
EOF
|
108
|
+
|
109
|
+
content = @file_merger.merge(path('a.css'))
|
110
|
+
assert_equal a_content, content
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def test_attributes
|
115
|
+
assert_not_nil @file_merger.files
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
class MockImportResolver
|
120
|
+
def resolve(file)
|
121
|
+
yield file
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. test_helper])) unless defined?(Juicer)
|
2
|
+
|
3
|
+
class TestCssDependencyResolver < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@resolver = Juicer::Merger::CssDependencyResolver.new
|
6
|
+
@file_setup = Juicer::Test::FileSetup.new($DATA_DIR)
|
7
|
+
@file_setup.create!
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_init
|
11
|
+
assert_equal [], @resolver.files
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_resolve
|
15
|
+
b_file = File.expand_path(path('b.css'))
|
16
|
+
a_file = File.expand_path(path('a.css'))
|
17
|
+
|
18
|
+
files = @resolver.resolve(path('a.css')) do |file|
|
19
|
+
assert b_file == file || a_file == file
|
20
|
+
b_file != file
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_equal [a_file], files
|
24
|
+
|
25
|
+
files = @resolver.resolve(path('a.css')) do |file|
|
26
|
+
assert b_file == file || a_file == file
|
27
|
+
true
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_equal [a_file, b_file], files.sort
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. test_helper])) unless defined?(Juicer)
|
2
|
+
|
3
|
+
class TestJavaScriptDependencyResolver < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@resolver = Juicer::Merger::JavaScriptDependencyResolver.new
|
7
|
+
@file_setup = Juicer::Test::FileSetup.new($DATA_DIR)
|
8
|
+
@file_setup.create!
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_init
|
12
|
+
assert_equal [], @resolver.files
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_resolve
|
16
|
+
b_file = File.expand_path(path('b.js'))
|
17
|
+
a_file = File.expand_path(path('a.js'))
|
18
|
+
|
19
|
+
files = @resolver.resolve(path('a.js')) do |file|
|
20
|
+
assert b_file == file || a_file == file, file
|
21
|
+
b_file != file
|
22
|
+
end
|
23
|
+
|
24
|
+
assert_equal [a_file], files
|
25
|
+
|
26
|
+
files = @resolver.resolve(path('a.js')) do |file|
|
27
|
+
assert b_file == file || a_file == file
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
assert_equal [a_file, b_file], files.sort
|
32
|
+
|
33
|
+
files = @resolver.resolve(path('b.js')) do |file|
|
34
|
+
assert b_file == file || a_file == file
|
35
|
+
true
|
36
|
+
end
|
37
|
+
|
38
|
+
assert_equal [a_file, b_file], files.sort
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), %w[.. .. test_helper])) unless defined?(Juicer)
|
2
|
+
|
3
|
+
class TestJavaScriptMerger < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@file_merger = Juicer::Merger::JavaScriptMerger.new
|
7
|
+
@file_setup = Juicer::Test::FileSetup.new($DATA_DIR)
|
8
|
+
@file_setup.create!
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
file = path('test_out.js')
|
13
|
+
File.delete(file) if File.exists?(file)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_init
|
17
|
+
Juicer::Merger::JavaScriptMerger.publicize_methods do
|
18
|
+
assert_equal Juicer::Merger::JavaScriptDependencyResolver, @file_merger.dependency_resolver.class
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_merge
|
23
|
+
Juicer::Merger::JavaScriptMerger.publicize_methods do
|
24
|
+
a_content = <<EOF
|
25
|
+
/**
|
26
|
+
* @depend b.js
|
27
|
+
*/
|
28
|
+
|
29
|
+
/* Dette er a.js */
|
30
|
+
|
31
|
+
EOF
|
32
|
+
content = @file_merger.merge(path('a.js'))
|
33
|
+
assert_equal a_content, content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_constructor
|
38
|
+
file_merger = Juicer::Merger::JavaScriptMerger.new(path('a.js'))
|
39
|
+
assert_equal 2, file_merger.files.length
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_append
|
43
|
+
@file_merger << path('a.js')
|
44
|
+
assert_equal 2, @file_merger.files.length
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_save
|
48
|
+
a_js = path('a.js')
|
49
|
+
b_js = path('b.js')
|
50
|
+
merged = <<EOF
|
51
|
+
/**
|
52
|
+
* @depends a.js
|
53
|
+
*/
|
54
|
+
|
55
|
+
/* Dette er b.css */
|
56
|
+
|
57
|
+
/**
|
58
|
+
* @depend b.js
|
59
|
+
*/
|
60
|
+
|
61
|
+
/* Dette er a.js */
|
62
|
+
|
63
|
+
EOF
|
64
|
+
|
65
|
+
@file_merger << a_js
|
66
|
+
ios = StringIO.new
|
67
|
+
@file_merger.save(ios)
|
68
|
+
assert_equal merged, ios.string
|
69
|
+
|
70
|
+
output_file = path('test_out.js')
|
71
|
+
@file_merger.save(output_file)
|
72
|
+
|
73
|
+
assert_equal merged, IO.read(output_file)
|
74
|
+
end
|
75
|
+
end
|