rash-command-shell 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/rash +9 -0
- data/lib/rash.rb +130 -0
- data/lib/rash/aliasing.rb +55 -0
- data/lib/rash/ext/filesystem.rb +138 -0
- data/lib/rash/jobcontrol.rb +21 -0
- data/lib/rash/prompt/irb.rb +80 -0
- data/lib/rash/redirection.rb +151 -0
- metadata +70 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 19cb922bc55b83424f375e375c2015dff74690720b4d611357646bfd11e04c44
|
4
|
+
data.tar.gz: 48ce02ad077cd0a89a7fc62987907cbfc0ca80997e398c6e9699ac4beacf4521
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6e1d9cd6e7270bd206d79db56b9ca20e2bab9b976c7e76b835c3af078e9a16816714807b8c96eafdc5f403369404bce243c31105bd33869fabb5fbffba65adf7
|
7
|
+
data.tar.gz: 6e36ba48448f4aed666807150a8819855ccb2e8802093f56cfc6f357277cd24a6ff91c43de0889affd15fddd2d642b1601ffcd7c347949766a434c124b1d7b1b
|
data/bin/rash
ADDED
data/lib/rash.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
class Environment
|
2
|
+
|
3
|
+
attr_reader :aliasing_disabled
|
4
|
+
attr_reader :superuser_mode
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
common_init
|
8
|
+
end
|
9
|
+
|
10
|
+
def chdir(dir = nil)
|
11
|
+
old = @working_directory
|
12
|
+
Dir.chdir(dir.nil? ? "~" : dir.to_s)
|
13
|
+
@working_directory = Dir.pwd
|
14
|
+
ENV["OLDPWD"] = old.to_s
|
15
|
+
Dir.pwd
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_path(path)
|
19
|
+
ENV["PATH"] += File::PATH_SEPARATOR + (path.respond_to?(:path) ? path.path : path.to_s)
|
20
|
+
end
|
21
|
+
|
22
|
+
def method_missing(m, *args, &block)
|
23
|
+
if args.length == 0 && !block_given?
|
24
|
+
ENV[m.to_s.upcase]
|
25
|
+
elsif m.to_s[-1] == "=" && args.length == 1 && !block_given?
|
26
|
+
ENV[m.to_s.upcase.delete_suffix("=")] = args[0].to_s
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def as_superuser(&block)
|
33
|
+
@superuser_mode = true
|
34
|
+
begin
|
35
|
+
block.call
|
36
|
+
ensure
|
37
|
+
@superuser_mode = false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def common_init
|
44
|
+
@working_directory = Dir.pwd
|
45
|
+
|
46
|
+
@aliases = {}
|
47
|
+
@aliasing_disabled = false
|
48
|
+
@active_jobs = []
|
49
|
+
|
50
|
+
@prompt = {
|
51
|
+
AUTO_INDENT: true,
|
52
|
+
RETURN: ""
|
53
|
+
}
|
54
|
+
ENV["RASHDIR"] = File.dirname(__FILE__)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
require_relative "rash/redirection"
|
59
|
+
require_relative "rash/aliasing"
|
60
|
+
require_relative "rash/jobcontrol"
|
61
|
+
|
62
|
+
$env = Environment.new
|
63
|
+
|
64
|
+
|
65
|
+
# note for later documentation: any aliases of cd must be functions, not
|
66
|
+
# environmental aliases. Limitation of implementation.
|
67
|
+
def cd(dir = nil)
|
68
|
+
$env.chdir(dir)
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
def run(file, *args)
|
73
|
+
filename = file.to_s
|
74
|
+
exe = (filename.start_with?("/") ? filename : File.expand_path(filename.strip))
|
75
|
+
unless File.executable?(exe)
|
76
|
+
raise SystemCallError.new("No such executable file - #{exe}", Errno::ENOENT::Errno)
|
77
|
+
end
|
78
|
+
system(exe, *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin})
|
79
|
+
end
|
80
|
+
|
81
|
+
|
82
|
+
# Defines `bash` psuedo-compatibility. Filesystem effects happen like normal
|
83
|
+
# and environmental variable changes are copied
|
84
|
+
def sourcesh(file)
|
85
|
+
bash_env = lambda do |cmd = nil|
|
86
|
+
tmpenv = `#{cmd + ';' if cmd} printenv`
|
87
|
+
tmpenv.split("\n").grep(/[a-zA-Z0-9_]+=.*/).map {|l| l.split("=")}
|
88
|
+
end
|
89
|
+
bash_source = lambda do |f|
|
90
|
+
Hash[bash_env.call("source #{File.realpath f}") - bash_env.()]
|
91
|
+
end
|
92
|
+
|
93
|
+
bash_source.call(file).each {|k,v| ENV[k] = v if k != "SHLVL" && k != "_"}
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def which(command)
|
98
|
+
cmd = File.expand_path(command)
|
99
|
+
return cmd if File.executable?(cmd) && !File.directory?(cmd)
|
100
|
+
|
101
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
102
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |pt|
|
103
|
+
path = File.expand_path(pt)
|
104
|
+
exts.each do |ext|
|
105
|
+
exe = File.join(path, "#{command}#{ext}")
|
106
|
+
return exe if File.executable?(exe) && !File.directory?(exe)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
nil
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
# Note that I defy convention and don't define `respond_to_missing?`. This
|
114
|
+
# is because doing so screws with irb.
|
115
|
+
def self.method_missing(m, *args, &block)
|
116
|
+
exe = which(m.to_s)
|
117
|
+
if exe || ($env.alias?(m) && !$env.aliasing_disabled)
|
118
|
+
if $env.superuser_mode
|
119
|
+
system("sudo", *$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin})
|
120
|
+
else
|
121
|
+
system(*$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin})
|
122
|
+
end
|
123
|
+
else
|
124
|
+
super
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
run_command_file = "#{$env.HOME}/.rashrc"
|
130
|
+
load run_command_file if File.file?(run_command_file)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class Environment
|
2
|
+
def make_alias(new_func, old_func)
|
3
|
+
@aliases[new_func.to_sym] = old_func.to_s.split(" ")
|
4
|
+
end
|
5
|
+
|
6
|
+
def clear_alias(func)
|
7
|
+
@aliases.delete(func.to_sym)
|
8
|
+
end
|
9
|
+
|
10
|
+
# recursive aliases not currently possible. In the works
|
11
|
+
def resolve_alias(f)
|
12
|
+
result = [f.to_s]
|
13
|
+
aliases = @aliases.dup
|
14
|
+
found_alias = true
|
15
|
+
while found_alias
|
16
|
+
found_alias = false
|
17
|
+
if aliases.has_key?(result[0].to_sym)
|
18
|
+
found_alias = true
|
19
|
+
match = result[0].to_sym
|
20
|
+
result[0] = aliases[match]
|
21
|
+
aliases.delete(match)
|
22
|
+
result.flatten!
|
23
|
+
end
|
24
|
+
end
|
25
|
+
result
|
26
|
+
end
|
27
|
+
|
28
|
+
def alias?(f)
|
29
|
+
@aliases.has_key?(f.to_sym)
|
30
|
+
end
|
31
|
+
|
32
|
+
def without_aliasing
|
33
|
+
old_aliasing = @aliasing_disabled
|
34
|
+
@aliasing_disabled = true
|
35
|
+
if block_given?
|
36
|
+
begin
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
@aliasing_disabled = old_aliasing
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_aliasing
|
45
|
+
old_aliasing = @aliasing_disabled
|
46
|
+
@aliasing_disabled = false
|
47
|
+
if block_given?
|
48
|
+
begin
|
49
|
+
yield
|
50
|
+
ensure
|
51
|
+
@aliasing_disabled = old_aliasing
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
class Environment
|
2
|
+
|
3
|
+
RASH_LOCAL_FILE = ".rashrc.local"
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
common_init
|
7
|
+
@working_directory = Directory.root("/")
|
8
|
+
traverse_filetree("/", Dir.pwd)
|
9
|
+
end
|
10
|
+
|
11
|
+
def chdir(dir = nil)
|
12
|
+
old = @working_directory
|
13
|
+
traverse_filetree(Dir.pwd, (dir.nil? ? "~" : dir.to_s))
|
14
|
+
ENV["OLDPWD"] = old.to_s
|
15
|
+
Dir.pwd
|
16
|
+
end
|
17
|
+
|
18
|
+
def local_def(name, &block)
|
19
|
+
@working_directory.add_local_method(name.to_sym, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def local_undef(name)
|
23
|
+
@working_directory.clear_local_method(name.to_sym)
|
24
|
+
end
|
25
|
+
|
26
|
+
def local_method?(name)
|
27
|
+
@working_directory.local_methods.key?(name.to_sym)
|
28
|
+
end
|
29
|
+
|
30
|
+
def local_call(name, *args, &block)
|
31
|
+
@working_directory.local_methods[name.to_sym].call(*args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
LOCAL_FUNCTIONS_ENABLED = true
|
37
|
+
|
38
|
+
# from and to are strings
|
39
|
+
def traverse_filetree(from, to)
|
40
|
+
abs_from = File.expand_path(from)
|
41
|
+
abs_to = File.expand_path(to)
|
42
|
+
raise SystemCallError(from, Errno::ENOENT::Errno) unless Dir.exists?(abs_from)
|
43
|
+
raise SystemCallError(to, Errno::ENOENT::Errno) unless Dir.exists?(abs_to)
|
44
|
+
|
45
|
+
from_parts = (abs_from == "/" ? [""] : abs_from.split(File::SEPARATOR))
|
46
|
+
to_parts = (abs_to == "/" ? [""] : abs_to.split(File::SEPARATOR))
|
47
|
+
common_path = from_parts.filter.with_index {|p, i| p == to_parts[i]}
|
48
|
+
|
49
|
+
from_parts = from_parts.drop(common_path.size)
|
50
|
+
to_parts = to_parts.drop(common_path.size)
|
51
|
+
|
52
|
+
from_parts.each do |p|
|
53
|
+
@working_directory.add_parent(File.expand_path("..")) if @working_directory.root?
|
54
|
+
@working_directory = @working_directory.parent
|
55
|
+
Dir.chdir(@working_directory.to_s)
|
56
|
+
end
|
57
|
+
|
58
|
+
to_parts.each do |p|
|
59
|
+
@working_directory = @working_directory.child(File.expand_path(p, @working_directory.to_s))
|
60
|
+
Dir.chdir(@working_directory.to_s)
|
61
|
+
# rashrc_local = @working_directory.to_s + File::SEPARATOR + RASH_LOCAL_FILE
|
62
|
+
load RASH_LOCAL_FILE if File.exists?(RASH_LOCAL_FILE) && !File.directory?(RASH_LOCAL_FILE)
|
63
|
+
end
|
64
|
+
|
65
|
+
Dir.pwd
|
66
|
+
end
|
67
|
+
|
68
|
+
class Directory
|
69
|
+
attr_reader :local_methods
|
70
|
+
attr_reader :parent, :children
|
71
|
+
|
72
|
+
def self.root(dir)
|
73
|
+
Directory.new(nil, dir)
|
74
|
+
end
|
75
|
+
|
76
|
+
def initialize(parent, dir)
|
77
|
+
@path = Dir.new(dir)
|
78
|
+
@parent = parent
|
79
|
+
@children = []
|
80
|
+
@local_methods = parent&.local_methods.dup || {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def root?
|
84
|
+
parent.nil?
|
85
|
+
end
|
86
|
+
|
87
|
+
def add_parent(dir)
|
88
|
+
@parent = Directory.root(dir)
|
89
|
+
@parent.add_child(self.to_s)
|
90
|
+
@parent
|
91
|
+
end
|
92
|
+
|
93
|
+
def child(path)
|
94
|
+
ch = @children.find {|c| c.to_s == path}
|
95
|
+
ch = add_child(path) unless ch
|
96
|
+
ch
|
97
|
+
end
|
98
|
+
|
99
|
+
def add_child(path)
|
100
|
+
dir = Directory.new(self, path)
|
101
|
+
@children << dir
|
102
|
+
dir
|
103
|
+
end
|
104
|
+
|
105
|
+
def add_local_method(name, &block)
|
106
|
+
raise ArgumentError.new "no method body provided" unless block_given?
|
107
|
+
@local_methods[name] = block # if name already exists, its function is overriden
|
108
|
+
name
|
109
|
+
end
|
110
|
+
|
111
|
+
# might not be useful
|
112
|
+
def clear_local_method(name)
|
113
|
+
@local_methods.delete(name)
|
114
|
+
name
|
115
|
+
end
|
116
|
+
|
117
|
+
def to_s
|
118
|
+
@path.path
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.method_missing(m, *args, &block)
|
124
|
+
exe = which(m.to_s)
|
125
|
+
if $env.local_method?(m)
|
126
|
+
$env.local_call(m, *args, &block)
|
127
|
+
elsif exe || ($env.alias?(m) && !$env.aliasing_disabled)
|
128
|
+
if $env.superuser_mode
|
129
|
+
system("sudo", *$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin})
|
130
|
+
else
|
131
|
+
system(*$env.resolve_alias(m), *args.flatten.map{|a| a.to_s}, {out: $stdout, err: $stderr, in: $stdin})
|
132
|
+
end
|
133
|
+
else
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
$env = Environment.new
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Environment
|
2
|
+
def jobs
|
3
|
+
@active_jobs.keep_if {|pid| Process.kill(0, pid) rescue false}
|
4
|
+
end
|
5
|
+
|
6
|
+
def async(&block)
|
7
|
+
pid = fork {
|
8
|
+
block.call
|
9
|
+
exit!(true)
|
10
|
+
}
|
11
|
+
@active_jobs << pid
|
12
|
+
Process.detach(pid)
|
13
|
+
pid
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def as_background(&block)
|
18
|
+
$env.async(&block)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
@@ -0,0 +1,80 @@
|
|
1
|
+
class Environment
|
2
|
+
attr_reader :prompt
|
3
|
+
def standard_prompt=(prompt)
|
4
|
+
@prompt[:prompt_i] = case prompt
|
5
|
+
when Proc
|
6
|
+
prompt
|
7
|
+
else
|
8
|
+
err_msg = "expecting stringable type or method that resolves to string"
|
9
|
+
raise ArgumentError.new(err_msg) unless prompt.respond_to?(:to_s)
|
10
|
+
lambda {prompt.to_s}
|
11
|
+
end
|
12
|
+
@prompt[:PROMPT_I] = "".tap {|s| def s.dup; $env.prompt[:prompt_i].call; end}
|
13
|
+
end
|
14
|
+
|
15
|
+
def indent_prompt=(prompt)
|
16
|
+
@prompt[:prompt_n] = case prompt
|
17
|
+
when Proc
|
18
|
+
prompt
|
19
|
+
else
|
20
|
+
err_msg = "expecting stringable type or method that resolves to string"
|
21
|
+
raise ArgumentError.new(err_msg) unless prompt.respond_to?(:to_s)
|
22
|
+
lambda {prompt.to_s}
|
23
|
+
end
|
24
|
+
|
25
|
+
@prompt[:PROMPT_N] = "".tap {|s| def s.dup; $env.prompt[:prompt_n].call; end}
|
26
|
+
end
|
27
|
+
|
28
|
+
def string_prompt=(prompt)
|
29
|
+
@prompt[:prompt_s] = case prompt
|
30
|
+
when Proc
|
31
|
+
prompt
|
32
|
+
else
|
33
|
+
err_msg = "expecting stringable type or method that resolves to string"
|
34
|
+
raise ArgumentError.new(err_msg) unless prompt.respond_to?(:to_s)
|
35
|
+
lambda {prompt.to_s}
|
36
|
+
end
|
37
|
+
|
38
|
+
@prompt[:PROMPT_S] = "".tap {|s| def s.dup; $env.prompt[:prompt_s].call; end}
|
39
|
+
end
|
40
|
+
|
41
|
+
def continued_prompt=(prompt)
|
42
|
+
@prompt[:prompt_c] = case prompt
|
43
|
+
when Proc
|
44
|
+
prompt
|
45
|
+
else
|
46
|
+
err_msg = "expecting stringable type or method that resolves to string"
|
47
|
+
raise ArgumentError.new(err_msg) unless prompt.respond_to?(:to_s)
|
48
|
+
lambda {prompt.to_s}
|
49
|
+
end
|
50
|
+
|
51
|
+
@prompt[:PROMPT_C] = "".tap {|s| def s.dup; $env.prompt[:prompt_c].call; end}
|
52
|
+
end
|
53
|
+
|
54
|
+
# This method can only be run from .rashrc. Anywhere else and it will simply do nothing
|
55
|
+
def return_value_header=(prompt)
|
56
|
+
@prompt[:RETURN] = prompt
|
57
|
+
end
|
58
|
+
|
59
|
+
def use_irb_prompt
|
60
|
+
if $0 == "irb"
|
61
|
+
IRB.conf[:PROMPT][:RASH] = @prompt
|
62
|
+
IRB.conf[:PROMPT_MODE] = :RASH
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
if $0 == "irb"
|
68
|
+
IRB.conf[:PROMPT][:RASH] = {
|
69
|
+
:PROMPT_I => "rash $",
|
70
|
+
:PROMPT_N => "rash ",
|
71
|
+
:PROMPT_S => "rash%l>",
|
72
|
+
:PROMPT_C => "rash >",
|
73
|
+
:RETURN => "%s\n" # used to printf
|
74
|
+
}
|
75
|
+
IRB.conf[:PROMPT_MODE] = :RASH
|
76
|
+
IRB.conf[:SAVE_HISTORY] = 1000
|
77
|
+
IRB.conf[:AP_NAME] = "rash"
|
78
|
+
IRB.conf[:AUTO_INDENT] = true
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,151 @@
|
|
1
|
+
class Environment
|
2
|
+
|
3
|
+
DEFAULT_IO = {in: STDIN, out: STDOUT, err: STDERR}
|
4
|
+
|
5
|
+
def reset_io
|
6
|
+
reset_stdout
|
7
|
+
reset_stderr
|
8
|
+
reset_stdin
|
9
|
+
end
|
10
|
+
|
11
|
+
def stdout=(file)
|
12
|
+
$stdout.flush
|
13
|
+
old_stdout = $stdout
|
14
|
+
case file
|
15
|
+
when String
|
16
|
+
$stdout = File.new(file, "w")
|
17
|
+
when :out
|
18
|
+
$stdout = STDOUT
|
19
|
+
when :err
|
20
|
+
$stdout = STDERR
|
21
|
+
else
|
22
|
+
raise ArgumentError.new("not an output stream - #{file}") unless file.is_a?(IO)
|
23
|
+
$stdout = file
|
24
|
+
end
|
25
|
+
old_stdout.close unless standard_stream?(old_stdout)
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_stdout
|
29
|
+
$stdout.flush
|
30
|
+
$stdout.close unless standard_stream?($stdout)
|
31
|
+
$stdout = DEFAULT_IO[:out]
|
32
|
+
end
|
33
|
+
|
34
|
+
def stderr=(file)
|
35
|
+
$stderr.flush
|
36
|
+
old_stderr = $stderr
|
37
|
+
case file
|
38
|
+
when String
|
39
|
+
$stderr = File.new(file, "w")
|
40
|
+
when :out
|
41
|
+
$stderr = STDOUT
|
42
|
+
when :err
|
43
|
+
$stderr = STDERR
|
44
|
+
else
|
45
|
+
raise ArgumentError.new("not an output stream - #{file}") unless file.is_a?(IO)
|
46
|
+
$stderr = file
|
47
|
+
end
|
48
|
+
old_stderr.close unless standard_stream?(old_stderr)
|
49
|
+
end
|
50
|
+
|
51
|
+
def reset_stderr
|
52
|
+
$stderr.flush
|
53
|
+
$stderr.close unless standard_stream?($stderr)
|
54
|
+
$stderr = DEFAULT_IO[:err]
|
55
|
+
end
|
56
|
+
|
57
|
+
def stdin=(file)
|
58
|
+
old_stdin = $stdin
|
59
|
+
case file
|
60
|
+
when String
|
61
|
+
$stdin = File.new(file, "r")
|
62
|
+
when :in
|
63
|
+
$stdin = STDIN
|
64
|
+
else
|
65
|
+
raise ArgumentError.new("not an input stream - #{file}") unless file.is_a?(IO)
|
66
|
+
$stdin = file
|
67
|
+
end
|
68
|
+
old_stdin.close unless standard_stream?(old_stdin)
|
69
|
+
end
|
70
|
+
|
71
|
+
def reset_stdin
|
72
|
+
$stdin.close unless standard_stream>($stdin)
|
73
|
+
$stdin = DEFAULT_IO[:in]
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def standard_stream?(f)
|
79
|
+
DEFAULT_IO.values.include?(f)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# If you want to append, you need to get the file object yourself.
|
84
|
+
# Check if not flushing immediately is a concern. If so, set $stdout.sync for files
|
85
|
+
def with_stdout_as(file = STDOUT)
|
86
|
+
$env.stdout = file
|
87
|
+
if block_given?
|
88
|
+
begin
|
89
|
+
yield $stdout
|
90
|
+
ensure
|
91
|
+
$env.reset_stdout
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def with_stderr_as(file = STDERR)
|
97
|
+
$env.stderr = file
|
98
|
+
if block_given?
|
99
|
+
begin
|
100
|
+
yield $stderr
|
101
|
+
ensure
|
102
|
+
$env.reset_stderr
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def with_stdin_as(file = STDIN)
|
108
|
+
$env.stdin = file
|
109
|
+
if block_given?
|
110
|
+
begin
|
111
|
+
yield $stdin
|
112
|
+
ensure
|
113
|
+
$env.reset_stdin
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def with_stdout_as_stderr
|
119
|
+
$env.stdout = $stderr
|
120
|
+
if block_given?
|
121
|
+
begin
|
122
|
+
yield $stdout
|
123
|
+
ensure
|
124
|
+
$env.reset_stdout
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def with_stderr_as_stdout
|
130
|
+
$env.stderr = $stdout
|
131
|
+
if block_given?
|
132
|
+
begin
|
133
|
+
yield $stderr
|
134
|
+
ensure
|
135
|
+
$env.reset_stderr
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def with_all_out_as(file)
|
141
|
+
$env.stdout = file
|
142
|
+
$env.stderr = $stdout
|
143
|
+
if block_given?
|
144
|
+
begin
|
145
|
+
yield $stdout
|
146
|
+
ensure
|
147
|
+
$env.reset_stdout
|
148
|
+
$env.reset_stderr
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rash-command-shell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kellen Watt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: irb
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.2.0
|
33
|
+
description: A Ruby-based shell
|
34
|
+
email:
|
35
|
+
executables:
|
36
|
+
- rash
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- bin/rash
|
41
|
+
- lib/rash.rb
|
42
|
+
- lib/rash/aliasing.rb
|
43
|
+
- lib/rash/ext/filesystem.rb
|
44
|
+
- lib/rash/jobcontrol.rb
|
45
|
+
- lib/rash/prompt/irb.rb
|
46
|
+
- lib/rash/redirection.rb
|
47
|
+
homepage: https://github.com/KellenWatt/rash
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubygems_version: 3.1.2
|
67
|
+
signing_key:
|
68
|
+
specification_version: 4
|
69
|
+
summary: Rash Ain't SH
|
70
|
+
test_files: []
|