rubysh 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +25 -4
- data/lib/rubysh/fd.rb +4 -0
- data/lib/rubysh/version.rb +1 -1
- data/lib/rubysh.rb +31 -23
- metadata +3 -3
data/README.md
CHANGED
@@ -22,8 +22,9 @@ are simple in __sh__, such as:
|
|
22
22
|
- redirecting a program's output to a file
|
23
23
|
- use a pre-tokenized array of arguments
|
24
24
|
|
25
|
-
|
26
|
-
|
25
|
+
(Some existing libraries make some of these tasks easy, but not all of
|
26
|
+
them at once.) Rubysh tries to emulate __sh__'s interface and
|
27
|
+
semantics as closely as possible.
|
27
28
|
|
28
29
|
## Features
|
29
30
|
|
@@ -64,14 +65,28 @@ quite decided on the right API for this yet.
|
|
64
65
|
|
65
66
|
## API
|
66
67
|
|
67
|
-
The Rubysh helper function produces instances of
|
68
|
-
can run
|
68
|
+
The Rubysh helper function produces instances of `BaseCommand`. You
|
69
|
+
can run `run` on these to spawn a subprocess and then `wait` for
|
69
70
|
it to complete. Alternatively, you can do:
|
70
71
|
|
71
72
|
command = Rubysh('ls')
|
72
73
|
runner = command.run_async
|
73
74
|
runner.wait
|
74
75
|
|
76
|
+
If you don't want to type `Rubysh` all the time, you can alias it with
|
77
|
+
the `AliasRubysh` helper:
|
78
|
+
|
79
|
+
AliasRubysh(:R)
|
80
|
+
R('ls')
|
81
|
+
|
82
|
+
## Safety
|
83
|
+
|
84
|
+
Rubysh takes a splatted array argument as a command specification. In
|
85
|
+
particular, it doesn't convert it back and forth a command-line
|
86
|
+
string, meaning you don't have to worry about spaces in
|
87
|
+
variables. (You should still always think twice before putting
|
88
|
+
untrusted arguments into a shell argument.)
|
89
|
+
|
75
90
|
## Installation
|
76
91
|
|
77
92
|
Rubysh is hosted on Rubygems. You can install by adding this line to
|
@@ -86,3 +101,9 @@ Or by installing directly via
|
|
86
101
|
## Contributing
|
87
102
|
|
88
103
|
Patches welcome! I'm happy to merge pull requests.
|
104
|
+
|
105
|
+
## Future features
|
106
|
+
|
107
|
+
- Support for environment variables
|
108
|
+
- Finer-grained IO control
|
109
|
+
- Subshell syntax (`cat <(ls)`, `echo $(ls)`)
|
data/lib/rubysh/fd.rb
CHANGED
data/lib/rubysh/version.rb
CHANGED
data/lib/rubysh.rb
CHANGED
@@ -13,7 +13,7 @@ require 'rubysh/subprocess'
|
|
13
13
|
require 'rubysh/triple_less_than'
|
14
14
|
require 'rubysh/util'
|
15
15
|
|
16
|
-
#
|
16
|
+
# Basic usage:
|
17
17
|
#
|
18
18
|
# Rubysh('ls', '/tmp')
|
19
19
|
# => Command: ls /tmp
|
@@ -24,39 +24,41 @@ require 'rubysh/util'
|
|
24
24
|
# Rubysh('ls', '/tmp', Rubysh.>('/tmp/outfile.txt'))
|
25
25
|
# => Command: ls /tmp > /tmp/outfile.txt
|
26
26
|
#
|
27
|
-
# TODO:
|
28
|
-
# => Command: (ls; ls) | grep foo
|
29
|
-
# => Command: echo <(ls /tmp)
|
30
|
-
# => Command: echo >(cat)
|
31
|
-
# something like the following to tee output:
|
32
|
-
# Rubysh('cat', Rubysh.stdout >> :pipe)
|
33
|
-
#
|
34
27
|
# If you want to capture output:
|
35
28
|
#
|
36
29
|
# Rubysh('cat', Rubysh.stdout > :pipe)
|
37
30
|
#
|
38
|
-
# Or for interactivity:
|
39
|
-
#
|
40
|
-
# q = Rubysh('cat', Rubysh.stdout > :stdout, Rubysh.stderr > :stderr, Rubysh.stdin < :stdin)
|
41
|
-
# q.write('my whole command')
|
42
|
-
# q.communicate # closes writeable pipes and reads from all readable pipes
|
43
|
-
# q.data_from(:stdout)
|
44
|
-
# q.data_from(1)
|
45
|
-
# q.status
|
46
|
-
#
|
47
31
|
# You can name pipes with whatever symbol name you want:
|
48
32
|
#
|
49
33
|
# Rubysh('cat', 2 > :stdout, 3 > :fd3)
|
50
34
|
#
|
51
|
-
#
|
35
|
+
# TODOs:
|
36
|
+
#
|
37
|
+
# => Command: (ls; ls) | grep foo
|
38
|
+
# => Command: echo <(ls /tmp)
|
39
|
+
# => Command: echo >(cat)
|
40
|
+
#
|
41
|
+
# Something like the following to tee output:
|
42
|
+
#
|
43
|
+
# Rubysh('cat', Rubysh.stdout >> :pipe)
|
44
|
+
#
|
45
|
+
# The following rough API needs to be fleshed out. Maybe something
|
46
|
+
# close to the following for interactivity:
|
47
|
+
#
|
48
|
+
# cmd = Rubysh('cat', Rubysh.stdout > :stdout, Rubysh.stderr > :stderr, Rubysh.stdin < :stdin)
|
49
|
+
# q = cmd.run_async
|
50
|
+
# q.write(:stdin, 'my whole command')
|
51
|
+
# q.communicate # closes writeable pipes and reads from all readable pipes
|
52
|
+
# q.data(:stdout)
|
53
|
+
# q.exitstatus
|
52
54
|
#
|
53
|
-
# q.write('my first command') # write data (while also reading from readable pipes
|
54
|
-
#
|
55
|
+
# q.write(:stdin, 'my first command') # write data (while also reading from readable pipes
|
56
|
+
# # in a select() loop)
|
55
57
|
# q.communicate(:partial => true) # read available data (don't close pipes)
|
56
|
-
# q.
|
57
|
-
# q.write('my second command')
|
58
|
+
# q.data(:stdout)
|
59
|
+
# q.write(:stdin, 'my second command')
|
58
60
|
#
|
59
|
-
#
|
61
|
+
# It'd be possible to support &, but I don't think it's needed:
|
60
62
|
# Rubysh('ls', '/tmp', Rubysh.&)
|
61
63
|
# => Command: ls /tmp &
|
62
64
|
|
@@ -79,6 +81,12 @@ def Rubysh(*args, &blk)
|
|
79
81
|
end
|
80
82
|
end
|
81
83
|
|
84
|
+
def AliasRubysh(name)
|
85
|
+
metaclass = class << self; self; end
|
86
|
+
metaclass.send(:alias_method, name, :Rubysh)
|
87
|
+
Object.const_set(name, Rubysh)
|
88
|
+
end
|
89
|
+
|
82
90
|
module Rubysh
|
83
91
|
# Convenience methods
|
84
92
|
def self.run(command)
|
metadata
CHANGED