From 342d2f2aa6037bd126c2247c6c6b9bf97f8c42bd Mon Sep 17 00:00:00 2001 From: zzak Date: Wed, 5 Dec 2012 02:55:07 +0000 Subject: * doc/shell.rd, doc/shell.rd.ja: Removed stale doc files * lib/shell.rb, lib/shell/*: Merge and updates docs from doc/shell.rd* git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38201 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 5 + lib/shell.rb | 117 +++++++++++++++-- lib/shell/command-processor.rb | 280 ++++++++++++++++++++++++++--------------- lib/shell/filter.rb | 36 +++++- lib/shell/version.rb | 2 +- 5 files changed, 324 insertions(+), 116 deletions(-) diff --git a/ChangeLog b/ChangeLog index d30d1ac47a..7d4656f197 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +Wed Dec 5 11:55:00 2012 Zachary Scott + + * doc/shell.rd, doc/shell.rd.ja: Removed stale doc files + * lib/shell.rb, lib/shell/*: Merge and updates docs from doc/shell.rd* + Wed Dec 5 11:42:38 2012 Koichi Sasada * test/ruby/test_settracefunc.rb: disable trace. diff --git a/lib/shell.rb b/lib/shell.rb index 3b6ebcc8f1..8c91090414 100644 --- a/lib/shell.rb +++ b/lib/shell.rb @@ -20,6 +20,72 @@ require "shell/command-processor" require "shell/process-controller" # Shell implements an idiomatic Ruby interface for common UNIX shell commands. +# +# It provides users the ability to execute commands with filters and pipes, +# like +sh+/+csh+ by using native facilities of Ruby. +# +# == Examples +# +# === Temp file creation +# +# In this example we will create three +tmpFile+'s in three different folders +# under the +/tmp+ directory. +# +# sh = Shell.cd("/tmp") # Change to the /tmp directory +# sh.mkdir "shell-test-1" unless sh.exists?("shell-test-1") +# # make the 'shell-test-1' directory if it doesn't already exist +# sh.cd("shell-test-1") # Change to the /tmp/shell-test-1 directory +# for dir in ["dir1", "dir3", "dir5"] +# if !sh.exists?(dir) +# sh.mkdir dir # make dir if it doesnt' already exist +# sh.cd(dir) do +# # change to the `dir` directory +# f = sh.open("tmpFile", "w") # open a new file in write mode +# f.print "TEST\n" # write to the file +# f.close # close the file handler +# end +# print sh.pwd # output the process working directory +# end +# end +# +# === Temp file creationg with self +# +# This example is identical to the first, except we're using +# CommandProcessor#transact. +# +# CommandProcessor#transact executes the given block against self, in this case +# +sh+; our Shell object. Within the block we can substitute +sh.cd+ to +cd+, +# because the scope within the block uses +sh+ already. +# +# sh = Shell.cd("/tmp") +# sh.transact do +# mkdir "shell-test-1" unless exists?("shell-test-1") +# cd("shell-test-1") +# for dir in ["dir1", "dir3", "dir5"] +# if !exists?(dir) +# mkdir dir +# cd(dir) do +# f = open("tmpFile", "w") +# f.print "TEST\n" +# f.close +# end +# print pwd +# end +# end +# end +# +# === Pipe /etc/printcap into a file +# +# In this example we will read the operating system file +/etc/printcap+, +# generated by +cupsd+, and then output it to a new file relative to the +pwd+ +# of +sh+. +# +# sh = Shell.new +# sh.cat("/etc/printcap") | sh.tee("tee1") > "tee2" +# (sh.cat < "/etc/printcap") | sh.tee("tee11") > "tee12" +# sh.cat("/etc/printcap") | sh.tee("tee1") >> "tee2" +# (sh.cat < "/etc/printcap") | sh.tee("tee11") >> "tee12" +# class Shell @RCS_ID='-$Id: shell.rb,v 1.9 2002/03/04 12:01:10 keiju Exp keiju $-' @@ -52,6 +118,10 @@ class Shell @verbose = val if val end + + # call-seq: + # Shell.cd(path) + # # Creates a new Shell instance with the current working directory # set to +path+. def cd(path) @@ -107,6 +177,11 @@ class Shell end + # call-seq: + # Shell.new(pwd, umask) -> obj + # + # Creates a Shell object which current directory is set to the process + # current directory, unless otherwise specified by the +pwd+ argument. def initialize(pwd = Dir.pwd, umask = nil) @cwd = File.expand_path(pwd) @dir_stack = [] @@ -122,6 +197,7 @@ class Shell @debug = Shell.debug end + # Returns the command search path in an array attr_reader :system_path # Sets the system path (the Shell instance's PATH environment variable). @@ -132,7 +208,10 @@ class Shell rehash end - attr_accessor :umask, :record_separator + + # Returns the umask + attr_accessor :umask + attr_accessor :record_separator attr_accessor :verbose, :debug def debug=(val) @@ -171,6 +250,13 @@ class Shell attr_reader :dir_stack alias dirs dir_stack + # call-seq: + # Shell.chdir(path) + # + # Creates a Shell object which current directory is set to +path+. + # + # If a block is given, it restores the current directory when the block ends. + # # If called as iterator, it restores the current directory when the # block ends. def chdir(path = nil, verbose = @verbose) @@ -196,6 +282,17 @@ class Shell end alias cd chdir + # call-seq: + # pushdir(path) + # pushdir(path) { &block } + # + # Pushes the current directory to the directory stack, changing the current + # directory to +path+. + # + # If +path+ is omitted, it exchanges its current directory and the top of its + # directory stack. + # + # If a block is given, it restores the current directory when the block ends. def pushdir(path = nil, verbose = @verbose) check_point @@ -228,6 +325,8 @@ class Shell end alias pushd pushdir + # Pops a directory from the directory stack, and sets the current directory + # to it. def popdir check_point @@ -243,36 +342,40 @@ class Shell end alias popd popdir - # - # process management - # + # Returns a list of scheduled jobs. def jobs @process_controller.jobs end + # call-seq: + # kill(signal, job) + # + # Sends the given +signal+ to the given +job+ def kill(sig, command) @process_controller.kill_job(sig, command) end - # - # command definitions - # + # Convenience method for Shell::CommandProcessor.def_system_command def Shell.def_system_command(command, path = command) CommandProcessor.def_system_command(command, path) end + # Convenience method for Shell::CommandProcessor.undef_system_command def Shell.undef_system_command(command) CommandProcessor.undef_system_command(command) end + # Convenience method for Shell::CommandProcessor.alias_command def Shell.alias_command(ali, command, *opts, &block) CommandProcessor.alias_command(ali, command, *opts, &block) end + # Convenience method for Shell::CommandProcessor.unalias_command def Shell.unalias_command(ali) CommandProcessor.unalias_command(ali) end + # Convenience method for Shell::CommandProcessor.install_system_commands def Shell.install_system_commands(pre = "sys_") CommandProcessor.install_system_commands(pre) end diff --git a/lib/shell/command-processor.rb b/lib/shell/command-processor.rb index da7fecf1d5..f52d0ead6d 100644 --- a/lib/shell/command-processor.rb +++ b/lib/shell/command-processor.rb @@ -18,6 +18,11 @@ require "shell/system-command" require "shell/builtin-command" class Shell + # In order to execute a command on your OS, you need to define it as a + # Shell method. + # + # Alternatively, you can execute any command via + # Shell::CommandProcessor#system even if it is not defined. class CommandProcessor # include Error @@ -76,23 +81,13 @@ class Shell @shell.expand_path(path) end + # call-seq: + # foreach(path, record_separator) -> Enumerator + # foreach(path, record_separator) { block } # - # File related commands - # Shell#foreach - # Shell#open - # Shell#unlink - # Shell#test + # See IO.foreach when +path+ is a file. # - # - - # - # CommandProcessor#foreach(path, rs) - # path: String - # rs: String - record separator - # iterator - # Same as: - # File#foreach (when path is file) - # Dir#foreach (when path is directory) - # path is relative to pwd + # See Dir.foreach when +path+ is a directory. # def foreach(path = nil, *rs) path = "." unless path @@ -105,15 +100,13 @@ class Shell end end + # call-seq: + # open(path, mode, permissions) -> Enumerator + # open(path, mode, permissions) { block } # - # CommandProcessor#open(path, mode) - # path: String - # mode: String - # return: File or Dir - # Same as: - # File#open (when path is file) - # Dir#open (when path is directory) - # mode has an effect only when path is a file + # See IO.open when +path+ is a file. + # + # See Dir.open when +path+ is a directory. # def open(path, mode = nil, perm = 0666, &b) path = expand_path(path) @@ -134,11 +127,12 @@ class Shell end # public :open + # call-seq: + # unlink(path) # - # CommandProcessor#unlink(path) - # same as: - # Dir#unlink (when path is directory) - # File#unlink (when path is file) + # See IO.unlink when +path+ is a file. + # + # See Dir.unlink when +path+ is a directory. # def unlink(path) @shell.check_point @@ -152,24 +146,21 @@ class Shell Void.new(@shell) end + # See Shell::CommandProcessor#test + alias top_level_test test + # call-seq: + # test(command, file1, file2) -> true or false + # [command, file1, file2] -> true or false # - # CommandProcessor#test(command, file1, file2) - # CommandProcessor#[command, file1, file2] - # command: char or String or Symbol - # file1: String - # file2: String(optional) - # return: Boolean - # same as: - # test() (when command is char or length 1 string or symbol) - # FileTest.command (others) - # example: + # Tests if the given +command+ exists in +file1+, or optionally +file2+. + # + # Example: # sh[?e, "foo"] # sh[:e, "foo"] # sh["e", "foo"] # sh[:exists?, "foo"] # sh["exists?", "foo"] # - alias top_level_test test def test(command, file1, file2=nil) file1 = expand_path(file1) file2 = expand_path(file2) if file2 @@ -198,20 +189,13 @@ class Shell end end end + # See Shell::CommandProcessor#test alias [] test + # call-seq: + # mkdir(path) # - # Dir related methods - # - # Shell#mkdir - # Shell#rmdir - # - #-- - # - # CommandProcessor#mkdir(*path) - # path: String - # same as Dir.mkdir() - # + # Same as Dir.mkdir, except multiple directories are allowed. def mkdir(*path) @shell.check_point notify("mkdir #{path.join(' ')}") @@ -232,11 +216,10 @@ class Shell Void.new(@shell) end + # call-seq: + # rmdir(path) # - # CommandProcessor#rmdir(*path) - # path: String - # same as Dir.rmdir() - # + # Same as Dir.rmdir, except multiple directories are allowed. def rmdir(*path) @shell.check_point notify("rmdir #{path.join(' ')}") @@ -247,13 +230,12 @@ class Shell Void.new(@shell) end + # call-seq: + # system(command, *options) -> SystemCommand + # + # Executes the given +command+ with the +options+ parameter. # - # CommandProcessor#system(command, *opts) - # command: String - # opts: String - # return: SystemCommand - # Same as system() function - # example: + # Example: # print sh.system("ls", "-l") # sh.system("ls", "-l") | sh.head > STDOUT # @@ -268,22 +250,26 @@ class Shell SystemCommand.new(@shell, find_system_command(command), *opts) end + # call-seq: + # rehash # - # ProcessCommand#rehash - # clear command hash table. - # + # Clears the command hash table. def rehash @system_commands = {} end - # - # ProcessCommand#transact - # - def check_point + def check_point # :nodoc: @shell.process_controller.wait_all_jobs_execution end - alias finish_all_jobs check_point + alias finish_all_jobs check_point # :nodoc: + # call-seq: + # transact { block } + # + # Executes a block as self + # + # Example: + # sh.transact { system("ls", "-l") | head > STDOUT } def transact(&block) begin @shell.instance_eval(&block) @@ -292,17 +278,27 @@ class Shell end end + # call-seq: + # out(device) { block } # - # internal commands - # + # Calls device.print on the result passing the _block_ to + # #transact def out(dev = STDOUT, &block) dev.print transact(&block) end + # call-seq: + # echo(*strings) -> Echo + # + # Returns a Echo object, for the given +strings+ def echo(*strings) Echo.new(@shell, *strings) end + # call-seq: + # cat(*filename) -> Cat + # + # Returns a Cat object, for the given +filenames+ def cat(*filenames) Cat.new(@shell, *filenames) end @@ -310,7 +306,10 @@ class Shell # def sort(*filenames) # Sort.new(self, *filenames) # end - + # call-seq: + # glob(pattern) -> Glob + # + # Returns a Glob filter object, with the given +pattern+ object def glob(pattern) Glob.new(@shell, pattern) end @@ -326,10 +325,18 @@ class Shell end end + # call-seq: + # tee(file) -> Tee + # + # Returns a Tee filter object, with the given +file+ command def tee(file) Tee.new(@shell, file) end + # call-seq: + # concat(*jobs) -> Concat + # + # Returns a Concat object, for the given +jobs+ def concat(*jobs) Concat.new(@shell, *jobs) end @@ -371,11 +378,17 @@ class Shell Shell.Fail Error::CommandNotFound, command end + # call-seq: + # def_system_command(command, path) -> Shell::SystemCommand + # + # Defines a command, registering +path+ as a Shell method for the given + # +command+. + # + # Shell::CommandProcessor.def_system_command "ls" + # #=> Defines ls. # - # CommandProcessor.def_system_command(command, path) - # command: String - # path: String - # define 'command()' method as method. + # Shell::CommandProcessor.def_system_command "sys_sort", "sort" + # #=> Defines sys_sort as sort # def self.def_system_command(command, path = command) begin @@ -390,6 +403,10 @@ class Shell Shell.debug.kind_of?(Integer) && Shell.debug > 1) end + # call-seq: + # undef_system_command(command) -> self + # + # Undefines a command def self.undef_system_command(command) command = command.id2name if command.kind_of?(Symbol) remove_method(command) @@ -398,15 +415,20 @@ class Shell self end - # define command alias - # ex) - # def_alias_command("ls_c", "ls", "-C", "-F") - # def_alias_command("ls_c", "ls"){|*opts| ["-C", "-F", *opts]} - # @alias_map = {} + # Returns a list of aliased commands def self.alias_map @alias_map end + # call-seq: + # alias_command(alias, command, *options) -> self + # + # Creates a command alias at the given +alias+ for the given +command+, + # passing any +options+ along with it. + # + # Shell::CommandProcessor.alias_command "lsC", "ls", "-CBF", "--show-control-chars" + # Shell::CommandProcessor.alias_command("lsC", "ls"){|*opts| ["-CBF", "--show-control-chars", *opts]} + # def self.alias_command(ali, command, *opts) ali = ali.id2name if ali.kind_of?(Symbol) command = command.id2name if command.kind_of?(Symbol) @@ -436,22 +458,57 @@ class Shell self end + # call-seq: + # unalias_command(alias) -> self + # + # Unaliases the given +alias+ command. def self.unalias_command(ali) ali = ali.id2name if ali.kind_of?(Symbol) @alias_map.delete ali.intern undef_system_command(ali) end - # - # CommandProcessor.def_builtin_commands(delegation_class, command_specs) - # delegation_class: Class or Module - # command_specs: [[command_name, [argument,...]],...] - # command_name: String - # arguments: String - # FILENAME?? -> expand_path(filename??) - # *FILENAME?? -> filename??.collect{|f|expand_path(f)}.join(", ") - # define command_name(argument,...) as - # delegation_class.command_name(argument,...) + # :nodoc: + # + # Delegates File and FileTest methods into Shell, including the following + # commands: + # + # * Shell#blockdev?(file) + # * Shell#chardev?(file) + # * Shell#directory?(file) + # * Shell#executable?(file) + # * Shell#executable_real?(file) + # * Shell#exist?(file)/Shell#exists?(file) + # * Shell#file?(file) + # * Shell#grpowned?(file) + # * Shell#owned?(file) + # * Shell#pipe?(file) + # * Shell#readable?(file) + # * Shell#readable_real?(file) + # * Shell#setgid?(file) + # * Shell#setuid?(file) + # * Shell#size(file)/Shell#size?(file) + # * Shell#socket?(file) + # * Shell#sticky?(file) + # * Shell#symlink?(file) + # * Shell#writable?(file) + # * Shell#writable_real?(file) + # * Shell#zero?(file) + # * Shell#syscopy(filename_from, filename_to) + # * Shell#copy(filename_from, filename_to) + # * Shell#move(filename_from, filename_to) + # * Shell#compare(filename_from, filename_to) + # * Shell#safe_unlink(*filenames) + # * Shell#makedirs(*filenames) + # * Shell#install(filename_from, filename_to, mode) + # + # And also, there are some aliases for convenience: + # + # * Shell#cmp <- Shell#compare + # * Shell#mv <- Shell#move + # * Shell#cp <- Shell#copy + # * Shell#rm_f <- Shell#safe_unlink + # * Shell#mkpath <- Shell#makedirs # def self.def_builtin_commands(delegation_class, command_specs) for meth, args in command_specs @@ -478,15 +535,16 @@ class Shell end end + # call-seq: + # install_system_commands(prefix = "sys_") # - # CommandProcessor.install_system_commands(pre) - # pre: String - command name prefix - # defines every command which belongs in default_system_path via - # CommandProcessor.command(). It doesn't define already defined - # methods twice. By default, "pre_" is prefixes to each method - # name. Characters that may not be used in a method name are - # all converted to '_'. Definition errors are just ignored. + # Defines all commands in the Shell.default_system_path as Shell method, + # all with given +prefix+ appended to their names. # + # Any invalid character names are converted to +_+, and errors are passed + # to Shell.notify. + # + # Methods already defined are skipped. def self.install_system_commands(pre = "sys_") defined_meth = {} for m in Shell.methods @@ -511,12 +569,7 @@ class Shell end end - #---------------------------------------------------------------------- - # - # class initializing methods - - # - #---------------------------------------------------------------------- - def self.add_delegate_command_to_shell(id) + def self.add_delegate_command_to_shell(id) # :nodoc: id = id.intern if id.kind_of?(String) name = id.id2name if Shell.method_defined?(id) @@ -552,8 +605,27 @@ class Shell end], __FILE__, __LINE__) end - # - # define default builtin commands + # Delegates File methods into Shell, including the following commands: + # + # * Shell#atime(file) + # * Shell#basename(file, *opt) + # * Shell#chmod(mode, *files) + # * Shell#chown(owner, group, *file) + # * Shell#ctime(file) + # * Shell#delete(*file) + # * Shell#dirname(file) + # * Shell#ftype(file) + # * Shell#join(*file) + # * Shell#link(file_from, file_to) + # * Shell#lstat(file) + # * Shell#mtime(file) + # * Shell#readlink(file) + # * Shell#rename(file_from, file_to) + # * Shell#split(file) + # * Shell#stat(file) + # * Shell#symlink(file_from, file_to) + # * Shell#truncate(file, length) + # * Shell#utime(atime, mtime, *file) # def self.install_builtin_commands # method related File. diff --git a/lib/shell/filter.rb b/lib/shell/filter.rb index df41b420ea..d53ed06315 100644 --- a/lib/shell/filter.rb +++ b/lib/shell/filter.rb @@ -9,11 +9,12 @@ # # -class Shell +class Shell #:nodoc: + # Any result of command exection is a Filter. # - # Filter - # A method to require - # each() + # This class includes Enumerable, therefore a Filter object can use all + # Enumerable + # facilities. # class Filter include Enumerable @@ -29,6 +30,10 @@ class Shell @input = filter end + # call-seq: + # each(record_separator=nil) { block } + # + # Iterates a block for each line. def each(rs = nil) rs = @shell.record_separator unless rs if @input @@ -36,6 +41,11 @@ class Shell end end + # call-seq: + # < source + # + # Inputs from +source+, which is either a string of a file name or an IO + # object. def < (src) case src when String @@ -49,6 +59,11 @@ class Shell end end + # call-seq: + # > source + # + # Outputs from +source+, which is either a string of a file name or an IO + # object. def > (to) case to when String @@ -66,6 +81,11 @@ class Shell self end + # call-seq: + # >> source + # + # Appends the output to +source+, which is either a string of a file name + # or an IO object. def >> (to) begin Shell.cd(@shell.pwd).append(to, self) @@ -74,6 +94,10 @@ class Shell end end + # call-seq: + # | filter + # + # Processes a pipeline. def | (filter) filter.input = self if active? @@ -82,6 +106,10 @@ class Shell filter end + # call-seq: + # filter1 + filter2 + # + # Outputs +filter1+, and then +filter2+ using Join.new def + (filter) Join.new(@shell, self, filter) end diff --git a/lib/shell/version.rb b/lib/shell/version.rb index cbdb0e5e96..2568627e2b 100644 --- a/lib/shell/version.rb +++ b/lib/shell/version.rb @@ -9,7 +9,7 @@ # # -class Shell +class Shell # :nodoc: @RELEASE_VERSION = "0.7" @LAST_UPDATE_DATE = "07/03/20" end -- cgit v1.2.3