ruby-sh 2.2.6 → 3.0.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.
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
- # Rubsh
1
+ # Rubsh (a.k.a. ruby-sh)
2
2
 
3
3
  Rubsh (a.k.a. ruby-sh) - Inspired by [python-sh], allows you to call any program as if it were a function:
4
4
 
5
5
  ```ruby
6
6
  require 'rubsh'
7
7
 
8
- sh = Rubsh.new
9
- print(sh.cmd('ifconfig').call_with('wlan0').stdout_data)
8
+ ifconfig = Rubsh.cmd('ifconfig')
9
+ print(ifconfig.call('wlan0').stdout_data)
10
10
  ```
11
11
 
12
12
  Output:
@@ -27,12 +27,11 @@ Note that these aren't Ruby functions, these are running the binary commands on
27
27
 
28
28
  When using this library you can:
29
29
 
30
- * Call any program as if it were a function.
31
- * Get an exception when exit code is not 0.
32
- * Force terminate the process if it does not finish within the timeout.
33
- * Always split the shell command into tokens, reduce command injection risk.
34
- * etc.
35
-
30
+ - Call any program as if it were a function.
31
+ - Get an exception when exit code is not 0.
32
+ - Force terminate the process if it does not finish within the timeout.
33
+ - Always split the shell command into tokens, reduce command injection risk.
34
+ - etc.
36
35
 
37
36
  ## Installation
38
37
 
@@ -44,50 +43,50 @@ gem 'ruby-sh', require: 'rubsh'
44
43
 
45
44
  And then execute:
46
45
 
47
- $ bundle install
46
+ ```console
47
+ $ bundle install
48
+ ```
48
49
 
49
50
  Or install it yourself as:
50
51
 
51
- $ gem install ruby-sh
52
-
52
+ ```console
53
+ $ gem install ruby-sh
54
+ ```
53
55
 
54
56
  ## Usage
55
57
 
56
58
  ### Basic Syntax
57
59
 
58
60
  ```ruby
59
- # Create a shell
60
- sh = Rubsh.new
61
-
62
- # Create a command, use `command`/`cmd`
63
- cmd = sh.cmd("ls")
61
+ # Create a command
62
+ ls = Rubsh.cmd("ls")
64
63
 
65
- # Invoke a command, use `call`/`call_with`
66
- result = cmd.call_with("-la")
64
+ # Invoke it
65
+ r = ls.call("-la")
67
66
 
68
67
  # Print result
69
- print result.stdout_data
68
+ print(r.stdout_data)
70
69
  ```
71
70
 
72
71
  ### Passing Arguments
73
72
 
74
73
  ```ruby
75
- sh.cmd("ls").call_with("-l", "/tmp", color: "always", human_readable: true)
74
+ Rubsh.cmd("ls").call("-l", "/tmp", color: "always", human_readable: true)
76
75
  # => ["/usr/bin/ls", "-l", "/tmp", "--color=always", "--human-readable"]
77
76
 
78
- sh.cmd("curl").call_with("https://www.ruby-lang.org/", o: "page.html", silent: true)
77
+ Rubsh.cmd("curl").call("https://www.ruby-lang.org/", o: "page.html", silent: true)
79
78
  # => ["/usr/bin/curl", "https://www.ruby-lang.org/", "-opage.html", "--silent"]
80
79
 
81
- sh.cmd("git").call(:status, { v: true })
80
+ Rubsh.cmd("git").call(:status, { v: true })
82
81
  # => ["/usr/bin/git", "status", "-v"]
83
82
 
84
- sh.cmd("git").call(:status, { v: true }, "--", ".")
83
+ Rubsh.cmd("git").call(:status, { v: true }, "--", ".")
85
84
  # => ["/usr/bin/git", "status", "-v", "--", "."]
86
85
 
87
- sh.cmd("git").call(:status, { v: proc{ true }, short: true }, "--", ".")
86
+ Rubsh.cmd("git").call(:status, { v: proc{ true }, short: true }, "--", ".")
88
87
  # => ["/usr/bin/git", "status", "-v", "--short", "--", "."]
89
88
 
90
- sh.cmd("git").call(:status, { v: true }, v: false)
89
+ Rubsh.cmd("git").call(:status, { v: true }, v: false)
91
90
  # => ["/usr/bin/git", "status"]
92
91
  ```
93
92
 
@@ -95,19 +94,19 @@ sh.cmd("git").call(:status, { v: true }, v: false)
95
94
 
96
95
  ```ruby
97
96
  # Successful
98
- r = sh.cmd("ls").call_with("/")
97
+ r = Rubsh.cmd("ls").call("/")
99
98
  r.exit_code # => 0
100
99
 
101
100
  # a `CommandReturnFailureError` raised when run failure
102
101
  begin
103
- sh.cmd("ls").call_with("/some/non-existant/folder")
102
+ Rubsh.cmd("ls").call("/some/non-existant/folder")
104
103
  rescue Rubsh::Exceptions::CommandReturnFailureError => e
105
104
  e.exit_code # => 2
106
105
  end
107
106
 
108
107
  # Treats as success use `:_ok_code`
109
- r = sh.cmd("ls").call_with("/some/non-existant/folder", _ok_code: [0, 1, 2])
110
- r = sh.cmd("ls").call_with("/some/non-existant/folder", _ok_code: 0..2)
108
+ r = Rubsh.cmd("ls").call("/some/non-existant/folder", _ok_code: [0, 1, 2])
109
+ r = Rubsh.cmd("ls").call("/some/non-existant/folder", _ok_code: 0..2)
111
110
  r.exit_code # => 2
112
111
  ```
113
112
 
@@ -115,29 +114,29 @@ r.exit_code # => 2
115
114
 
116
115
  ```ruby
117
116
  # Filename
118
- sh.cmd("ls").call_with(_out: "/tmp/dir_content")
119
- sh.cmd("ls").call_with(_out: ["/tmp/dir_content", "w"])
120
- sh.cmd("ls").call_with(_out: ["/tmp/dir_content", "w", 0600])
121
- sh.cmd("ls").call_with(_out: ["/tmp/dir_content", File::WRONLY|File::EXCL|File::CREAT, 0600])
117
+ Rubsh.cmd("ls").call(_out: "/tmp/dir_content")
118
+ Rubsh.cmd("ls").call(_out: ["/tmp/dir_content", "w"])
119
+ Rubsh.cmd("ls").call(_out: ["/tmp/dir_content", "w", 0600])
120
+ Rubsh.cmd("ls").call(_out: ["/tmp/dir_content", File::WRONLY|File::EXCL|File::CREAT, 0600])
122
121
 
123
122
  # File object
124
- File.open("/tmp/dir_content", "w") { |f| sh.cmd("ls").call_with(_out: f) }
123
+ File.open("/tmp/dir_content", "w") { |f| Rubsh.cmd("ls").call(_out: f) }
125
124
 
126
125
  # `stdout_data` & `stderr_data`
127
- r = sh.cmd("sh").call_with("-c", "echo out; echo err >&2")
126
+ r = Rubsh.cmd("sh").call("-c", "echo out; echo err >&2")
128
127
  r.stdout_data # => "out\n"
129
128
  r.stderr_data # => "err\n"
130
129
 
131
130
  # Redirects stderr and stderr to the same place use `_err_to_out`
132
- r = sh.cmd("sh").call_with("-c", "echo out; echo err >&2", _err_to_out: true)
131
+ r = Rubsh.cmd("sh").call("-c", "echo out; echo err >&2", _err_to_out: true)
133
132
  r.stdout_data # => "out\nerr\n"
134
133
  r.stderr_data # => nil
135
134
 
136
135
  # Read input from data
137
- sh.cmd("cat").call_with(_in_data: "hello").stdout_data # => "hello"
136
+ Rubsh.cmd("cat").call(_in_data: "hello").stdout_data # => "hello"
138
137
 
139
138
  # Read input from file
140
- sh.cmd("cat").call_with(_in: "/some/existant/file")
139
+ Rubsh.cmd("cat").call(_in: "/some/existant/file")
141
140
  ```
142
141
 
143
142
  ### Incremental Iteration
@@ -146,9 +145,9 @@ sh.cmd("cat").call_with(_in: "/some/existant/file")
146
145
  # By default, output is line-buffered, so the body of the loop will only run
147
146
  # when your process produces a newline. You can change this by changing the
148
147
  # buffer size of the command’s output with `_out_bufsize`/`_err_bufsize`.
149
- tail = sh.cmd("tail")
150
- tail.call_with("-f", "/var/log/some_log_file.log", _capture: ->(stdout, _stderr) {
151
- print stdout
148
+ tail = Rubsh.cmd("tail")
149
+ tail.call("-f", "/var/log/some_log_file.log", _capture: ->(stdout, _stderr) {
150
+ print(stdout)
152
151
  })
153
152
  ```
154
153
 
@@ -156,43 +155,43 @@ tail.call_with("-f", "/var/log/some_log_file.log", _capture: ->(stdout, _stderr)
156
155
 
157
156
  ```ruby
158
157
  # Blocks
159
- sh.cmd("sleep").call_with(3)
160
- p "...3 seconds later"
158
+ Rubsh.cmd("sleep").call(3)
159
+ print("...3 seconds later")
161
160
 
162
161
  # Doesn't block
163
- r = sh.cmd("sleep").call_with(3, _bg: true)
164
- p "prints immediately!"
162
+ r = Rubsh.cmd("sleep").call(3, _bg: true)
163
+ print("prints immediately!")
165
164
  r.wait()
166
- p "...and 3 seconds later"
165
+ print("...and 3 seconds later")
167
166
 
168
167
  # Timeout
169
- r = sh.cmd("sleep").call_with(30, _bg: true)
170
- p "prints immediately!"
168
+ r = Rubsh.cmd("sleep").call(30, _bg: true)
169
+ print("prints immediately!")
171
170
  r.wait(timeout: 3)
172
- p "...and 3 seconds later"
171
+ print("...and 3 seconds later")
173
172
  ```
174
173
 
175
174
  ### Baking
176
175
 
177
176
  ```ruby
178
- ll = sh.cmd("ls").bake("-l")
179
- ll.call_with("/tmp") # => ["/usr/bin/ls", "-l", "/tmp"]
177
+ ll = Rubsh.cmd("ls").bake("-l")
178
+ ll.call("/tmp") # => ["/usr/bin/ls", "-l", "/tmp"]
180
179
 
181
180
  # Equivalent
182
- sh.cmd("ls").call_with("-l", "/tmp")
181
+ Rubsh.cmd("ls").call("-l", "/tmp")
183
182
 
184
183
  # Calling whoami on a server. this is a lot to type out, especially if you wanted
185
184
  # to call many commands (not just whoami) back to back on the same server resolves
186
185
  # to "/usr/bin/ssh myserver.com -p 1393 whoami"
187
- sh.cmd('ssh').call_with("myserver.com", "-p 1393", "whoami")
186
+ Rubsh.cmd('ssh').call("myserver.com", "-p 1393", "whoami")
188
187
 
189
188
  # Wouldn't it be nice to bake the common parameters into the ssh command?
190
- myserver = sh.cmd('ssh').bake("myserver.com", p: 1393)
191
- myserver.call_with('whoami')
192
- myserver.call_with('pwd')
189
+ myserver = Rubsh.cmd('ssh').bake("myserver.com", p: 1393)
190
+ myserver.call('whoami')
191
+ myserver.call('pwd')
193
192
 
194
193
  # With a special kwarg
195
- sleep = sh.cmd('sleep').bake(_timeout: 2)
194
+ sleep = Rubsh.cmd('sleep').bake(_timeout: 2)
196
195
  sleep.call(1) # => ok
197
196
  sleep.call(3) # => a `CommandReturnFailureError` raised
198
197
  ```
@@ -201,83 +200,67 @@ sleep.call(3) # => a `CommandReturnFailureError` raised
201
200
 
202
201
  ```ruby
203
202
  # Use `bake`
204
- gst = sh.cmd("git").bake("status")
203
+ gst = Rubsh.cmd("git").bake("status")
205
204
 
206
- gst.call_with() # => ["/usr/bin/git", "status"]
207
- gst.call_with("-s") # => ["/usr/bin/git", "status", "-s"]
205
+ gst.call() # => ["/usr/bin/git", "status"]
206
+ gst.call("-s") # => ["/usr/bin/git", "status", "-s"]
208
207
  ```
209
208
 
210
- ### Piping
211
-
212
- ```ruby
213
- # Run a series of commands connected by `_pipeline`
214
- r = sh.pipeline(_in_data: "hello world") do |pipeline|
215
- sh.cmd("cat").call_with(_pipeline: pipeline)
216
- sh.cmd("wc").call_with("-c", _pipeline: pipeline)
217
- end
218
- r.stdout_data # => "11\n"
219
- ```
220
-
221
-
222
209
  ## Reference
223
210
 
224
211
  ### Special Kwargs
225
212
 
226
- * `_in_data`:
227
- * use: Specifies an argument for the process to use as its standard input data.
228
- * default value: `nil`
229
- * `_in`:
230
- * use: Specifies an argument for the process to use as its standard input.
231
- * default value: `nil`
232
- * `_out`:
233
- * use: Where to redirect STDOUT to.
234
- * default value: `nil`
235
- * `_err`:
236
- * use: Where to redirect STDERR to.
237
- * default value: `nil`
238
- * `_err_to_out`:
239
- * use: If true, duplicate the file descriptor bound to the process’s STDOUT also to STDERR.
240
- * default value: `false`
241
- * `_capture`:
242
- * use: Iterates over STDOUT/STDERR.
243
- * default value: `nil`
244
- * `_bg`:
245
- * use: Runs a command in the background. The command will return immediately, and you will have to run RunningCommand#wait on it to ensure it terminates.
246
- * default value: `false`
247
- * `_timeout`:
248
- * use: How much time, in seconds, we should give the process to complete. If the process does not finish within the timeout, it will be terminated.
249
- * default value: `nil`
250
- * `_env`:
251
- * use: A dictionary defining the only environment variables that will be made accessible to the process. If not specified, the calling process’s environment variables are used.
252
- * default value: `nil`
253
- * `_cwd`:
254
- * use: Current working directory of the process.
255
- * default value: `nil`
256
- * `_ok_code`:
257
- * use: Some misbehaved programs use exit codes other than 0 to indicate success. Set to treats as success.
258
- * default value: `[0]`
259
- * `_no_out`:
260
- * use: Disables STDOUT being internally stored. This is useful for commands that produce huge amounts of output that you don’t need, that would otherwise be hogging memory if stored internally by Rubsh.
261
- * default value: `false`
262
- * `_no_err`:
263
- * use: Disables STDERR being internally stored. This is useful for commands that produce huge amounts of output that you don’t need, that would otherwise be hogging memory if stored internally by Rubsh.
264
- * default value: `false`
265
- * `_out_bufsize`:
266
- * use: The STDOUT buffer size. nil for unbuffered, 0 for line buffered, anything else for a buffer of that amount.
267
- * default value: `0`
268
- * `_err_bufsize`:
269
- * use: The STDERR buffer size. nil for unbuffered, 0 for line buffered, anything else for a buffer of that amount.
270
- * default value: `0`
271
- * `_long_sep`:
272
- * use: This is the character(s) that separate a program’s long argument’s key from the value.
273
- * default value: `"="`
274
- * `_long_prefix`:
275
- * use: This is the character(s) that prefix a long argument for the program being run. Some programs use single dashes, for example, and do not understand double dashes.
276
- * default value: `"--"`
277
- * `_pipeline`:
278
- * use: Specifies the :pipeline.
279
- * default value: `nil`
280
-
213
+ - `_in_data`:
214
+ - use: Specifies an argument for the process to use as its standard input data.
215
+ - default value: `nil`
216
+ - `_in`:
217
+ - use: Specifies an argument for the process to use as its standard input.
218
+ - default value: `nil`
219
+ - `_out`:
220
+ - use: Where to redirect STDOUT to.
221
+ - default value: `nil`
222
+ - `_err`:
223
+ - use: Where to redirect STDERR to.
224
+ - default value: `nil`
225
+ - `_err_to_out`:
226
+ - use: If true, duplicate the file descriptor bound to the process’s STDOUT also to STDERR.
227
+ - default value: `false`
228
+ - `_capture`:
229
+ - use: Iterates over STDOUT/STDERR.
230
+ - default value: `nil`
231
+ - `_bg`:
232
+ - use: Runs a command in the background. The command will return immediately, and you will have to run RunningCommand#wait on it to ensure it terminates.
233
+ - default value: `false`
234
+ - `_timeout`:
235
+ - use: How much time, in seconds, we should give the process to complete. If the process does not finish within the timeout, it will be terminated.
236
+ - default value: `nil`
237
+ - `_env`:
238
+ - use: A dictionary defining the only environment variables that will be made accessible to the process. If not specified, the calling process’s environment variables are used.
239
+ - default value: `nil`
240
+ - `_cwd`:
241
+ - use: Current working directory of the process.
242
+ - default value: `nil`
243
+ - `_ok_code`:
244
+ - use: Some misbehaved programs use exit codes other than 0 to indicate success. Set to treats as success.
245
+ - default value: `[0]`
246
+ - `_no_out`:
247
+ - use: Disables STDOUT being internally stored. This is useful for commands that produce huge amounts of output that you don’t need, that would otherwise be hogging memory if stored internally by Rubsh.
248
+ - default value: `false`
249
+ - `_no_err`:
250
+ - use: Disables STDERR being internally stored. This is useful for commands that produce huge amounts of output that you don’t need, that would otherwise be hogging memory if stored internally by Rubsh.
251
+ - default value: `false`
252
+ - `_out_bufsize`:
253
+ - use: The STDOUT buffer size. nil for unbuffered, 0 for line buffered, anything else for a buffer of that amount.
254
+ - default value: `0`
255
+ - `_err_bufsize`:
256
+ - use: The STDERR buffer size. nil for unbuffered, 0 for line buffered, anything else for a buffer of that amount.
257
+ - default value: `0`
258
+ - `_long_sep`:
259
+ - use: This is the character(s) that separate a program’s long argument’s key from the value.
260
+ - default value: `"="`
261
+ - `_long_prefix`:
262
+ - use: This is the character(s) that prefix a long argument for the program being run. Some programs use single dashes, for example, and do not understand double dashes.
263
+ - default value: `"--"`
281
264
 
282
265
  ## FAQ
283
266
 
@@ -288,9 +271,8 @@ Glob expansion is a feature of a shell, like Bash, and is performed by the shell
288
271
  ### How do I execute a bash builtin?
289
272
 
290
273
  ```ruby
291
- sh = Rubsh.new
292
- rawsh = sh.cmd('bash').bake('-c')
293
- print(rawsh.call_with('echo Hello').stdout_data) # => "Hello\n"
274
+ rawsh = Rubsh.cmd('bash').bake('-c')
275
+ print(rawsh.call('echo Hello').stdout_data) # => "Hello\n"
294
276
  ```
295
277
 
296
278
  ### How do I call a program that isn’t in $PATH?
@@ -298,16 +280,7 @@ print(rawsh.call_with('echo Hello').stdout_data) # => "Hello\n"
298
280
  Use absolute binpath
299
281
 
300
282
  ```ruby
301
- sh = Rubsh.new
302
- sh.cmd('/path/to/command').call()
303
- ```
304
-
305
- Or use `Rubsh::Shell::Env#path`
306
-
307
- ```ruby
308
- sh = Rubsh.new
309
- sh.env.path << "/dir/to/command/"
310
- sh.cmd('command').call()
283
+ Rubsh.cmd('/path/to/command').call()
311
284
  ```
312
285
 
313
286
  ### How do I run a command and connect it to stdout and stdin?
@@ -325,36 +298,29 @@ my-command --arg1=val1 arg2 --arg3=val3
325
298
  Use:
326
299
 
327
300
  ```ruby
328
- sh = Rubsh.new
329
- sh.cmd('my-command').call_with({ arg1: "val1" }, "args2", { arg3: "val3" })
301
+ Rubsh.cmd('my-command').call({ arg1: "val1" }, "args2", { arg3: "val3" })
330
302
  ```
331
303
 
332
-
333
304
  ## Development
334
305
 
335
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
306
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
336
307
 
337
308
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
338
309
 
339
-
340
310
  ## Contributing
341
311
 
342
312
  Bug reports and pull requests are welcome on GitHub at https://github.com/souk4711/rubsh. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/souk4711/rubsh/blob/main/CODE_OF_CONDUCT.md).
343
313
 
344
-
345
314
  ## Acknowledgements
346
315
 
347
- * Special thanks to [python-sh].
348
-
316
+ - Special thanks to [python-sh].
349
317
 
350
318
  ## License
351
319
 
352
320
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
353
321
 
354
-
355
322
  ## Code of Conduct
356
323
 
357
324
  Everyone interacting in the Rubsh project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/souk4711/rubsh/blob/main/CODE_OF_CONDUCT.md).
358
325
 
359
-
360
- [python-sh]:https://github.com/amoffat/sh
326
+ [python-sh]: https://github.com/amoffat/sh
data/lib/rubsh/command.rb CHANGED
@@ -6,8 +6,7 @@ module Rubsh
6
6
  # When a Command object is called, the result that is returned is a RunningCommand
7
7
  # object, which represents the Command put into an execution state.
8
8
  class Command
9
- def initialize(sh, prog)
10
- @sh = sh
9
+ def initialize(prog)
11
10
  @prog = prog.to_s
12
11
  @progpath = resolve_progpath(@prog)
13
12
  @baked_opts = []
@@ -18,8 +17,7 @@ module Rubsh
18
17
  # @return [RunningCommand] An new instance of RunningCommand with execution state.
19
18
  # @example
20
19
  #
21
- # sh = Rubsh::Shell.new
22
- # git = Rubsh::Command.new(sh, "git")
20
+ # git = Rubsh::Command.new("git")
23
21
  # git.call() # => ["git"]
24
22
  # git.call("") # => ["git", ""]
25
23
  # git.call("status") # => ["git", "status"]
@@ -30,17 +28,16 @@ module Rubsh
30
28
  # git.call(:status, { v: proc{ true }, short: true }, "--", ".") # => ["git", "status", "-v", "--short=true", "--", "."]
31
29
  # git.call(:status, { untracked_files: "normal" }, "--", ".") # => ["git", "status", "--untracked-files=normal", "--", "."]
32
30
  def call(*args, **kwargs)
33
- rcmd = RunningCommand.new(@sh, @prog, @progpath, *@baked_opts, *args, **kwargs)
31
+ rcmd = RunningCommand.new(@prog, @progpath, *@baked_opts, *args, **kwargs)
34
32
  rcmd.__run
35
33
  rcmd
36
34
  end
37
- alias_method :call_with, :call
38
35
 
39
36
  # @param args [String, Symbol, #to_s, Hash]
40
37
  # @param kwargs [Hash]
41
38
  # @return [Command] a new instance of Command with baked options.
42
39
  def bake(*args, **kwargs)
43
- cmd = Command.new(@sh, @prog)
40
+ cmd = Command.new(@prog)
44
41
  cmd.__bake!(*@baked_opts, *args, **kwargs)
45
42
  cmd
46
43
  end
@@ -70,7 +67,7 @@ module Rubsh
70
67
  progpath = prog
71
68
  end
72
69
  else
73
- @sh.env.path.each do |path|
70
+ ::ENV["PATH"].split(::File::PATH_SEPARATOR).each do |path|
74
71
  filepath = ::File.join(path, prog)
75
72
  if ::File.executable?(filepath) && ::File.file?(filepath)
76
73
  progpath = filepath