grimen-packr 3.1.2
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 +20 -0
- data/README.rdoc +108 -0
- data/bin/packr +97 -0
- data/lib/packr.rb +55 -0
- data/lib/packr/base62.rb +150 -0
- data/lib/packr/collection.rb +147 -0
- data/lib/packr/encoder.rb +35 -0
- data/lib/packr/engine.rb +20 -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 -0
- data/lib/packr/shrinker.rb +123 -0
- data/lib/packr/words.rb +39 -0
- data/test/assets/packed/controls.js +1 -0
- data/test/assets/packed/domready.js +1 -0
- data/test/assets/packed/dragdrop.js +1 -0
- data/test/assets/packed/effects.js +1 -0
- data/test/assets/packed/prototype.js +1 -0
- data/test/assets/packed/prototype_shrunk.js +1 -0
- data/test/assets/packed/selector.js +1 -0
- data/test/assets/src/controls.js +833 -0
- data/test/assets/src/domready.js +36 -0
- data/test/assets/src/dragdrop.js +942 -0
- data/test/assets/src/effects.js +1088 -0
- data/test/assets/src/prototype.js +2515 -0
- data/test/assets/src/selector.js +666 -0
- data/test/assets/test/controls.js +1 -0
- data/test/assets/test/domready.js +1 -0
- data/test/assets/test/dragdrop.js +1 -0
- data/test/assets/test/effects.js +1 -0
- data/test/assets/test/prototype.js +1 -0
- data/test/assets/test/prototype_shrunk.js +1 -0
- data/test/assets/test/selector.js +1 -0
- data/test/test_packr.rb +156 -0
- metadata +139 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
module Packr
|
2
|
+
class Encoder
|
3
|
+
|
4
|
+
def initialize(pattern = nil, encoder = nil, ignore = nil)
|
5
|
+
@parser = Parser.new(ignore)
|
6
|
+
@parser.put(pattern, "") if pattern
|
7
|
+
@encoder = encoder
|
8
|
+
end
|
9
|
+
|
10
|
+
def search(script)
|
11
|
+
words = Words.new
|
12
|
+
@parser.put_at(-1, lambda { |word, *args|
|
13
|
+
words.add(word)
|
14
|
+
})
|
15
|
+
@parser.exec(script)
|
16
|
+
words
|
17
|
+
end
|
18
|
+
|
19
|
+
def encode(script)
|
20
|
+
words = search(script)
|
21
|
+
words.sort!
|
22
|
+
index = 0
|
23
|
+
words.each do |word, key|
|
24
|
+
word.encoded = @encoder.call(index)
|
25
|
+
index += 1
|
26
|
+
end
|
27
|
+
@parser.put_at(-1, lambda { |word, *args|
|
28
|
+
words.get(word).encoded
|
29
|
+
})
|
30
|
+
@parser.exec(script)
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
data/lib/packr/engine.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Packr
|
2
|
+
class Engine
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@minifier = Minifier.new
|
6
|
+
@shrinker = Shrinker.new
|
7
|
+
@privates = Privates.new
|
8
|
+
@base62 = Base62.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def pack(script, options = {})
|
12
|
+
script = @minifier.minify(script)
|
13
|
+
script = @shrinker.shrink(script, options[:protect]) if options[:shrink_vars]
|
14
|
+
script = @privates.encode(script) if options[:private]
|
15
|
+
script = @base62.encode(script) if options[:base62]
|
16
|
+
script
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
data/lib/packr/map.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
module Packr
|
2
|
+
# This is effectively a wrapper for Hash instances - we're including it
|
3
|
+
# to maintain similarity with the JavaScript version for easier maintainance.
|
4
|
+
class Map
|
5
|
+
|
6
|
+
def initialize(values = nil)
|
7
|
+
@values = {}
|
8
|
+
merge(values) unless values.nil?
|
9
|
+
end
|
10
|
+
|
11
|
+
def clear
|
12
|
+
@values.clear
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy
|
16
|
+
self.class.new(@values)
|
17
|
+
end
|
18
|
+
|
19
|
+
def each
|
20
|
+
@values.each { |key, value| yield(value, key) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def get(key)
|
24
|
+
@values[key.to_s]
|
25
|
+
end
|
26
|
+
|
27
|
+
def get_keys
|
28
|
+
@values.keys
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_values
|
32
|
+
@values.values
|
33
|
+
end
|
34
|
+
|
35
|
+
def has?(key)
|
36
|
+
@values.has_key?(key.to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge(*args)
|
40
|
+
args.each do |values|
|
41
|
+
values = values.get_values if values.is_a?(Map)
|
42
|
+
values.each { |key, value| put(key, value) }
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
def remove(key)
|
48
|
+
@values.delete(key.to_s)
|
49
|
+
end
|
50
|
+
|
51
|
+
def put(key, value = nil)
|
52
|
+
value ||= key
|
53
|
+
# Create the new entry (or overwrite the old entry).
|
54
|
+
@values[key.to_s] = value
|
55
|
+
end
|
56
|
+
|
57
|
+
def size
|
58
|
+
@values.length
|
59
|
+
end
|
60
|
+
|
61
|
+
def union(*values)
|
62
|
+
copy.merge(*values)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Packr
|
2
|
+
class Minifier
|
3
|
+
|
4
|
+
def self.conditional_comments
|
5
|
+
@@conditional_comments
|
6
|
+
end
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@concat = Packr::CONCAT.union(DATA)
|
10
|
+
|
11
|
+
def @concat.exec(script)
|
12
|
+
parsed = super(script)
|
13
|
+
while parsed != script
|
14
|
+
script = parsed
|
15
|
+
parsed = super(script)
|
16
|
+
end
|
17
|
+
parsed
|
18
|
+
end
|
19
|
+
|
20
|
+
@comments = DATA.union(COMMENTS)
|
21
|
+
@clean = DATA.union(CLEAN)
|
22
|
+
@whitespace = DATA.union(WHITESPACE)
|
23
|
+
|
24
|
+
@@conditional_comments = @comments.copy
|
25
|
+
@@conditional_comments.put_at(-1, " \\3")
|
26
|
+
@whitespace.remove_at(2) # conditional comments
|
27
|
+
@comments.remove_at(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
def minify(script)
|
31
|
+
# packing with no additional options
|
32
|
+
script += "\n"
|
33
|
+
script = script.gsub(CONTINUE, "")
|
34
|
+
script = @comments.exec(script)
|
35
|
+
script = @clean.exec(script)
|
36
|
+
script = @whitespace.exec(script)
|
37
|
+
script = @concat.exec(script)
|
38
|
+
script
|
39
|
+
end
|
40
|
+
|
41
|
+
CONTINUE = /\\\r?\n/
|
42
|
+
|
43
|
+
CLEAN = Parser.new.
|
44
|
+
put("\\(\\s*([^;)]*)\\s*;\\s*([^;)]*)\\s*;\\s*([^;)]*)\\)", "(\\1;\\2;\\3)"). # for (;;) loops
|
45
|
+
put("throw[^};]+[};]", IGNORE). # a safari 1.3 bug
|
46
|
+
put(";+\\s*([};])", "\\1")
|
47
|
+
|
48
|
+
COMMENTS = Parser.new.
|
49
|
+
put(";;;[^\\n]*\\n", REMOVE).
|
50
|
+
put("(COMMENT1)\\n\\s*(REGEXP)?", "\n\\3").
|
51
|
+
put("(COMMENT2)\\s*(REGEXP)?", lambda do |*args|
|
52
|
+
match, comment, b, regexp = args[0..3]
|
53
|
+
if comment =~ /^\/\*@/ and comment =~ /@\*\/$/
|
54
|
+
# comments = Minifier.conditional_comments.exec(comment)
|
55
|
+
else
|
56
|
+
comment = ""
|
57
|
+
end
|
58
|
+
comment + " " + (regexp || "")
|
59
|
+
end)
|
60
|
+
|
61
|
+
Packr::CONCAT = Parser.new.
|
62
|
+
put("(STRING1)\\+(STRING1)", lambda { |*args| args[1][0...-1] + args[3][1..-1] }).
|
63
|
+
put("(STRING2)\\+(STRING2)", lambda { |*args| args[1][0...-1] + args[3][1..-1] })
|
64
|
+
|
65
|
+
WHITESPACE = Parser.new.
|
66
|
+
put("/\\/\\/@[^\\n]*\\n", IGNORE).
|
67
|
+
put("@\\s+\\b", "@ "). # protect conditional comments
|
68
|
+
put("\\b\\s+@", " @").
|
69
|
+
put("(\\d)\\s+(\\.\\s*[a-z\\$_\\[(])", "\\1 \\2"). # http://dean.edwards.name/weblog/2007/04/packer3/#comment84066
|
70
|
+
put("([+-])\\s+([+-])", "\\1 \\2"). # c = a++ +b;
|
71
|
+
put("\\b\\s+\\$\\s+\\b", " $ "). # var $ in
|
72
|
+
put("\\$\\s+\\b", "$ "). # object$ in
|
73
|
+
put("\\b\\s+\\$", " $"). # return $object
|
74
|
+
# put("\\b\\s+#", " #"). # CSS
|
75
|
+
put("\\b\\s+\\b", SPACE).
|
76
|
+
put("\\s+", REMOVE)
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
data/lib/packr/parser.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
module Packr
|
2
|
+
class Parser < RegexpGroup
|
3
|
+
|
4
|
+
def put(expression, replacement)
|
5
|
+
expression = DICTIONARY.exec(expression) if expression.is_a?(String)
|
6
|
+
super(expression, replacement)
|
7
|
+
end
|
8
|
+
|
9
|
+
# STRING1 requires backslashes to fix concat bug
|
10
|
+
DICTIONARY = RegexpGroup.new.
|
11
|
+
put(:OPERATOR, /return|typeof|[\[(\^=,{}:;&|!*?]/.source).
|
12
|
+
put(:CONDITIONAL, /\/\*@\w*|\w*@\*\/|\/\/@\w*|@\w+/.source).
|
13
|
+
put(:COMMENT1, /\/\/[^\n]*/.source).
|
14
|
+
put(:COMMENT2, /\/\*[^*]*\*+([^\/][^*]*\*+)*\//.source).
|
15
|
+
put(:REGEXP, /\/(\\[\/\\]|[^*\/])(\\.|[^\/\n\\])*\/[gim]*/.source).
|
16
|
+
put(:STRING1, /\'(\\.|[^\'\\])*\'/.source).
|
17
|
+
put(:STRING2, /"(\\.|[^"\\])*"/.source)
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Packr
|
2
|
+
class Privates < Encoder
|
3
|
+
|
4
|
+
IGNORE = {
|
5
|
+
:CONDITIONAL => Packr::IGNORE,
|
6
|
+
"(OPERATOR)(REGXEP)" => Packr::IGNORE
|
7
|
+
}
|
8
|
+
|
9
|
+
PATTERN = /\b_[\da-zA-Z$][\w$]*\b/
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
super(PATTERN, lambda { |index|
|
13
|
+
"_" + Packr.encode62(index)
|
14
|
+
}, IGNORE)
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Packr
|
2
|
+
class RegexpGroup < Collection
|
3
|
+
|
4
|
+
IGNORE = "\\0"
|
5
|
+
BACK_REF = /\\(\d+)/
|
6
|
+
ESCAPE_CHARS = /\\./
|
7
|
+
ESCAPE_BRACKETS = /\(\?[:=!]|\[[^\]]+\]/
|
8
|
+
BRACKETS = /\(/
|
9
|
+
LOOKUP = /\\(\d+)/
|
10
|
+
LOOKUP_SIMPLE = /^\\\d+$/
|
11
|
+
|
12
|
+
def initialize(values = nil, ignore_case = false)
|
13
|
+
super(values)
|
14
|
+
@ignore_case = !!ignore_case
|
15
|
+
end
|
16
|
+
|
17
|
+
def exec(string, override = nil)
|
18
|
+
string = string.to_s # type-safe
|
19
|
+
return string if @keys.empty?
|
20
|
+
override = 0 if override == IGNORE
|
21
|
+
string.gsub(Regexp.new(self.to_s, @ignore_case && Regexp::IGNORECASE)) do |match|
|
22
|
+
offset, i, result = 1, 0, match
|
23
|
+
arguments = [match] + $~.captures + [$~.begin(0), string]
|
24
|
+
# Loop through the items.
|
25
|
+
each do |item, key|
|
26
|
+
nxt = offset + item.length + 1
|
27
|
+
if arguments[offset] # do we have a result?
|
28
|
+
replacement = override.nil? ? item.replacement : override
|
29
|
+
case replacement
|
30
|
+
when Proc
|
31
|
+
result = replacement.call(*arguments[offset...nxt])
|
32
|
+
when Numeric
|
33
|
+
result = arguments[offset + replacement]
|
34
|
+
else
|
35
|
+
result = replacement
|
36
|
+
end
|
37
|
+
end
|
38
|
+
offset = nxt
|
39
|
+
end
|
40
|
+
result
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def insert_at(index, expression, replacement)
|
45
|
+
expression = expression.is_a?(Regexp) ? expression.source : expression.to_s
|
46
|
+
super(index, expression, replacement)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test(string)
|
50
|
+
exec(string) != string
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
offset = 1
|
55
|
+
"(" + map { |item, key|
|
56
|
+
# Fix back references.
|
57
|
+
expression = item.to_s.gsub(BACK_REF) { |m| "\\" + (offset + $1.to_i) }
|
58
|
+
offset += item.length + 1
|
59
|
+
expression
|
60
|
+
}.join(")|(") + ")"
|
61
|
+
end
|
62
|
+
|
63
|
+
class Item
|
64
|
+
attr_accessor :expression, :length, :replacement
|
65
|
+
|
66
|
+
def initialize(expression, replacement = nil)
|
67
|
+
@expression = expression
|
68
|
+
|
69
|
+
if replacement.nil?
|
70
|
+
replacement = IGNORE
|
71
|
+
elsif replacement.respond_to?(:replacement)
|
72
|
+
replacement = replacement.replacement
|
73
|
+
elsif !replacement.is_a?(Proc)
|
74
|
+
replacement = replacement.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
# does the pattern use sub-expressions?
|
78
|
+
if replacement.is_a?(String) and replacement =~ LOOKUP
|
79
|
+
# a simple lookup? (e.g. "\2")
|
80
|
+
if replacement.gsub(/\n/, " ") =~ LOOKUP_SIMPLE
|
81
|
+
# store the index (used for fast retrieval of matched strings)
|
82
|
+
replacement = replacement[1..-1].to_i
|
83
|
+
else # a complicated lookup (e.g. "Hello \2 \1")
|
84
|
+
# build a function to do the lookup
|
85
|
+
# Improved version by Alexei Gorkov:
|
86
|
+
q = '"'
|
87
|
+
replacement_string = replacement.
|
88
|
+
gsub(/\\/, "\\\\").
|
89
|
+
gsub(/"/, "\\x22").
|
90
|
+
gsub(/\n/, "\\n").
|
91
|
+
gsub(/\r/, "\\r").
|
92
|
+
gsub(/\\(\d+)/, q + "+(args[\\1]||" + q+q + ")+" + q).
|
93
|
+
gsub(/(['"])\1\+(.*)\+\1\1$/, '\1')
|
94
|
+
replacement = lambda { |*args| eval(q + replacement_string + q) }
|
95
|
+
|
96
|
+
# My old crappy version:
|
97
|
+
# q = (replacement.gsub(/\\./, "") =~ /'/) ? '"' : "'"
|
98
|
+
# replacement = replacement.gsub(/\r/, "\\r").gsub(/\\(\d+)/,
|
99
|
+
# q + "+(args[\\1]||" + q+q + ")+" + q)
|
100
|
+
# replacement_string = q + replacement.gsub(/(['"])\1\+(.*)\+\1\1$/, '\1') + q
|
101
|
+
# replacement = lambda { |*args| eval(replacement_string) }
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@length = RegexpGroup.count(@expression)
|
106
|
+
@replacement = replacement
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
@expression.respond_to?(:source) ? @expression.source : @expression.to_s
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.count(expression)
|
115
|
+
# Count the number of sub-expressions in a Regexp/RegexpGroup::Item.
|
116
|
+
expression = expression.to_s.gsub(ESCAPE_CHARS, "").gsub(ESCAPE_BRACKETS, "")
|
117
|
+
expression.scan(BRACKETS).length
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module Packr
|
2
|
+
class Shrinker
|
3
|
+
|
4
|
+
ENCODED_DATA = /~\^(\d+)\^~/
|
5
|
+
PREFIX = '@'
|
6
|
+
SHRUNK = /\@\d+\b/
|
7
|
+
|
8
|
+
def decode_data(script)
|
9
|
+
# put strings and regular expressions back
|
10
|
+
script.gsub(ENCODED_DATA) { |match| @strings[$1.to_i] }
|
11
|
+
end
|
12
|
+
|
13
|
+
def encode_data(script)
|
14
|
+
# encode strings and regular expressions
|
15
|
+
@strings = [] # encoded strings and regular expressions
|
16
|
+
DATA.exec(script, lambda { |match, *args|
|
17
|
+
operator, regexp = args[0].to_s, args[1].to_s
|
18
|
+
replacement = "~^#{@strings.length}^~"
|
19
|
+
unless regexp.empty?
|
20
|
+
replacement = operator + replacement
|
21
|
+
match = regexp
|
22
|
+
end
|
23
|
+
@strings << match
|
24
|
+
replacement
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
def shrink(script, protected_names = [])
|
29
|
+
script = encode_data(script)
|
30
|
+
protected_names ||= []
|
31
|
+
protected_names = protected_names.map { |s| s.to_s }
|
32
|
+
|
33
|
+
# identify blocks, particularly identify function blocks (which define scope)
|
34
|
+
__block = /((catch|do|if|while|with|function)\b[^~{};]*(\(\s*[^{};]*\s*\))\s*)?(\{[^{}]*\})/
|
35
|
+
__brackets = /\{[^{}]*\}|\[[^\[\]]*\]|\([^\(\)]*\)|~[^~]+~/
|
36
|
+
__encoded_block = /~#?(\d+)~/
|
37
|
+
__identifier = /[a-zA-Z_$][\w\$]*/
|
38
|
+
__scoped = /~#(\d+)~/
|
39
|
+
__var = /\bvar\b/
|
40
|
+
__vars = /\bvar\s+[\w$]+[^;#]*|\bfunction\s+[\w$]+/
|
41
|
+
__var_tidy = /\b(var|function)\b|\sin\s+[^;]+/
|
42
|
+
__var_equal = /\s*=[^,;]*/
|
43
|
+
|
44
|
+
blocks = [] # store program blocks (anything between braces {})
|
45
|
+
total = 0
|
46
|
+
# decoder for program blocks
|
47
|
+
decode_blocks = lambda do |script, encoded|
|
48
|
+
script = script.gsub(encoded) { |match| blocks[$1.to_i] } while script =~ encoded
|
49
|
+
script
|
50
|
+
end
|
51
|
+
|
52
|
+
# encoder for program blocks
|
53
|
+
encode_blocks = lambda do |match|
|
54
|
+
prefix, block_type, args, block = $1 || "", $2, $3, $4
|
55
|
+
if block_type == 'function'
|
56
|
+
# decode the function block (THIS IS THE IMPORTANT BIT)
|
57
|
+
# We are retrieving all sub-blocks and will re-parse them in light
|
58
|
+
# of newly shrunk variables
|
59
|
+
block = args + decode_blocks.call(block, __scoped)
|
60
|
+
prefix = prefix.gsub(__brackets, "")
|
61
|
+
|
62
|
+
# create the list of variable and argument names
|
63
|
+
args = args[1...-1]
|
64
|
+
|
65
|
+
if args != '_no_shrink_'
|
66
|
+
vars = block.scan(__vars).join(";").gsub(__var, ";var")
|
67
|
+
vars = vars.gsub(__brackets, "") while vars =~ __brackets
|
68
|
+
vars = vars.gsub(__var_tidy, "").gsub(__var_equal, "")
|
69
|
+
end
|
70
|
+
block = decode_blocks.call(block, __encoded_block)
|
71
|
+
|
72
|
+
# process each identifier
|
73
|
+
if args != '_no_shrink_'
|
74
|
+
count, short_id = 0, nil
|
75
|
+
ids = [args, vars].join(",").scan(__identifier)
|
76
|
+
processed = {}
|
77
|
+
ids.each do |id|
|
78
|
+
if !processed['#' + id] and !protected_names.include?(id)
|
79
|
+
processed['#' + id] = true
|
80
|
+
id = Packr.rescape(id)
|
81
|
+
# encode variable names
|
82
|
+
count += 1 while block =~ Regexp.new("#{PREFIX}#{count}\\b")
|
83
|
+
reg = Regexp.new("([^\\w$.])#{id}([^\\w$:])")
|
84
|
+
block = block.gsub(reg, "\\1#{PREFIX}#{count}\\2") while block =~ reg
|
85
|
+
reg = Regexp.new("([^{,\\w$.])#{id}:")
|
86
|
+
block = block.gsub(reg, "\\1#{PREFIX}#{count}:")
|
87
|
+
count += 1
|
88
|
+
end
|
89
|
+
end
|
90
|
+
total = [total, count].max
|
91
|
+
end
|
92
|
+
replacement = "#{prefix}~#{blocks.length}~"
|
93
|
+
blocks << block
|
94
|
+
else
|
95
|
+
replacement = "~##{blocks.length}~"
|
96
|
+
blocks << (prefix + block)
|
97
|
+
end
|
98
|
+
replacement
|
99
|
+
end
|
100
|
+
|
101
|
+
# encode blocks, as we encode we replace variable and argument names
|
102
|
+
script = script.gsub(__block, &encode_blocks) while script =~ __block
|
103
|
+
|
104
|
+
# put the blocks back
|
105
|
+
script = decode_blocks.call(script, __encoded_block)
|
106
|
+
|
107
|
+
short_id, count = nil, 0
|
108
|
+
shrunk = Encoder.new(SHRUNK, lambda { |object|
|
109
|
+
# find the next free short name
|
110
|
+
begin
|
111
|
+
short_id = Packr.encode52(count)
|
112
|
+
count += 1
|
113
|
+
end while script =~ Regexp.new("[^\\w$.]#{short_id}[^\\w$:]")
|
114
|
+
short_id
|
115
|
+
})
|
116
|
+
script = shrunk.encode(script)
|
117
|
+
|
118
|
+
decode_data(script)
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|