#!/usr/bin/env ruby ### ### inline-require - expand 'require "foo"' into inline code ### ### usage: inline-require [-h] [-I path[,path2,..]] script ### ### copyright(c) 2006-2011 kuwata-lab.com all rights reserved. ### 2.7.0 ### $Rev: 10 $ ### class InlineRequire def initialize(opts={}) @opts = opts.dup end attr_accessor :opts def expand(filename) sbuf = '' inlined = [] level = 0 expand_require(filename, sbuf, inlined, level) return sbuf end private def expand_require(filename, sbuf, inlined, level) raise "*** assertion error" if inlined.include?(filename) remove_comment = @opts[:remove_comment] expand_indented = @opts[:expand_indented] keep_filename = @opts[:keep_filename] loaded_features = @opts[:loaded_features] inlined << filename prog = File.read(filename) n = 0 flag_if_file = false prog.each_line do |line| n += 1 ## comment out from 'if __FILE__ == $0' to 'end' if level > 0 if flag_if_file sbuf << "#" << line flag_if_file = false if line =~ /^end$/ next end if line =~ /^if\s+__FILE__\s*==\s*\$0(\s+then)?$/ || line =~ /^if\s+\$0\s*==\s*__FILE__(\s+then)?$/ flag_if_file = true sbuf << "#" << line next end end ## find 'require "foo"' and expand it to inline code flag_inline = false pattern = expand_indented ? /^[ \t]*require ['"](.*)["']\s*$/ \ : /^require ['"](.*)["']\s*$/ if line =~ pattern libname = $1 libpath = find_library(libname) $stderr.puts "*** debug: libpath=#{libpath.inspect}" if $debug_mode unless libpath #raise "file '#{filename}'(line #{n}): library '#{libname}' not found." warn "file '#{filename}'(line #{n}): library '#{libname}' not found." else flag_inline = true if libpath =~ /\.rb$/ && local_library?(libpath) end end if !flag_inline sbuf << line unless remove_comment && line =~ /^[ \t]*\#/ elsif inlined.include?(libpath) sbuf << "#--already included #{line}" unless remove_comment else if keep_filename @n ||= 0; @n += 1; n = @n end sbuf << "#--begin of #{line}" unless remove_comment sbuf << "$LOADED_FEATURES << '#{libname}.rb'\n" if loaded_features sbuf << "eval <<'END_OF_SCRIPT__#{n}', TOPLEVEL_BINDING, '#{libpath}', 1\n" if keep_filename expand_require(libpath, sbuf, inlined, level+1) sbuf << "END_OF_SCRIPT__#{n}\n" if keep_filename sbuf << "#--end of #{line}" unless remove_comment end end #sbuf << "\n" if sbuf[-1] != ?\n end def local_library?(libpath) return libpath !~ /^\// end def find_library(libname) if libname =~ /^\.rb$/ libname_rb = libname libname_so = nil elsif libname =~ /^\.so$/ libname_rb = nil libname_so = libname else libname_rb = libname + ".rb" libname_so = libname + ".so" end $LOAD_PATH.each do |path| if libname_rb libpath = path + "/" + libname_rb return libpath if test(?f, libpath) end if libname_so libpath = path + "/" + libname_so return libpath if test(?f, libpath) end end return nil end end if __FILE__ == $0 begin require "optparse" op = OptionParser.new options = {} op.on("-h", "--help") {|v| options[:help] = v } op.on("-I libpath") {|v| options[:libpath] = v } op.on("-i") {|v| options[:expand_indented] = v } op.on("-c") {|v| options[:remove_comment] = v } op.on("-k") {|v| options[:keep_filename] = v } op.on("-l") {|v| options[:loaded_features] = v } op.on("-D") {|v| options[:debug] = v } op.parse!() $debug_mode = options[:debug] if options[:help] command = File.basename($0) puts "Usage: #{command} [-h] [-I path[,path2,..]] script" puts " -h : help" puts " -i : expand indented require(), too" puts " -c : remove comment lines start with '#'" puts " -k : keep filename (for debugging)" puts " -l : append libs to $LOADED_FEATURES" puts " -I path[,path2,...] : ruby library path" exit(0) end if options[:libpath] rubylib_paths = options[:libpath].split(/,/) else rubylib_paths = [] end $stderr.puts "*** debug: rubylib_paths=#{rubylib_paths.inspect}" if $debug_mode $LOAD_PATH.concat(rubylib_paths) filenames = ARGV opts = { :expand_indented => options[:expand_indented], :remove_comment => options[:remove_comment], :keep_filename => options[:keep_filename], :loaded_features => options[:loaded_features] } inline_require = InlineRequire.new(opts) filenames.each do |filename| print inline_require.expand(filename) end rescue => ex if $debug_mode raise ex else $stderr.puts ex.message end end end