diff --git a/lib/thor/shell.rb b/lib/thor/shell.rb index 4b62a2a82..f3719ce54 100644 --- a/lib/thor/shell.rb +++ b/lib/thor/shell.rb @@ -21,7 +21,7 @@ def shell end module Shell - SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] + SHELL_DELEGATED_METHODS = [:ask, :error, :set_color, :yes?, :no?, :say, :say_error, :say_status, :print_in_columns, :print_table, :print_wrapped, :file_collision, :terminal_width] attr_writer :shell autoload :Basic, File.expand_path("shell/basic", __dir__) diff --git a/lib/thor/shell/basic.rb b/lib/thor/shell/basic.rb index bf5fdf88f..23320db0e 100644 --- a/lib/thor/shell/basic.rb +++ b/lib/thor/shell/basic.rb @@ -103,6 +103,23 @@ def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/) stdout.flush end + # Say (print) an error to the user. If the sentence ends with a whitespace + # or tab character, a new line is not appended (print + flush). Otherwise + # are passed straight to puts (behavior got from Highline). + # + # ==== Example + # say_error("error: something went wrong") + # + def say_error(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) + return if quiet? + + buffer = prepare_message(message, *color) + buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") + + stderr.print(buffer) + stderr.flush + end + # Say a status with the given color and appends the message. Since this # method is used frequently by actions, it allows nil or false to be given # in log_status, avoiding the message from being shown. If a Symbol is diff --git a/spec/shell/basic_spec.rb b/spec/shell/basic_spec.rb index 94cb3cb89..e4e877690 100644 --- a/spec/shell/basic_spec.rb +++ b/spec/shell/basic_spec.rb @@ -190,6 +190,48 @@ def shell end end + describe "#say_error" do + it "prints a message to the user" do + expect($stderr).to receive(:print).with("Running...\n") + shell.say_error("Running...") + end + + it "prints a message to the user without new line if it ends with a whitespace" do + expect($stderr).to receive(:print).with("Running... ") + shell.say_error("Running... ") + end + + it "does not use a new line with whitespace+newline embedded" do + expect($stderr).to receive(:print).with("It's \nRunning...\n") + shell.say_error("It's \nRunning...") + end + + it "prints a message to the user without new line" do + expect($stderr).to receive(:print).with("Running...") + shell.say_error("Running...", nil, false) + end + + it "coerces everything to a string before printing" do + expect($stderr).to receive(:print).with("this_is_not_a_string\n") + shell.say_error(:this_is_not_a_string, nil, true) + end + + it "does not print a message if muted" do + expect($stderr).not_to receive(:print) + shell.mute do + shell.say_error("Running...") + end + end + + it "does not print a message if base is set to quiet" do + shell.base = MyCounter.new [1, 2] + expect(shell.base).to receive(:options).and_return(:quiet => true) + + expect($stderr).not_to receive(:print) + shell.say_error("Running...") + end + end + describe "#print_wrapped" do let(:message) do "Creates a back-up of the given folder by compressing it in a .tar.gz\n"\