komenda 0.0.2 → 0.0.3

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.
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