test-cmd.rb 1.1.0 → 2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 050e40eb1971d85c78300e005a7a633b3e56288dfaad75e201e73c4d51a43ecc
4
- data.tar.gz: 7d1fcfd581aa09af2d6159ac809fe40bf4cc68a351026b44c2ceb32d50269e7c
3
+ metadata.gz: c6c0bc0c0b5e20d51b2455762362ee54301e95c6171a6427dbdf6ea85acdc834
4
+ data.tar.gz: 9bcbbe35149e54547b7e01a678de58a068e4a35a0728d454fa613f26d2d9c3ee
5
5
  SHA512:
6
- metadata.gz: 291d1ee4ad90a5d8f10006a62f4662b1a9c95a555677646d5d860055b05c8c78b9b112d3365928fa1ff17389bc1f6020e1ee30f327ba366847a9503122f1bec2
7
- data.tar.gz: 6d965b87d2443829f36916cbbc3192b5a2eb0e53a1cde069fc4f66d803bbd6f70a7208a607e767f685f7939d914bd112754e29773d8647e336d7d4766e4c6ee3
6
+ metadata.gz: ec35ba65fefe5c978fe9d467d90f1c9719a984078f2bafb22f1a9e1757ca322533ee99c7f77d4268bbb051986230685058da3da88ca2674567b264d915b5f97b
7
+ data.tar.gz: 517746b21cb1edd44a3d96216ae3b842b88acec38c6b3fad389d3748ef8cacc241f4baf205aa1fe285a2aea92c5775e359a04d6fd89f5f9f2e205a7e13784bf8
data/README.md CHANGED
@@ -1,35 +1,76 @@
1
- ## About
1
+ <p align="center">
2
+ <a href="https://r.uby.dev">
3
+ <img
4
+ src="rubydev.svg"
5
+ width="400"
6
+ height="200"
7
+ border="0"
8
+ alt="a r.uby.dev project"
9
+ >
10
+ </a>
11
+ </p>
12
+
13
+ > A [r.uby.dev](https://r.uby.dev) project.
14
+
15
+ Welcome to the canonical test-cmd.rb repository.
16
+
17
+ test-cmd.rb is a Go-inspired, object-oriented interface for running
18
+ commands on UNIX-like systems, in the spirit of Go's `os/exec`. A
19
+ command is built up and then spawned so its standard output and
20
+ error streams, process ID, and exit status are captured in the
21
+ background. Predicates, callbacks, and process control cover the
22
+ common cases with a small and dependency-free API.
2
23
 
3
- test-cmd.rb provides an object-oriented interface for spawning
4
- a command on UNIX-like operating systems. The library is intended
5
- to be simple, lightweight, and easy to use.
24
+ ## Install
25
+
26
+ test-cmd.rb can be installed via rubygems.org:
6
27
 
7
- ## Examples
28
+ gem install test-cmd.rb
29
+
30
+ ## Quick start
8
31
 
9
32
  ### Commands
10
33
 
11
- #### Callbacks
34
+ A command is created with
35
+ [`Test::Command#initialize`](https://r.uby.dev/api-docs/test-cmd.rb/Test/Command.html#initialize-instance_method)
36
+ which takes the name or path of a command, and given additional
37
+ arguments with
38
+ [`Test::Command#argv`](https://r.uby.dev/api-docs/test-cmd.rb/Test/Command.html#argv-instance_method).
39
+ The instance has access to the command's process ID, exit status,
40
+ standard output stream, and standard error stream.
41
+
42
+ ```ruby
43
+ require "test-cmd"
44
+ Test::Command.new("ls").argv("-l").stdout
45
+ ```
46
+
47
+ <details>
48
+ <summary>Callbacks</summary>
49
+ <br>
12
50
 
13
51
  The success and failure callbacks provide hooks for when
14
52
  a command exits successfully or unsuccessfully. The callbacks
15
53
  are passed an instance of
16
- [Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html)
54
+ [Test::Command](https://r.uby.dev/api-docs/test-cmd.rb/Test/Command.html)
17
55
  that has access to the command's process ID, exit status,
18
- standard ouput stream, and standard error stream:
56
+ standard output stream, and standard error stream.
19
57
 
20
- ``` ruby
58
+ ```ruby
21
59
  require "test-cmd"
22
- cmd("ruby", "-e", "exit 0")
60
+ Test::Command.new("ruby", "-e", "exit 0")
23
61
  .success { print "The command [#{_1.pid}] was successful", "\n" }
24
62
  .failure { print "The command [#{_1.pid}] was unsuccessful", "\n" }
25
63
  ```
64
+ </details>
26
65
 
27
- #### Assertions
66
+ <details>
67
+ <summary>Assertions</summary>
68
+ <br>
28
69
 
29
70
  The following example demonstrates how tests might be written with
30
- test-unit from the standard library. The
31
- [`cmd`](https://0x1eef.github.io/x/test-cmd.rb/Kernel.html#cmd-instance_method)
32
- method takes the name or path of a command, alongside any arguments. The tests
71
+ test-unit from the standard library. A
72
+ [Test::Command](https://r.uby.dev/api-docs/test-cmd.rb/Test/Command.html)
73
+ takes the name or path of a command, alongside any arguments. The tests
33
74
  assert against the exit status, standard output stream, and standard error
34
75
  stream of the spawned ruby process:
35
76
 
@@ -57,29 +98,18 @@ class CmdTest < Test::Unit::TestCase
57
98
  private
58
99
 
59
100
  def ruby(code)
60
- cmd("ruby", "-e", code)
101
+ Test::Command.new("ruby", "-e", code)
61
102
  end
62
103
  end
63
104
  ```
105
+ </details>
64
106
 
65
107
  ## Documentation
66
108
 
67
109
  A complete API reference is available at
68
- [0x1eef.github.io/x/test-cmd.rb](https://0x1eef.github.io/x/test-cmd.rb)
69
-
70
- ## Install
71
-
72
- test-cmd.rb can be installed via rubygems.org:
73
-
74
- gem install test-cmd.rb
75
-
76
- ## Sources
77
-
78
- * [github.com/@0x1eef](https://github.com/0x1eef/test-cmd.rb#readme)
79
- * [gitlab.com/@0x1eef](https://gitlab.com/0x1eef/test-cmd.rb#about)
110
+ [r.uby.dev/api-docs/test-cmd.rb](https://r.uby.dev/api-docs/test-cmd.rb)
80
111
 
81
112
  ## License
82
113
 
83
- [BSD Zero Clause](https://choosealicense.com/licenses/0bsd/)
84
- <br>
85
- See [LICENSE](./LICENSE)
114
+ This software is released under the terms of the BSD Zero Clause license. <br>
115
+ See [LICENSE](./LICENSE) for details.
data/Rakefile.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require "bundler/setup"
2
+ require "bundler/gem_tasks"
2
3
  require "rake/testtask"
3
4
 
4
5
  Rake::TestTask.new do |t|
data/lib/test/cmd.rb CHANGED
@@ -4,7 +4,7 @@ end unless defined?(Test)
4
4
  ##
5
5
  # test-cmd.rb provides an object oriented interface
6
6
  # for spawning a command
7
- class Test::Cmd
7
+ class Test::Command
8
8
  ##
9
9
  # @api private
10
10
  class Pipe < Struct.new(:r, :w)
@@ -22,7 +22,7 @@ class Test::Cmd
22
22
  # A command to spawn
23
23
  # @param [Array<String>] argv
24
24
  # Zero or more command-line arguments
25
- # @return [Test::Cmd]
25
+ # @return [Test::Command]
26
26
  def initialize(cmd, *argv)
27
27
  @cmd = cmd
28
28
  @argv = argv.dup
@@ -31,28 +31,54 @@ class Test::Cmd
31
31
  @stdout = ""
32
32
  @stderr = ""
33
33
  @enoent = false
34
- @waiter = Queue.new
35
34
  end
36
35
 
37
36
  ##
38
37
  # @param [Array<String, #to_s>] argv
39
38
  # Command-line arguments
40
- # @return [Test::Cmd]
39
+ # @return [Test::Command]
41
40
  def argv(*argv)
42
41
  tap { @argv.concat(argv) }
43
42
  end
44
43
 
45
44
  ##
46
45
  # Spawns a command
47
- # @return [Test::Cmd]
46
+ # @return [Test::Command]
48
47
  def spawn
49
48
  return self if @spawned
50
49
  tap do
51
50
  @spawned = true
52
51
  @out, @err = Pipe.pair, Pipe.pair
53
- produce(@out, @err)
54
- @waiter.pop
52
+ ##
53
+ # Spawn in the calling thread so the command's fds are
54
+ # wired up before the reader thread starts. We then close
55
+ # our own copies of the write ends so the reader thread
56
+ # observes EOF the moment the child exits, and reads both
57
+ # streams with whole-buffer reads rather than a byte at
58
+ # a time.
59
+ @pid = Process.spawn(
60
+ @cmd, *@argv,
61
+ {out: @out.w, err: @err.w, in: IO::NULL}
62
+ )
63
+ @out.w.close
64
+ @err.w.close
65
+ @producer = Thread.new do
66
+ @stdout = @out.r.read
67
+ @stderr = @err.r.read
68
+ Process.wait
69
+ @status = $?
70
+ ensure
71
+ @out.r.close
72
+ @err.r.close
73
+ end
55
74
  end
75
+ rescue Errno::ENOENT => ex
76
+ @stderr = ex.message
77
+ @enoent = true
78
+ ##
79
+ # Capture a real non-zero status so predicates like
80
+ # #success? work even though the command never spawned.
81
+ @status = Process.waitpid2(Process.spawn("false")).last
56
82
  end
57
83
 
58
84
  ##
@@ -60,7 +86,7 @@ class Test::Cmd
60
86
  # Returns the status of a process
61
87
  def status
62
88
  spawn
63
- consume(@producer, @out, @err)
89
+ consume
64
90
  @status
65
91
  end
66
92
 
@@ -87,7 +113,7 @@ class Test::Cmd
87
113
  # Returns the contents of stdout
88
114
  def stdout
89
115
  spawn
90
- consume(@producer, @out, @err)
116
+ consume
91
117
  @stdout
92
118
  end
93
119
 
@@ -96,7 +122,7 @@ class Test::Cmd
96
122
  # Returns the contents of stderr
97
123
  def stderr
98
124
  spawn
99
- consume(@producer, @out, @err)
125
+ consume
100
126
  @stderr
101
127
  end
102
128
  # @endgroup
@@ -139,7 +165,7 @@ class Test::Cmd
139
165
  # Returns true when a command can't be found
140
166
  def command_not_found?
141
167
  spawn
142
- consume(@producer, @out, @err)
168
+ consume
143
169
  @enoent
144
170
  end
145
171
  alias_method :not_found?, :command_not_found?
@@ -149,33 +175,33 @@ class Test::Cmd
149
175
  # @group Callbacks
150
176
 
151
177
  ##
152
- # @yieldparam [Test::Cmd] cmd
153
- # Yields an instance of {Test::Cmd Test::Cmd}
178
+ # @yieldparam [Test::Command] cmd
179
+ # Yields an instance of {Test::Command Test::Command}
154
180
  # @example
155
- # cmd("ruby", "-e", "exit 0")
156
- # .success { print "Command [#{_1.pid}] exited successfully", "\n" }
157
- # .failure { }
158
- # @return [Test::Cmd]
181
+ # Test::Command.new("ruby", "-e", "exit 0").success do
182
+ # print "ok pid #{_1.pid}", "\n"
183
+ # end
184
+ # @return [Test::Command]
159
185
  def success
160
186
  tap do
161
187
  spawn
162
- consume(@producer, @out, @err)
188
+ consume
163
189
  status.success? ? yield(self) : nil
164
190
  end
165
191
  end
166
192
 
167
193
  ##
168
- # @yieldparam [Test::Cmd] cmd
169
- # Yields an instance of {Test::Cmd Test::Cmd}
194
+ # @yieldparam [Test::Command] cmd
195
+ # Yields an instance of {Test::Command Test::Command}
170
196
  # @example
171
- # cmd("ruby", "-e", "exit 1")
172
- # .success { }
173
- # .failure { print "Command [#{_1.pid}] exited unsuccessfully", "\n" }
174
- # @return [Test::Cmd]
197
+ # Test::Command.new("ruby", "-e", "exit 1").failure do
198
+ # print "fail pid #{_1.pid}", "\n"
199
+ # end
200
+ # @return [Test::Command]
175
201
  def failure
176
202
  tap do
177
203
  spawn
178
- consume(@producer, @out, @err)
204
+ consume
179
205
  status.success? ? nil : yield(self)
180
206
  end
181
207
  end
@@ -184,53 +210,12 @@ class Test::Cmd
184
210
  private
185
211
 
186
212
  ##
187
- # @param [Test::Cmd::Pipe] out
188
- # A pipe for stdout
189
- # @param [Test::Cmd::Pipe] err
190
- # A pipe for stderr
191
- # @return [Thread]
192
- # Returns a thread for a spawned command
193
- def produce(out, err)
194
- @producer = Thread.new do
195
- @pid = Process.spawn(@cmd, *@argv, {out: out.w, err: err.w})
196
- @waiter.push(nil)
197
- Process.wait
198
- @status = $?
199
- rescue Errno::ENOENT => ex
200
- @cmd, @argv, @stderr = "false", [], ex.message
201
- @enoent = true
202
- retry
203
- end
204
- end
205
-
206
- ##
207
- # @param [Thread] thread
208
- # A thread for a spawned command
209
- # @param [Test::Cmd::Pipe] out
210
- # A pipe for stdout
211
- # @param [Test::Cmd::Pipe] err
212
- # A pipe for stderr
213
+ # Blocks until the spawned command has finished, its
214
+ # output has been read, and its exit status captured.
215
+ # Safe to call more than once.
213
216
  # @return [void]
214
- def consume(thread, out, err)
215
- return if @consumed
216
- sleep 0.01 while thread.alive?
217
- loop do
218
- io, _ = IO.select([out.r, err.r], nil, nil, 0.01)
219
- io&.include?(out.r) ? @stdout << out.r.read(1) : nil
220
- io&.include?(err.r) ? @stderr << err.r.read(1) : nil
221
- break unless thread.alive? || IO.select([out.r, err.r], nil, nil, 0.01)
222
- end
223
- ensure
224
- [out, err].each(&:close)
225
- @consumed = true
226
- end
227
- end
228
-
229
- module Kernel
230
- ##
231
- # @param (see Test::Cmd#initialize)
232
- # @return (see Test::Cmd#initialize)
233
- def cmd(cmd, *argv)
234
- Test::Cmd.new(cmd, *argv)
217
+ def consume
218
+ return unless @producer&.alive?
219
+ @producer.join
235
220
  end
236
- end
221
+ end
data/rubydev.svg ADDED
@@ -0,0 +1,185 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 560 220" role="img" aria-labelledby="title desc">
2
+ <title id="title">r.uby.dev</title>
3
+ <desc id="desc">A wide r.uby.dev wordmark with three small ruby gemstones moving around the text.</desc>
4
+ <defs>
5
+ <linearGradient id="body" x1="45" y1="35" x2="211" y2="224" gradientUnits="userSpaceOnUse">
6
+ <stop offset="0" stop-color="#ff7468"/>
7
+ <stop offset="0.42" stop-color="#cc342d"/>
8
+ <stop offset="1" stop-color="#5b090d"/>
9
+ </linearGradient>
10
+ <linearGradient id="table" x1="75" y1="31" x2="166" y2="104" gradientUnits="userSpaceOnUse">
11
+ <stop offset="0" stop-color="#fff3ec"/>
12
+ <stop offset="0.26" stop-color="#ff8f84"/>
13
+ <stop offset="1" stop-color="#d62f2c"/>
14
+ </linearGradient>
15
+ <linearGradient id="right" x1="150" y1="59" x2="219" y2="195" gradientUnits="userSpaceOnUse">
16
+ <stop offset="0" stop-color="#bb2026"/>
17
+ <stop offset="1" stop-color="#3c0407"/>
18
+ </linearGradient>
19
+ <linearGradient id="center" x1="99" y1="104" x2="146" y2="226" gradientUnits="userSpaceOnUse">
20
+ <stop offset="0" stop-color="#ff6c61"/>
21
+ <stop offset="0.48" stop-color="#c82d2a"/>
22
+ <stop offset="1" stop-color="#8d1618"/>
23
+ </linearGradient>
24
+ <radialGradient id="glow" cx="38%" cy="22%" r="66%">
25
+ <stop offset="0" stop-color="#fff8ed" stop-opacity="0.68"/>
26
+ <stop offset="0.42" stop-color="#ffb0a7" stop-opacity="0.18"/>
27
+ <stop offset="1" stop-color="#ffb0a7" stop-opacity="0"/>
28
+ </radialGradient>
29
+ <linearGradient id="wordmark" x1="0" y1="76" x2="0" y2="138" gradientUnits="userSpaceOnUse">
30
+ <stop offset="0" stop-color="#ffffff"/>
31
+ <stop offset="0.48" stop-color="#e1e4e8"/>
32
+ <stop offset="1" stop-color="#aeb8c2"/>
33
+ </linearGradient>
34
+ <linearGradient id="accentLine" x1="90" y1="0" x2="470" y2="0" gradientUnits="userSpaceOnUse">
35
+ <stop offset="0" stop-color="#30363d"/>
36
+ <stop offset="0.5" stop-color="#cc342d"/>
37
+ <stop offset="1" stop-color="#30363d"/>
38
+ </linearGradient>
39
+ <filter id="shadow" x="-18%" y="-18%" width="136%" height="146%">
40
+ <feDropShadow dx="0" dy="10" stdDeviation="9" flood-color="#000" flood-opacity="0.34"/>
41
+ </filter>
42
+ <filter id="textShadow" x="-20%" y="-45%" width="140%" height="190%">
43
+ <feDropShadow dx="0" dy="7" stdDeviation="6" flood-color="#000" flood-opacity="0.55"/>
44
+ </filter>
45
+ <symbol id="gemstone" viewBox="0 0 256 256">
46
+ <path d="M33 91 78 30h100l45 61-95 134Z" fill="url(#body)" stroke="#250507" stroke-width="7" stroke-linejoin="round"/>
47
+ <path d="M78 30h100l-50 61Z" fill="url(#table)" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
48
+ <path d="M33 91h95l-52 44Z" fill="#e93c35" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
49
+ <path d="M223 91h-95l52 44Z" fill="url(#right)" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
50
+ <path d="M76 135 128 225 33 91Z" fill="#9f1b1d" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
51
+ <path d="M180 135 128 225 223 91Z" fill="#62080d" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
52
+ <path d="M76 135h104l-52 90Z" fill="url(#center)" stroke="#250507" stroke-width="4" stroke-linejoin="round"/>
53
+ <path d="M78 30 128 91 76 135 33 91Z" fill="#d9322d" opacity="0.72"/>
54
+ <path d="M178 30 128 91 180 135 223 91Z" fill="#8f1519" opacity="0.72"/>
55
+ <path d="M128 91 76 135h104Z" fill="#ff6257" opacity="0.5"/>
56
+ <path d="M49 91 84 43h43L86 96Z" fill="url(#glow)"/>
57
+ <path d="M85 62 101 43h35L93 87Z" fill="#fff6eb" opacity="0.52"/>
58
+ <path d="M97 153h62" fill="none" stroke="#ffaba2" stroke-width="4" stroke-linecap="round" opacity="0.25"/>
59
+ </symbol>
60
+ </defs>
61
+ <style>
62
+ svg {
63
+ color-scheme: light dark;
64
+ --wordmark-fill: #24292f;
65
+ --wordmark-halo: #ffffff;
66
+ --wordmark-outline: #d0d7de;
67
+ --rule: #d0d7de;
68
+ --rule-strong: #8c959f;
69
+ --accent-shadow: #d0d7de;
70
+ }
71
+ .wordmark-halo {
72
+ fill: none;
73
+ stroke: var(--wordmark-halo);
74
+ stroke-width: 16;
75
+ stroke-linejoin: round;
76
+ paint-order: stroke;
77
+ }
78
+ .wordmark-outline {
79
+ fill: none;
80
+ stroke: var(--wordmark-outline);
81
+ stroke-width: 8;
82
+ stroke-linejoin: round;
83
+ paint-order: stroke;
84
+ }
85
+ .wordmark-fill {
86
+ fill: var(--wordmark-fill);
87
+ }
88
+ .tagline {
89
+ fill: var(--wordmark-fill);
90
+ opacity: 0.78;
91
+ }
92
+ .rule {
93
+ stroke: var(--rule);
94
+ }
95
+ .rule-strong {
96
+ stroke: var(--rule-strong);
97
+ }
98
+ .accent-shadow {
99
+ stroke: var(--accent-shadow);
100
+ }
101
+ .gem {
102
+ animation-duration: 8.5s;
103
+ animation-iteration-count: infinite;
104
+ animation-timing-function: ease-in-out;
105
+ }
106
+ .gem-a { animation-name: gem-a; }
107
+ .gem-b { animation-name: gem-b; animation-duration: 9.5s; }
108
+ .gem-c { animation-name: gem-c; animation-duration: 10s; }
109
+ .gem-front {
110
+ opacity: 0;
111
+ animation-duration: 18s;
112
+ animation-iteration-count: infinite;
113
+ animation-timing-function: ease-in-out;
114
+ }
115
+ .gem-front-a { animation-name: gem-front-a; }
116
+ .gem-front-b { animation-name: gem-front-b; animation-delay: -6s; }
117
+ .gem-front-c { animation-name: gem-front-c; animation-delay: -12s; }
118
+ @keyframes gem-a {
119
+ 0%, 100% { transform: translate(42px, 82px) rotate(-10deg); }
120
+ 35% { transform: translate(66px, 45px) rotate(5deg); }
121
+ 70% { transform: translate(84px, 118px) rotate(-18deg); }
122
+ }
123
+ @keyframes gem-b {
124
+ 0%, 100% { transform: translate(236px, 13px) rotate(3deg); }
125
+ 33% { transform: translate(192px, 28px) rotate(-9deg); }
126
+ 66% { transform: translate(292px, 24px) rotate(12deg); }
127
+ }
128
+ @keyframes gem-c {
129
+ 0%, 100% { transform: translate(430px, 78px) rotate(8deg); }
130
+ 38% { transform: translate(397px, 45px) rotate(-4deg); }
131
+ 72% { transform: translate(446px, 117px) rotate(16deg); }
132
+ }
133
+ @media (prefers-reduced-motion: reduce) {
134
+ .gem { animation: none; }
135
+ .gem-front { animation: none; opacity: 0; }
136
+ .gem-a { transform: translate(42px, 82px) rotate(-10deg); }
137
+ .gem-b { transform: translate(236px, 13px) rotate(3deg); }
138
+ .gem-c { transform: translate(430px, 78px) rotate(8deg); }
139
+ }
140
+ @keyframes gem-front-a {
141
+ 0%, 42%, 51%, 100% { opacity: 0; }
142
+ 45%, 48% { opacity: 0.9; }
143
+ }
144
+ @keyframes gem-front-b {
145
+ 0%, 57%, 66%, 100% { opacity: 0; }
146
+ 60%, 63% { opacity: 0.86; }
147
+ }
148
+ @keyframes gem-front-c {
149
+ 0%, 72%, 81%, 100% { opacity: 0; }
150
+ 75%, 78% { opacity: 0.88; }
151
+ }
152
+ </style>
153
+
154
+ <path class="rule" d="M32 38h496M32 182h496" stroke-width="1" opacity="0.62"/>
155
+ <path class="rule-strong" d="M90 32h380" stroke-width="2" stroke-linecap="round" opacity="0.72"/>
156
+
157
+ <g filter="url(#shadow)" opacity="0.92">
158
+ <g class="gem gem-a"><use href="#gemstone" width="78" height="78"/></g>
159
+ <g class="gem gem-b"><use href="#gemstone" width="84" height="84"/></g>
160
+ <g class="gem gem-c"><use href="#gemstone" width="78" height="78"/></g>
161
+ </g>
162
+
163
+ <g font-family="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif" text-anchor="middle">
164
+ <text class="wordmark-halo" x="280" y="126" fill="none" stroke="#ffffff"
165
+ font-size="72" font-weight="800"
166
+ filter="url(#textShadow)">r.uby.dev</text>
167
+ <text class="wordmark-outline" x="280" y="126" fill="none" stroke="#d0d7de"
168
+ font-size="72" font-weight="800">r.uby.dev</text>
169
+ <text class="wordmark-fill" x="280" y="126" fill="#24292f"
170
+ font-size="72" font-weight="800">r.uby.dev</text>
171
+ </g>
172
+
173
+ <g filter="url(#shadow)">
174
+ <g class="gem gem-a"><use class="gem-front gem-front-a" href="#gemstone" width="78" height="78"/></g>
175
+ <g class="gem gem-b"><use class="gem-front gem-front-b" href="#gemstone" width="84" height="84"/></g>
176
+ <g class="gem gem-c"><use class="gem-front gem-front-c" href="#gemstone" width="78" height="78"/></g>
177
+ </g>
178
+
179
+ <path class="accent-shadow" d="M90 176h380" stroke-width="8" stroke-linecap="round"/>
180
+ <path d="M90 176h380" stroke="url(#accentLine)" stroke-width="4" stroke-linecap="round"/>
181
+ <circle cx="280" cy="176" r="5" fill="#cc342d"/>
182
+ <text class="tagline" x="280" y="204"
183
+ font-family="system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif"
184
+ text-anchor="middle" font-size="18" font-weight="650">Building cool stuff with Ruby</text>
185
+ </svg>
data/test/cmd_test.rb CHANGED
@@ -1,28 +1,28 @@
1
1
  require_relative "setup"
2
2
 
3
- class Test::Cmd
3
+ class Test::Command
4
4
  class Test < Test::Unit::TestCase
5
5
  private
6
6
 
7
7
  def ruby(str)
8
- cmd "ruby", "-e", str
8
+ ::Test::Command.new "ruby", "-e", str
9
9
  end
10
10
  end
11
11
  end
12
12
 
13
- class Test::Cmd
13
+ class Test::Command
14
14
  ##
15
- # Test::Cmd#argv
15
+ # Test::Command#argv
16
16
  class ARGVTest < Test
17
17
  def test_ruby_argv
18
- assert_equal "42\n", cmd("ruby")
18
+ assert_equal "42\n", ::Test::Command.new("ruby")
19
19
  .argv("-e", "warn 42")
20
20
  .stderr
21
21
  end
22
22
  end
23
23
 
24
24
  ##
25
- # Test::Cmd#{exit_status, status, success?}
25
+ # Test::Command#{exit_status, status, success?}
26
26
  class ExitStatusTest < Test
27
27
  def test_ruby_exit_status_success
28
28
  assert_equal 0, ruby("exit 0").exit_status
@@ -38,12 +38,12 @@ class Test::Cmd
38
38
  end
39
39
 
40
40
  def test_nonexistent_command
41
- assert_equal false, cmd("/a/path/that/is/not/found").success?
41
+ assert_equal false, ::Test::Command.new("/a/path/that/is/not/found").success?
42
42
  end
43
43
  end
44
44
 
45
45
  ##
46
- # Test::Cmd#{stdout,stderr}
46
+ # Test::Command#{stdout,stderr}
47
47
  class OutputTest < Test
48
48
  def test_ruby_stdout
49
49
  assert_equal "42\n", ruby("puts 42").stdout
@@ -68,12 +68,12 @@ class Test::Cmd
68
68
 
69
69
  def test_nonexistent_command
70
70
  assert_equal "No such file or directory - /a/path/that/is/not/found",
71
- cmd("/a/path/that/is/not/found").stderr
71
+ ::Test::Command.new("/a/path/that/is/not/found").stderr
72
72
  end
73
73
  end
74
74
 
75
75
  ##
76
- # Test::Cmd#{success, failure}
76
+ # Test::Command#{success, failure}
77
77
  class CallbackTest < Test
78
78
  def test_ruby_success_callback
79
79
  call_ok, call_fail = [false, false]
@@ -95,7 +95,7 @@ class Test::Cmd
95
95
  end
96
96
 
97
97
  ##
98
- # Test::Cmd#spawned?
98
+ # Test::Command#spawned?
99
99
  class SpawnedTest < Test
100
100
  def test_spawned_before_spawn
101
101
  assert_equal false, ruby("puts 42").spawned?
@@ -107,11 +107,11 @@ class Test::Cmd
107
107
  end
108
108
 
109
109
  ##
110
- # Test::Cmd#command_not_found?
110
+ # Test::Command#command_not_found?
111
111
  class CommandNotFoundTest < Test
112
112
  def test_command_not_found
113
- assert_equal true, cmd("/a/path/that/is/not/found").command_not_found?
114
- assert_equal true, cmd("/a/path/that/is/not/found").not_found?
113
+ assert_equal true, ::Test::Command.new("/a/path/that/is/not/found").command_not_found?
114
+ assert_equal true, ::Test::Command.new("/a/path/that/is/not/found").not_found?
115
115
  end
116
116
  end
117
117
  end
data/test-cmd.rb.gemspec CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |gem|
4
4
  gem.name = "test-cmd.rb"
5
5
  gem.authors = ["robert"]
6
6
  gem.email = ["robert@r.uby.dev"]
7
- gem.homepage = "https://github.com/1robertrb/test-cmd.rb#readme"
8
- gem.version = "1.1.0"
7
+ gem.homepage = "https://github.com/0x1eef/test-cmd.rb#readme"
8
+ gem.version = "2.0.0"
9
9
  gem.required_ruby_version = ">= 3.0"
10
10
  gem.licenses = ["0BSD"]
11
11
  gem.files = `git ls-files`.split($/)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-cmd.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - robert
@@ -96,10 +96,11 @@ files:
96
96
  - Rakefile.rb
97
97
  - lib/test-cmd.rb
98
98
  - lib/test/cmd.rb
99
+ - rubydev.svg
99
100
  - test-cmd.rb.gemspec
100
101
  - test/cmd_test.rb
101
102
  - test/setup.rb
102
- homepage: https://github.com/1robertrb/test-cmd.rb#readme
103
+ homepage: https://github.com/0x1eef/test-cmd.rb#readme
103
104
  licenses:
104
105
  - 0BSD
105
106
  metadata: {}
@@ -117,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
117
118
  - !ruby/object:Gem::Version
118
119
  version: '0'
119
120
  requirements: []
120
- rubygems_version: 4.0.6
121
+ rubygems_version: 4.0.16
121
122
  specification_version: 4
122
123
  summary: test-cmd.rb provides an object-oriented interface for spawning a command
123
124
  test_files: []