juicer 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Manifest.txt +58 -0
- data/Rakefile +44 -0
- data/Readme.rdoc +143 -0
- data/bin/juicer +8 -0
- data/lib/juicer.rb +70 -0
- data/lib/juicer/binary.rb +173 -0
- data/lib/juicer/cache_buster.rb +45 -0
- data/lib/juicer/chainable.rb +106 -0
- data/lib/juicer/cli.rb +56 -0
- data/lib/juicer/command/install.rb +59 -0
- data/lib/juicer/command/list.rb +50 -0
- data/lib/juicer/command/merge.rb +185 -0
- data/lib/juicer/command/util.rb +32 -0
- data/lib/juicer/command/verify.rb +60 -0
- data/lib/juicer/core.rb +59 -0
- data/lib/juicer/css_cache_buster.rb +99 -0
- data/lib/juicer/install/base.rb +186 -0
- data/lib/juicer/install/jslint_installer.rb +51 -0
- data/lib/juicer/install/rhino_installer.rb +52 -0
- data/lib/juicer/install/yui_compressor_installer.rb +66 -0
- data/lib/juicer/jslint.rb +90 -0
- data/lib/juicer/merger/base.rb +74 -0
- data/lib/juicer/merger/css_dependency_resolver.rb +25 -0
- data/lib/juicer/merger/dependency_resolver.rb +82 -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 +112 -0
- data/lib/juicer/minifyer/yui_compressor.rb +129 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +50 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +300 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +47 -0
- data/tasks/test.rake +40 -0
- data/tasks/test/setup.rake +35 -0
- data/test/bin/jslint.js +474 -0
- data/test/bin/rhino1_7R1.zip +0 -0
- data/test/bin/rhino1_7R2-RC1.zip +0 -0
- data/test/bin/yuicompressor +238 -0
- data/test/bin/yuicompressor-2.3.5.zip +0 -0
- data/test/bin/yuicompressor-2.4.2.zip +0 -0
- data/test/juicer/command/test_install.rb +53 -0
- data/test/juicer/command/test_list.rb +69 -0
- data/test/juicer/command/test_merge.rb +155 -0
- data/test/juicer/command/test_util.rb +54 -0
- data/test/juicer/command/test_verify.rb +33 -0
- data/test/juicer/install/test_installer_base.rb +195 -0
- data/test/juicer/install/test_jslint_installer.rb +54 -0
- data/test/juicer/install/test_rhino_installer.rb +57 -0
- data/test/juicer/install/test_yui_compressor_installer.rb +56 -0
- data/test/juicer/merger/test_base.rb +122 -0
- data/test/juicer/merger/test_css_dependency_resolver.rb +36 -0
- data/test/juicer/merger/test_javascript_dependency_resolver.rb +39 -0
- data/test/juicer/merger/test_javascript_merger.rb +74 -0
- data/test/juicer/merger/test_stylesheet_merger.rb +178 -0
- data/test/juicer/minifyer/test_yui_compressor.rb +159 -0
- data/test/juicer/test_cache_buster.rb +58 -0
- data/test/juicer/test_chainable.rb +94 -0
- data/test/juicer/test_core.rb +47 -0
- data/test/juicer/test_css_cache_buster.rb +72 -0
- data/test/juicer/test_jslint.rb +33 -0
- data/test/test_helper.rb +146 -0
- data/test/test_juicer.rb +4 -0
- metadata +194 -0
data/History.txt
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
== 0.2.0 / 2009-xx-xx
|
2
|
+
|
3
|
+
* Refactored the minifyers execute method from compress to save
|
4
|
+
* Refactored Juicer::Merger::FileMerger -> Juicer::Merger::Base
|
5
|
+
* Refactored the mergers and minifyers to be chainable commands.
|
6
|
+
* Added Chainable module
|
7
|
+
|
8
|
+
== 0.1.0 / 2008-12-17
|
9
|
+
|
10
|
+
* Dug up old project and set it up with Mr Bones
|
data/Manifest.txt
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
Rakefile
|
4
|
+
Readme.rdoc
|
5
|
+
bin/juicer
|
6
|
+
lib/juicer.rb
|
7
|
+
lib/juicer/binary.rb
|
8
|
+
lib/juicer/cache_buster.rb
|
9
|
+
lib/juicer/chainable.rb
|
10
|
+
lib/juicer/cli.rb
|
11
|
+
lib/juicer/command/install.rb
|
12
|
+
lib/juicer/command/list.rb
|
13
|
+
lib/juicer/command/merge.rb
|
14
|
+
lib/juicer/command/util.rb
|
15
|
+
lib/juicer/command/verify.rb
|
16
|
+
lib/juicer/core.rb
|
17
|
+
lib/juicer/css_cache_buster.rb
|
18
|
+
lib/juicer/install/base.rb
|
19
|
+
lib/juicer/install/jslint_installer.rb
|
20
|
+
lib/juicer/install/rhino_installer.rb
|
21
|
+
lib/juicer/install/yui_compressor_installer.rb
|
22
|
+
lib/juicer/jslint.rb
|
23
|
+
lib/juicer/merger/base.rb
|
24
|
+
lib/juicer/merger/css_dependency_resolver.rb
|
25
|
+
lib/juicer/merger/dependency_resolver.rb
|
26
|
+
lib/juicer/merger/javascript_dependency_resolver.rb
|
27
|
+
lib/juicer/merger/javascript_merger.rb
|
28
|
+
lib/juicer/merger/stylesheet_merger.rb
|
29
|
+
lib/juicer/minifyer/yui_compressor.rb
|
30
|
+
tasks/test/setup.rake
|
31
|
+
test/bin/jslint.js
|
32
|
+
test/bin/rhino1_7R1.zip
|
33
|
+
test/bin/rhino1_7R2-RC1.zip
|
34
|
+
test/bin/yuicompressor
|
35
|
+
test/bin/yuicompressor-2.3.5.zip
|
36
|
+
test/bin/yuicompressor-2.4.2.zip
|
37
|
+
test/juicer/command/test_install.rb
|
38
|
+
test/juicer/command/test_list.rb
|
39
|
+
test/juicer/command/test_merge.rb
|
40
|
+
test/juicer/command/test_util.rb
|
41
|
+
test/juicer/command/test_verify.rb
|
42
|
+
test/juicer/install/test_installer_base.rb
|
43
|
+
test/juicer/install/test_jslint_installer.rb
|
44
|
+
test/juicer/install/test_rhino_installer.rb
|
45
|
+
test/juicer/install/test_yui_compressor_installer.rb
|
46
|
+
test/juicer/merger/test_base.rb
|
47
|
+
test/juicer/merger/test_css_dependency_resolver.rb
|
48
|
+
test/juicer/merger/test_javascript_dependency_resolver.rb
|
49
|
+
test/juicer/merger/test_javascript_merger.rb
|
50
|
+
test/juicer/merger/test_stylesheet_merger.rb
|
51
|
+
test/juicer/minifyer/test_yui_compressor.rb
|
52
|
+
test/juicer/test_cache_buster.rb
|
53
|
+
test/juicer/test_chainable.rb
|
54
|
+
test/juicer/test_core.rb
|
55
|
+
test/juicer/test_css_cache_buster.rb
|
56
|
+
test/juicer/test_jslint.rb
|
57
|
+
test/test_helper.rb
|
58
|
+
test/test_juicer.rb
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Look in the tasks/setup.rb file for the various options that can be
|
2
|
+
# configured in this Rakefile. The .rake files in the tasks directory
|
3
|
+
# are where the options are used.
|
4
|
+
|
5
|
+
begin
|
6
|
+
require 'bones'
|
7
|
+
load 'tasks/test/setup.rake'
|
8
|
+
Bones.setup
|
9
|
+
rescue LoadError
|
10
|
+
load 'tasks/setup.rb'
|
11
|
+
end
|
12
|
+
|
13
|
+
ensure_in_path 'lib'
|
14
|
+
require 'juicer'
|
15
|
+
|
16
|
+
task :default => 'test:run'
|
17
|
+
|
18
|
+
PROJ.name = 'juicer'
|
19
|
+
PROJ.authors = 'Christian Johansen'
|
20
|
+
PROJ.email = 'christian@cjohansen.no'
|
21
|
+
PROJ.url = 'http://www.cjohansen.no/en/projects/juicer'
|
22
|
+
PROJ.version = Juicer::VERSION
|
23
|
+
PROJ.rubyforge.name = 'juicer'
|
24
|
+
PROJ.readme_file = 'Readme.rdoc'
|
25
|
+
PROJ.exclude = %w(tmp$ bak$ ~$ CVS \.svn ^pkg ^doc \.git ^rcov ^test\/data gemspec ^test\/bin$)
|
26
|
+
PROJ.rdoc.remote_dir = 'juicer'
|
27
|
+
|
28
|
+
PROJ.spec.opts << '--color'
|
29
|
+
|
30
|
+
PROJ.gem.extras[:post_install_message] = <<-MSG
|
31
|
+
Juicer does not ship with third party libraries. You probably want to install
|
32
|
+
Yui Compressor and JsLint now:
|
33
|
+
|
34
|
+
juicer install yui_compressor
|
35
|
+
juicer install jslint
|
36
|
+
|
37
|
+
Happy juicing!
|
38
|
+
MSG
|
39
|
+
|
40
|
+
CLOBBER.include "test/data"
|
41
|
+
|
42
|
+
depend_on 'cmdparse'
|
43
|
+
depend_on 'hpricot'
|
44
|
+
depend_on 'rubyzip'
|
data/Readme.rdoc
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
= Juicer
|
2
|
+
Official URL: http://github.com/cjohansen/juicer/tree/master
|
3
|
+
Christian Johansen (http://www.cjohansen.no)
|
4
|
+
|
5
|
+
== DESCRIPTION:
|
6
|
+
|
7
|
+
Juicer is a command line tool that helps you ship frontend code for production.
|
8
|
+
|
9
|
+
High level overview; Juicer can
|
10
|
+
|
11
|
+
* figure out which files depend on each other and merge them together, reducing
|
12
|
+
the number of http requests per page view, thus improving performance
|
13
|
+
* use YUI Compressor to compress code, thus improving performance
|
14
|
+
* verify that your JavaScript is safe to minify/compress by running JsLint on it
|
15
|
+
* cycle asset hosts in CSS files
|
16
|
+
* add "cache busters" to URLs in CSS files
|
17
|
+
* recalculate relative URLs in CSS files, as well as convert them to absolute
|
18
|
+
(or convert absolute URLs to relative URLs)
|
19
|
+
|
20
|
+
== FEATURES:
|
21
|
+
|
22
|
+
=== Merging and minifying
|
23
|
+
|
24
|
+
Juicer can read @import statements in CSS files and use them to combine all your
|
25
|
+
stylesheets into a single file. This file may be minified using the YUI
|
26
|
+
Compressor. Eventually it will support other minifying tools too.
|
27
|
+
|
28
|
+
Juicer can treat your JavaScript files much the same way too, parsing a comment
|
29
|
+
switch @depend, as this example shows:
|
30
|
+
|
31
|
+
/**
|
32
|
+
* My script file
|
33
|
+
*
|
34
|
+
* @depend jquery-1.2.0.js
|
35
|
+
*/
|
36
|
+
var myNS = {
|
37
|
+
myObject = {}
|
38
|
+
};
|
39
|
+
|
40
|
+
Running <tt>juicer merge</tt> on this file will result in a minified file
|
41
|
+
<tt>filename.min.js</tt> containing the file jquery-1.2.0.js (located in the
|
42
|
+
same directory) and the code above.
|
43
|
+
|
44
|
+
You can use @import (CSS files) and @depend (JavaScript) recursively, effectively
|
45
|
+
creating a dependency chain for Juicer to climb and merge.
|
46
|
+
|
47
|
+
=== Paths
|
48
|
+
|
49
|
+
When merging CSS files, you may want to merge CSS files in different directories.
|
50
|
+
You may also want the resulting CSS file to end up in another directory as well.
|
51
|
+
Juicer automatically recalculates referenced URLs to reflect this change.
|
52
|
+
|
53
|
+
Absolute URLs are not changed by default, but if you provide juicer merge with
|
54
|
+
--document-root [DIR] and --relative-urls then absolute URLs are converted to
|
55
|
+
URLs relative to output directory. You can also use --absolute-urls to convert
|
56
|
+
all URLs to absolute ones.
|
57
|
+
|
58
|
+
=== Cache busters
|
59
|
+
|
60
|
+
Juicer supports so-called cache busters. A cache buster is a pattern in a path
|
61
|
+
whose only purpose is to "trick" browsers to redownload a file when it has
|
62
|
+
changed in cases where a far future expires header is used.
|
63
|
+
|
64
|
+
There are two types of cache busters; soft ones add a parameter to the URL, like
|
65
|
+
so: http://assets/images/1.png?cb1234567890, ie the letters "cb" (as in cache
|
66
|
+
buster) and then the timestamp of the files mtime.
|
67
|
+
|
68
|
+
Unfortunately, the popular web proxy Squid shipped for some time with a default
|
69
|
+
configuration which would not treat a URL as a "new" URL if the only thing changed
|
70
|
+
was the GET parameters. For this reason Juicer provides hard cache busters.
|
71
|
+
|
72
|
+
Hard cache busters result in URLs such as http://assets/images/1-cb1234567890.png,
|
73
|
+
ie URLs that require either renaming of files, or (more conveniently) a web
|
74
|
+
server configuration that will forward URLs to the right files anyway.
|
75
|
+
|
76
|
+
== PLANNED FEATURES:
|
77
|
+
|
78
|
+
Juicer 0.2.0 is the first usable release. Work will continue from here. Improving
|
79
|
+
documentation and APIs is one concern, but there are also new features planned:
|
80
|
+
|
81
|
+
* Support more minifiers, JsMin (Ruby port), Packer and possibly others
|
82
|
+
* Add support for CssTidy to compress CSS files
|
83
|
+
* juicer build, a command that can build several files in one swoop using a
|
84
|
+
configuration file
|
85
|
+
* juicer doc, a command that produces documentation using YUI Doc or JsDoc
|
86
|
+
|
87
|
+
If you have any ideas, feature requests, want to contribute or whatever, fork
|
88
|
+
the project on github, or get in touch through christian (at) cjohansen.no.
|
89
|
+
|
90
|
+
== SYNOPSIS:
|
91
|
+
|
92
|
+
juicer merge myfile.css
|
93
|
+
-> Produces myfile.min.css which may contain several CSS files, minified
|
94
|
+
|
95
|
+
juicer merge myfile.js
|
96
|
+
-> Produces myfile.min.js, minified and combined
|
97
|
+
|
98
|
+
juicer help
|
99
|
+
|
100
|
+
== REQUIREMENTS:
|
101
|
+
|
102
|
+
In order to use YUI Compressor and JsMin (requires Rhino) you need Java
|
103
|
+
installed and the java executable available on your path.
|
104
|
+
|
105
|
+
== INSTALL:
|
106
|
+
|
107
|
+
$ gem install juicer
|
108
|
+
$ juicer install yui_compressor
|
109
|
+
|
110
|
+
You need Java installed and available on your PATH. During gem installation,
|
111
|
+
Juicer will download and install YUI Compressor, JsLint and Rhino for you.
|
112
|
+
|
113
|
+
== For developers
|
114
|
+
|
115
|
+
Before running tests you should run
|
116
|
+
rake test:setup
|
117
|
+
|
118
|
+
which brings in third party libraries (ie, requires a working network connection)
|
119
|
+
|
120
|
+
== LICENSE:
|
121
|
+
|
122
|
+
(The MIT License)
|
123
|
+
|
124
|
+
Copyright (c) 2008-2009 Christian Johansen
|
125
|
+
|
126
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
127
|
+
a copy of this software and associated documentation files (the
|
128
|
+
'Software'), to deal in the Software without restriction, including
|
129
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
130
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
131
|
+
permit persons to whom the Software is furnished to do so, subject to
|
132
|
+
the following conditions:
|
133
|
+
|
134
|
+
The above copyright notice and this permission notice shall be
|
135
|
+
included in all copies or substantial portions of the Software.
|
136
|
+
|
137
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
138
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
139
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
140
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
141
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
142
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
143
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/bin/juicer
ADDED
data/lib/juicer.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require "logger"
|
2
|
+
|
3
|
+
module Juicer
|
4
|
+
|
5
|
+
# :stopdoc:
|
6
|
+
VERSION = '0.2.0'
|
7
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
8
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
9
|
+
LOGGER = Logger.new(STDOUT)
|
10
|
+
@@home = nil
|
11
|
+
# :startdoc:
|
12
|
+
|
13
|
+
# Returns the version string for the library.
|
14
|
+
#
|
15
|
+
def self.version
|
16
|
+
VERSION
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the installation directory for Juicer
|
20
|
+
#
|
21
|
+
def self.home
|
22
|
+
return @@home if @@home
|
23
|
+
return ENV['JUICER_HOME'] if ENV['JUICER_HOME']
|
24
|
+
return File.join(ENV['HOME'], ".juicer") if ENV['HOME']
|
25
|
+
return File.join(ENV['APPDATA'], "juicer") if ENV['APPDATA']
|
26
|
+
return File.join(ENV['HOMEDRIVE'], ENV['HOMEPATH'], "juicer") if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
|
27
|
+
return File.join(ENV['USERPROFILE'], "juicer") if ENV['USERPROFILE']
|
28
|
+
return File.join(ENV['Personal'], "juicer") if ENV['Personal']
|
29
|
+
end
|
30
|
+
|
31
|
+
# Set home directory
|
32
|
+
#
|
33
|
+
def self.home=(home)
|
34
|
+
@@home = home
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the library path for the module. If any arguments are given,
|
38
|
+
# they will be joined to the end of the libray path using
|
39
|
+
# <tt>File.join</tt>.
|
40
|
+
#
|
41
|
+
def self.libpath( *args )
|
42
|
+
args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns the lpath for the module. If any arguments are given,
|
46
|
+
# they will be joined to the end of the path using
|
47
|
+
# <tt>File.join</tt>.
|
48
|
+
#
|
49
|
+
def self.path( *args )
|
50
|
+
args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Utility method used to require all files ending in .rb that lie in the
|
54
|
+
# directory below this file that has the same name as the filename passed
|
55
|
+
# in. Optionally, a specific _directory_ name can be passed in such that
|
56
|
+
# the _filename_ does not have to be equivalent to the directory.
|
57
|
+
#
|
58
|
+
def self.require_all_libs_relative_to( fname, dir = nil )
|
59
|
+
dir ||= ::File.basename(fname, '.*')
|
60
|
+
search_me = ::File.expand_path(::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
61
|
+
|
62
|
+
Dir.glob(search_me).sort.each { |rb| require rb }
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
Juicer.require_all_libs_relative_to(__FILE__)
|
68
|
+
|
69
|
+
class FileNotFoundError < Exception
|
70
|
+
end
|
@@ -0,0 +1,173 @@
|
|
1
|
+
require File.expand_path(File.join(File.dirname(__FILE__), "chainable"))
|
2
|
+
|
3
|
+
module Juicer
|
4
|
+
|
5
|
+
# Defines an abstract implementation of a binary that needs to be "shelled
|
6
|
+
# out" to be run. Provides a starting point when wrapping and API around a
|
7
|
+
# shell binary.
|
8
|
+
#
|
9
|
+
# The module requires the including class to define the default_options
|
10
|
+
# method. It should return a hash of options where options are keys and
|
11
|
+
# default values are the values. Only options defined in this hash will be
|
12
|
+
# allowed to set on the binary.
|
13
|
+
#
|
14
|
+
module Binary
|
15
|
+
|
16
|
+
# Initialize binary with options
|
17
|
+
# options = Hash of options, optional
|
18
|
+
#
|
19
|
+
def initialize(binary, options = {})
|
20
|
+
@options = self.respond_to?(:defualt_options) ? default_options.merge(options) : options
|
21
|
+
@opt_set = false
|
22
|
+
@command = nil
|
23
|
+
@binary = binary
|
24
|
+
@path = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def path
|
28
|
+
@path
|
29
|
+
end
|
30
|
+
|
31
|
+
# Run command
|
32
|
+
#
|
33
|
+
def execute(params = nil)
|
34
|
+
#puts "#{self.command} #{params}"
|
35
|
+
cmd = IO.popen("#{self.command} #{params}", "r")
|
36
|
+
results = cmd.gets(nil)
|
37
|
+
cmd.close
|
38
|
+
results
|
39
|
+
end
|
40
|
+
|
41
|
+
# Return the value of a given option
|
42
|
+
# opt = The option to return value for
|
43
|
+
#
|
44
|
+
def get_opt(opt)
|
45
|
+
@options[opt] || nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return options as a cli arguments string. Optionally accepts a list of
|
49
|
+
# options to exclude from the generated string
|
50
|
+
#
|
51
|
+
def options(*excludes)
|
52
|
+
excludes = excludes.flatten.collect { |exc| exc.to_sym }
|
53
|
+
@options.inject("") do |str, opt|
|
54
|
+
if opt[1].nil? || excludes.include?(opt[0].to_sym)
|
55
|
+
str
|
56
|
+
else
|
57
|
+
val = opt[1] == true ? '' : opt[1]
|
58
|
+
option = opt[0].to_s
|
59
|
+
option = (option.length == 1 ? "-" : "--") + option.gsub('_', '-')
|
60
|
+
"#{str} #{option} #{val}".strip
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Set an option. Important: you can only set options that are predefined by the
|
66
|
+
# implementing class
|
67
|
+
# opt = The option to set
|
68
|
+
# value = The value of the option
|
69
|
+
#
|
70
|
+
def set_opt(opt, value)
|
71
|
+
opt = opt.to_sym
|
72
|
+
if @options.key?(opt)
|
73
|
+
@options[opt] = value
|
74
|
+
@opt_set = true
|
75
|
+
else
|
76
|
+
msg = "Illegal option '#{opt}', specify one of: #{@options.keys.join(', ')}"
|
77
|
+
raise ArgumentError.new(msg)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Performs simple parsing of a string of parameters. All recognized
|
82
|
+
# parameters are set, non-existent arguments raise an ArgumentError
|
83
|
+
#
|
84
|
+
def set_opts(options)
|
85
|
+
options = options.split " "
|
86
|
+
option = nil
|
87
|
+
regex = /^--?([^=]*)(=(.*))?/
|
88
|
+
|
89
|
+
while word = options.shift
|
90
|
+
if word =~ regex
|
91
|
+
if option
|
92
|
+
set_opt option, true
|
93
|
+
end
|
94
|
+
|
95
|
+
if $3
|
96
|
+
set_opt $1, $3
|
97
|
+
else
|
98
|
+
option = $1
|
99
|
+
end
|
100
|
+
else
|
101
|
+
set_opt option, word
|
102
|
+
option = nil
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Constructs the command to use
|
108
|
+
#
|
109
|
+
def command
|
110
|
+
return @command if !@opt_set && @command
|
111
|
+
@opt_set = false
|
112
|
+
@command = "#{@binary} #{options}"
|
113
|
+
end
|
114
|
+
|
115
|
+
# Locate the binary to execute. The binary is searched for in the
|
116
|
+
# following places:
|
117
|
+
#
|
118
|
+
# 1) The paths specified through my_binary.path << "/usr/bin"
|
119
|
+
# 2) The path specified by the given environment variable
|
120
|
+
# 3) Current working directory
|
121
|
+
#
|
122
|
+
# The name of the binary may be a glob pattern, resulting in +locate+
|
123
|
+
# returning an array of matches. This is useful in cases where the path
|
124
|
+
# is expected to store several versions oof a binary in the same directory,
|
125
|
+
# like /usr/bin/ruby /usr/bin/ruby1.8 /usr/bin/ruby1.9
|
126
|
+
#
|
127
|
+
# +locate+ always returns an array, or nil if no binaries where found.
|
128
|
+
# The result is always all files matching the given pattern in *one* of
|
129
|
+
# the specified paths - ie the first path where the pattern matches
|
130
|
+
# something.
|
131
|
+
#
|
132
|
+
def locate(bin_glob, env = nil)
|
133
|
+
path << ENV[env] if env && ENV.key?(env) && File.exist?(ENV[env])
|
134
|
+
|
135
|
+
(path << Dir.pwd).each do |path|
|
136
|
+
files = Dir.glob(File.expand_path(File.join(path, bin_glob)))
|
137
|
+
return files unless files.empty?
|
138
|
+
end
|
139
|
+
|
140
|
+
nil
|
141
|
+
end
|
142
|
+
|
143
|
+
# Allows for options to be set and read directly on the object as though they were
|
144
|
+
# standard attributes. compressor.verbose translates to
|
145
|
+
# compressor.get_opt('verbose') and compressor.verbose = true to
|
146
|
+
# compressor.set_opt('verbose', true)
|
147
|
+
def method_missing(m, *args)
|
148
|
+
if @options.key?(m)
|
149
|
+
# Only hit method_missing once per option
|
150
|
+
self.class.send(:define_method, m) do # def verbose
|
151
|
+
get_opt(m) # get_opt(:verbose)
|
152
|
+
end # end
|
153
|
+
|
154
|
+
return get_opt(m)
|
155
|
+
end
|
156
|
+
|
157
|
+
return super unless m.to_s =~ /=$/
|
158
|
+
|
159
|
+
opt = m.to_s.sub(/=$/, "").to_sym
|
160
|
+
|
161
|
+
if @options.key?(opt)
|
162
|
+
# Only hit method_missing once per option
|
163
|
+
self.class.send(:define_method, m) do # def verbose=(val)
|
164
|
+
set_opt(opt, args[0]) # set_opt(:verbose, val)
|
165
|
+
end # end
|
166
|
+
|
167
|
+
return set_opt(opt, args[0])
|
168
|
+
end
|
169
|
+
|
170
|
+
super
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|