shell 0.0.1 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,147 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # shell/builtin-command.rb -
4
+ # $Release Version: 0.7 $
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require_relative "filter"
14
+
15
+ class Shell
16
+ class BuiltInCommand < Filter
17
+ def wait?
18
+ false
19
+ end
20
+ def active?
21
+ true
22
+ end
23
+ end
24
+
25
+ class Void < BuiltInCommand
26
+ def initialize(sh, *opts)
27
+ super sh
28
+ end
29
+
30
+ def each(rs = nil)
31
+ # do nothing
32
+ end
33
+ end
34
+
35
+ class Echo < BuiltInCommand
36
+ def initialize(sh, *strings)
37
+ super sh
38
+ @strings = strings
39
+ end
40
+
41
+ def each(rs = nil)
42
+ rs = @shell.record_separator unless rs
43
+ for str in @strings
44
+ yield str + rs
45
+ end
46
+ end
47
+ end
48
+
49
+ class Cat < BuiltInCommand
50
+ def initialize(sh, *filenames)
51
+ super sh
52
+ @cat_files = filenames
53
+ end
54
+
55
+ def each(rs = nil)
56
+ if @cat_files.empty?
57
+ super
58
+ else
59
+ for src in @cat_files
60
+ @shell.foreach(src, rs){|l| yield l}
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ class Glob < BuiltInCommand
67
+ def initialize(sh, pattern)
68
+ super sh
69
+
70
+ @pattern = pattern
71
+ end
72
+
73
+ def each(rs = nil)
74
+ if @pattern[0] == ?/
75
+ @files = Dir[@pattern]
76
+ else
77
+ prefix = @shell.pwd+"/"
78
+ @files = Dir[prefix+@pattern].collect{|p| p.sub(prefix, "")}
79
+ end
80
+ rs = @shell.record_separator unless rs
81
+ for f in @files
82
+ yield f+rs
83
+ end
84
+ end
85
+ end
86
+
87
+ class AppendIO < BuiltInCommand
88
+ def initialize(sh, io, filter)
89
+ super sh
90
+ @input = filter
91
+ @io = io
92
+ end
93
+
94
+ def input=(filter)
95
+ @input.input=filter
96
+ for l in @input
97
+ @io << l
98
+ end
99
+ end
100
+
101
+ end
102
+
103
+ class AppendFile < AppendIO
104
+ def initialize(sh, to_filename, filter)
105
+ @file_name = to_filename
106
+ io = sh.open(to_filename, "a")
107
+ super(sh, io, filter)
108
+ end
109
+
110
+ def input=(filter)
111
+ begin
112
+ super
113
+ ensure
114
+ @io.close
115
+ end
116
+ end
117
+ end
118
+
119
+ class Tee < BuiltInCommand
120
+ def initialize(sh, filename)
121
+ super sh
122
+ @to_filename = filename
123
+ end
124
+
125
+ def each(rs = nil)
126
+ to = @shell.open(@to_filename, "w")
127
+ begin
128
+ super{|l| to << l; yield l}
129
+ ensure
130
+ to.close
131
+ end
132
+ end
133
+ end
134
+
135
+ class Concat < BuiltInCommand
136
+ def initialize(sh, *jobs)
137
+ super(sh)
138
+ @jobs = jobs
139
+ end
140
+
141
+ def each(rs = nil)
142
+ while job = @jobs.shift
143
+ job.each{|l| yield l}
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,668 @@
1
+ # frozen_string_literal: false
2
+ #
3
+ # shell/command-controller.rb -
4
+ # $Release Version: 0.7 $
5
+ # $Revision$
6
+ # by Keiju ISHITSUKA(keiju@ruby-lang.org)
7
+ #
8
+ # --
9
+ #
10
+ #
11
+ #
12
+
13
+ require "e2mmap"
14
+
15
+ require_relative "error"
16
+ require_relative "filter"
17
+ require_relative "system-command"
18
+ require_relative "builtin-command"
19
+
20
+ class Shell
21
+ # In order to execute a command on your OS, you need to define it as a
22
+ # Shell method.
23
+ #
24
+ # Alternatively, you can execute any command via
25
+ # Shell::CommandProcessor#system even if it is not defined.
26
+ class CommandProcessor
27
+
28
+ #
29
+ # initialize of Shell and related classes.
30
+ #
31
+ m = [:initialize, :expand_path]
32
+ if Object.methods.first.kind_of?(String)
33
+ NoDelegateMethods = m.collect{|x| x.id2name}
34
+ else
35
+ NoDelegateMethods = m
36
+ end
37
+
38
+ def self.initialize
39
+
40
+ install_builtin_commands
41
+
42
+ # define CommandProcessor#methods to Shell#methods and Filter#methods
43
+ for m in CommandProcessor.instance_methods(false) - NoDelegateMethods
44
+ add_delegate_command_to_shell(m)
45
+ end
46
+
47
+ def self.method_added(id)
48
+ add_delegate_command_to_shell(id)
49
+ end
50
+ end
51
+
52
+ #
53
+ # include run file.
54
+ #
55
+ def self.run_config
56
+ rc = "~/.rb_shell"
57
+ begin
58
+ load File.expand_path(rc) if ENV.key?("HOME")
59
+ rescue LoadError, Errno::ENOENT
60
+ rescue
61
+ print "load error: #{rc}\n"
62
+ print $!.class, ": ", $!, "\n"
63
+ for err in $@[0, $@.size - 2]
64
+ print "\t", err, "\n"
65
+ end
66
+ end
67
+ end
68
+
69
+ def initialize(shell)
70
+ @shell = shell
71
+ @system_commands = {}
72
+ end
73
+
74
+ #
75
+ # CommandProcessor#expand_path(path)
76
+ # path: String
77
+ # return: String
78
+ # returns the absolute path for <path>
79
+ #
80
+ def expand_path(path)
81
+ @shell.expand_path(path)
82
+ end
83
+
84
+ # call-seq:
85
+ # foreach(path, record_separator) -> Enumerator
86
+ # foreach(path, record_separator) { block }
87
+ #
88
+ # See IO.foreach when +path+ is a file.
89
+ #
90
+ # See Dir.foreach when +path+ is a directory.
91
+ #
92
+ def foreach(path = nil, *rs)
93
+ path = "." unless path
94
+ path = expand_path(path)
95
+
96
+ if File.directory?(path)
97
+ Dir.foreach(path){|fn| yield fn}
98
+ else
99
+ IO.foreach(path, *rs){|l| yield l}
100
+ end
101
+ end
102
+
103
+ # call-seq:
104
+ # open(path, mode, permissions) -> Enumerator
105
+ # open(path, mode, permissions) { block }
106
+ #
107
+ # See IO.open when +path+ is a file.
108
+ #
109
+ # See Dir.open when +path+ is a directory.
110
+ #
111
+ def open(path, mode = nil, perm = 0666, &b)
112
+ path = expand_path(path)
113
+ if File.directory?(path)
114
+ Dir.open(path, &b)
115
+ else
116
+ if @shell.umask
117
+ f = File.open(path, mode, perm)
118
+ File.chmod(perm & ~@shell.umask, path)
119
+ if block_given?
120
+ f.each(&b)
121
+ end
122
+ f
123
+ else
124
+ File.open(path, mode, perm, &b)
125
+ end
126
+ end
127
+ end
128
+
129
+ # call-seq:
130
+ # unlink(path)
131
+ #
132
+ # See IO.unlink when +path+ is a file.
133
+ #
134
+ # See Dir.unlink when +path+ is a directory.
135
+ #
136
+ def unlink(path)
137
+ @shell.check_point
138
+
139
+ path = expand_path(path)
140
+ if File.directory?(path)
141
+ Dir.unlink(path)
142
+ else
143
+ IO.unlink(path)
144
+ end
145
+ Void.new(@shell)
146
+ end
147
+
148
+ # See Shell::CommandProcessor#test
149
+ alias top_level_test test
150
+ # call-seq:
151
+ # test(command, file1, file2) -> true or false
152
+ # [command, file1, file2] -> true or false
153
+ #
154
+ # Tests if the given +command+ exists in +file1+, or optionally +file2+.
155
+ #
156
+ # Example:
157
+ # sh[?e, "foo"]
158
+ # sh[:e, "foo"]
159
+ # sh["e", "foo"]
160
+ # sh[:exists?, "foo"]
161
+ # sh["exists?", "foo"]
162
+ #
163
+ def test(command, file1, file2=nil)
164
+ file1 = expand_path(file1)
165
+ file2 = expand_path(file2) if file2
166
+ command = command.id2name if command.kind_of?(Symbol)
167
+
168
+ case command
169
+ when Integer
170
+ if file2
171
+ top_level_test(command, file1, file2)
172
+ else
173
+ top_level_test(command, file1)
174
+ end
175
+ when String
176
+ if command.size == 1
177
+ if file2
178
+ top_level_test(command, file1, file2)
179
+ else
180
+ top_level_test(command, file1)
181
+ end
182
+ else
183
+ if file2
184
+ FileTest.send(command, file1, file2)
185
+ else
186
+ FileTest.send(command, file1)
187
+ end
188
+ end
189
+ end
190
+ end
191
+ # See Shell::CommandProcessor#test
192
+ alias [] test
193
+
194
+ # call-seq:
195
+ # mkdir(path)
196
+ #
197
+ # Same as Dir.mkdir, except multiple directories are allowed.
198
+ def mkdir(*path)
199
+ @shell.check_point
200
+ notify("mkdir #{path.join(' ')}")
201
+
202
+ perm = nil
203
+ if path.last.kind_of?(Integer)
204
+ perm = path.pop
205
+ end
206
+ for dir in path
207
+ d = expand_path(dir)
208
+ if perm
209
+ Dir.mkdir(d, perm)
210
+ else
211
+ Dir.mkdir(d)
212
+ end
213
+ File.chmod(d, 0666 & ~@shell.umask) if @shell.umask
214
+ end
215
+ Void.new(@shell)
216
+ end
217
+
218
+ # call-seq:
219
+ # rmdir(path)
220
+ #
221
+ # Same as Dir.rmdir, except multiple directories are allowed.
222
+ def rmdir(*path)
223
+ @shell.check_point
224
+ notify("rmdir #{path.join(' ')}")
225
+
226
+ for dir in path
227
+ Dir.rmdir(expand_path(dir))
228
+ end
229
+ Void.new(@shell)
230
+ end
231
+
232
+ # call-seq:
233
+ # system(command, *options) -> SystemCommand
234
+ #
235
+ # Executes the given +command+ with the +options+ parameter.
236
+ #
237
+ # Example:
238
+ # print sh.system("ls", "-l")
239
+ # sh.system("ls", "-l") | sh.head > STDOUT
240
+ #
241
+ def system(command, *opts)
242
+ if opts.empty?
243
+ if command =~ /\*|\?|\{|\}|\[|\]|<|>|\(|\)|~|&|\||\\|\$|;|'|`|"|\n/
244
+ return SystemCommand.new(@shell, find_system_command("sh"), "-c", command)
245
+ else
246
+ command, *opts = command.split(/\s+/)
247
+ end
248
+ end
249
+ SystemCommand.new(@shell, find_system_command(command), *opts)
250
+ end
251
+
252
+ # call-seq:
253
+ # rehash
254
+ #
255
+ # Clears the command hash table.
256
+ def rehash
257
+ @system_commands = {}
258
+ end
259
+
260
+ def check_point # :nodoc:
261
+ @shell.process_controller.wait_all_jobs_execution
262
+ end
263
+ alias finish_all_jobs check_point # :nodoc:
264
+
265
+ # call-seq:
266
+ # transact { block }
267
+ #
268
+ # Executes a block as self
269
+ #
270
+ # Example:
271
+ # sh.transact { system("ls", "-l") | head > STDOUT }
272
+ def transact(&block)
273
+ begin
274
+ @shell.instance_eval(&block)
275
+ ensure
276
+ check_point
277
+ end
278
+ end
279
+
280
+ # call-seq:
281
+ # out(device) { block }
282
+ #
283
+ # Calls <code>device.print</code> on the result passing the _block_ to
284
+ # #transact
285
+ def out(dev = STDOUT, &block)
286
+ dev.print transact(&block)
287
+ end
288
+
289
+ # call-seq:
290
+ # echo(*strings) -> Echo
291
+ #
292
+ # Returns a Echo object, for the given +strings+
293
+ def echo(*strings)
294
+ Echo.new(@shell, *strings)
295
+ end
296
+
297
+ # call-seq:
298
+ # cat(*filename) -> Cat
299
+ #
300
+ # Returns a Cat object, for the given +filenames+
301
+ def cat(*filenames)
302
+ Cat.new(@shell, *filenames)
303
+ end
304
+
305
+ # def sort(*filenames)
306
+ # Sort.new(self, *filenames)
307
+ # end
308
+ # call-seq:
309
+ # glob(pattern) -> Glob
310
+ #
311
+ # Returns a Glob filter object, with the given +pattern+ object
312
+ def glob(pattern)
313
+ Glob.new(@shell, pattern)
314
+ end
315
+
316
+ def append(to, filter)
317
+ case to
318
+ when String
319
+ AppendFile.new(@shell, to, filter)
320
+ when IO
321
+ AppendIO.new(@shell, to, filter)
322
+ else
323
+ Shell.Fail Error::CantApplyMethod, "append", to.class
324
+ end
325
+ end
326
+
327
+ # call-seq:
328
+ # tee(file) -> Tee
329
+ #
330
+ # Returns a Tee filter object, with the given +file+ command
331
+ def tee(file)
332
+ Tee.new(@shell, file)
333
+ end
334
+
335
+ # call-seq:
336
+ # concat(*jobs) -> Concat
337
+ #
338
+ # Returns a Concat object, for the given +jobs+
339
+ def concat(*jobs)
340
+ Concat.new(@shell, *jobs)
341
+ end
342
+
343
+ # %pwd, %cwd -> @pwd
344
+ def notify(*opts)
345
+ Shell.notify(*opts) {|mes|
346
+ yield mes if iterator?
347
+
348
+ mes.gsub!("%pwd", "#{@cwd}")
349
+ mes.gsub!("%cwd", "#{@cwd}")
350
+ }
351
+ end
352
+
353
+ #
354
+ # private functions
355
+ #
356
+ def find_system_command(command)
357
+ return command if /^\// =~ command
358
+ case path = @system_commands[command]
359
+ when String
360
+ if exists?(path)
361
+ return path
362
+ else
363
+ Shell.Fail Error::CommandNotFound, command
364
+ end
365
+ when false
366
+ Shell.Fail Error::CommandNotFound, command
367
+ end
368
+
369
+ for p in @shell.system_path
370
+ path = join(p, command)
371
+ begin
372
+ st = File.stat(path)
373
+ rescue SystemCallError
374
+ next
375
+ else
376
+ next unless st.executable? and !st.directory?
377
+ @system_commands[command] = path
378
+ return path
379
+ end
380
+ end
381
+ @system_commands[command] = false
382
+ Shell.Fail Error::CommandNotFound, command
383
+ end
384
+
385
+ # call-seq:
386
+ # def_system_command(command, path) -> Shell::SystemCommand
387
+ #
388
+ # Defines a command, registering +path+ as a Shell method for the given
389
+ # +command+.
390
+ #
391
+ # Shell::CommandProcessor.def_system_command "ls"
392
+ # #=> Defines ls.
393
+ #
394
+ # Shell::CommandProcessor.def_system_command "sys_sort", "sort"
395
+ # #=> Defines sys_sort as sort
396
+ #
397
+ def self.def_system_command(command, path = command)
398
+ begin
399
+ eval((d = %Q[def #{command}(*opts)
400
+ SystemCommand.new(@shell, '#{path}', *opts)
401
+ end]), nil, __FILE__, __LINE__ - 1)
402
+ rescue SyntaxError
403
+ Shell.notify "warn: Can't define #{command} path: #{path}."
404
+ end
405
+ Shell.notify "Define #{command} path: #{path}.", Shell.debug?
406
+ Shell.notify("Definition of #{command}: ", d,
407
+ Shell.debug.kind_of?(Integer) && Shell.debug > 1)
408
+ end
409
+
410
+ # call-seq:
411
+ # undef_system_command(command) -> self
412
+ #
413
+ # Undefines a command
414
+ def self.undef_system_command(command)
415
+ command = command.id2name if command.kind_of?(Symbol)
416
+ remove_method(command)
417
+ Shell.module_eval{remove_method(command)}
418
+ Filter.module_eval{remove_method(command)}
419
+ self
420
+ end
421
+
422
+ @alias_map = {}
423
+ # Returns a list of aliased commands
424
+ def self.alias_map
425
+ @alias_map
426
+ end
427
+ # call-seq:
428
+ # alias_command(alias, command, *options) -> self
429
+ #
430
+ # Creates a command alias at the given +alias+ for the given +command+,
431
+ # passing any +options+ along with it.
432
+ #
433
+ # Shell::CommandProcessor.alias_command "lsC", "ls", "-CBF", "--show-control-chars"
434
+ # Shell::CommandProcessor.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]}
435
+ #
436
+ def self.alias_command(ali, command, *opts)
437
+ ali = ali.id2name if ali.kind_of?(Symbol)
438
+ command = command.id2name if command.kind_of?(Symbol)
439
+ begin
440
+ if iterator?
441
+ @alias_map[ali.intern] = proc
442
+
443
+ eval((d = %Q[def #{ali}(*opts)
444
+ @shell.__send__(:#{command},
445
+ *(CommandProcessor.alias_map[:#{ali}].call *opts))
446
+ end]), nil, __FILE__, __LINE__ - 1)
447
+
448
+ else
449
+ args = opts.collect{|opt| '"' + opt + '"'}.join(",")
450
+ eval((d = %Q[def #{ali}(*opts)
451
+ @shell.__send__(:#{command}, #{args}, *opts)
452
+ end]), nil, __FILE__, __LINE__ - 1)
453
+ end
454
+ rescue SyntaxError
455
+ Shell.notify "warn: Can't alias #{ali} command: #{command}."
456
+ Shell.notify("Definition of #{ali}: ", d)
457
+ raise
458
+ end
459
+ Shell.notify "Define #{ali} command: #{command}.", Shell.debug?
460
+ Shell.notify("Definition of #{ali}: ", d,
461
+ Shell.debug.kind_of?(Integer) && Shell.debug > 1)
462
+ self
463
+ end
464
+
465
+ # call-seq:
466
+ # unalias_command(alias) -> self
467
+ #
468
+ # Unaliases the given +alias+ command.
469
+ def self.unalias_command(ali)
470
+ ali = ali.id2name if ali.kind_of?(Symbol)
471
+ @alias_map.delete ali.intern
472
+ undef_system_command(ali)
473
+ end
474
+
475
+ # :nodoc:
476
+ #
477
+ # Delegates File and FileTest methods into Shell, including the following
478
+ # commands:
479
+ #
480
+ # * Shell#blockdev?(file)
481
+ # * Shell#chardev?(file)
482
+ # * Shell#directory?(file)
483
+ # * Shell#executable?(file)
484
+ # * Shell#executable_real?(file)
485
+ # * Shell#exist?(file)/Shell#exists?(file)
486
+ # * Shell#file?(file)
487
+ # * Shell#grpowned?(file)
488
+ # * Shell#owned?(file)
489
+ # * Shell#pipe?(file)
490
+ # * Shell#readable?(file)
491
+ # * Shell#readable_real?(file)
492
+ # * Shell#setgid?(file)
493
+ # * Shell#setuid?(file)
494
+ # * Shell#size(file)/Shell#size?(file)
495
+ # * Shell#socket?(file)
496
+ # * Shell#sticky?(file)
497
+ # * Shell#symlink?(file)
498
+ # * Shell#writable?(file)
499
+ # * Shell#writable_real?(file)
500
+ # * Shell#zero?(file)
501
+ # * Shell#syscopy(filename_from, filename_to)
502
+ # * Shell#copy(filename_from, filename_to)
503
+ # * Shell#move(filename_from, filename_to)
504
+ # * Shell#compare(filename_from, filename_to)
505
+ # * Shell#safe_unlink(*filenames)
506
+ # * Shell#makedirs(*filenames)
507
+ # * Shell#install(filename_from, filename_to, mode)
508
+ #
509
+ # And also, there are some aliases for convenience:
510
+ #
511
+ # * Shell#cmp <- Shell#compare
512
+ # * Shell#mv <- Shell#move
513
+ # * Shell#cp <- Shell#copy
514
+ # * Shell#rm_f <- Shell#safe_unlink
515
+ # * Shell#mkpath <- Shell#makedirs
516
+ #
517
+ def self.def_builtin_commands(delegation_class, command_specs)
518
+ for meth, args in command_specs
519
+ arg_str = args.collect{|arg| arg.downcase}.join(", ")
520
+ call_arg_str = args.collect{
521
+ |arg|
522
+ case arg
523
+ when /^(FILENAME.*)$/
524
+ format("expand_path(%s)", $1.downcase)
525
+ when /^(\*FILENAME.*)$/
526
+ # \*FILENAME* -> filenames.collect{|fn| expand_path(fn)}.join(", ")
527
+ $1.downcase + '.collect{|fn| expand_path(fn)}'
528
+ else
529
+ arg
530
+ end
531
+ }.join(", ")
532
+ d = %Q[def #{meth}(#{arg_str})
533
+ #{delegation_class}.#{meth}(#{call_arg_str})
534
+ end]
535
+ Shell.notify "Define #{meth}(#{arg_str})", Shell.debug?
536
+ Shell.notify("Definition of #{meth}: ", d,
537
+ Shell.debug.kind_of?(Integer) && Shell.debug > 1)
538
+ eval d
539
+ end
540
+ end
541
+
542
+ # call-seq:
543
+ # install_system_commands(prefix = "sys_")
544
+ #
545
+ # Defines all commands in the Shell.default_system_path as Shell method,
546
+ # all with given +prefix+ appended to their names.
547
+ #
548
+ # Any invalid character names are converted to +_+, and errors are passed
549
+ # to Shell.notify.
550
+ #
551
+ # Methods already defined are skipped.
552
+ def self.install_system_commands(pre = "sys_")
553
+ defined_meth = {}
554
+ for m in Shell.methods
555
+ defined_meth[m] = true
556
+ end
557
+ sh = Shell.new
558
+ for path in Shell.default_system_path
559
+ next unless sh.directory? path
560
+ sh.cd path
561
+ sh.foreach do
562
+ |cn|
563
+ if !defined_meth[pre + cn] && sh.file?(cn) && sh.executable?(cn)
564
+ command = (pre + cn).gsub(/\W/, "_").sub(/^([0-9])/, '_\1')
565
+ begin
566
+ def_system_command(command, sh.expand_path(cn))
567
+ rescue
568
+ Shell.notify "warn: Can't define #{command} path: #{cn}"
569
+ end
570
+ defined_meth[command] = command
571
+ end
572
+ end
573
+ end
574
+ end
575
+
576
+ def self.add_delegate_command_to_shell(id) # :nodoc:
577
+ id = id.intern if id.kind_of?(String)
578
+ name = id.id2name
579
+ if Shell.method_defined?(id)
580
+ Shell.notify "warn: override definition of Shell##{name}."
581
+ Shell.notify "warn: alias Shell##{name} to Shell##{name}_org.\n"
582
+ Shell.module_eval "alias #{name}_org #{name}"
583
+ end
584
+ Shell.notify "method added: Shell##{name}.", Shell.debug?
585
+ Shell.module_eval(%Q[def #{name}(*args, &block)
586
+ begin
587
+ @command_processor.__send__(:#{name}, *args, &block)
588
+ rescue Exception
589
+ $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
590
+ $@.delete_if{|s| /^\\(eval\\):/ =~ s}
591
+ raise
592
+ end
593
+ end], __FILE__, __LINE__)
594
+
595
+ if Shell::Filter.method_defined?(id)
596
+ Shell.notify "warn: override definition of Shell::Filter##{name}."
597
+ Shell.notify "warn: alias Shell##{name} to Shell::Filter##{name}_org."
598
+ Filter.module_eval "alias #{name}_org #{name}"
599
+ end
600
+ Shell.notify "method added: Shell::Filter##{name}.", Shell.debug?
601
+ Filter.module_eval(%Q[def #{name}(*args, &block)
602
+ begin
603
+ self | @shell.__send__(:#{name}, *args, &block)
604
+ rescue Exception
605
+ $@.delete_if{|s| /:in `__getobj__'$/ =~ s} #`
606
+ $@.delete_if{|s| /^\\(eval\\):/ =~ s}
607
+ raise
608
+ end
609
+ end], __FILE__, __LINE__)
610
+ end
611
+
612
+ # Delegates File methods into Shell, including the following commands:
613
+ #
614
+ # * Shell#atime(file)
615
+ # * Shell#basename(file, *opt)
616
+ # * Shell#chmod(mode, *files)
617
+ # * Shell#chown(owner, group, *file)
618
+ # * Shell#ctime(file)
619
+ # * Shell#delete(*file)
620
+ # * Shell#dirname(file)
621
+ # * Shell#ftype(file)
622
+ # * Shell#join(*file)
623
+ # * Shell#link(file_from, file_to)
624
+ # * Shell#lstat(file)
625
+ # * Shell#mtime(file)
626
+ # * Shell#readlink(file)
627
+ # * Shell#rename(file_from, file_to)
628
+ # * Shell#split(file)
629
+ # * Shell#stat(file)
630
+ # * Shell#symlink(file_from, file_to)
631
+ # * Shell#truncate(file, length)
632
+ # * Shell#utime(atime, mtime, *file)
633
+ #
634
+ def self.install_builtin_commands
635
+ # method related File.
636
+ # (exclude open/foreach/unlink)
637
+ normal_delegation_file_methods = [
638
+ ["atime", ["FILENAME"]],
639
+ ["basename", ["fn", "*opts"]],
640
+ ["chmod", ["mode", "*FILENAMES"]],
641
+ ["chown", ["owner", "group", "*FILENAME"]],
642
+ ["ctime", ["FILENAMES"]],
643
+ ["delete", ["*FILENAMES"]],
644
+ ["dirname", ["FILENAME"]],
645
+ ["ftype", ["FILENAME"]],
646
+ ["join", ["*items"]],
647
+ ["link", ["FILENAME_O", "FILENAME_N"]],
648
+ ["lstat", ["FILENAME"]],
649
+ ["mtime", ["FILENAME"]],
650
+ ["readlink", ["FILENAME"]],
651
+ ["rename", ["FILENAME_FROM", "FILENAME_TO"]],
652
+ ["split", ["pathname"]],
653
+ ["stat", ["FILENAME"]],
654
+ ["symlink", ["FILENAME_O", "FILENAME_N"]],
655
+ ["truncate", ["FILENAME", "length"]],
656
+ ["utime", ["atime", "mtime", "*FILENAMES"]]]
657
+
658
+ def_builtin_commands(File, normal_delegation_file_methods)
659
+ alias_method :rm, :delete
660
+
661
+ # method related FileTest
662
+ def_builtin_commands(FileTest,
663
+ FileTest.singleton_methods(false).collect{|m| [m, ["FILENAME"]]})
664
+
665
+ end
666
+
667
+ end
668
+ end