rubysh 0.0.1 → 0.0.2
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.
- 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