komenda 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9bde725b71b20821b932fda1e83ba82215bfd27d
4
- data.tar.gz: e682bef86069a8d1d175c9e2d84b14f10c3068ac
3
+ metadata.gz: 88de98a8e1d12b4b613978ba42a78e239e4a37d5
4
+ data.tar.gz: 0bf5019ac2520a5c51290d7b80a897c3c32ae86c
5
5
  SHA512:
6
- metadata.gz: ea96829bf08645726f9cc7727e1531c533a528f6f3b4a8cf3cb75648e206b1b624531b89bab09d34e1df06447fd316702945af386aeda93f47add7b83fbb571e
7
- data.tar.gz: de7ce00b2c06fa819b2a4b8e3efeaf3cf784e108a78d3b1479db7b3c7aa07f40cbf2599edeb09fecbc7c907c969d0c84d239f88e3e43b7fbaa22ff9a73f6c7dc
6
+ metadata.gz: 4ecef5f25f1866b5fe846489b26db3e6e4682a87e74d3b7a2a4adabe19ce80d886cd0239e4d6a828ac132b3d89b1cfa51b83b6a2e067d2ceb5626205997e6f24
7
+ data.tar.gz: b0af38deff1bb138effcda501f5c3c87b2f12ceba21d82b251ecf333347e4a76e8f344e206f44cdf26fb3e1a0cfdd50f6476ad37303ed93462b656e6e3073d4c
data/README.md CHANGED
@@ -6,14 +6,14 @@ Usage
6
6
  -----
7
7
  Run a command:
8
8
  ```ruby
9
- Komenda.run("date")
9
+ Komenda.run('date')
10
10
  ```
11
11
 
12
12
  The `run()` method will block until the sub process finished.
13
13
 
14
14
  It will expose the output and exit status as a `Komenda::Result` value:
15
15
  ```ruby
16
- result = Komenda.run("date")
16
+ result = Komenda.run('date')
17
17
  result.stdout # => "Tue Nov 26 14:45:03 EST 2013\n"
18
18
  result.stderr # => ""
19
19
  result.output # => "Tue Nov 26 14:45:03 EST 2013\n" (combined stdout + stderr)
@@ -21,9 +21,42 @@ result.status # => 0
21
21
  result.success? # => true
22
22
  result.pid # => 32157
23
23
  ```
24
+ The program and its arguments can be passed as an array:
25
+ ```ruby
26
+ result = Komenda.run(['echo', '-n', 'hello'])
27
+ result.output # => "hello"
28
+ ```
24
29
 
25
30
  The `run()` method has a second argument `options`, which expects these keys:
26
31
  - **`env`** (Hash): The environment variables to use. Defaults to the current process' environment.
32
+ - **`cwd`** (String): Directory to change to before running the process. Defaults to `nil`.
33
+
34
+ ### Advanced usage
35
+ The `create()` method creates a `Process` which can be `start()`ed (in a Thread) and then `wait_for()`ed until finished.
36
+ ```ruby
37
+ process = Komenda.create('date')
38
+ thread = process.start
39
+ result = process.wait_for
40
+ ```
41
+
42
+ To start a process and wait for it to finish, call the process' `run()` method:
43
+ ```
44
+ process = Komenda.create('date')
45
+ result = process.run
46
+ ```
47
+
48
+ Event callbacks can be registered with `Process.on()`, for example for when output is written.
49
+ ```ruby
50
+ process = Komenda.create('date')
51
+ process.on(:stdout) { |output| puts "STDOUT: #{output}" }
52
+ result = process.wait_for
53
+ ```
54
+ The following events are emitted:
55
+ - **`.on(:stdout) { |output| }`**: When data is available on STDOUT.
56
+ - **`.on(:stderr) { |output| }`**: When data is available on STDERR.
57
+ - **`.on(:output) { |output| }`**: When data is available on STDOUT or STDERR.
58
+ - **`.on(:exit) { |result| }`**: When the process finishes.
59
+ - **`.on(:error) { |exception| }`**: When process execution fails (e.g. executable file cannot be found).
27
60
 
28
61
  Development
29
62
  -----------
@@ -41,4 +74,4 @@ TODO
41
74
  ----
42
75
  Add options for:
43
76
  - Passing STDIN
44
- - Making `run()` fail when exit status is not "0"
77
+ - Making `run()` fail when exit status is not '0'
data/lib/komenda.rb CHANGED
@@ -1,18 +1,26 @@
1
1
  require 'open3'
2
+ require 'event_emitter'
2
3
 
3
- require 'komenda/definition'
4
- require 'komenda/runner'
4
+ require 'komenda/process_builder'
5
+ require 'komenda/process'
5
6
  require 'komenda/result'
6
7
 
7
8
  module Komenda
8
9
 
9
- # @param [String] cmd
10
+ # @param [String] command
11
+ # @param [Hash] options
12
+ # @return [Komenda::Process]
13
+ def self.create(command, options = {})
14
+ process_builder = Komenda::ProcessBuilder.new(command, options)
15
+ process_builder.create
16
+ end
17
+
18
+ # @param [String] command
10
19
  # @param [Hash] options
11
20
  # @return [Komenda::Result]
12
- def self.run(cmd, options = {})
13
- definition = Komenda::Definition.new(cmd, options)
14
- runner = Komenda::Runner.new
15
- runner.run(definition)
21
+ def self.run(command, options = {})
22
+ process_builder = Komenda::ProcessBuilder.new(command, options)
23
+ process_builder.create.run
16
24
  end
17
25
 
18
26
  end
@@ -0,0 +1,109 @@
1
+ module Komenda
2
+ class Process
3
+
4
+ attr_reader :output
5
+
6
+ include EventEmitter
7
+
8
+ # @param [ProcessBuilder] process_builder
9
+ def initialize(process_builder)
10
+ @process_builder = process_builder
11
+ @output = {:stdout => '', :stderr => '', :combined => ''}
12
+ @exit_status = nil
13
+ @thread = nil
14
+
15
+ on(:stdout) { |data| @output[:stdout] += data }
16
+ on(:stderr) { |data| @output[:stderr] += data }
17
+ on(:output) { |data| @output[:combined] += data }
18
+ process_builder.events.each do |event|
19
+ on(event[:type], &event[:listener])
20
+ end
21
+ end
22
+
23
+ # @return [Thread]
24
+ def start
25
+ raise 'Already started' if is_started?
26
+ @thread = Thread.new { run_process(@process_builder) }
27
+ end
28
+
29
+ # @return [Komenda::Result]
30
+ def wait_for
31
+ raise 'Process not started' unless is_started?
32
+ @thread.join
33
+ result
34
+ end
35
+
36
+ # @return [Komenda::Result]
37
+ def run
38
+ start unless is_started?
39
+ wait_for
40
+ end
41
+
42
+ # @return [TrueClass, FalseClass]
43
+ def running?
44
+ raise 'Process not started' unless is_started?
45
+ @thread.alive?
46
+ end
47
+
48
+ # @return [Komenda::Result]
49
+ def result
50
+ raise 'Process not started' unless is_started?
51
+ raise 'Process not finished' unless is_finished?
52
+ Komenda::Result.new(@output, @exit_status)
53
+ end
54
+
55
+ private
56
+
57
+ # @return [TrueClass, FalseClass]
58
+ def is_started?
59
+ !@thread.nil?
60
+ end
61
+
62
+ # @return [TrueClass, FalseClass]
63
+ def is_finished?
64
+ !@exit_status.nil?
65
+ end
66
+
67
+ # @param [ProcessBuilder] process_builder
68
+ def run_process(process_builder)
69
+ begin
70
+ if process_builder.cwd.nil?
71
+ run_popen3(process_builder)
72
+ else
73
+ Dir.chdir(process_builder.cwd) { run_popen3(process_builder) }
74
+ end
75
+ rescue Exception => exception
76
+ emit(:error, exception)
77
+ raise exception
78
+ end
79
+ end
80
+
81
+ # @param [ProcessBuilder] process_builder
82
+ def run_popen3(process_builder)
83
+ Open3.popen3(process_builder.env, *process_builder.command) do |stdin, stdout, stderr, wait_thr|
84
+ stdin.close
85
+
86
+ streams_read_open = [stdout, stderr]
87
+ begin
88
+ streams_read_available, _, _ = IO.select(streams_read_open)
89
+
90
+ streams_read_available.each do |stream|
91
+ if stream.eof?
92
+ stream.close
93
+ streams_read_open.delete(stream)
94
+ else
95
+ data = stream.readpartial(4096)
96
+ emit(:stdout, data) if stdout === stream
97
+ emit(:stderr, data) if stderr === stream
98
+ emit(:output, data)
99
+ end
100
+ end
101
+ end until streams_read_open.empty?
102
+
103
+ @exit_status = wait_thr.value
104
+ emit(:exit, result)
105
+ end
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,31 @@
1
+ module Komenda
2
+ class ProcessBuilder
3
+
4
+ attr_reader :command
5
+ attr_reader :env
6
+ attr_reader :cwd
7
+ attr_reader :events
8
+
9
+ # @param [String, String[]] command
10
+ # @param [Hash] options
11
+ def initialize(command, options = {})
12
+ defaults = {
13
+ :env => ENV.to_hash,
14
+ :cwd => nil,
15
+ :events => {},
16
+ }
17
+ options = defaults.merge(options)
18
+
19
+ @command = command.is_a?(Array) ? command.map { |v| String(v) } : String(command)
20
+ @env = Hash[options[:env].to_hash.map { |k, v| [String(k), String(v)] }]
21
+ @cwd = options[:cwd].nil? ? nil : String(options[:cwd])
22
+ @events = Hash[options[:events].to_hash.map { |k, v| [k.to_sym, v.to_proc] }]
23
+ end
24
+
25
+ # @return [Komenda::Process]
26
+ def create
27
+ Komenda::Process.new(self)
28
+ end
29
+
30
+ end
31
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: komenda
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cargo Media
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-02 00:00:00.000000000 Z
12
+ date: 2015-11-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -53,6 +53,20 @@ dependencies:
53
53
  - - "~>"
54
54
  - !ruby/object:Gem::Version
55
55
  version: '2.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: event_emitter
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '0.2'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '0.2'
56
70
  description: Convenience wrapper around `Open3` to run shell commands in Ruby.
57
71
  email: hello@cargomedia.ch
58
72
  executables: []
@@ -62,9 +76,9 @@ files:
62
76
  - LICENSE
63
77
  - README.md
64
78
  - lib/komenda.rb
65
- - lib/komenda/definition.rb
79
+ - lib/komenda/process.rb
80
+ - lib/komenda/process_builder.rb
66
81
  - lib/komenda/result.rb
67
- - lib/komenda/runner.rb
68
82
  homepage: https://github.com/cargomedia/komenda
69
83
  licenses:
70
84
  - MIT
@@ -1,20 +0,0 @@
1
- module Komenda
2
- class Definition
3
-
4
- attr_reader :cmd
5
- attr_reader :env
6
-
7
- # @param [String] cmd
8
- # @param [Hash] options
9
- def initialize(cmd, options = {})
10
- defaults = {
11
- :env => ENV.to_hash,
12
- }
13
- options = defaults.merge(options)
14
-
15
- @cmd = String(cmd)
16
- @env = Hash[options[:env].to_hash.map { |k, v| [String(k), String(v)] }]
17
- end
18
-
19
- end
20
- end
@@ -1,37 +0,0 @@
1
- module Komenda
2
- class Runner
3
-
4
- # @param [Komenda::Definition] definition
5
- # @return [Komenda::Result]
6
- def run(definition)
7
- output = {:stdout => '', :stderr => '', :combined => ''}
8
- status = nil
9
-
10
- Open3.popen3(definition.env, definition.cmd) do |stdin, stdout, stderr, wait_thr|
11
- stdin.close
12
-
13
- streams_read_open = [stdout, stderr]
14
- begin
15
- streams_read_available, _, _ = IO.select(streams_read_open)
16
-
17
- streams_read_available.each do |stream|
18
- if stream.eof?
19
- stream.close
20
- streams_read_open.delete(stream)
21
- else
22
- data = stream.readpartial(4096)
23
- output[:stdout] += data if stdout === stream
24
- output[:stderr] += data if stderr === stream
25
- output[:combined] += data
26
- end
27
- end
28
- end until streams_read_open.empty?
29
-
30
- status = wait_thr.value
31
- end
32
-
33
- Komenda::Result.new(output, status)
34
- end
35
-
36
- end
37
- end