coque 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 344cd271557b02f3d3b01fc25a524fe44a2ecf4a
4
- data.tar.gz: 74a4a0f32297f6c2e7368fab1c89a3317e52168d
3
+ metadata.gz: c69c98fb67e7afee6ad27390978968a86ebc9bb8
4
+ data.tar.gz: 09d45720d414295f7c1b4f887702b5439a3cbfb7
5
5
  SHA512:
6
- metadata.gz: 4561c894a43b60ef8baaa903e1ac732473927deff5dc9fc9d3c8ce7c3bdba1aa361d783830f20762546574e82baeb252c0d5d8139ed569ffe84b8fa839e32068
7
- data.tar.gz: e3a6a90e1a67e085a4aab4c5261340599ac9941bdd86da01c645830cb051d2c85fac54fc038308eaba8598cb5b061e9f79de84b9c808561ae39a08774dd4bea9
6
+ metadata.gz: bd2afeb39c8afe1e1681a4fc7934d6116afdcc9616861c9abfe60ebbe86be469bd47af231568a4fc38c2e382cacf3ce0c6402fe5ab8ef232f804b1cbad699539
7
+ data.tar.gz: 7ee2833b41ecae0a0b9f7deb06d2a678bd2cb0eea1197a9aba826b2b5c2ea0ba5d38d57ec373e3dbe57d27c1ed53d212dc035f3646f2a2c11ee4f7acbac31540
data/README.md CHANGED
@@ -39,7 +39,7 @@ pipeline.run.to_a
39
39
 
40
40
  Coque can also create "Rb" commands, which integrate Ruby code with streaming, line-wise processing of other commands:
41
41
 
42
- ```
42
+ ```rb
43
43
  c1 = Coque["printf", '"a\nb\nc\n"']
44
44
  c2 = Coque.rb { |line| puts line.upcase }
45
45
  (c1 | c2).run.to_a
@@ -48,7 +48,7 @@ c2 = Coque.rb { |line| puts line.upcase }
48
48
 
49
49
  Rb commands can also take "pre" and "post" blocks
50
50
 
51
- ```
51
+ ```rb
52
52
  dict = Coque["cat", "/usr/share/dict/words"]
53
53
  rb_wc = Coque.rb { @lines += 1 }.pre { @lines = 0 }.post { puts @lines }
54
54
 
@@ -71,7 +71,7 @@ File.read("/tmp/error.txt")
71
71
  # => "cat: /doesntexist.txt: No such file or directory\n"
72
72
  ```
73
73
 
74
- Coque commands can also be derived from a `Coque::Context`:
74
+ Coque commands can also be derived from a `Coque::Context`, which enables changing directory, setting environment variables, and unsetting child env:
75
75
 
76
76
  ```rb
77
77
  c = Coque.context
@@ -83,6 +83,20 @@ Coque.context.chdir("/tmp")["pwd"].run.to_a
83
83
 
84
84
  Coque.context.setenv("my_key": "pizza")["echo", "$my_key"].run.to_a
85
85
  # => ["pizza"]
86
+
87
+ ENV["my_key"] = "pizza"
88
+ Coque["echo", "$my_key"].run.to_a
89
+ # => ["pizza"]
90
+
91
+ Coque.context.disinherit_env["echo", "$my_key"].to_a
92
+ # => [""]
93
+ ```
94
+
95
+ Coque also includes a `Coque.source` helper for feeding Ruby enumerables into shell pipelines:
96
+
97
+ ```rb
98
+ (Coque.source(1..500) | Coque["wc", "-l"]).run.to_a
99
+ # => ["500"]
86
100
  ```
87
101
 
88
102
  ### Streaming Performance
data/lib/coque/cmd.rb CHANGED
@@ -4,12 +4,11 @@ module Coque
4
4
  attr_reader :context
5
5
 
6
6
  def |(other)
7
- verify_redirectable(other)
8
7
  case other
9
8
  when Cmd
10
- Pipeline.new([self, other])
9
+ Pipeline.new([self.clone, other.clone])
11
10
  when Pipeline
12
- Pipeline.new([self] + other.commands)
11
+ Pipeline.new([self.clone] + other.commands)
13
12
  end
14
13
  end
15
14
 
@@ -17,19 +16,22 @@ module Coque
17
16
  raise "Not Implemented - Override"
18
17
  end
19
18
 
20
- def ensure_default_fds
21
- if self.stdin.nil?
22
- inr, inw = IO.pipe
23
- inw.close
24
- self.stdin = inr
25
- end
19
+ def get_default_fds
20
+ stdin = if self.stdin
21
+ self.stdin
22
+ else
23
+ inr, inw = IO.pipe
24
+ inw.close
25
+ inr
26
+ end
26
27
 
27
- if self.stdout.nil?
28
- outr, outw = IO.pipe
29
- self.stdout = outw
30
- # only used for Result if this is the last command in a pipe
31
- @stdout_read = outr
32
- end
28
+ stdoutr, stdoutw = if self.stdout
29
+ [self.stdout, self.stdout]
30
+ else
31
+ IO.pipe
32
+ end
33
+
34
+ [stdin, stdoutr, stdoutw]
33
35
  end
34
36
  end
35
37
  end
@@ -16,12 +16,11 @@ module Coque
16
16
  end
17
17
 
18
18
  def |(other)
19
- verify_redirectable(other)
20
19
  case other
21
20
  when Pipeline
22
21
  Pipeline.new(commands + other.commands)
23
22
  when Cmd
24
- Pipeline.new(commands + [other])
23
+ Pipeline.new(commands + [other.clone])
25
24
  end
26
25
  end
27
26
 
data/lib/coque/rb.rb CHANGED
@@ -32,10 +32,10 @@ module Coque
32
32
  end
33
33
 
34
34
  def run
35
- ensure_default_fds
35
+ stdin, stdoutr, stdoutw = get_default_fds
36
36
 
37
37
  pid = fork do
38
- STDOUT.reopen(stdout)
38
+ STDOUT.reopen(stdoutw)
39
39
  Dir.chdir(context.dir)
40
40
  if context.disinherits_env?
41
41
  ENV.clear
@@ -47,8 +47,8 @@ module Coque
47
47
  stdin.each_line(&@block)
48
48
  @post_block.call if @post_block
49
49
  end
50
- stdout.close
51
- Result.new(pid, stdout_read)
50
+ stdoutw.close
51
+ Result.new(pid, stdoutr)
52
52
  end
53
53
  end
54
54
  end
@@ -37,50 +37,20 @@ module Coque
37
37
  end
38
38
  end
39
39
 
40
- def stdin_redirected?
41
- defined? @stdin
42
- end
43
-
44
- def stdout_redirected?
45
- defined? @stdout
46
- end
47
-
48
- def stderr_redirected?
49
- defined? @stderr
50
- end
51
-
52
40
  def stderr=(s)
53
- if stderr_redirected?
54
- raise RedirectionError.new("Can't set stderr of #{self} to #{s}, is already set to #{stderr}")
55
- else
56
- @stderr = getio(s, "w")
57
- end
41
+ @stderr = getio(s, "w")
58
42
  end
59
43
 
60
44
  def stdout=(s)
61
- if stdout_redirected?
62
- raise RedirectionError.new("Can't set stdout of #{self} to #{s}, is already set to #{stdout}")
63
- else
64
- @stdout = getio(s, "w")
65
- end
45
+ @stdout = getio(s, "w")
66
46
  end
67
47
 
68
48
  def stdin=(s)
69
- if stdin_redirected?
70
- raise RedirectionError.new("Can't set stdin of #{self} to #{s}, is already set to #{stdin}")
71
- else
72
- @stdin = getio(s, "r")
73
- end
49
+ @stdin = getio(s, "r")
74
50
  end
75
51
 
76
- def verify_redirectable(other)
77
- if self.stdout_redirected?
78
- raise RedirectionError.new("Can't pipe #{self} into #{other} -- #{self}'s STDIN is already redirected")
79
- end
80
-
81
- if other.stdin_redirected?
82
- raise RedirectionError.new("Can't pipe #{self} into #{other} -- #{other}'s STDIN is already redirected")
83
- end
52
+ def to_a
53
+ run.to_a
84
54
  end
85
55
 
86
56
  private
data/lib/coque/sh.rb CHANGED
@@ -1,13 +1,16 @@
1
1
  module Coque
2
2
  class Sh < Cmd
3
3
  attr_reader :args, :context
4
- def initialize(context, args)
4
+ def initialize(context, args, stdin = nil, stdout = nil, stderr = nil)
5
5
  @context = context
6
6
  @args = args
7
+ self.stdin = stdin if stdin
8
+ self.stdout = stdout if stdout
9
+ self.stderr = stderr if stderr
7
10
  end
8
11
 
9
12
  def clone
10
- self.class.new(context, args)
13
+ self.class.new(context, args, stdin, stdout, stderr)
11
14
  end
12
15
 
13
16
  def to_s
@@ -23,9 +26,9 @@ module Coque
23
26
  end
24
27
 
25
28
  def run
26
- ensure_default_fds
29
+ stdin, stdoutr, stdoutw = get_default_fds
27
30
  opts = {in: stdin, stdin.fileno => stdin.fileno,
28
- out: stdout, stdout.fileno => stdout.fileno,
31
+ out: stdoutw, stdoutw.fileno => stdoutw.fileno,
29
32
  chdir: context.dir, unsetenv_others: context.disinherits_env?}
30
33
 
31
34
  # Redirect err to out: (e.g. for 2>&1)
@@ -38,8 +41,8 @@ module Coque
38
41
 
39
42
  pid = spawn(context.env, args.join(" "), opts.merge(err_opts))
40
43
 
41
- stdout.close
42
- Result.new(pid, stdout_read)
44
+ stdoutw.close
45
+ Result.new(pid, stdoutr)
43
46
  end
44
47
  end
45
48
  end
data/lib/coque/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Coque
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/coque.rb CHANGED
@@ -24,4 +24,8 @@ module Coque
24
24
  def self.pipeline(*commands)
25
25
  commands.reduce(:|)
26
26
  end
27
+
28
+ def self.source(enumerable)
29
+ Coque.rb.post { enumerable.each { |e| puts e} }
30
+ end
27
31
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: coque
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Horace Williams
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-06-06 00:00:00.000000000 Z
11
+ date: 2018-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler