diff --git a/README.md b/README.md index 317902a..320d998 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,16 @@ The default timeout of 5 seconds can be overridden: Snitcher.snitch("c2354d53d2", timeout: 10) ``` +Passing a block will set the `status` to `0` on success. If the block raises +an execption, `status` will get set to `1` and `message` will get set to the +exceptions's message. + +```ruby +Snitcher.snitch("c2354d53d2") do + # your code here +end +``` + ## API Access ### Setup diff --git a/lib/snitcher.rb b/lib/snitcher.rb index 9fd9536..93678a4 100644 --- a/lib/snitcher.rb +++ b/lib/snitcher.rb @@ -23,34 +23,22 @@ module Snitcher # @option opts [Float, Fixnum] :timeout Number of seconds to wait for a # response from the server. Default is 5 seconds. # + # @yield When a block is given, the block is executed. If the block raises an + # exception, the exception message is used as the check-in message and the stauts + # is set to 1. If the block succeeds, the status is set to 0. + # # @example # Snitch.snitch("c2354d53d2") # # => true # + # @example + # Snitch.snitch("c2354d53d2") do + # # do something + # end + # # @return [Boolean] if the check-in succeeded. - def snitch!(token, opts = {}) - params = {} - params[:m] = opts[:message] if opts[:message] - - # It's unnecessary to send an empty status - if opts[:status] && opts[:status] != "" - params[:s] = opts[:status] - end - - uri = URI.parse(checkin_url(opts, token)) - if params.any? - uri.query = URI.encode_www_form(params) - end - - opts = initialize_opts(opts, uri) - - Net::HTTP.start(uri.host, uri.port, opts) do |http| - request = Net::HTTP::Get.new(uri.request_uri) - request["User-Agent"] = user_agent - - response = http.request(request) - response.is_a?(Net::HTTPSuccess) - end + def snitch!(token, opts = {}, &block) + process_snitch(true, token, opts, &block) end # Check-in to Dead Man's Snitch. @@ -70,15 +58,22 @@ def snitch!(token, opts = {}) # @option opts [Float, Fixnum] :timeout Number of seconds to wait for a # response from the server. Default is 5 seconds. # + # @yield When a block is given, the block is executed. If the block raises an + # exception, the exception message is used as the check-in message and the stauts + # is set to 1. If the block succeeds, the status is set to 0. + # # @example # Snitch.snitch("c2354d53d2") # # => true # + # @example + # Snitch.snitch("c2354d53d2") do + # # do something + # end + # # @return [Boolean] if the check-in succeeded. - def snitch(*args) - snitch!(*args) - rescue StandardError - false + def snitch(token, opts = {}, &block) + process_snitch(false, token, opts, &block) end private @@ -112,6 +107,55 @@ def user_agent "Snitcher; #{engine}/#{RUBY_VERSION}; #{RUBY_PLATFORM}; v#{::Snitcher::VERSION}" end + + def process_snitch(raise_reporting_error, token, opts = {}) + result = false + + # Run the block if given, and set status/message based on the result + block_error = nil + if block_given? + begin + yield + opts[:status] ||= 0 + rescue StandardError => e + block_error = e + opts[:message] ||= e.inspect + opts[:status] ||= 1 + end + end + + begin + params = {} + params[:m] = opts[:message] if opts[:message] + + # It's unnecessary to send an empty status + if opts[:status] && opts[:status] != "" + params[:s] = opts[:status] + end + + uri = URI.parse(checkin_url(opts, token)) + if params.any? + uri.query = URI.encode_www_form(params) + end + + opts = initialize_opts(opts, uri) + + result = Net::HTTP.start(uri.host, uri.port, opts) do |http| + request = Net::HTTP::Get.new(uri.request_uri) + request["User-Agent"] = user_agent + + response = http.request(request) + response.is_a?(Net::HTTPSuccess) + end + rescue StandardError => e + raise(e) if raise_reporting_error + end + + # Re-raise a block error if needed + raise block_error if block_error + + result + end end require "snitcher/version" diff --git a/spec/snitcher_spec.rb b/spec/snitcher_spec.rb index 1b76c39..4825803 100644 --- a/spec/snitcher_spec.rb +++ b/spec/snitcher_spec.rb @@ -66,6 +66,22 @@ expect { Snitcher.snitch!(token) }.to raise_error(Timeout::Error) end + + describe "with a block" do + let(:user_code) { double("block", do_something: true) } + + it "sets code to 0 if the block succeeds" do + Snitcher.snitch!(token) { user_code.do_something } + expect(user_code).to have_received(:do_something) + expect(a_request(:get, "https://nosnch.in/#{token}?s=0")).to have_been_made.once + end + + it "sets code to 1 and message to exception if the block errors" do + expect(user_code).to receive(:do_something_bad).and_raise(ArgumentError, "bad argument") + expect { Snitcher.snitch!(token) { user_code.do_something_bad } }.to raise_error(ArgumentError, "bad argument") + expect(a_request(:get, "https://nosnch.in/#{token}?m=%23%3CArgumentError:%20bad%20argument%3E&s=1")).to have_been_made.once + end + end end describe ".snitch" do @@ -82,6 +98,30 @@ result = Snitcher.snitch(token) expect(result).to be(false) end + + describe "with a block" do + let(:user_code) { double("block", do_something: true) } + + it "sets code to 0 if the block succeeds" do + Snitcher.snitch!(token) { user_code.do_something } + expect(user_code).to have_received(:do_something) + expect(a_request(:get, "https://nosnch.in/#{token}?s=0")).to have_been_made.once + end + + it "sets code to 1 and message to exception if the block errors" do + expect(user_code).to receive(:do_something_bad).and_raise(ArgumentError, "bad argument") + expect { Snitcher.snitch!(token) { user_code.do_something_bad } }.to raise_error(ArgumentError, "bad argument") + expect(a_request(:get, "https://nosnch.in/#{token}?m=%23%3CArgumentError:%20bad%20argument%3E&s=1")).to have_been_made.once + end + + it "does not raise an error if the block succeeds but reporting fails" do + stub_request(:get, "https://nosnch.in/#{token}").to_return(status: 202) + + result = Snitcher.snitch!(token) { user_code.do_something } + expect(user_code).to have_received(:do_something) + expect(result).to be(true) + end + end end describe "inclusion" do