diff --git a/lib/pact/shared/active_support_support.rb b/lib/pact/shared/active_support_support.rb index 0f693ef..2e4826b 100644 --- a/lib/pact/shared/active_support_support.rb +++ b/lib/pact/shared/active_support_support.rb @@ -2,22 +2,28 @@ module Pact module ActiveSupportSupport - extend self def fix_all_the_things thing - if thing.is_a?(Regexp) - fix_regexp(thing) - elsif thing.is_a?(Array) - thing.each{ | it | fix_all_the_things it } - elsif thing.is_a?(Hash) - thing.values.each{ | it | fix_all_the_things it } - elsif thing.class.name.start_with?("Pact") - thing.instance_variables.collect{ | iv_name | thing.instance_variable_get(iv_name)}.each do | iv | - fix_all_the_things iv + if defined?(ActiveSupport) + if thing.is_a?(Regexp) + fix_regexp(thing) + elsif thing.is_a?(Array) + thing.collect{ | it | fix_all_the_things it } + elsif thing.is_a?(Hash) + thing.each_with_object({}) { | (k, v), new_hash | new_hash[k] = fix_all_the_things(v) } + elsif thing.is_a?(Pact::Term) + # matcher Regexp is fixed in its own as_json method + thing + elsif thing.class.name.start_with?("Pact") + warn_about_regexp(thing) + thing + else + thing end + else + thing end - thing end # ActiveSupport JSON overwrites (i.e. TRAMPLES) the json methods of the Regexp class directly @@ -27,10 +33,7 @@ def fix_all_the_things thing # original as_json to the Regexp instances in the ConsumerContract before we write them to the # pact file. If anyone can find a better way, please submit a pull request ASAP! def fix_regexp regexp - def regexp.as_json options = {} - {:json_class => 'Regexp', "o" => self.options, "s" => self.source } - end - regexp + {:json_class => 'Regexp', "o" => regexp.options, "s" => regexp.source } end # Having Active Support JSON loaded somehow kills the formatting of pretty_generate for objects. @@ -49,5 +52,14 @@ def remove_unicode json json.gsub(/\\u([0-9A-Za-z]{4})/) {|s| [$1.to_i(16)].pack("U")} end + def warn_about_regexp(thing) + thing.instance_variables.each do | iv_name | + iv = thing.instance_variable_get(iv_name) + if iv.is_a?(Regexp) + require 'pact/configuration' + Pact.configuration.error_stream.puts("WARN: Instance variable #{iv_name} for class #{thing.class.name} is a Regexp and isn't been serialized properly. Please raise an issue at https://github.com/pact-foundation/pact-support/issues/new.") + end + end + end end end diff --git a/lib/pact/term.rb b/lib/pact/term.rb index 388dbd9..b2b4d05 100644 --- a/lib/pact/term.rb +++ b/lib/pact/term.rb @@ -31,7 +31,7 @@ def initialize(attributes = {}) end def to_hash - { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher)} } + { json_class: self.class.name, data: { generate: generate, matcher: fix_regexp(matcher) } } end def as_json(options = {}) diff --git a/spec/lib/pact/consumer_contract/active_support_support_spec.rb b/spec/lib/pact/consumer_contract/active_support_support_spec.rb index 338f015..a441662 100644 --- a/spec/lib/pact/consumer_contract/active_support_support_spec.rb +++ b/spec/lib/pact/consumer_contract/active_support_support_spec.rb @@ -1,24 +1,28 @@ -require 'spec_helper' require 'pact/shared/active_support_support' +require 'pact/configuration' module Pact - describe ActiveSupportSupport do - include ActiveSupportSupport + class TestClassWithRegexpInstanceVariables + attr_accessor :pattern, :not_pattern + def initialize + @pattern = /foo/ + @not_pattern = "bar" + end + end + describe ActiveSupportSupport do + include ActiveSupportSupport describe "fix_regexp" do let(:regexp) { /moose/ } subject { fix_regexp regexp } - it "returns the original regexp" do - expect(subject).to be(regexp) - end - it "fixes the as_json method for Regexp that ActiveSupport tramples beneath its destructive hooves of destruction" do expect(subject.to_json).to eq("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"moose\"}") end + end describe "fix_all_the_things" do @@ -28,16 +32,36 @@ module Pact subject { fix_all_the_things(hash) } - it "returns the original object" do - expect(subject).to be(hash) - end - it "finds all the Regexp objects in hashes or Pact class attributes and fixes the as_json method" do json = subject.to_json expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"a*b\"}") expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"blah\"}") expect(json).to include("{\"json_class\":\"Regexp\",\"o\":0,\"s\":\"alligator\"}") end + + context "with Pact class that have Regexp instance variables" do + before do + allow(Pact).to receive_message_chain(:configuration, :error_stream).and_return(error_stream) + end + + let(:error_stream) { double('stream', puts: nil) } + let(:thing_to_serialize) do + { + something: { + blah: [ TestClassWithRegexpInstanceVariables.new ] + } + } + end + + subject { fix_all_the_things(thing_to_serialize) } + + context "when ActiveSupportSupport is defined" do + it "prints a warning", skip: ENV['LOAD_ACTIVE_SUPPORT'] != 'true' do + expect(error_stream).to receive(:puts).with("WARN: Instance variable @pattern for class Pact::TestClassWithRegexpInstanceVariables is a Regexp and isn't been serialized properly. Please raise an issue at https://github.com/pact-foundation/pact-support/issues/new.") + subject.to_json + end + end + end end describe "fix_json_formatting" do