#!/usr/bin/env ruby

###
### inline-require - expand 'require "foo"' into inline code
###
### usage: inline-require [-h] [-I path[,path2,..]] script
###
### copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
### 2.6.2
### $Rev: 2 $
###


class InlineRequire

   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)
      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
         if line =~ /^\s*require ['"](.*)["']\s*$/
            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
         elsif inlined.include?(libpath)
            sbuf << "#--already included #{line}"
         else
            sbuf << "#--begin of #{line}"
            expand_require(libpath, sbuf, inlined, level+1)
            sbuf << "#--end of #{line}"
         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
      rubylib_paths = []
      flag_help = false
      while ARGV[0] && ARGV[0][0] == ?-
         opt = ARGV.shift
         case opt
         when '-h', '--help'
            flag_help = true
         when '-I'
            arg = ARGV.shift
            raise "-I: library path required." unless arg
            rubylib_paths.concat(arg.split(/,/))
         when '-D'
            $debug_mode = true
         else
            raise "#{opt}: invalid option."
         end
      end

      if flag_help
         command = File.basename($0)
         puts "Usage: #{command} [-h] [-I path[,path2,..]] script"
         puts "  -h                   : help"
         puts "  -I path[,path2,...]  : ruby library path"
         exit(0)
      end

      $stderr.puts "*** debug: rubylib_paths=#{rubylib_paths.inspect}" if $debug_mode
      $LOAD_PATH.concat(rubylib_paths)

      filenames = ARGV

      inline_require = InlineRequire.new
      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
