Skip to content

Instantly share code, notes, and snippets.

@aoitaku
Last active December 28, 2015 08:22
Show Gist options
  • Save aoitaku/ffacb3281542d9acadc1 to your computer and use it in GitHub Desktop.
Save aoitaku/ffacb3281542d9acadc1 to your computer and use it in GitHub Desktop.
arb.rb
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
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