packr 1.0.2 → 3.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.
- data/History.txt +16 -0
- data/Manifest.txt +19 -0
- data/README.txt +112 -0
- data/Rakefile +12 -0
- data/bin/packr +91 -0
- data/lib/packr.rb +68 -240
- data/lib/packr/base62.rb +150 -0
- data/lib/packr/collection.rb +147 -0
- data/lib/packr/constants.rb +8 -0
- data/lib/packr/encoder.rb +35 -0
- data/lib/packr/map.rb +66 -0
- data/lib/packr/minifier.rb +80 -0
- data/lib/packr/parser.rb +21 -0
- data/lib/packr/privates.rb +19 -0
- data/lib/packr/regexp_group.rb +122 -122
- data/lib/packr/shrinker.rb +123 -0
- data/lib/packr/words.rb +39 -84
- data/lib/string.rb +6 -5
- data/test/test_packr.rb +140 -0
- metadata +79 -51
- data/README +0 -118
- data/test/assets/packed/controls.js +0 -1
- data/test/assets/packed/dragdrop.js +0 -1
- data/test/assets/packed/effects.js +0 -1
- data/test/assets/packed/prototype.js +0 -1
- data/test/assets/packed/prototype_shrunk.js +0 -1
- data/test/assets/src/controls.js +0 -833
- data/test/assets/src/dragdrop.js +0 -942
- data/test/assets/src/effects.js +0 -1088
- data/test/assets/src/prototype.js +0 -2515
- data/test/packr_test.rb +0 -68
data/History.txt
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
=== 3.1.0 / 2009-02-22
|
2
|
+
|
3
|
+
* Project is now a gem, not a Rails plugin
|
4
|
+
* Improved local variable compression
|
5
|
+
* Private field obfuscation
|
6
|
+
* Changed variable protection, protected variables must be supplied
|
7
|
+
as options to Packr#pack.
|
8
|
+
|
9
|
+
=== 1.0.2 / 2007-12-13
|
10
|
+
|
11
|
+
* Added variable protection, protecting $super for use with Prototype
|
12
|
+
|
13
|
+
=== 1.0.0 / 2007-12-04
|
14
|
+
|
15
|
+
* Initial release, compatible with Packer 3.0
|
16
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/packr
|
6
|
+
lib/packr.rb
|
7
|
+
lib/string.rb
|
8
|
+
lib/packr/map.rb
|
9
|
+
lib/packr/collection.rb
|
10
|
+
lib/packr/regexp_group.rb
|
11
|
+
lib/packr/constants.rb
|
12
|
+
lib/packr/encoder.rb
|
13
|
+
lib/packr/minifier.rb
|
14
|
+
lib/packr/parser.rb
|
15
|
+
lib/packr/privates.rb
|
16
|
+
lib/packr/shrinker.rb
|
17
|
+
lib/packr/words.rb
|
18
|
+
lib/packr/base62.rb
|
19
|
+
test/test_packr.rb
|
data/README.txt
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
= PackR
|
2
|
+
|
3
|
+
* http://github.com/jcoglan/packr
|
4
|
+
* http://dean.edwards.name/packer/
|
5
|
+
* http://base2.googlecode.com
|
6
|
+
|
7
|
+
== Description
|
8
|
+
|
9
|
+
PackR is a Ruby version of Dean Edwards' JavaScript compressor.
|
10
|
+
|
11
|
+
== Features
|
12
|
+
|
13
|
+
* Whitespace and comment removal
|
14
|
+
* Compression of local variable names
|
15
|
+
* Compression and obfuscation of 'private' (_underscored) identifiers
|
16
|
+
* Base-62 encoding
|
17
|
+
|
18
|
+
== Synopsis
|
19
|
+
|
20
|
+
To call from within a Ruby program:
|
21
|
+
|
22
|
+
require 'rubygems'
|
23
|
+
require 'packr'
|
24
|
+
|
25
|
+
code = File.read('my_script.js')
|
26
|
+
compressed = Packr.pack(code)
|
27
|
+
File.open('my_script.min.js', 'wb') { |f| f.write(compressed) }
|
28
|
+
|
29
|
+
This method takes a number of options to control compression, for example:
|
30
|
+
|
31
|
+
compressed = Packr.pack(code, :shrink_vars => true, :base62 => true)
|
32
|
+
|
33
|
+
The full list of available options is:
|
34
|
+
|
35
|
+
* <tt>:shrink_vars</tt> -- set to +true+ to compress local variable names
|
36
|
+
* <tt>:private</tt> -- set to +true+ to obfuscate 'private' identifiers, i.e.
|
37
|
+
names beginning with a single underscore
|
38
|
+
* <tt>:base62</tt> -- encode the program using base 62
|
39
|
+
* <tt>:protect</tt> -- an array of variable names to protect from compression, e.g.
|
40
|
+
|
41
|
+
compressed = Packr.pack(code, :shrink_vars => true,
|
42
|
+
:protect => %w[$super self])
|
43
|
+
|
44
|
+
To call from the command line (use <tt>packr --help</tt> to see available options):
|
45
|
+
|
46
|
+
packr my_script.js > my_script.min.js
|
47
|
+
|
48
|
+
== Notes
|
49
|
+
|
50
|
+
This program is not a JavaScript parser, and rewrites your files using regular
|
51
|
+
expressions. Be sure to include semicolons and braces everywhere they are required
|
52
|
+
so that your program will work correctly when packed down to a single line.
|
53
|
+
|
54
|
+
By far the most efficient way to serve JavaScript over the web is to use PackR
|
55
|
+
with the --shrink-vars flag, combined with gzip compression. If you don't have access
|
56
|
+
to your server config to set up mod_deflate, you can generate gzip files using
|
57
|
+
(on Unix-like systems):
|
58
|
+
|
59
|
+
packr -s my-file.js | gzip > my-file.js.gz
|
60
|
+
|
61
|
+
You can then get Apache to serve the files by putting this in your .htaccess file:
|
62
|
+
|
63
|
+
AddEncoding gzip .gz
|
64
|
+
RewriteCond %{HTTP:Accept-encoding} gzip
|
65
|
+
RewriteCond %{HTTP_USER_AGENT} !Safari
|
66
|
+
RewriteCond %{REQUEST_FILENAME}.gz -f
|
67
|
+
RewriteRule ^(.*)$ $1.gz [QSA,L]
|
68
|
+
|
69
|
+
If you really cannot serve gzip files, use the --base62 option to further compress
|
70
|
+
your code. This mode is at its best when compressing large files with many repeated
|
71
|
+
tokens.
|
72
|
+
|
73
|
+
The --private option can be used to stop other programs calling private methods
|
74
|
+
in your code by renaming anything beginning with a single underscore. Beware that
|
75
|
+
you should not use this if the generated file contains 'private' methods that need
|
76
|
+
to be accessible by other files. Also know that all the files that access any
|
77
|
+
particular private method must be compressed together so they all get the same
|
78
|
+
rewritten name for the private method.
|
79
|
+
|
80
|
+
== Requirements
|
81
|
+
|
82
|
+
* Rubygems
|
83
|
+
* Oyster (installed automatically)
|
84
|
+
|
85
|
+
== Installation
|
86
|
+
|
87
|
+
sudo gem install packr -y
|
88
|
+
|
89
|
+
== License
|
90
|
+
|
91
|
+
(The MIT License)
|
92
|
+
|
93
|
+
Copyright (c) 2004-2009 Dean Edwards, James Coglan
|
94
|
+
|
95
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
96
|
+
a copy of this software and associated documentation files (the
|
97
|
+
'Software'), to deal in the Software without restriction, including
|
98
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
99
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
100
|
+
permit persons to whom the Software is furnished to do so, subject to
|
101
|
+
the following conditions:
|
102
|
+
|
103
|
+
The above copyright notice and this permission notice shall be
|
104
|
+
included in all copies or substantial portions of the Software.
|
105
|
+
|
106
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
107
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
108
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
109
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
110
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
111
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
112
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/packr
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'oyster'
|
3
|
+
require 'packr'
|
4
|
+
|
5
|
+
spec = Oyster.spec do
|
6
|
+
name "packr -- JavaScript code compressor based on Dean Edwards' Packer"
|
7
|
+
|
8
|
+
synopsis <<-EOS
|
9
|
+
packr [OPTIONS] INPUT_FILES > OUTPUT_FILE
|
10
|
+
cat INPUT_FILES | packr [OPTIONS] > OUTPUT_FILE
|
11
|
+
EOS
|
12
|
+
|
13
|
+
description <<-EOS
|
14
|
+
PackR is a program for compressing JavaScript programs. It can remove whitespace
|
15
|
+
and comments, compress local variable names, compress/obfuscate private identifiers,
|
16
|
+
and encode the program in base-62.
|
17
|
+
|
18
|
+
When invoked from the command line, it concatenates all the code in INPUT_FILES (or
|
19
|
+
from standard input) and compresses the code using the given options, printing the
|
20
|
+
result to standard output. You can pipe this output into another file to save it.
|
21
|
+
EOS
|
22
|
+
|
23
|
+
flag :'shrink-vars', :default => true,
|
24
|
+
:desc => 'Shrink local variable names inside functions'
|
25
|
+
|
26
|
+
flag :private, :default => false,
|
27
|
+
:desc => 'Obfuscate private identifiers, i.e. names beginning with a single underscore'
|
28
|
+
|
29
|
+
flag :base62, :default => false,
|
30
|
+
:desc => 'Encode the program using base 62'
|
31
|
+
|
32
|
+
array :protect, :default => [],
|
33
|
+
:desc => 'List of variable names to protect from compression when using --shrink-vars'
|
34
|
+
|
35
|
+
notes <<-EOS
|
36
|
+
This program is not a JavaScript parser, and rewrites your files using regular
|
37
|
+
expressions. Be sure to include semicolons and braces everywhere they are required
|
38
|
+
so that your program will work correctly when packed down to a single line.
|
39
|
+
|
40
|
+
By far the most efficient way to serve JavaScript over the web is to use PackR
|
41
|
+
with the --shrink-vars flag, combined with gzip compression. If you don't have access
|
42
|
+
to your server config to set up mod_deflate, you can generate gzip files using
|
43
|
+
(on Unix-like systems):
|
44
|
+
|
45
|
+
packr -s my-file.js | gzip > my-file.js.gz
|
46
|
+
|
47
|
+
You can then get Apache to serve the files by putting this in your .htaccess file:
|
48
|
+
|
49
|
+
AddEncoding gzip .gz
|
50
|
+
RewriteCond %{HTTP:Accept-encoding} gzip
|
51
|
+
RewriteCond %{HTTP_USER_AGENT} !Safari
|
52
|
+
RewriteCond %{REQUEST_FILENAME}.gz -f
|
53
|
+
RewriteRule ^(.*)$ $1.gz [QSA,L]
|
54
|
+
|
55
|
+
If you really cannot serve gzip files, use the --base62 option to further compress
|
56
|
+
your code. This mode is at its best when compressing large files with many repeated
|
57
|
+
tokens.
|
58
|
+
|
59
|
+
The --private option can be used to stop other programs calling private methods
|
60
|
+
in your code by renaming anything beginning with a single underscore. Beware that
|
61
|
+
you should not use this if the generated file contains 'private' methods that need
|
62
|
+
to be accessible by other files. Also know that all the files that access any
|
63
|
+
particular private method must be compressed together so they all get the same
|
64
|
+
rewritten name for the private method.
|
65
|
+
EOS
|
66
|
+
|
67
|
+
author <<-EOS
|
68
|
+
Original JavaScript version by Dean Edwards, Ruby port by James Coglan <jcoglan@googlemail.com>
|
69
|
+
EOS
|
70
|
+
|
71
|
+
copyright <<-EOS
|
72
|
+
Copyright (c) 2004-2008 Dean Edwards, James Coglan. This program is free software,
|
73
|
+
distributed under the MIT license.
|
74
|
+
EOS
|
75
|
+
end
|
76
|
+
|
77
|
+
begin; opts = spec.parse
|
78
|
+
rescue Oyster::HelpRendered; exit
|
79
|
+
end
|
80
|
+
|
81
|
+
inputs = opts[:unclaimed]
|
82
|
+
code = inputs.empty? ?
|
83
|
+
$stdin.read :
|
84
|
+
inputs.map { |f| File.read(f) }.join("\n")
|
85
|
+
|
86
|
+
$stdout.puts Packr.pack(code,
|
87
|
+
:shrink_vars => !!opts[:'shrink-vars'],
|
88
|
+
:protect => opts[:protect],
|
89
|
+
:private => !!opts[:private],
|
90
|
+
:base62 => !!opts[:base62])
|
91
|
+
|
data/lib/packr.rb
CHANGED
@@ -1,240 +1,68 @@
|
|
1
|
-
# PackR -- a Ruby port of Packer by Dean Edwards
|
2
|
-
# Packer version 3.
|
3
|
-
# http://www.opensource.org/licenses/mit-license
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
:COMMENT1 => /(\/\/|;;;)[^\n]*/.source,
|
70
|
-
:COMMENT2 => /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source,
|
71
|
-
:CONDITIONAL => /\/\*@|@\*\/|\/\/@[^\n]*\n/.source,
|
72
|
-
:REGEXP => /\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*/.source,
|
73
|
-
:STRING1 => /'(\\.|[^'\\])*'/.source,
|
74
|
-
:STRING2 => /"(\\.|[^"\\])*"/.source
|
75
|
-
)
|
76
|
-
|
77
|
-
WHITESPACE = RegexpGroup.new(
|
78
|
-
"(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])" => "\\1 \\2", # http://dean.edwards.name/weblog/2007/04/packer3/#comment84066
|
79
|
-
"([+-])\\s+([+-])" => "\\1 \\2", # c = a++ +b;
|
80
|
-
"\\b\\s+\\$\\s+\\b" => " $ ", # var $ in
|
81
|
-
"\\$\\s+\\b" => "$ ", # object$ in
|
82
|
-
"\\b\\s+\\$" => " $", # return $object
|
83
|
-
"\\b\\s+\\b" => SPACE,
|
84
|
-
"\\s+" => REMOVE
|
85
|
-
)
|
86
|
-
|
87
|
-
def initialize
|
88
|
-
@data = {}
|
89
|
-
DATA.values.each { |item| @data[JAVASCRIPT.exec(item.expression)] = item.replacement }
|
90
|
-
@data = RegexpGroup.new(@data)
|
91
|
-
@whitespace = @data.union(WHITESPACE)
|
92
|
-
@clean = @data.union(CLEAN)
|
93
|
-
@protected_names = PROTECTED_NAMES
|
94
|
-
end
|
95
|
-
|
96
|
-
def protect_vars(*args)
|
97
|
-
args = args.map { |arg| arg.to_s.strip }.select { |arg| arg =~ /^[a-z\_\$][a-z0-9\_\$]*$/i }
|
98
|
-
@protected_names = (@protected_names + args).uniq
|
99
|
-
end
|
100
|
-
|
101
|
-
def minify(script)
|
102
|
-
script = script.gsub(CONTINUE, "")
|
103
|
-
script = @data.exec(script)
|
104
|
-
script = @whitespace.exec(script)
|
105
|
-
script = @clean.exec(script)
|
106
|
-
script
|
107
|
-
end
|
108
|
-
|
109
|
-
def pack(script, options = {})
|
110
|
-
script = minify(script + "\n")
|
111
|
-
script = shrink_variables(script) if options[:shrink_vars]
|
112
|
-
script = base62_encode(script) if options[:base62]
|
113
|
-
script
|
114
|
-
end
|
115
|
-
|
116
|
-
def pack_file(path, options = {})
|
117
|
-
path = path.gsub(Regexp.new("^((#{RAILS_ROOT.gsub(/\./, "\\.")})?/)?"), RAILS_ROOT + '/')
|
118
|
-
script = File.read(path)
|
119
|
-
script = pack(script, options)
|
120
|
-
File.open(path, 'wb') { |f| f.write(script) }
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
def base62_encode(script)
|
126
|
-
words = Words.new(script)
|
127
|
-
encode = lambda { |word| words.get(word).encoded }
|
128
|
-
|
129
|
-
# build the packed script
|
130
|
-
|
131
|
-
p = escape(script.gsub(Words::WORDS, &encode))
|
132
|
-
a = [[words.size, 2].max, 62].min
|
133
|
-
c = words.size
|
134
|
-
k = words.to_s
|
135
|
-
e = self.class.const_get("ENCODE#{a > 10 ? (a > 36 ? 62 : 36) : 10}")
|
136
|
-
r = a > 10 ? "e(c)" : "c"
|
137
|
-
|
138
|
-
# the whole thing
|
139
|
-
UNPACK.call(p,a,c,k,e,r)
|
140
|
-
end
|
141
|
-
|
142
|
-
def escape(script)
|
143
|
-
# single quotes wrap the final string so escape them
|
144
|
-
# also escape new lines required by conditional comments
|
145
|
-
script.gsub(/([\\'])/) { |match| "\\#{$1}" }.gsub(/[\r\n]+/, "\\n")
|
146
|
-
end
|
147
|
-
|
148
|
-
def shrink_variables(script)
|
149
|
-
data = [] # encoded strings and regular expressions
|
150
|
-
regexp= /^[^'"]\//
|
151
|
-
store = lambda do |string|
|
152
|
-
replacement = "##{data.length}"
|
153
|
-
if string =~ regexp
|
154
|
-
replacement = string[0].chr + replacement
|
155
|
-
string = string[1..-1]
|
156
|
-
end
|
157
|
-
data << string
|
158
|
-
replacement
|
159
|
-
end
|
160
|
-
|
161
|
-
# Base52 encoding (a-Z)
|
162
|
-
encode52 = lambda do |c|
|
163
|
-
(c < 52 ? '' : encode52.call((c.to_f / 52).to_i) ) +
|
164
|
-
((c = c % 52) > 25 ? (c + 39).chr : (c + 97).chr)
|
165
|
-
end
|
166
|
-
|
167
|
-
# identify blocks, particularly identify function blocks (which define scope)
|
168
|
-
__block = /(function\s*[\w$]*\s*\(\s*([^\)]*)\s*\)\s*)?(\{([^{}]*)\})/
|
169
|
-
__var = /var\s+/
|
170
|
-
__var_name = /var\s+[\w$]+/
|
171
|
-
__comma = /\s*,\s*/
|
172
|
-
blocks = [] # store program blocks (anything between braces {})
|
173
|
-
|
174
|
-
# decoder for program blocks
|
175
|
-
encoded = /~(\d+)~/
|
176
|
-
decode = lambda do |script|
|
177
|
-
script = script.gsub(encoded) { |match| blocks[$1.to_i] } while script =~ encoded
|
178
|
-
script
|
179
|
-
end
|
180
|
-
|
181
|
-
# encoder for program blocks
|
182
|
-
encode = lambda do |match|
|
183
|
-
block, func, args = match, $1, $2
|
184
|
-
if func # the block is a function block
|
185
|
-
|
186
|
-
# decode the function block (THIS IS THE IMPORTANT BIT)
|
187
|
-
# We are retrieving all sub-blocks and will re-parse them in light
|
188
|
-
# of newly shrunk variables
|
189
|
-
block = decode.call(block)
|
190
|
-
|
191
|
-
# create the list of variable and argument names
|
192
|
-
vars = block.scan(__var_name).join(",").gsub(__var, "")
|
193
|
-
ids = (args.split(__comma) + vars.split(__comma)).uniq
|
194
|
-
|
195
|
-
#process each identifier
|
196
|
-
count = 0
|
197
|
-
ids.each do |id|
|
198
|
-
id = id.strip
|
199
|
-
if id and id.length > 1 and !@protected_names.include?(id) # > 1 char
|
200
|
-
id = id.rescape
|
201
|
-
# find the next free short name (check everything in the current scope)
|
202
|
-
short_id = encode52.call(count)
|
203
|
-
while block =~ Regexp.new("[^\\w$.]#{short_id}[^\\w$:]")
|
204
|
-
count += 1
|
205
|
-
short_id = encode52.call(count)
|
206
|
-
end
|
207
|
-
# replace the long name with the short name
|
208
|
-
reg = Regexp.new("([^\\w$.])#{id}([^\\w$:])")
|
209
|
-
block = block.gsub(reg, "\\1#{short_id}\\2") while block =~ reg
|
210
|
-
reg = Regexp.new("([^{,\\w$.])#{id}:")
|
211
|
-
block = block.gsub(reg, "\\1#{short_id}:")
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
replacement = "~#{blocks.length}~"
|
216
|
-
blocks << block
|
217
|
-
replacement
|
218
|
-
end
|
219
|
-
|
220
|
-
# encode strings and regular expressions
|
221
|
-
script = @data.exec(script, &store)
|
222
|
-
|
223
|
-
# remove closures (this is for base2 namespaces only)
|
224
|
-
script = script.gsub(/new function\(_\)\s*\{/, "{;#;")
|
225
|
-
|
226
|
-
# encode blocks, as we encode we replace variable and argument names
|
227
|
-
script = script.gsub(__block, &encode) while script =~ __block
|
228
|
-
|
229
|
-
# put the blocks back
|
230
|
-
script = decode.call(script)
|
231
|
-
|
232
|
-
# put back the closure (for base2 namespaces only)
|
233
|
-
script = script.gsub(/\{;#;/, "new function(_){")
|
234
|
-
|
235
|
-
# put strings and regular expressions back
|
236
|
-
script = script.gsub(/#(\d+)/) { |match| data[$1.to_i] }
|
237
|
-
|
238
|
-
script
|
239
|
-
end
|
240
|
-
end
|
1
|
+
# PackR -- a Ruby port of Packer by Dean Edwards
|
2
|
+
# Packer version 3.1 copyright 2004-2009, Dean Edwards
|
3
|
+
# http://www.opensource.org/licenses/mit-license
|
4
|
+
|
5
|
+
[ '/string',
|
6
|
+
'/packr/map',
|
7
|
+
'/packr/collection',
|
8
|
+
'/packr/regexp_group',
|
9
|
+
'/packr/constants',
|
10
|
+
'/packr/encoder',
|
11
|
+
'/packr/parser',
|
12
|
+
'/packr/minifier',
|
13
|
+
'/packr/privates',
|
14
|
+
'/packr/shrinker',
|
15
|
+
'/packr/words',
|
16
|
+
'/packr/base62'
|
17
|
+
].each do |path|
|
18
|
+
require File.dirname(__FILE__) + path
|
19
|
+
end
|
20
|
+
|
21
|
+
class Packr
|
22
|
+
|
23
|
+
VERSION = '3.1.0'
|
24
|
+
|
25
|
+
DATA = Parser.new.
|
26
|
+
put("STRING1", IGNORE).
|
27
|
+
put('STRING2', IGNORE).
|
28
|
+
put("CONDITIONAL", IGNORE). # conditional comments
|
29
|
+
put("(OPERATOR)\\s*(REGEXP)", "\\1\\2")
|
30
|
+
|
31
|
+
def self.encode62(c)
|
32
|
+
(c < 62 ? '' : encode62((c / 62.0).to_i)) +
|
33
|
+
((c = c % 62) > 35 ? (c+29).chr : c.to_s(36))
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.encode52(c)
|
37
|
+
# Base52 encoding (a-Z)
|
38
|
+
encode = lambda do |d|
|
39
|
+
(d < 52 ? '' : encode.call((d / 52.0).to_i)) +
|
40
|
+
((d = d % 52) > 25 ? (d + 39).chr : (d + 97).chr)
|
41
|
+
end
|
42
|
+
encoded = encode.call(c.to_i)
|
43
|
+
encoded = encoded[1..-1] + '0' if encoded =~ /^(do|if|in)$/
|
44
|
+
encoded
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.pack(script, options = {})
|
48
|
+
@packr ||= self.new
|
49
|
+
@packr.pack(script, options)
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize
|
53
|
+
@minifier = Minifier.new
|
54
|
+
@shrinker = Shrinker.new
|
55
|
+
@privates = Privates.new
|
56
|
+
@base62 = Base62.new
|
57
|
+
end
|
58
|
+
|
59
|
+
def pack(script, options = {})
|
60
|
+
script = @minifier.minify(script)
|
61
|
+
script = @shrinker.shrink(script, options[:protect]) if options[:shrink_vars]
|
62
|
+
script = @privates.encode(script) if options[:private]
|
63
|
+
script = @base62.encode(script) if options[:base62]
|
64
|
+
script
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|