From 9a4fa0ce26c7f5acfac036ebc95459fef8c5392e Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 12:20:22 +0100 Subject: [PATCH 01/13] custom error formatter for KeywordArgs problem: - it is impossible to quickly understand the contract violation with big hashes solution: - provide custom error formatter just for keywordargs, that gives you extra information about: - Missing Contract definition (for unspecified keys in contract) - Invalid Args (validation failures) - Missing Args (required values, that are missing) --- lib/contracts.rb | 18 +---- lib/contracts/error_formatter.rb | 124 +++++++++++++++++++++++++++++++ spec/error_formatter_spec.rb | 64 ++++++++++++++++ spec/fixtures/fixtures.rb | 5 ++ 4 files changed, 195 insertions(+), 16 deletions(-) create mode 100644 lib/contracts/error_formatter.rb create mode 100644 spec/error_formatter_spec.rb diff --git a/lib/contracts.rb b/lib/contracts.rb index f7367d5..d4c447a 100644 --- a/lib/contracts.rb +++ b/lib/contracts.rb @@ -1,6 +1,7 @@ require "contracts/builtin_contracts" require "contracts/decorators" require "contracts/errors" +require "contracts/error_formatter" require "contracts/formatters" require "contracts/invariants" require "contracts/method_reference" @@ -115,22 +116,7 @@ def to_s # This function is used by the default #failure_callback method # and uses the hash passed into the failure_callback method. def self.failure_msg(data) - expected = Contracts::Formatters::Expected.new(data[:contract]).contract - position = Contracts::Support.method_position(data[:method]) - method_name = Contracts::Support.method_name(data[:method]) - - header = if data[:return_value] - "Contract violation for return value:" - else - "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:" - end - - %{#{header} - Expected: #{expected}, - Actual: #{data[:arg].inspect} - Value guarded in: #{data[:class]}::#{method_name} - With Contract: #{data[:contracts]} - At: #{position} } + Contracts::ErrorFormatters.failure_msg(data) end # Callback for when a contract fails. By default it raises diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb new file mode 100644 index 0000000..f0a653f --- /dev/null +++ b/lib/contracts/error_formatter.rb @@ -0,0 +1,124 @@ +module Contracts + class ErrorFormatters + def self.failure_msg(data) + class_for(data).new(data).message + end + + def self.class_for(data) + return Contracts::KeywordArgsErrorFormatter if is_keysword_args?(data) + return DefaultErrorFormatter + end + + def self.is_keysword_args?(data) + data[:contract].is_a?(Contracts::Builtin::KeywordArgs) && data[:arg].is_a?(Hash) + end + end + + class DefaultErrorFormatter + include Contracts::Colorize + attr_accessor :data + def initialize(data) + @data = data + end + + def message + %{#{header} + Expected: #{expected}, + Actual: #{data[:arg].inspect} + Value guarded in: #{data[:class]}::#{method_name} + With Contract: #{data[:contracts]} + At: #{green(position)} } + end + + private + def header + if data[:return_value] + "Contract violation for return value:" + else + "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:" + end + end + + def expected + Contracts::Formatters::Expected.new(data[:contract]).contract + end + + def position + Contracts::Support.method_position(data[:method]) + end + + def method_name + Contracts::Support.method_name(data[:method]) + end + end + + class KeywordArgsErrorFormatter < DefaultErrorFormatter + def message + s = [] + s << header + s << "Expected: #{expected}" + s << "Actual: #{data[:arg].inspect}" + s << "Missing Contract: #{missing_contract_info}" if !missing_contract_info.empty? + s << "Invalid Args: #{invalid_args_info}" if !invalid_args_info.empty? + s << "Missing Args: #{missing_args_info}" if !missing_args_info.empty? + s << "Value guarded in: #{data[:class]}::#{method_name}" + s << "With Contract: #{data[:contracts]}" + s << "At: #{position}" + + s.join("\n") + end + + private + + def missing_args_info + @missing_args_info ||= begin + missing_keys = contract_options.keys - arg.keys + contract_options.select do |key, value| + missing_keys.include?(key) + end + end + end + + def missing_contract_info + @missing_contract_info ||= begin + contract_keys = contract_options.keys + arg.select{|key, value| !contract_keys.include?(key)} + end + end + + def invalid_args_info + @invalid_args_info ||= begin + invalid_keys = [] + arg.each do |key, value| + if contract = contract_options[key] + if !(check_contract(contract, value)) + invalid_keys.push(key) + end + end + end + invalid_keys.map do |key| + {key => arg[key], :contract => contract_options[key] } + end + end + end + + def check_contract(contract, value) + if contract.respond_to?(:valid?) + contract.valid?(value) + else + value.is_a?(contract) + end + rescue + false + end + + + def contract_options + @contract_options ||= data[:contract].send(:options) + end + + def arg + data[:arg] + end + end +end diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb new file mode 100644 index 0000000..6a3828f --- /dev/null +++ b/spec/error_formatter_spec.rb @@ -0,0 +1,64 @@ +RSpec.describe "Contracts::ErrorFormatters" do + before :all do + @o = GenericExample.new + end + + describe "self.class_for" do + it "returns the right formatter for passed in data" do + end + end + + def format_message(str) + str.split("\n").map(&:strip).join("\n") + end + + describe "self.failure_msg" do + it "includes normal information" do + expect do + @o.simple_keywordargs(age: "2", invalid_third: 1) + end.to raise_error do |e| + error_msg = %Q{Contract violation for argument 1 of 1: +Expected: (KeywordArgs[{:name=>String, :age=>Fixnum}]) +Actual: {:age=>"2", :invalid_third=>1} +Missing Contract: {:invalid_third=>1} +Invalid Args: [{:age=>"2", :contract=>Fixnum}] +Missing Args: {:name=>String} +Value guarded in: GenericExample::simple_keywordargs +With Contract: KeywordArgs => NilClass} + + expect(e.class).to eq(ParamContractError) + expect(format_message(e.message)).to include(format_message(error_msg)) + end + end + + it "includes Missing Contract information" do + expect do + @o.simple_keywordargs(age: "2", invalid_third: 1, invalid_fourth: 1) + end.to raise_error do |e| + diff_msg = %Q{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} + expect(e.class).to eq(ParamContractError) + expect(e.message).to include(diff_msg) + end + end + + it "includes Invalid Args information" do + expect do + @o.simple_keywordargs(age: "2", invalid_third: 1) + end.to raise_error do |e| + diff_msg = %Q{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} + expect(e.class).to eq(ParamContractError) + expect(e.message).to include(diff_msg) + end + end + + it "includes Missing Args information" do + expect do + @o.simple_keywordargs(age: "2", invalid_third: 1) + end.to raise_error do |e| + diff_msg = %Q{Missing Args: {:name=>String}} + expect(e.class).to eq(ParamContractError) + expect(e.message).to include(diff_msg) + end + end + end +end diff --git a/spec/fixtures/fixtures.rb b/spec/fixtures/fixtures.rb index b6d2bea..5f0d727 100644 --- a/spec/fixtures/fixtures.rb +++ b/spec/fixtures/fixtures.rb @@ -132,6 +132,11 @@ def person_keywordargs(name, age) def hash_keywordargs(data) end + Contract C::KeywordArgs[:name => String, :age => Fixnum] => nil + def simple_keywordargs(name:, age:) + end + + Contract (/foo/) => nil def should_contain_foo(s) end From a7a2e1642c3581b58a49019e270d005af23a020d Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 12:24:22 +0100 Subject: [PATCH 02/13] fix: remove Contracts::Colorize (was used before) --- lib/contracts/error_formatter.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index f0a653f..5a25b23 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -15,7 +15,6 @@ def self.is_keysword_args?(data) end class DefaultErrorFormatter - include Contracts::Colorize attr_accessor :data def initialize(data) @data = data From 3ff321944f0e9f02022b8c5d15e92ed0d3f3e8f9 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 12:29:30 +0100 Subject: [PATCH 03/13] fix: dont use new hash args to keep compatibility with Ruby 1.8 --- spec/fixtures/fixtures.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/fixtures/fixtures.rb b/spec/fixtures/fixtures.rb index 5f0d727..18ad975 100644 --- a/spec/fixtures/fixtures.rb +++ b/spec/fixtures/fixtures.rb @@ -133,7 +133,7 @@ def hash_keywordargs(data) end Contract C::KeywordArgs[:name => String, :age => Fixnum] => nil - def simple_keywordargs(name:, age:) + def simple_keywordargs(data) end From d0d3711ffacefc85d69d29ca42078fc9ef9d1ae9 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 12:30:02 +0100 Subject: [PATCH 04/13] change message building logic for default_error_formatter for consistency --- lib/contracts/error_formatter.rb | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index 5a25b23..2eb8028 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -21,12 +21,15 @@ def initialize(data) end def message - %{#{header} - Expected: #{expected}, - Actual: #{data[:arg].inspect} - Value guarded in: #{data[:class]}::#{method_name} - With Contract: #{data[:contracts]} - At: #{green(position)} } + s = [] + s << header + s << "Expected: #{expected}" + s << "Actual: #{data[:arg].inspect}" + s << "Value guarded in: #{data[:class]}::#{method_name}" + s << "With Contract: #{data[:contracts]}" + s << "At: #{position}" + + s.join("\n") end private From c65e92f224ac79fff1d8d3fd2f899ae47793421d Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 13:05:28 +0100 Subject: [PATCH 05/13] adjust error formatting just for cucumber specs --- lib/contracts/error_formatter.rb | 33 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index 2eb8028..a751917 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -21,15 +21,12 @@ def initialize(data) end def message - s = [] - s << header - s << "Expected: #{expected}" - s << "Actual: #{data[:arg].inspect}" - s << "Value guarded in: #{data[:class]}::#{method_name}" - s << "With Contract: #{data[:contracts]}" - s << "At: #{position}" - - s.join("\n") + %{#{header} + Expected: #{expected}, + Actual: #{data[:arg].inspect} + Value guarded in: #{data[:class]}::#{method_name} + With Contract: #{data[:contracts]} + At: #{position} } end private @@ -57,15 +54,15 @@ def method_name class KeywordArgsErrorFormatter < DefaultErrorFormatter def message s = [] - s << header - s << "Expected: #{expected}" - s << "Actual: #{data[:arg].inspect}" - s << "Missing Contract: #{missing_contract_info}" if !missing_contract_info.empty? - s << "Invalid Args: #{invalid_args_info}" if !invalid_args_info.empty? - s << "Missing Args: #{missing_args_info}" if !missing_args_info.empty? - s << "Value guarded in: #{data[:class]}::#{method_name}" - s << "With Contract: #{data[:contracts]}" - s << "At: #{position}" + s << "#{header}" + s << " Expected: #{expected}" + s << " Actual: #{data[:arg].inspect}" + s << " Missing Contract: #{missing_contract_info}" if !missing_contract_info.empty? + s << " Invalid Args: #{invalid_args_info}" if !invalid_args_info.empty? + s << " Missing Args: #{missing_args_info}" if !missing_args_info.empty? + s << " Value guarded in: #{data[:class]}::#{method_name}" + s << " With Contract: #{data[:contracts]}" + s << " At: #{position} " s.join("\n") end From 6d839f6ee97858a57be9bbd10c4fc71e5dda1abb Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 13:41:08 +0100 Subject: [PATCH 06/13] please rubocop --- lib/contracts/error_formatter.rb | 36 +++++++++++++++----------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index a751917..e3d0f2f 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -5,11 +5,11 @@ def self.failure_msg(data) end def self.class_for(data) - return Contracts::KeywordArgsErrorFormatter if is_keysword_args?(data) - return DefaultErrorFormatter + return Contracts::KeywordArgsErrorFormatter if keysword_args?(data) + DefaultErrorFormatter end - def self.is_keysword_args?(data) + def self.keysword_args?(data) data[:contract].is_a?(Contracts::Builtin::KeywordArgs) && data[:arg].is_a?(Hash) end end @@ -29,13 +29,14 @@ def message At: #{position} } end - private + private + def header if data[:return_value] - "Contract violation for return value:" - else - "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:" - end + "Contract violation for return value:" + else + "Contract violation for argument #{data[:arg_pos]} of #{data[:total_args]}:" + end end def expected @@ -57,9 +58,9 @@ def message s << "#{header}" s << " Expected: #{expected}" s << " Actual: #{data[:arg].inspect}" - s << " Missing Contract: #{missing_contract_info}" if !missing_contract_info.empty? - s << " Invalid Args: #{invalid_args_info}" if !invalid_args_info.empty? - s << " Missing Args: #{missing_args_info}" if !missing_args_info.empty? + s << " Missing Contract: #{missing_contract_info}" unless missing_contract_info.empty? + s << " Invalid Args: #{invalid_args_info}" unless invalid_args_info.empty? + s << " Missing Args: #{missing_args_info}" unless missing_args_info.empty? s << " Value guarded in: #{data[:class]}::#{method_name}" s << " With Contract: #{data[:contracts]}" s << " At: #{position} " @@ -72,7 +73,7 @@ def message def missing_args_info @missing_args_info ||= begin missing_keys = contract_options.keys - arg.keys - contract_options.select do |key, value| + contract_options.select do |key, _value| missing_keys.include?(key) end end @@ -81,7 +82,7 @@ def missing_args_info def missing_contract_info @missing_contract_info ||= begin contract_keys = contract_options.keys - arg.select{|key, value| !contract_keys.include?(key)} + arg.select { |key, _value| !contract_keys.include?(key) } end end @@ -89,11 +90,9 @@ def invalid_args_info @invalid_args_info ||= begin invalid_keys = [] arg.each do |key, value| - if contract = contract_options[key] - if !(check_contract(contract, value)) - invalid_keys.push(key) - end - end + contract = contract_options[key] + next unless contract + invalid_keys.push(key) unless check_contract(contract, value) end invalid_keys.map do |key| {key => arg[key], :contract => contract_options[key] } @@ -111,7 +110,6 @@ def check_contract(contract, value) false end - def contract_options @contract_options ||= data[:contract].send(:options) end From 759ff79ed9bb5daecb2805e63bb3843cf6ac284f Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 13:50:41 +0100 Subject: [PATCH 07/13] further rubocop pleasing... --- spec/error_formatter_spec.rb | 47 +++++++++++++++--------------------- spec/fixtures/fixtures.rb | 1 - 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb index 6a3828f..85fe696 100644 --- a/spec/error_formatter_spec.rb +++ b/spec/error_formatter_spec.rb @@ -12,52 +12,43 @@ def format_message(str) str.split("\n").map(&:strip).join("\n") end + def fails(msg, &block) + expect { block.call }.to raise_error do |e| + expect(e).to be_a(ParamContractError) + expect(format_message(e.message)).to include(format_message(msg)) + end + end + describe "self.failure_msg" do it "includes normal information" do - expect do + msg = %{Contract violation for argument 1 of 1: + Expected: (KeywordArgs[{:name=>String, :age=>Fixnum}]) + Actual: {:age=>"2", :invalid_third=>1} + Missing Contract: {:invalid_third=>1} + Invalid Args: [{:age=>"2", :contract=>Fixnum}] + Missing Args: {:name=>String} + Value guarded in: GenericExample::simple_keywordargs + With Contract: KeywordArgs => NilClass} + fails msg do @o.simple_keywordargs(age: "2", invalid_third: 1) - end.to raise_error do |e| - error_msg = %Q{Contract violation for argument 1 of 1: -Expected: (KeywordArgs[{:name=>String, :age=>Fixnum}]) -Actual: {:age=>"2", :invalid_third=>1} -Missing Contract: {:invalid_third=>1} -Invalid Args: [{:age=>"2", :contract=>Fixnum}] -Missing Args: {:name=>String} -Value guarded in: GenericExample::simple_keywordargs -With Contract: KeywordArgs => NilClass} - - expect(e.class).to eq(ParamContractError) - expect(format_message(e.message)).to include(format_message(error_msg)) end end it "includes Missing Contract information" do - expect do + fails %{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} do @o.simple_keywordargs(age: "2", invalid_third: 1, invalid_fourth: 1) - end.to raise_error do |e| - diff_msg = %Q{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} - expect(e.class).to eq(ParamContractError) - expect(e.message).to include(diff_msg) end end it "includes Invalid Args information" do - expect do + fails %{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} do @o.simple_keywordargs(age: "2", invalid_third: 1) - end.to raise_error do |e| - diff_msg = %Q{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} - expect(e.class).to eq(ParamContractError) - expect(e.message).to include(diff_msg) end end it "includes Missing Args information" do - expect do + fails %{Missing Args: {:name=>String}} do @o.simple_keywordargs(age: "2", invalid_third: 1) - end.to raise_error do |e| - diff_msg = %Q{Missing Args: {:name=>String}} - expect(e.class).to eq(ParamContractError) - expect(e.message).to include(diff_msg) end end end diff --git a/spec/fixtures/fixtures.rb b/spec/fixtures/fixtures.rb index 18ad975..4272a2d 100644 --- a/spec/fixtures/fixtures.rb +++ b/spec/fixtures/fixtures.rb @@ -136,7 +136,6 @@ def hash_keywordargs(data) def simple_keywordargs(data) end - Contract (/foo/) => nil def should_contain_foo(s) end From 20c0e37bbb6915ec32854523d1de7211900b09e0 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 14:02:02 +0100 Subject: [PATCH 08/13] fixes for ruby 1.8 --- spec/error_formatter_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb index 85fe696..2eac385 100644 --- a/spec/error_formatter_spec.rb +++ b/spec/error_formatter_spec.rb @@ -30,25 +30,25 @@ def fails(msg, &block) Value guarded in: GenericExample::simple_keywordargs With Contract: KeywordArgs => NilClass} fails msg do - @o.simple_keywordargs(age: "2", invalid_third: 1) + @o.simple_keywordargs(:age => "2", :invalid_third => 1) end end it "includes Missing Contract information" do fails %{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} do - @o.simple_keywordargs(age: "2", invalid_third: 1, invalid_fourth: 1) + @o.simple_keywordargs(:age => "2", :invalid_third => 1, :invalid_fourth => 1) end end it "includes Invalid Args information" do fails %{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} do - @o.simple_keywordargs(age: "2", invalid_third: 1) + @o.simple_keywordargs(:age => "2", :invalid_third => 1) end end it "includes Missing Args information" do fails %{Missing Args: {:name=>String}} do - @o.simple_keywordargs(age: "2", invalid_third: 1) + @o.simple_keywordargs(:age => "2", :invalid_third => 1) end end end From 7adfdc44e7044a3acf720ca3a688c0c343f4365e Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Wed, 21 Dec 2016 14:20:56 +0100 Subject: [PATCH 09/13] not gonna please ruby 1.8 anymore, it is ridiculous. run error_formatter_spec only for rubies > 1.8 --- spec/error_formatter_spec.rb | 50 +++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 24 deletions(-) diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb index 2eac385..41c23db 100644 --- a/spec/error_formatter_spec.rb +++ b/spec/error_formatter_spec.rb @@ -19,36 +19,38 @@ def fails(msg, &block) end end - describe "self.failure_msg" do - it "includes normal information" do - msg = %{Contract violation for argument 1 of 1: - Expected: (KeywordArgs[{:name=>String, :age=>Fixnum}]) - Actual: {:age=>"2", :invalid_third=>1} - Missing Contract: {:invalid_third=>1} - Invalid Args: [{:age=>"2", :contract=>Fixnum}] - Missing Args: {:name=>String} - Value guarded in: GenericExample::simple_keywordargs - With Contract: KeywordArgs => NilClass} - fails msg do - @o.simple_keywordargs(:age => "2", :invalid_third => 1) + if ruby_version > 1.8 + describe "self.failure_msg" do + it "includes normal information" do + msg = %{Contract violation for argument 1 of 1: + Expected: (KeywordArgs[{:name=>String, :age=>Fixnum}]) + Actual: {:age=>"2", :invalid_third=>1} + Missing Contract: {:invalid_third=>1} + Invalid Args: [{:age=>"2", :contract=>Fixnum}] + Missing Args: {:name=>String} + Value guarded in: GenericExample::simple_keywordargs + With Contract: KeywordArgs => NilClass} + fails msg do + @o.simple_keywordargs(:age => "2", :invalid_third => 1) + end end - end - it "includes Missing Contract information" do - fails %{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} do - @o.simple_keywordargs(:age => "2", :invalid_third => 1, :invalid_fourth => 1) + it "includes Missing Contract information" do + fails %{Missing Contract: {:invalid_third=>1, :invalid_fourth=>1}} do + @o.simple_keywordargs(:age => "2", :invalid_third => 1, :invalid_fourth => 1) + end end - end - it "includes Invalid Args information" do - fails %{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} do - @o.simple_keywordargs(:age => "2", :invalid_third => 1) + it "includes Invalid Args information" do + fails %{Invalid Args: [{:age=>"2", :contract=>Fixnum}]} do + @o.simple_keywordargs(:age => "2", :invalid_third => 1) + end end - end - it "includes Missing Args information" do - fails %{Missing Args: {:name=>String}} do - @o.simple_keywordargs(:age => "2", :invalid_third => 1) + it "includes Missing Args information" do + fails %{Missing Args: {:name=>String}} do + @o.simple_keywordargs(:age => "2", :invalid_third => 1) + end end end end From 4208b2313920383666b0770c2725691285d69cae Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Thu, 22 Dec 2016 10:34:08 +0100 Subject: [PATCH 10/13] fixes typo: keywords_args? -> keyword_args? --- lib/contracts/error_formatter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index e3d0f2f..2bb9577 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -5,11 +5,11 @@ def self.failure_msg(data) end def self.class_for(data) - return Contracts::KeywordArgsErrorFormatter if keysword_args?(data) + return Contracts::KeywordArgsErrorFormatter if keyword_args?(data) DefaultErrorFormatter end - def self.keysword_args?(data) + def self.keyword_args?(data) data[:contract].is_a?(Contracts::Builtin::KeywordArgs) && data[:arg].is_a?(Hash) end end From fabfe6a890be3fad9863b4a067d038fc7d4b2fe6 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Thu, 22 Dec 2016 10:45:21 +0100 Subject: [PATCH 11/13] replace: _value -> _ --- lib/contracts/error_formatter.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/contracts/error_formatter.rb b/lib/contracts/error_formatter.rb index 2bb9577..94d4834 100644 --- a/lib/contracts/error_formatter.rb +++ b/lib/contracts/error_formatter.rb @@ -73,7 +73,7 @@ def message def missing_args_info @missing_args_info ||= begin missing_keys = contract_options.keys - arg.keys - contract_options.select do |key, _value| + contract_options.select do |key, _| missing_keys.include?(key) end end @@ -82,7 +82,7 @@ def missing_args_info def missing_contract_info @missing_contract_info ||= begin contract_keys = contract_options.keys - arg.select { |key, _value| !contract_keys.include?(key) } + arg.select { |key, _| !contract_keys.include?(key) } end end From 1630fb5719aa7509f8080d20c5901a4f9731680e Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Thu, 22 Dec 2016 11:14:44 +0100 Subject: [PATCH 12/13] specs for Contracts::ErrorFormatters.class_for --- spec/error_formatter_spec.rb | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb index 41c23db..4ed7589 100644 --- a/spec/error_formatter_spec.rb +++ b/spec/error_formatter_spec.rb @@ -2,9 +2,20 @@ before :all do @o = GenericExample.new end + C = Contracts::Builtin describe "self.class_for" do - it "returns the right formatter for passed in data" do + let(:keywordargs_contract) {C::KeywordArgs[:name => String, :age => Fixnum]} + let(:other_contract) {[C::Num, C::Num, C::Num]} + + it "returns KeywordArgsErrorFormatter for KeywordArgs contract" do + data_keywordargs = {:contract => keywordargs_contract, :arg => {:b => 2}} + expect(Contracts::ErrorFormatters.class_for(data_keywordargs)).to eq(Contracts::KeywordArgsErrorFormatter) + end + + it "returns Contracts::DefaultErrorFormatter for other contracts" do + data_default = {:contract => other_contract, :arg => {:b => 2}} + expect(Contracts::ErrorFormatters.class_for(data_default)).to eq(Contracts::DefaultErrorFormatter) end end From 04f5fb4749d60050e2f9c4dabd1d2d0ab7fe4243 Mon Sep 17 00:00:00 2001 From: Roman Heinrich Date: Thu, 22 Dec 2016 11:33:46 +0100 Subject: [PATCH 13/13] for rubocop --- spec/error_formatter_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/error_formatter_spec.rb b/spec/error_formatter_spec.rb index 4ed7589..c9023d4 100644 --- a/spec/error_formatter_spec.rb +++ b/spec/error_formatter_spec.rb @@ -5,8 +5,8 @@ C = Contracts::Builtin describe "self.class_for" do - let(:keywordargs_contract) {C::KeywordArgs[:name => String, :age => Fixnum]} - let(:other_contract) {[C::Num, C::Num, C::Num]} + let(:keywordargs_contract) { C::KeywordArgs[:name => String, :age => Fixnum] } + let(:other_contract) { [C::Num, C::Num, C::Num] } it "returns KeywordArgsErrorFormatter for KeywordArgs contract" do data_keywordargs = {:contract => keywordargs_contract, :arg => {:b => 2}}