Last active
December 28, 2015 08:22
-
-
Save aoitaku/ffacb3281542d9acadc1 to your computer and use it in GitHub Desktop.
arb.rb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'zlib' | |
module Kernel | |
alias require_without_arb require | |
alias require_relative_without_arb require_relative | |
def require(filename) | |
if ArchivedRuby.arb_loaded? | |
return if $LOADED_FEATURES.include?(filename) | |
ArchivedRuby.load_from_arb(filename) | |
$LOADED_FEATURES << filename | |
end | |
rescue ArchivedRuby::LoadError | |
require_without_arb(filename) | |
end | |
def require_relative(filename) | |
if ArchivedRuby.arb_loaded? | |
dir = File.dirname(parse_caller(caller.first).first) | |
filename = dir + '/' + filename if dir != '.' | |
ArchivedRuby.load_relative_from_arb(filename) | |
end | |
rescue ArchivedRuby::LoadError | |
require_without_arb(filename) | |
end | |
def parse_caller(at) | |
if /^(.+?)(?::(\d+))?:in `(.*)'/ =~ at | |
file = $1 | |
line = $2.to_i | |
method = $3 | |
[file, line, method] | |
end | |
end | |
end | |
module ArchivedRuby ; end | |
class ArchivedRuby::LoadError < StandardError ; end | |
module ArchivedRuby | |
@@loaded_archives = {} | |
@@current_dir = '.' | |
@@current_arb = '' | |
def self.relative_path?(file) | |
file == File.basename(file) | |
end | |
def self.absolute_path?(file) | |
not relative_path?(file) | |
end | |
def self.end_with_ext?(file) | |
file == File.basename(file, '.arb') + '.arb' | |
end | |
def self.end_without_ext?(file) | |
not end_with_ext?(file) | |
end | |
def self.suffix_ext(file) | |
end_without_ext?(file) ? file + '.arb' : file | |
end | |
def self.search_load_path(file) | |
$LOAD_PATH.find {|dir| File.exist?(dir + "/" + file) } | |
end | |
def self.unpack_header(arb) | |
header_size = File.binread(arb, 2).unpack("v").first | |
header_data = File.binread(arb, header_size - 2, 2).unpack("C*") | |
{}.tap do |header| | |
i = 0 | |
while (i < header_data.size) | |
struct_size = header_data[i, 2].pack("C*").unpack("v").first | |
name_length = header_data[i+10] | |
header.store(header_data[i+11, name_length].pack("C*").unpack("a*").first, [ | |
header_data[i+6, 4].pack("C*").unpack("V").first, | |
header_data[i+2, 4].pack("C*").unpack("V").first | |
]) | |
i += struct_size | |
end | |
end | |
end | |
def self.load_from_arb(file) | |
@@loaded_archives.each do |path, arb| | |
load_path = File.dirname(path) + '/' + File.basename(path, '.arb') | |
next unless $LOAD_PATH.include?(load_path) | |
rb_path = (File.dirname(file) == '.' ? '' : File.dirname(file) + '/') + (File.basename(file, '.rb') + '.rb') | |
arb_path = path | |
if arb.find {|path, (length, offset)| path == rb_path } | |
dir = load_path + (File.dirname(file) == '.' ? '' : '/' + File.dirname(file)) | |
dir = dir.slice((__dir__.length+1)..dir.length) | |
script = Zlib::Inflate.inflate(File.binread(arb_path, *@@loaded_archives[arb_path][rb_path])) | |
_arb_path = arb_path.slice((__dir__.length + 1)..arb_path.length) | |
_arb_path = (File.dirname(_arb_path) == '.' ? '' : File.dirname(_arb_path) + '/') + File.basename(_arb_path, '.arb') | |
_dir = dir.slice((_arb_path.length + 1)..dir.length) | |
rb_path = rb_path.slice((_dir.length + 1)..rb_path.length) if _dir | |
__current_dir, @@current_dir = @@current_dir, File.dirname(dir + '/' + rb_path) | |
__current_arb, @@current_arb = @@current_arb, arb_path | |
Kernel.eval(script.force_encoding('UTF-8'), Object::TOPLEVEL_BINDING, dir + '/' + rb_path, 1) | |
@@current_dir = __current_dir | |
@@current_arb = __current_arb | |
return | |
end | |
end | |
raise ArchivedRuby::LoadError | |
end | |
def self.load_relative_from_arb(file) | |
if file.start_with? (__dir__) | |
file = file.slice((__dir__.length + 1)..file.length) | |
end | |
if @@current_arb == '' | |
dir = __dir__ + '/' + File.dirname(file) | |
arb_path = dir + '.arb' | |
else | |
arb_path = @@current_arb | |
end | |
if @@loaded_archives.find {|path, arb| path == arb_path} | |
if @@current_dir != '.' | |
_arb_path = arb_path.slice((__dir__.length + 1)..arb_path.length) | |
_arb_path = (File.dirname(_arb_path) == '.' ? '' : File.dirname(_arb_path) + '/') + File.basename(_arb_path, '.arb') | |
_file = file.slice((_arb_path.length+1)..file.length) | |
rb_path = (File.dirname(_file) == '.' ? '' : File.dirname(_file) + '/') + File.basename(_file, '.rb') + '.rb' | |
else | |
rb_path = File.basename(file, '.rb') + '.rb' | |
end | |
if @@loaded_archives[arb_path].find {|path, (length, offset)| path == rb_path } | |
script = Zlib::Inflate.inflate(File.binread(arb_path, *@@loaded_archives[arb_path][rb_path])) | |
__current_dir, @@current_dir = @@current_dir, File.dirname(File.dirname(file) + '/' + File.basename(rb_path)) | |
__current_arb, @@current_arb = @@current_arb, arb_path | |
Kernel.eval(script.force_encoding('UTF-8'), Object::TOPLEVEL_BINDING, File.dirname(file) + '/' + File.basename(rb_path), 1) | |
@@current_dir = __current_dir | |
@@current_arb = __current_arb | |
return | |
end | |
end | |
raise ArchivedRuby::LoadError | |
end | |
def self.load(arb) | |
arb = suffix_ext(arb) | |
if relative_path?(arb) | |
path = search_load_path(arb) | |
return false unless path | |
file = path + "/" + arb | |
else | |
return false unless File.exist?(arb) | |
path = File.dirname(arb) | |
file = arb | |
end | |
header = unpack_header(file) | |
@@loaded_archives.store(file, header) | |
end | |
def self.arb_loaded? | |
not @@loaded_archives.empty? | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'zlib' | |
module Packer | |
def self.pack(dir) | |
header = [] | |
chunks = "" | |
Dir.glob("#{dir}/**/*.rb") do |res| | |
name = res.slice((dir.length+1)..res.length) | |
bin = Zlib::Deflate.deflate(File.binread(res), Zlib::BEST_SPEED) | |
struct = [ | |
11 + name.bytesize, # 16bit int | |
chunks.size, # 32bit int | |
bin.size, # 32bit int | |
name.bytesize, # 8bit int | |
name # ASCII string | |
] | |
header << struct | |
chunks << bin | |
end | |
return nil if chunks.empty? | |
header_size = header.inject(2) {|sum, struct| sum + struct.first } | |
[[header_size].pack("v"), *header.map {|struct| | |
struct[1] += header_size | |
struct.pack("vVVCa*") | |
}].join("") + chunks | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment