问题
I have a situation where I'd like to be able to minify (not compile) a Ruby script. The goals are to:
- Reduce the overall character count of the script;
- Perform a degree of obfuscation to make it difficult for others to modify the code.
We can assume that:
- Yes, I know what I'm doing, and I really do want to minify and obfuscate the code.
- The source Ruby code has a simple syntax and doesn't use any advanced metaprogramming techniques or the like.
Is there any existing library or tool for this? If not, what would be the best way to get started to develop a simple minifier (ideally, also written in Ruby)?
回答1:
I created a simple script that reads a Ruby file, generates a minified and obfuscated version, and then interprets the output to regenerate it again. I created a Ruby file and used command expansion to run a Shell script that may be executed with ruby main.rb
:
main.rb
class MinifyAndObfuscateRuby
def initialize(shell_script="./main.sh")
@shell_script = shell_script
run_shell_script
end
private
def run_shell_script
%x[sh #{@shell_script}]
end
end
I wrote the Shell script, which takes an input Ruby source file and generates an output file based on the input. Optionally you can just run this directly with with sh main.sh
(instead of using the main.rb
wrapper that I added for testing with RSpec). Note that most of the main.sh code shared in the repository is shown below, but for brevity I have omitted details of the recover_source
function, which tries to re-generate the original Ruby source file in a second output file.
main.sh
#!/bin/bash
# Purpose: Simple script that reads a Ruby file, generates a minified and
# obfuscated version, and then interprets the output to regenerate it again.
# Execute either by running `main.rb` Ruby file (uses command expansion to run this Shell script)
# with `ruby main.rb` or with directly with `sh main.sh`. Outputs are automatically
# generated in an ./outputs subdirectory.
# declare and instantiate variables
MINLEN=0 # optionally exclude iteration of blank lines when MINLENGTH is 1
input_file="./source.rb"
reverse=""
output_file="./outputs/output_minified_and_obfuscated.min.rb"
output_file_recovered="./outputs/output_unminified_and_unobfuscated.rb"
# obfuscate: by reversing each line
function obfuscate {
for (( i=$len-1; i>=0; i-- )); do
reverse="$reverse${line:$i:1}"
done
reverse+="\n"
}
# minify: find instances of the tuple keys in the variable containing the
# reversed input file string and replace with respective tuple values
function minify {
find_data='eriuqer;*r* fed;*d* dne;*e* edulcni;*i* ssalc;*c* redaer_rtta;*ar*';
for tuple in $find_data; do
key=$(echo $tuple | cut -d ';' -f 1);
value=$(echo $tuple | cut -d ';' -f 2);
reverse=${reverse/$key/$value}
done
}
function process_source {
# read lines from input file
while IFS= read -r line || [ -n "$line" ]; do
len=${#line}
if [ "$len" -ge "$MINLEN" ]; then
obfuscate
minify
fi
done < "$input_file"
echo "$output_file not found. Creating $output_file and adding minified and obfuscated contents"
! [[ -d "outputs" ]] && mkdir outputs
touch $output_file
echo $reverse >> $output_file
}
# check if output Ruby file already exists and if so regenerate source, otherwise create it
if [ -f "$output_file" ] && ! [ -f "$output_file_recovered" ]; then
echo "$output_file already exists."
recover_source # see source code for details of this method
exit 0
elif [ -f "$input_file" ] && ! [ -f "$output_file_recovered" ]; then
process_source
exit 0
else
echo "$output_file and $output_file_recovered have both already been generated."
echo "Deleted temporary files and restarting process..."
[ -f "$output_file" ] && rm -f "$output_file"
[ -f "$output_file_recovered" ] && rm -f "$output_file_recovered"
[ -d "outputs" ] && rmdir outputs
exit 0
fi
The example source code file I used is shown below:
source.rb
require 'bigdecimal'
class Obfiscate
include Comparable
attr_reader :name
def initialize(name)
@name = name
end
end
It applies a degree of obfuscation by reversing each line in the source file and uses regular expressions replace Ruby syntax with my own custom abbreviations (i.e. replace require
with *r*
, class
with *c*
, attr_accessor
with *ar*
, def
with *d*
, and end
with *e*
) to reduce the overall character count and optionally remove blank lines as shown in sample output below:
./outputs/output_minified_and_obfuscated.min.rb
'lamicedgib' *r*
etacsifbO *c*
elbarapmoC
eman: *ar*
)eman(ezilaitini *d*
eman = eman@
*e*
*e*
来源:https://stackoverflow.com/questions/40142307/how-can-i-minify-a-ruby-source-file