blue_shell 0.6 → 0.7

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.
@@ -9,14 +9,33 @@ module BlueShell
9
9
 
10
10
  attr_reader :out, :err, :exit
11
11
 
12
+ def initialize
13
+ @hooks = { stderr: [], stdout: [] }
14
+ @executing = false
15
+ end
16
+
17
+ # Add a lambda to execute on every line of stdout. The lambda
18
+ # should accept one parameter, a string, the line of output.
19
+ # @example Pushing to the console
20
+ # lambda { |line| puts line }
21
+ # @param [Symbol] the stream to hook into (:stderr or :stdout)
22
+ # @param [Lambda] the code to execute
23
+ def add_hook(type, lambda)
24
+ # TODO: This should be a custom error
25
+ raise "May not add hooks while executing." if @executing
26
+
27
+ @hooks[type] << lambda
28
+ end
29
+
12
30
  # Execute the given command. Will block until the command completes.
13
31
  # param [String] the command to execute in bash
14
32
  # param [Integer] the number of seconds to wait for it to complete
15
33
  def execute!(command, timeout = 30)
16
- # Executing via a file seems clunky, but it is the best way to
34
+ # Executing via a file seems clunky, but it is a good way to
17
35
  # ensure everything happens exactly as we expect it to without
18
36
  # trying to deal with escaping the world properly.
19
37
  file = Tempfile.new('command')
38
+
20
39
  begin
21
40
  file << command
22
41
  file.flush
@@ -28,8 +47,8 @@ module BlueShell
28
47
  @err = []
29
48
 
30
49
  # Must have a sink for stdout for the proc to exit
31
- out_thread = read_thread(proc.getInputStream, @out)
32
- err_thread = read_thread(proc.getErrorStream, @err)
50
+ out_thread = read_thread(:stdout, proc.getInputStream, @out)
51
+ err_thread = read_thread(:stderr, proc.getErrorStream, @err)
33
52
 
34
53
  out_thread.join
35
54
  err_thread.join
@@ -37,6 +56,9 @@ module BlueShell
37
56
  @out = @out.join("\n")
38
57
  @err = @err.join("\n")
39
58
 
59
+ # Noticed some cases where the join isn't good enough in the wild.
60
+ proc.waitFor
61
+
40
62
  @exit = proc.exitValue
41
63
  end
42
64
  ensure
@@ -45,13 +67,14 @@ module BlueShell
45
67
  end
46
68
  end
47
69
 
48
- def read_thread(stream, sink)
49
- Thread.new(stream, sink) do |stream, sink|
70
+ def read_thread(type, stream, sink)
71
+ Thread.new(@hooks[type], stream, sink) do |hooks, stream, sink|
50
72
  line = nil
51
73
  br = BufferedReader.new(InputStreamReader.new(stream))
52
74
 
53
75
  while(line = br.readLine) do
54
76
  sink << line
77
+ hooks.each { |hook| hook.call(line) }
55
78
  end
56
79
  end
57
80
  end
@@ -1,3 +1,3 @@
1
1
  module BlueShell
2
- VERSION = "0.6"
2
+ VERSION = "0.7"
3
3
  end
@@ -25,4 +25,20 @@ describe BlueShell::Bash do
25
25
  @shell.execute!("ls -l /")
26
26
  @shell.out.must_include "\n"
27
27
  end
28
+
29
+ it "should execute stdout hooks" do
30
+ me = nil
31
+
32
+ @shell.add_hook(:stdout, lambda { |line| me = line })
33
+ @shell.execute!("echo hello")
34
+ me.must_equal "hello"
35
+ end
36
+
37
+ it "should execute stderr hooks" do
38
+ me = nil
39
+
40
+ @shell.add_hook(:stderr, lambda { |line| me = line })
41
+ @shell.execute!("omg")
42
+ me.must_include "omg: command not found"
43
+ end
28
44
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blue_shell
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.6'
4
+ version: '0.7'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-07 00:00:00.000000000 Z
12
+ date: 2012-11-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: minitest