rant 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/COPYING +504 -0
  2. data/README +203 -0
  3. data/Rantfile +104 -0
  4. data/TODO +19 -0
  5. data/bin/rant +12 -0
  6. data/bin/rant-import +12 -0
  7. data/devel-notes +50 -0
  8. data/doc/configure.rdoc +40 -0
  9. data/doc/csharp.rdoc +74 -0
  10. data/doc/rant-import.rdoc +32 -0
  11. data/doc/rant.rdoc +24 -0
  12. data/doc/rantfile.rdoc +227 -0
  13. data/doc/rubyproject.rdoc +210 -0
  14. data/lib/rant.rb +9 -0
  15. data/lib/rant/cs_compiler.rb +334 -0
  16. data/lib/rant/import.rb +291 -0
  17. data/lib/rant/import/rubydoc.rb +125 -0
  18. data/lib/rant/import/rubypackage.rb +417 -0
  19. data/lib/rant/import/rubytest.rb +97 -0
  20. data/lib/rant/plugin/README +50 -0
  21. data/lib/rant/plugin/configure.rb +345 -0
  22. data/lib/rant/plugin/csharp.rb +275 -0
  23. data/lib/rant/plugin_methods.rb +41 -0
  24. data/lib/rant/rantenv.rb +217 -0
  25. data/lib/rant/rantfile.rb +664 -0
  26. data/lib/rant/rantlib.rb +1118 -0
  27. data/lib/rant/rantsys.rb +258 -0
  28. data/lib/rant/rantvar.rb +82 -0
  29. data/rantmethods.rb +79 -0
  30. data/run_import +7 -0
  31. data/run_rant +7 -0
  32. data/setup.rb +1360 -0
  33. data/test/Rantfile +2 -0
  34. data/test/plugin/configure/Rantfile +47 -0
  35. data/test/plugin/configure/test_configure.rb +58 -0
  36. data/test/plugin/csharp/Hello.cs +10 -0
  37. data/test/plugin/csharp/Rantfile +30 -0
  38. data/test/plugin/csharp/src/A.cs +8 -0
  39. data/test/plugin/csharp/src/B.cs +8 -0
  40. data/test/plugin/csharp/test_csharp.rb +99 -0
  41. data/test/project1/Rantfile +127 -0
  42. data/test/project1/test_project.rb +203 -0
  43. data/test/project2/buildfile +14 -0
  44. data/test/project2/rantfile.rb +20 -0
  45. data/test/project2/sub1/Rantfile +12 -0
  46. data/test/project2/test_project.rb +87 -0
  47. data/test/project_rb1/README +14 -0
  48. data/test/project_rb1/bin/wgrep +5 -0
  49. data/test/project_rb1/lib/wgrep.rb +56 -0
  50. data/test/project_rb1/rantfile.rb +30 -0
  51. data/test/project_rb1/test/tc_wgrep.rb +21 -0
  52. data/test/project_rb1/test/text +3 -0
  53. data/test/project_rb1/test_project_rb1.rb +153 -0
  54. data/test/test_env.rb +47 -0
  55. data/test/test_filetask.rb +57 -0
  56. data/test/test_lighttask.rb +49 -0
  57. data/test/test_metatask.rb +29 -0
  58. data/test/test_rant_interface.rb +65 -0
  59. data/test/test_sys.rb +61 -0
  60. data/test/test_task.rb +115 -0
  61. data/test/toplevel.rf +11 -0
  62. data/test/ts_all.rb +4 -0
  63. data/test/tutil.rb +95 -0
  64. metadata +133 -0
data/lib/rant.rb ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rant/rantlib'
4
+
5
+ include Rant
6
+
7
+ if $0 == __FILE__
8
+ exit Rant.run
9
+ end
@@ -0,0 +1,334 @@
1
+
2
+ require 'rant/rantenv'
3
+
4
+ module Rant
5
+ # An object extending this module acts as an
6
+ # interface to a C# Compiler.
7
+ class CsCompiler
8
+
9
+ LIB_SYSTEM_XML = "System.Xml.dll"
10
+ LIB_SYSTEM_DRAWING = "System.Drawing.dll"
11
+ LIB_SYSTEM_FORMS = "System.Windows.Forms.dll"
12
+
13
+ class << self
14
+ # Get the short name for the compiler referenced by this path.
15
+ def cs_compiler_name(path)
16
+ case path
17
+ when /csc(\.exe)?$/i
18
+ "csc"
19
+ when /cscc(\.exe)?$/i
20
+ "cscc"
21
+ when /mcs(\.exe)?$/i
22
+ "mcs"
23
+ else
24
+ nil
25
+ end
26
+ end
27
+
28
+ # Search for a C# compiler in PATH and some
29
+ # usual locations.
30
+ def look_for_cs_compiler
31
+ csc_bin = nil
32
+ if Env.on_windows?
33
+ csc_bin = "csc" if Env.find_bin "csc"
34
+ unless csc_bin
35
+ csc_bin = look_for_csc
36
+ end
37
+ end
38
+ csc_bin = "cscc" if !csc_bin && Env.find_bin("cscc")
39
+ csc_bin = "mcs" if !csc_bin && Env.find_bin("mcs")
40
+ csc_bin
41
+ end
42
+
43
+ # Searches for csc in some usual directories.
44
+ # Ment to be used on windows only!
45
+ def look_for_csc
46
+ # Is there a way to get a list of all available
47
+ # drives?
48
+ ("C".."Z").each { |drive|
49
+ ["WINDOWS", "WINNT"].each { |win_dir|
50
+ frame_dir = drive + ':\\' + win_dir +
51
+ '\Microsoft.NET\Framework'
52
+ next unless test(?d,frame_dir)
53
+ csc_pathes = []
54
+ Dir.entries(frame_dir).each { |e|
55
+ vdir = File.join(frame_dir, e)
56
+ if test(?d, vdir)
57
+ csc_path = File.join(vdir, "csc.exe")
58
+ if test(?e,csc_path)
59
+ csc_pathes << csc_path
60
+ end
61
+ end
62
+ }
63
+ next if csc_pathes.empty?
64
+ return csc_pathes.sort.last
65
+ }
66
+ }
67
+ nil
68
+ rescue
69
+ nil
70
+ end
71
+ end
72
+
73
+ # Short name for compiler, such as "csc", "cscc" or "mcs".
74
+ attr_reader :csc_name
75
+ # Descriptive name for compiler.
76
+ attr_reader :long_name
77
+ # Compiler path, or cmd on PATH
78
+ # Look also at the #csc and #csc= methods. Most times they do
79
+ # what you need.
80
+ attr_accessor :csc_bin
81
+ # Debug flag.
82
+ attr_accessor :debug
83
+ # Target filename.
84
+ attr_accessor :out
85
+ # Libraries to link angainst (usually dlls).
86
+ attr_accessor :libs
87
+ # Preprocessor defines.
88
+ attr_reader :defines
89
+ # Other args, could be options.
90
+ # Initialized to an empty array.
91
+ attr_accessor :misc_args
92
+ # Hash with compiler specific arguments.
93
+ attr_accessor :specific_args
94
+ # Sourcefiles.
95
+ attr_accessor :sources
96
+ # Resources to embedd in assembly.
97
+ attr_accessor :resources
98
+ # Library link pathes.
99
+ attr_reader :lib_link_pathes
100
+ # Entry point for executable.
101
+ attr_accessor :entry
102
+ # Optimize, defaults to true
103
+ attr_accessor :optimize
104
+ # Enable compiler warnings, defaults to true
105
+ attr_accessor :warnings
106
+
107
+ def initialize(compiler_name=nil)
108
+ self.csc_name = (compiler_name || "cscc")
109
+ @long_name = "C# Compiler"
110
+ @defines = []
111
+ @libs = []
112
+ @sources = nil
113
+ @misc_args = []
114
+ @specific_args = {
115
+ "cscc" => [],
116
+ "csc" => [],
117
+ "mcs" => [],
118
+ }
119
+ @resources = []
120
+ @debug = false
121
+ @out = "a.out"
122
+ @lib_link_pathes = []
123
+ @entry = nil
124
+ @optimize = true
125
+ @warnings = true
126
+ @csc = nil
127
+ @csc_bin = nil
128
+ end
129
+
130
+ # Command to invoke compiler.
131
+ def csc
132
+ @csc_bin || @csc_name
133
+ end
134
+
135
+ # Set this to command to invoke your compiler. Contrary to
136
+ # +cc_bin+, this also tries to determine which interface to
137
+ # use for this compiler. Finally it sets +cc_bin+.
138
+ def csc=(cmd)
139
+ name = self.class.cs_compiler_name(cmd)
140
+ @csc_name = name if name
141
+ @csc_bin = cmd
142
+ end
143
+
144
+ def csc_name= new_name
145
+ unless ["cscc", "csc", "mcs"].include?(new_name)
146
+ raise "Unsupported C# compiler `#{new_name}'"
147
+ end
148
+ @csc_name = new_name
149
+ @long_name = case @csc_name
150
+ when "cscc": "DotGNU C# compiler"
151
+ when "csc": "MS Visual.NET C# compiler"
152
+ when "mcs": "Mono C# compiler"
153
+ end
154
+ end
155
+
156
+ # Shortcut for +specific_args+.
157
+ def sargs
158
+ @specific_args
159
+ end
160
+
161
+ # Generate compilation command for executable.
162
+ def cmd_exe
163
+ send @csc_name + "_cmd_exe"
164
+ end
165
+
166
+ def cscc_cmd_exe
167
+ # This generates the compilation command
168
+ # for cscc.
169
+ cc_cmd = csc.dup
170
+ cc_cmd << " -e#{entry}" if entry
171
+ cc_cmd << cc_cmd_args
172
+ cc_cmd
173
+ end
174
+
175
+ def csc_cmd_exe
176
+ # This generates the compilation command
177
+ # for csc.
178
+ cc_cmd = csc.dup
179
+ # Use target:winexe only if not debugging,
180
+ # because this will suppress a background console window.
181
+ cc_cmd << " /target:winexe" unless debug
182
+ cc_cmd << " /main:#{entry}" if entry
183
+ cc_cmd << cc_cmd_args
184
+ cc_cmd
185
+ end
186
+
187
+ def mcs_cmd_exe
188
+ # Generate compilation command for mcs.
189
+ cc_cmd = csc.dup
190
+ cc_cmd << " -target:exe"
191
+ cc_cmd << " -main:#{entry}" if entry
192
+ cc_cmd << cc_cmd_args
193
+ cc_cmd
194
+ end
195
+
196
+ # Generate command for DLL.
197
+ def cmd_dll
198
+ send @csc_name + "_cmd_dll"
199
+ end
200
+
201
+ def cscc_cmd_dll
202
+ cc_cmd = csc.dup
203
+ cc_cmd << " -shared"
204
+ cc_cmd << cc_cmd_args
205
+ cc_cmd
206
+ end
207
+
208
+ def csc_cmd_dll
209
+ cc_cmd = csc.dup
210
+ cc_cmd << " /target:library"
211
+ cc_cmd << cc_cmd_args
212
+ cc_cmd
213
+ end
214
+
215
+ def mcs_cmd_dll
216
+ cc_cmd = csc.dup
217
+ cc_cmd << " -target:library"
218
+ cc_cmd << cc_cmd_args
219
+ cc_cmd
220
+ end
221
+
222
+ # Generate command for object file.
223
+ def cmd_object
224
+ send @csc_name + "_cmd_object"
225
+ end
226
+
227
+ def cscc_cmd_object
228
+ cc_cmd = csc.dup
229
+ cc_cmd << " -c"
230
+ cc_cmd << cc_cmd_args
231
+ cc_cmd
232
+ end
233
+
234
+ def csc_cmd_object
235
+ cc_cmd = csc.dup
236
+ cc_cmd << " /target:module"
237
+ cc_cmd << cc_cmd_args
238
+ cc_cmd
239
+ end
240
+
241
+ def mcs_cmd_object
242
+ cc_cmd = csc.dup
243
+ cc_cmd << " -target:module"
244
+ cc_cmd << cc_cmd_args
245
+ cc_cmd
246
+ end
247
+
248
+ def to_s
249
+ csc + "\n" + "Interface: " + csc_name
250
+ end
251
+
252
+ private
253
+ def cc_cmd_args
254
+ send @csc_name + "_cmd_args"
255
+ end
256
+
257
+ def cscc_cmd_args
258
+ cc_args = ""
259
+ cc_args << " -o #{out}" if out
260
+ cc_args << " -g -DDEBUG" if debug
261
+ defines.each { |p|
262
+ cc_args << " -D#{p}"
263
+ }
264
+ cc_args << " -Wall" if warnings
265
+ cc_args << " -O2" if optimize
266
+ lib_link_pathes.each { |p|
267
+ cc_args << " -L #{Env.shell_path(p)}"
268
+ }
269
+ libs.each { |p|
270
+ cc_args << " -l #{Env.shell_path(p)}"
271
+ }
272
+ cc_args << " " << misc_args.join(' ') if misc_args
273
+ sargs = specific_args["cscc"]
274
+ cc_args << " " << sargs.join(' ') if sargs
275
+ resources.each { |p|
276
+ cc_args << " -fresources=#{Env.shell_path(p)}"
277
+ }
278
+ cc_args << " " << sources.arglist if sources
279
+ cc_args
280
+ end
281
+
282
+ def csc_cmd_args
283
+ cc_args = ""
284
+ cc_args << " /out:#{Env.shell_path(out)}" if out
285
+ cc_args << " /debug /d:DEBUG" if debug
286
+ defines.each { |p|
287
+ cc_args << " /d:#{p}"
288
+ }
289
+ cc_args << " /optimize" if optimize
290
+ # TODO: cc_args << " -Wall" if warnings
291
+ lib_link_pathes.each { |p|
292
+ #TODO: cc_args << " -L #{p}"
293
+ }
294
+ libs.each { |p|
295
+ cc_args << " /r:#{Env.shell_path(p)}"
296
+ }
297
+ cc_args << " " << misc_args.join(' ') if misc_args
298
+ sargs = specific_args["csc"]
299
+ cc_args << " " << sargs.join(' ') if sargs
300
+ resources.each { |p|
301
+ cc_args << " /res:#{Env.shell_path(p)}"
302
+ }
303
+ cc_args << " " << sources.arglist if sources
304
+ cc_args
305
+ end
306
+
307
+ def mcs_cmd_args
308
+ cc_args = ""
309
+ cc_args << " -o #{Env.shell_path(out)}" if out
310
+ cc_args << " -g -d:DEBUG" if debug
311
+ defines.each { |p|
312
+ cc_args << " -d:#{p}"
313
+ }
314
+ cc_args << " -optimize" if optimize
315
+ # Warning level for mcs: highest 4, default 2
316
+ cc_args << " -warn:4" if warnings
317
+ lib_link_pathes.each { |p|
318
+ cc_args << " -L #{Env.shell_path(p)}"
319
+ }
320
+ if libs && !libs.empty?
321
+ cc_args << " -r:" + (libs.collect { |p| Env.shell_path(p) }).join(',')
322
+ end
323
+ cc_args << " " << misc_args.join(' ') if misc_args
324
+ sargs = specific_args["mcs"]
325
+ cc_args << " " << sargs.join(' ') if sargs
326
+ resources.each { |p|
327
+ cc_args << " -resource:#{Env.shell_path(p)}"
328
+ }
329
+ cc_args << " " << sources.arglist if sources
330
+ cc_args
331
+ end
332
+
333
+ end # class CsCompiler
334
+ end # module Rant
@@ -0,0 +1,291 @@
1
+
2
+ # import.rb - Library for the rant-import command.
3
+ #
4
+ # Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
5
+
6
+ require 'getoptlong'
7
+ require 'rant/rantlib'
8
+
9
+ module Rant
10
+
11
+ class RantImportDoneException < RantDoneException
12
+ end
13
+
14
+ class RantImportAbortException < RantAbortException
15
+ end
16
+
17
+ # This class is the implementation for the rant-import command.
18
+ # Usage similar to RantApp class.
19
+ class RantImport
20
+ include Rant::Console
21
+
22
+ # TODO: We currently only look for imports and plugins
23
+ # relative to this LIB_DIR. We should also look in all pathes
24
+ # in $LOAD_PATH after looking in LIB_DIR.
25
+ LIB_DIR = File.expand_path(File.dirname(__FILE__))
26
+
27
+ OPTIONS = [
28
+ [ "--help", "-h", GetoptLong::NO_ARGUMENT,
29
+ "Print this help and exit." ],
30
+ [ "--version", "-v", GetoptLong::NO_ARGUMENT,
31
+ "Print version of rant-import and exit." ],
32
+ [ "--plugins", "-p", GetoptLong::REQUIRED_ARGUMENT,
33
+ "Include PLUGINS (comma separated list)." ],
34
+ [ "--imports", "-i", GetoptLong::REQUIRED_ARGUMENT,
35
+ "Include IMPORTS (coma separated list)." ],
36
+ [ "--force", GetoptLong::NO_ARGUMENT,
37
+ "Force overwriting of output file." ],
38
+ [ "--with-comments", GetoptLong::NO_ARGUMENT,
39
+ "Include comments from Rant sources." ],
40
+ [ "--reduce-whitespace", "-r",GetoptLong::NO_ARGUMENT,
41
+ "Remove as much whitespace from Rant sources as possible." ],
42
+ [ "--auto", "-a", GetoptLong::NO_ARGUMENT,
43
+ "Automatically try to determine imports and plugins.\n" +
44
+ "Warning: loads Rantfile!" ],
45
+ [ "--rantfile", "-f", GetoptLong::REQUIRED_ARGUMENT,
46
+ "Load RANTFILE. This also sets --auto!\n" +
47
+ "May be given multiple times." ],
48
+ ]
49
+
50
+ class << self
51
+ def run(first_arg=nil, *other_args)
52
+ other_args = other_args.flatten
53
+ args = first_arg.nil? ? ARGV.dup : ([first_arg] + other_args)
54
+ new(args).run
55
+ end
56
+ end
57
+
58
+ # Arguments, usually those given on commandline.
59
+ attr :args
60
+ # Plugins to import.
61
+ attr :plugins
62
+ # Imports to import ;)
63
+ attr :imports
64
+ # Filename where the monolithic rant script goes to.
65
+ attr :mono_fn
66
+ # Skip comments? Defaults to true.
67
+ attr_accessor :skip_comments
68
+ # Remove whitespace from Rant sources? Defaults to false.
69
+ attr_accessor :reduce_whitespace
70
+ # Try automatic determination of imports and plugins?
71
+ # Defaults to false.
72
+ attr_accessor :auto
73
+
74
+ def initialize(*args)
75
+ @args = args.flatten
76
+ @msg_prefix = "rant-import: "
77
+ @plugins = []
78
+ @imports = []
79
+ @mono_fn = nil
80
+ @force = false
81
+ @rantapp = nil
82
+ @core_imports = []
83
+ @included_plugins = []
84
+ @included_imports = []
85
+ @skip_comments = true
86
+ @reduce_whitespace = false
87
+ @auto = false
88
+ @arg_rantfiles = []
89
+ end
90
+
91
+ def run
92
+ process_args
93
+
94
+ if @auto
95
+ @rantapp = RantApp.new(
96
+ %w(-v --stop-after-load) +
97
+ @arg_rantfiles.collect { |rf| "-f#{rf}" }
98
+ )
99
+ unless @rantapp.run == 0
100
+ abort("Auto-determination of required code failed.")
101
+ end
102
+ @imports.concat(@rantapp.imports)
103
+ @plugins.concat(@rantapp.plugins.map { |p| p.name })
104
+ end
105
+
106
+ if File.exist?(@mono_fn) && !@force
107
+ abort("#{@mono_fn} exists. Rant won't overwrite this file.",
108
+ "Add --force to override this restriction.")
109
+ end
110
+ File.open(@mono_fn, "w") { |mf|
111
+ mf << <<EOH
112
+ #!/usr/bin/env ruby
113
+
114
+ # #@mono_fn - Monolithic rant script, autogenerated by rant-import.
115
+ #
116
+ # Copyright (C) 2005 Stefan Lang <langstefan@gmx.at>
117
+ #
118
+ # This program is free software.
119
+ # You can distribute/modify this program under the terms of
120
+ # the GNU LGPL, Lesser General Public License version 2.1.
121
+ EOH
122
+ mf << mono_rant_core
123
+ mf << mono_imports
124
+ mf << mono_plugins
125
+ mf << <<EOF
126
+
127
+ Rant::CODE_IMPORTS.concat %w(#{@included_imports.join(' ')}
128
+ #{(@included_plugins.map do |i| "plugin/" + i end).join(' ')})
129
+
130
+ # Catch a `require "rant"', sad...
131
+ alias require_backup_by_rant require
132
+ def require libf
133
+ if libf == "rant"
134
+ self.class.instance_eval { include Rant }
135
+ else
136
+ begin
137
+ require_backup_by_rant libf
138
+ rescue
139
+ raise $!, caller
140
+ end
141
+ end
142
+ end
143
+
144
+ Rant.run
145
+ EOF
146
+ }
147
+ msg "Done.",
148
+ "Included imports: " + @included_imports.join(', '),
149
+ "Included plugins: " + @included_plugins.join(', '),
150
+ "Your monolithic rant was written to `#@mono_fn'!"
151
+
152
+ done
153
+ rescue RantImportDoneException
154
+ 0
155
+ rescue RantImportAbortException
156
+ $stderr.puts "rant-import aborted!"
157
+ 1
158
+ end
159
+
160
+ def process_args
161
+ # WARNING: we currently have to fool getoptlong,
162
+ # by temporory changing ARGV!
163
+ # This could cause problems.
164
+ old_argv = ARGV.dup
165
+ ARGV.replace(@args.dup)
166
+ cmd_opts = GetoptLong.new(*OPTIONS.collect { |lst| lst[0..-2] })
167
+ cmd_opts.quiet = true
168
+ cmd_opts.each { |opt, value|
169
+ case opt
170
+ when "--version"
171
+ puts "rant-import #{Rant::VERSION}"
172
+ done
173
+ when "--help": help
174
+ when "--force": @force = true
175
+ when "--with-comments": @skip_comments = false
176
+ when "--reduce-whitespace": @reduce_whitespace = true
177
+ when "--imports"
178
+ @imports.concat(value.split(/\s*,\s*/))
179
+ when "--plugins"
180
+ @plugins.concat(value.split(/\s*,\s*/))
181
+ when "--auto"
182
+ @auto = true
183
+ when "--rantfile"
184
+ @auto = true
185
+ @arg_rantfiles << value.dup
186
+ end
187
+ }
188
+ rem_args = ARGV.dup
189
+ unless rem_args.size == 1 && !@mono_fn
190
+ abort("Exactly one argument (besides options) required.",
191
+ "Type `rant-import --help' for usage.")
192
+ end
193
+ @mono_fn = rem_args.first if rem_args.first
194
+ rescue GetoptLong::Error => e
195
+ abort(e.message)
196
+ ensure
197
+ ARGV.replace(old_argv)
198
+ end
199
+
200
+ def done
201
+ raise RantImportDoneException
202
+ end
203
+
204
+ def help
205
+ puts "rant-import [OPTIONS] [-i IMPORT1,IMPORT2,...] [-p PLUGIN1,PLUGIN2...] MONO_RANT"
206
+ puts
207
+ puts " Write a monolithic rant script to MONO_RANT."
208
+ puts
209
+ puts "Options are:"
210
+ print option_listing(OPTIONS)
211
+ done
212
+ end
213
+
214
+ def abort(*text)
215
+ err_msg(*text) unless text.empty?
216
+ raise RantImportAbortException
217
+ end
218
+
219
+ # Get a monolithic rant script (as string) containing only the
220
+ # Rant core.
221
+ def mono_rant_core
222
+ # Starting point is rant/rantlib.rb.
223
+ rantlib_f = File.join(LIB_DIR, "rantlib.rb")
224
+ begin
225
+ rantlib = File.read rantlib_f
226
+ rescue
227
+ abort("When trying to read `#{rantlib_f}': #$!",
228
+ "This file should contains the core of rant, so import is impossible.",
229
+ "Please check your rant installation!")
230
+ end
231
+ @core_imports << "rantlib"
232
+ resolve_requires rantlib
233
+ end
234
+
235
+ def mono_imports
236
+ rs = ""
237
+ @imports.each { |name|
238
+ next if @included_imports.include? name
239
+ path = File.join(LIB_DIR, "import", "#{name}.rb")
240
+ unless File.exist? path
241
+ abort("No such import - #{name}")
242
+ end
243
+ msg "Including import `#{name}'", path
244
+ @included_imports << name.dup
245
+ rs << resolve_requires(File.read(path))
246
+ }
247
+ rs
248
+ end
249
+
250
+ def mono_plugins
251
+ rs = ""
252
+ @plugins.each { |name|
253
+ lc_name = name.downcase
254
+ next if @included_plugins.include? lc_name
255
+ path = File.join(LIB_DIR, "plugin", "#{lc_name}.rb")
256
+ unless File.exist? path
257
+ abort("No such plugin - #{name}")
258
+ end
259
+ msg "Including plugin `#{lc_name}'", path
260
+ @included_plugins << lc_name
261
+ rs << resolve_requires(File.read(path))
262
+ }
263
+ rs
264
+ end
265
+
266
+ # +script+ is a string. This method resolves requires of rant/
267
+ # code by directly inserting the code.
268
+ def resolve_requires script
269
+ rs = ""
270
+ script.each { |line|
271
+ # skip shebang line
272
+ next if line =~ /^#! ?(\/|\\)?\w/
273
+ # skip pure comment lines
274
+ next if line =~ /^\s*#/ if @skip_comments
275
+ if line =~ /\s*(require|load)\s+('|")rant\/(\w+)(\.rb)?('|")/
276
+ name = $3
277
+ next if @core_imports.include? name
278
+ path = File.join(LIB_DIR, "#{name}.rb")
279
+ msg "Including `#{name}'", path
280
+ @core_imports << name
281
+ rs << resolve_requires(File.read(path))
282
+ else
283
+ line.sub!(/^\s+/, '') if @reduce_whitespace
284
+ rs << line
285
+ end
286
+ }
287
+ rs
288
+ end
289
+
290
+ end # class RantImport
291
+ end # module Rant