From f6e7c1d12bace2f0df74a8f3f8f28180b462304b Mon Sep 17 00:00:00 2001 From: Sergei Gerasenko Date: Tue, 3 Mar 2026 23:31:54 -0600 Subject: [PATCH 1/3] Fix a debug mode bug When executing a command like so: ``` RubyShell.debug = true sh do end ``` The `debug` mode was ignored due to the logic of the `debug` method. --- lib/rubyshell.rb | 3 +- spec/debugger_spec.rb | 157 +++++++++++------------------------------- 2 files changed, 44 insertions(+), 116 deletions(-) diff --git a/lib/rubyshell.rb b/lib/rubyshell.rb index fc30d06..94f9f54 100644 --- a/lib/rubyshell.rb +++ b/lib/rubyshell.rb @@ -27,7 +27,8 @@ def debug=(value) def debug(value = true) # rubocop:disable Style/OptionalBooleanParameter previous_value = @debug_mode - @debug_mode = value + # Default to the value of @debug_mode if value is nil + @debug_mode = value.nil? ? @debug_mode : value result = yield diff --git a/spec/debugger_spec.rb b/spec/debugger_spec.rb index e159359..16d24f7 100644 --- a/spec/debugger_spec.rb +++ b/spec/debugger_spec.rb @@ -7,6 +7,34 @@ end end + RSpec.shared_examples "a logged command" do |expected_output| + it "returns the command output" do + expect(subject_method).to eq(expected_output) + end + + it "logs all debug information" do + subject_method + log = log_output.join + + expect(log).to include("Executed: echo #{expected_output}") + expect(log).to match(/Duration: \d+\.\d+s/) + expect(log).to match(/Pid: \d+/) + expect(log).to include("Exit code: 0") + expect(log).to include("Stdout: \"#{expected_output}\"") + end + end + + RSpec.shared_examples "a silent command" do + it "returns the command output" do + expect(subject_method).to eq("hello") + end + + it "does not log anything" do + subject_method + expect(log_output).to be_empty + end + end + describe ".run_wrapper" do let(:log_output) { [] } let(:logger) { double("Logger", info: nil) } @@ -16,145 +44,44 @@ allow(RubyShell).to receive(:logger).and_return(logger) end - after do - RubyShell.debug = false - end + after { RubyShell.debug = false } context "when debug mode is disabled" do def subject_method sh.echo("hello") end - - it "returns the command output" do - expect(subject_method).to eq("hello") - end - - it "does not log anything" do - subject_method - - expect(log_output).to be_empty - end + it_behaves_like "a silent command" end context "when debug mode is enabled via block" do def subject_method sh(debug: true) { echo("hello") } end - - it "returns the command output" do - expect(subject_method).to eq("hello") - end - - it "logs the command executed" do - subject_method - - expect(log_output.join).to include("Executed: echo hello") - end - - it "logs the duration" do - subject_method - - expect(log_output.join).to match(/Duration: \d+\.\d+s/) - end - - it "logs the pid" do - subject_method - - expect(log_output.join).to match(/Pid: \d+/) - end - - it "logs the exit code" do - subject_method - - expect(log_output.join).to include("Exit code: 0") - end - - it "logs the stdout" do - subject_method - - expect(log_output.join).to include('Stdout: "hello"') - end + it_behaves_like "a logged command", "hello" end context "when debug mode is enabled via command option" do def subject_method sh.echo("hello", _debug: true) end - - it "returns the command output" do - expect(subject_method).to eq("hello") - end - - it "logs the command executed" do - subject_method - - expect(log_output.join).to include("Executed: echo hello") - end - - it "logs the duration" do - subject_method - - expect(log_output.join).to match(/Duration: \d+\.\d+s/) - end - - it "logs the pid" do - subject_method - - expect(log_output.join).to match(/Pid: \d+/) - end - - it "logs the exit code" do - subject_method - - expect(log_output.join).to include("Exit code: 0") - end - - it "logs the stdout" do - subject_method - - expect(log_output.join).to include('Stdout: "hello"') - end + it_behaves_like "a logged command", "hello" end context "when debug mode is enabled globally" do before { RubyShell.debug = true } - def subject_method - sh.echo("world") - end - - it "returns the command output" do - expect(subject_method).to eq("world") - end - - it "logs the command executed" do - subject_method - - expect(log_output.join).to include("Executed: echo world") - end - - it "logs the duration" do - subject_method - - expect(log_output.join).to match(/Duration: \d+\.\d+s/) - end - - it "logs the pid" do - subject_method - - expect(log_output.join).to match(/Pid: \d+/) + context "when command is used as a method" do + def subject_method + sh.echo("world") + end + it_behaves_like "a logged command", "world" end - it "logs the exit code" do - subject_method - - expect(log_output.join).to include("Exit code: 0") - end - - it "logs the stdout" do - subject_method - - expect(log_output.join).to include('Stdout: "world"') + context "when command is executed in a block" do + def subject_method + sh { echo("world") } + end + it_behaves_like "a logged command", "world" end end end From 3b4bae7f103daabf7e214896618e72fa6f273630 Mon Sep 17 00:00:00 2001 From: Albert Alef Date: Mon, 9 Mar 2026 22:18:21 -0300 Subject: [PATCH 2/3] refactor: making tests follow the contributing md --- spec/debugger_spec.rb | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/spec/debugger_spec.rb b/spec/debugger_spec.rb index 16d24f7..7c25fc1 100644 --- a/spec/debugger_spec.rb +++ b/spec/debugger_spec.rb @@ -12,15 +12,34 @@ expect(subject_method).to eq(expected_output) end - it "logs all debug information" do + it "logs the command executed" do subject_method - log = log_output.join - expect(log).to include("Executed: echo #{expected_output}") - expect(log).to match(/Duration: \d+\.\d+s/) - expect(log).to match(/Pid: \d+/) - expect(log).to include("Exit code: 0") - expect(log).to include("Stdout: \"#{expected_output}\"") + expect(log_output.join).to include("Executed: echo #{expected_output}") + end + + it "logs the duration" do + subject_method + + expect(log_output.join).to match(/Duration: \d+\.\d+s/) + end + + it "logs the pid" do + subject_method + + expect(log_output.join).to match(/Pid: \d+/) + end + + it "logs the exit code" do + subject_method + + expect(log_output.join).to include("Exit code: 0") + end + + it "logs the stdout" do + subject_method + + expect(log_output.join).to include("Stdout: \"#{expected_output}\"") end end From 6bc7822eb2d627cc8c36fad238b2f5420d310086 Mon Sep 17 00:00:00 2001 From: Albert Alef Date: Mon, 9 Mar 2026 22:19:51 -0300 Subject: [PATCH 3/3] refactor: remove not necessary comment --- lib/rubyshell.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/rubyshell.rb b/lib/rubyshell.rb index 94f9f54..c97ade9 100644 --- a/lib/rubyshell.rb +++ b/lib/rubyshell.rb @@ -27,7 +27,6 @@ def debug=(value) def debug(value = true) # rubocop:disable Style/OptionalBooleanParameter previous_value = @debug_mode - # Default to the value of @debug_mode if value is nil @debug_mode = value.nil? ? @debug_mode : value result = yield