test-cmd.rb 0.12.4 → 1.1.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: 9543aef60b39eebdd49dcd4a1a33b9f08841cdc7ad0176402266d0236bdb483c
4
- data.tar.gz: 44f38f751770d9cee2d734a768b07d10a67227d3841aec53648a9ecff89ca26a
3
+ metadata.gz: 050e40eb1971d85c78300e005a7a633b3e56288dfaad75e201e73c4d51a43ecc
4
+ data.tar.gz: 7d1fcfd581aa09af2d6159ac809fe40bf4cc68a351026b44c2ceb32d50269e7c
5
5
  SHA512:
6
- metadata.gz: be9bba3851638c04d87a114f92fc2ee28b8683e3df14b13b9a37f7a9749ea0075589def7acf65c8b554e62f6e8575b9ccde4aa9f61b024f65a6455f360686559
7
- data.tar.gz: 04db2f4f1b84bb1ce41acfa570778bcec93d64593d58825356c1b9e48ff08b181f8c13c516bbfe70fa8065ecf18b83488df1a8ac1354632e3513765be24a47c6
6
+ metadata.gz: 291d1ee4ad90a5d8f10006a62f4662b1a9c95a555677646d5d860055b05c8c78b9b112d3365928fa1ff17389bc1f6020e1ee30f327ba366847a9503122f1bec2
7
+ data.tar.gz: 6d965b87d2443829f36916cbbc3192b5a2eb0e53a1cde069fc4f66d803bbd6f70a7208a607e767f685f7939d914bd112754e29773d8647e336d7d4766e4c6ee3
data/.rubocop.yml CHANGED
@@ -8,16 +8,20 @@ require:
8
8
  inherit_gem:
9
9
  standard: config/base.yml
10
10
 
11
+ ##
12
+ # Enabled
11
13
  AllCops:
12
14
  TargetRubyVersion: 3.1
13
15
  Include:
14
16
  - 'lib/**/*.rb'
15
17
  - 'test/**/*.rb'
16
18
 
17
- Style/MultilineIfModifier:
18
- Exclude:
19
- - 'lib/test-cmd.rb'
20
-
19
+ ##
20
+ # Disabled
21
21
  Layout/MultilineMethodCallIndentation:
22
22
  Exclude:
23
23
  - 'test/*.rb'
24
+ Layout/ArgumentAlignment:
25
+ Enabled: false
26
+ Style/MultilineIfModifier:
27
+ Enabled: false
data/Gemfile CHANGED
File without changes
data/README.md CHANGED
@@ -1,16 +1,21 @@
1
1
  ## About
2
2
 
3
3
  test-cmd.rb provides an object-oriented interface for spawning
4
- a command.
4
+ a command on UNIX-like operating systems. The library is intended
5
+ to be simple, lightweight, and easy to use.
5
6
 
6
7
  ## Examples
7
8
 
8
- ### Callbacks
9
+ ### Commands
10
+
11
+ #### Callbacks
9
12
 
10
13
  The success and failure callbacks provide hooks for when
11
14
  a command exits successfully or unsuccessfully. The callbacks
12
15
  are passed an instance of
13
- [Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html):
16
+ [Test::Cmd](https://0x1eef.github.io/x/test-cmd.rb/Test/Cmd.html)
17
+ that has access to the command's process ID, exit status,
18
+ standard ouput stream, and standard error stream:
14
19
 
15
20
  ``` ruby
16
21
  require "test-cmd"
@@ -19,12 +24,14 @@ cmd("ruby", "-e", "exit 0")
19
24
  .failure { print "The command [#{_1.pid}] was unsuccessful", "\n" }
20
25
  ```
21
26
 
22
- ### Test::Unit
27
+ #### Assertions
23
28
 
24
29
  The following example demonstrates how tests might be written with
25
30
  test-unit from the standard library. The
26
31
  [`cmd`](https://0x1eef.github.io/x/test-cmd.rb/Kernel.html#cmd-instance_method)
27
- method takes the name or path of a command, alongside any arguments:
32
+ method takes the name or path of a command, alongside any arguments. The tests
33
+ assert against the exit status, standard output stream, and standard error
34
+ stream of the spawned ruby process:
28
35
 
29
36
  ```ruby
30
37
  require "test/unit"
@@ -68,8 +75,8 @@ test-cmd.rb can be installed via rubygems.org:
68
75
 
69
76
  ## Sources
70
77
 
71
- * [GitHub](https://github.com/0x1eef/test-cmd.rb#readme)
72
- * [GitLab](https://gitlab.com/0x1eef/test-cmd.rb#about)
78
+ * [github.com/@0x1eef](https://github.com/0x1eef/test-cmd.rb#readme)
79
+ * [gitlab.com/@0x1eef](https://gitlab.com/0x1eef/test-cmd.rb#about)
73
80
 
74
81
  ## License
75
82
 
data/Rakefile.rb CHANGED
File without changes
data/lib/test/cmd.rb CHANGED
@@ -1,11 +1,9 @@
1
- unless defined?(Test)
2
- module Test
3
- end
4
- end
1
+ module Test
2
+ end unless defined?(Test)
5
3
 
6
4
  ##
7
5
  # test-cmd.rb provides an object oriented interface
8
- # for spawning a command.
6
+ # for spawning a command
9
7
  class Test::Cmd
10
8
  ##
11
9
  # @api private
@@ -33,6 +31,7 @@ class Test::Cmd
33
31
  @stdout = ""
34
32
  @stderr = ""
35
33
  @enoent = false
34
+ @waiter = Queue.new
36
35
  end
37
36
 
38
37
  ##
@@ -48,51 +47,20 @@ class Test::Cmd
48
47
  # @return [Test::Cmd]
49
48
  def spawn
50
49
  return self if @spawned
51
-
52
50
  tap do
53
- out, err = Pipe.pair, Pipe.pair
54
51
  @spawned = true
55
- t = Thread.new do
56
- Process.spawn(@cmd, *@argv, {out: out.w, err: err.w})
57
- Process.wait
58
- @status = $?
59
- rescue Errno::ENOENT => ex
60
- @cmd, @argv, @stderr = "false", [], ex.message
61
- @enoent = true
62
- retry
63
- end
64
- loop do
65
- io, _ = IO.select([out.r, err.r], nil, nil, 0.01)
66
- io&.include?(out.r) ? @stdout << out.r.read(1) : nil
67
- io&.include?(err.r) ? @stderr << err.r.read(1) : nil
68
- break unless t.alive? || IO.select([out.r, err.r], nil, nil, 0.01)
69
- end
70
- ensure
71
- [out, err].each(&:close)
52
+ @out, @err = Pipe.pair, Pipe.pair
53
+ produce(@out, @err)
54
+ @waiter.pop
72
55
  end
73
56
  end
74
57
 
75
- ##
76
- # @return [String]
77
- # Returns the contents of stdout
78
- def stdout
79
- spawn
80
- @stdout
81
- end
82
-
83
- ##
84
- # @return [String]
85
- # Returns the contents of stderr
86
- def stderr
87
- spawn
88
- @stderr
89
- end
90
-
91
58
  ##
92
59
  # @return [Process::Status]
93
60
  # Returns the status of a process
94
61
  def status
95
62
  spawn
63
+ consume(@producer, @out, @err)
96
64
  @status
97
65
  end
98
66
 
@@ -111,6 +79,31 @@ class Test::Cmd
111
79
  end
112
80
  alias_method :exitstatus, :exit_status
113
81
 
82
+ ##
83
+ # @group IO
84
+
85
+ ##
86
+ # @return [String]
87
+ # Returns the contents of stdout
88
+ def stdout
89
+ spawn
90
+ consume(@producer, @out, @err)
91
+ @stdout
92
+ end
93
+
94
+ ##
95
+ # @return [String]
96
+ # Returns the contents of stderr
97
+ def stderr
98
+ spawn
99
+ consume(@producer, @out, @err)
100
+ @stderr
101
+ end
102
+ # @endgroup
103
+
104
+ ##
105
+ # @group Predicates
106
+
114
107
  ##
115
108
  # @return [Boolean]
116
109
  # Returns true when a command exited successfully
@@ -119,52 +112,118 @@ class Test::Cmd
119
112
  end
120
113
 
121
114
  ##
122
- # Yields an instance of {Test::Cmd Test::Cmd}.
123
- #
115
+ # @return [Boolean]
116
+ # Returns true when a command has been spawned
117
+ def spawned?
118
+ @spawned
119
+ end
120
+
121
+ ##
122
+ # @return [Boolean]
123
+ # Returns true when a command is running
124
+ def alive?
125
+ @producer&.alive?
126
+ end
127
+ alias_method :running?, :alive?
128
+
129
+ ##
130
+ # Sends SIGKILL to a running command
131
+ # @return [void]
132
+ def kill!
133
+ return unless alive?
134
+ Process.kill("SIGKILL", @pid)
135
+ end
136
+
137
+ ##
138
+ # @return [Boolean]
139
+ # Returns true when a command can't be found
140
+ def command_not_found?
141
+ spawn
142
+ consume(@producer, @out, @err)
143
+ @enoent
144
+ end
145
+ alias_method :not_found?, :command_not_found?
146
+ # @endgroup
147
+
148
+ ##
149
+ # @group Callbacks
150
+
151
+ ##
152
+ # @yieldparam [Test::Cmd] cmd
153
+ # Yields an instance of {Test::Cmd Test::Cmd}
124
154
  # @example
125
155
  # cmd("ruby", "-e", "exit 0")
126
156
  # .success { print "Command [#{_1.pid}] exited successfully", "\n" }
127
157
  # .failure { }
128
- #
129
158
  # @return [Test::Cmd]
130
159
  def success
131
160
  tap do
132
161
  spawn
162
+ consume(@producer, @out, @err)
133
163
  status.success? ? yield(self) : nil
134
164
  end
135
165
  end
136
166
 
137
167
  ##
138
- # Yields an instance of {Test::Cmd Test::Cmd}.
139
- #
168
+ # @yieldparam [Test::Cmd] cmd
169
+ # Yields an instance of {Test::Cmd Test::Cmd}
140
170
  # @example
141
171
  # cmd("ruby", "-e", "exit 1")
142
172
  # .success { }
143
173
  # .failure { print "Command [#{_1.pid}] exited unsuccessfully", "\n" }
144
- #
145
174
  # @return [Test::Cmd]
146
175
  def failure
147
176
  tap do
148
177
  spawn
178
+ consume(@producer, @out, @err)
149
179
  status.success? ? nil : yield(self)
150
180
  end
151
181
  end
182
+ # @endgroup
183
+
184
+ private
152
185
 
153
186
  ##
154
- # @return [Boolean]
155
- # Returns true when a command has been spawned
156
- def spawned?
157
- @spawned
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
158
204
  end
159
205
 
160
206
  ##
161
- # @return [Boolean]
162
- # Returns true when a command can't be found
163
- def command_not_found?
164
- spawn
165
- @enoent
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
+ # @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
166
226
  end
167
- alias_method :not_found?, :command_not_found?
168
227
  end
169
228
 
170
229
  module Kernel
data/test-cmd.rb.gemspec CHANGED
@@ -2,16 +2,15 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = "test-cmd.rb"
5
- gem.authors = ["0x1eef"]
6
- gem.email = ["0x1eef@protonmail.com"]
7
- gem.homepage = "https://github.com/0x1eef/test-cmd.rb#readme"
8
- gem.version = "0.12.4"
5
+ gem.authors = ["robert"]
6
+ gem.email = ["robert@r.uby.dev"]
7
+ gem.homepage = "https://github.com/1robertrb/test-cmd.rb#readme"
8
+ gem.version = "1.1.0"
9
9
  gem.required_ruby_version = ">= 3.0"
10
10
  gem.licenses = ["0BSD"]
11
11
  gem.files = `git ls-files`.split($/)
12
12
  gem.require_paths = ["lib"]
13
- gem.summary = "An object-oriented interface for spawning a command"
14
- gem.metadata = { "documentation_uri" => "https://0x1eef.github.io/x/test-cmd.rb/" }
13
+ gem.summary = "test-cmd.rb provides an object-oriented interface for spawning a command"
15
14
  gem.description = gem.summary
16
15
  gem.add_development_dependency "test-unit", "~> 3.5.7"
17
16
  gem.add_development_dependency "yard", "~> 0.9"
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-cmd.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.4
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
- - '0x1eef'
8
- autorequire:
7
+ - robert
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2024-06-16 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: test-unit
@@ -80,16 +79,15 @@ dependencies:
80
79
  - - "~>"
81
80
  - !ruby/object:Gem::Version
82
81
  version: '13.1'
83
- description: An object-oriented interface for spawning a command
82
+ description: test-cmd.rb provides an object-oriented interface for spawning a command
84
83
  email:
85
- - 0x1eef@protonmail.com
84
+ - robert@r.uby.dev
86
85
  executables: []
87
86
  extensions: []
88
87
  extra_rdoc_files: []
89
88
  files:
90
89
  - ".github/workflows/specs.yml"
91
90
  - ".gitignore"
92
- - ".gitlab-ci.yml"
93
91
  - ".projectile"
94
92
  - ".rubocop.yml"
95
93
  - Gemfile
@@ -101,12 +99,10 @@ files:
101
99
  - test-cmd.rb.gemspec
102
100
  - test/cmd_test.rb
103
101
  - test/setup.rb
104
- homepage: https://github.com/0x1eef/test-cmd.rb#readme
102
+ homepage: https://github.com/1robertrb/test-cmd.rb#readme
105
103
  licenses:
106
104
  - 0BSD
107
- metadata:
108
- documentation_uri: https://0x1eef.github.io/x/test-cmd.rb/
109
- post_install_message:
105
+ metadata: {}
110
106
  rdoc_options: []
111
107
  require_paths:
112
108
  - lib
@@ -121,8 +117,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
121
117
  - !ruby/object:Gem::Version
122
118
  version: '0'
123
119
  requirements: []
124
- rubygems_version: 3.5.9
125
- signing_key:
120
+ rubygems_version: 4.0.6
126
121
  specification_version: 4
127
- summary: An object-oriented interface for spawning a command
122
+ summary: test-cmd.rb provides an object-oriented interface for spawning a command
128
123
  test_files: []
data/.gitlab-ci.yml DELETED
@@ -1,16 +0,0 @@
1
- stages:
2
- - test
3
-
4
- test-ruby31:
5
- stage: test
6
- image: ruby:3.1.2
7
- script:
8
- - bundle install
9
- - bundle exec ruby test/*_test.rb
10
-
11
- test-ruby32:
12
- stage: test
13
- image: ruby:3.2.0
14
- script:
15
- - bundle install
16
- - bundle exec ruby test/*_test.rb