File: inline-require

package info (click to toggle)
kwalify 0.7.2-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 1,852 kB
  • ctags: 1,188
  • sloc: ruby: 8,446; xml: 172; makefile: 36; java: 36
file content (179 lines) | stat: -rwxr-xr-x 5,647 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#!/usr/bin/env ruby

###
### inline-require - expand 'require "foo"' into inline code
###
### usage: inline-require [-h] [-I path[,path2,..]] script
###
### copyright(c) 2005-2010 kuwata-lab all rights reserved.
### 0.7.2
### $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