shoulda-matchers 4.2.0 → 4.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/{MIT-LICENSE → LICENSE} +1 -1
  3. data/README.md +167 -85
  4. data/lib/shoulda/matchers/action_controller/callback_matcher.rb +4 -2
  5. data/lib/shoulda/matchers/action_controller/filter_param_matcher.rb +3 -2
  6. data/lib/shoulda/matchers/action_controller/permit_matcher.rb +26 -21
  7. data/lib/shoulda/matchers/action_controller/redirect_to_matcher.rb +6 -8
  8. data/lib/shoulda/matchers/action_controller/render_template_matcher.rb +6 -8
  9. data/lib/shoulda/matchers/action_controller/render_with_layout_matcher.rb +16 -13
  10. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +2 -1
  11. data/lib/shoulda/matchers/action_controller/route_matcher.rb +5 -6
  12. data/lib/shoulda/matchers/action_controller/route_params.rb +1 -1
  13. data/lib/shoulda/matchers/action_controller/set_session_or_flash_matcher.rb +19 -13
  14. data/lib/shoulda/matchers/active_model/allow_mass_assignment_of_matcher.rb +18 -16
  15. data/lib/shoulda/matchers/active_model/allow_value_matcher.rb +29 -27
  16. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_changed_value_error.rb +1 -1
  17. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter.rb +5 -5
  18. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setter_and_validator.rb +2 -2
  19. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters.rb +1 -1
  20. data/lib/shoulda/matchers/active_model/allow_value_matcher/attribute_setters_and_validators.rb +1 -1
  21. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +1 -1
  22. data/lib/shoulda/matchers/active_model/have_secure_password_matcher.rb +51 -25
  23. data/lib/shoulda/matchers/active_model/helpers.rb +1 -1
  24. data/lib/shoulda/matchers/active_model/numericality_matchers/comparison_matcher.rb +32 -30
  25. data/lib/shoulda/matchers/active_model/numericality_matchers/numeric_type_matcher.rb +1 -1
  26. data/lib/shoulda/matchers/active_model/qualifiers/ignoring_interference_by_writer.rb +1 -1
  27. data/lib/shoulda/matchers/active_model/validate_absence_of_matcher.rb +9 -1
  28. data/lib/shoulda/matchers/active_model/validate_confirmation_of_matcher.rb +2 -2
  29. data/lib/shoulda/matchers/active_model/validate_exclusion_of_matcher.rb +9 -8
  30. data/lib/shoulda/matchers/active_model/validate_inclusion_of_matcher.rb +28 -46
  31. data/lib/shoulda/matchers/active_model/validate_length_of_matcher.rb +33 -9
  32. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +71 -26
  33. data/lib/shoulda/matchers/active_model/validate_presence_of_matcher.rb +2 -2
  34. data/lib/shoulda/matchers/active_model/validation_matcher.rb +31 -6
  35. data/lib/shoulda/matchers/active_model/validation_matcher/build_description.rb +2 -4
  36. data/lib/shoulda/matchers/active_model/validation_message_finder.rb +2 -4
  37. data/lib/shoulda/matchers/active_model/validator.rb +3 -3
  38. data/lib/shoulda/matchers/active_record.rb +26 -23
  39. data/lib/shoulda/matchers/active_record/accept_nested_attributes_for_matcher.rb +6 -3
  40. data/lib/shoulda/matchers/active_record/association_matcher.rb +118 -47
  41. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +5 -2
  42. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +4 -4
  43. data/lib/shoulda/matchers/active_record/association_matchers/inverse_of_matcher.rb +1 -1
  44. data/lib/shoulda/matchers/active_record/association_matchers/join_table_matcher.rb +11 -6
  45. data/lib/shoulda/matchers/active_record/association_matchers/model_reflection.rb +14 -15
  46. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +30 -8
  47. data/lib/shoulda/matchers/active_record/association_matchers/option_verifier.rb +23 -5
  48. data/lib/shoulda/matchers/active_record/association_matchers/optional_matcher.rb +3 -3
  49. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +1 -1
  50. data/lib/shoulda/matchers/active_record/association_matchers/required_matcher.rb +3 -3
  51. data/lib/shoulda/matchers/active_record/association_matchers/source_matcher.rb +3 -2
  52. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +7 -5
  53. data/lib/shoulda/matchers/active_record/define_enum_for_matcher.rb +8 -8
  54. data/lib/shoulda/matchers/active_record/have_attached_matcher.rb +185 -0
  55. data/lib/shoulda/matchers/active_record/have_db_column_matcher.rb +39 -17
  56. data/lib/shoulda/matchers/active_record/have_db_index_matcher.rb +1 -1
  57. data/lib/shoulda/matchers/active_record/have_implicit_order_column.rb +106 -0
  58. data/lib/shoulda/matchers/active_record/have_readonly_attribute_matcher.rb +12 -10
  59. data/lib/shoulda/matchers/active_record/have_rich_text_matcher.rb +83 -0
  60. data/lib/shoulda/matchers/active_record/have_secure_token_matcher.rb +30 -9
  61. data/lib/shoulda/matchers/active_record/serialize_matcher.rb +13 -9
  62. data/lib/shoulda/matchers/active_record/uniqueness.rb +1 -1
  63. data/lib/shoulda/matchers/active_record/uniqueness/test_model_creator.rb +1 -3
  64. data/lib/shoulda/matchers/active_record/uniqueness/test_models.rb +0 -2
  65. data/lib/shoulda/matchers/active_record/validate_uniqueness_of_matcher.rb +80 -73
  66. data/lib/shoulda/matchers/doublespeak.rb +2 -1
  67. data/lib/shoulda/matchers/doublespeak/double.rb +1 -1
  68. data/lib/shoulda/matchers/doublespeak/double_collection.rb +3 -3
  69. data/lib/shoulda/matchers/doublespeak/double_implementation_registry.rb +8 -5
  70. data/lib/shoulda/matchers/doublespeak/object_double.rb +1 -1
  71. data/lib/shoulda/matchers/doublespeak/stub_implementation.rb +1 -5
  72. data/lib/shoulda/matchers/doublespeak/world.rb +2 -2
  73. data/lib/shoulda/matchers/error.rb +1 -1
  74. data/lib/shoulda/matchers/independent.rb +0 -1
  75. data/lib/shoulda/matchers/independent/delegate_method_matcher.rb +14 -13
  76. data/lib/shoulda/matchers/integrations/configuration.rb +1 -1
  77. data/lib/shoulda/matchers/integrations/libraries/action_controller.rb +1 -1
  78. data/lib/shoulda/matchers/integrations/libraries/rails.rb +2 -2
  79. data/lib/shoulda/matchers/integrations/test_frameworks/active_support_test_case.rb +1 -1
  80. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_4.rb +1 -1
  81. data/lib/shoulda/matchers/integrations/test_frameworks/minitest_5.rb +1 -1
  82. data/lib/shoulda/matchers/integrations/test_frameworks/missing_test_framework.rb +1 -1
  83. data/lib/shoulda/matchers/integrations/test_frameworks/test_unit.rb +1 -1
  84. data/lib/shoulda/matchers/rails_shim.rb +9 -3
  85. data/lib/shoulda/matchers/util.rb +16 -4
  86. data/lib/shoulda/matchers/util/word_wrap.rb +8 -8
  87. data/lib/shoulda/matchers/version.rb +1 -1
  88. data/lib/shoulda/matchers/warn.rb +3 -3
  89. data/shoulda-matchers.gemspec +10 -7
  90. metadata +11 -9
  91. data/lib/shoulda/matchers/independent/delegate_method_matcher/stubbed_target.rb +0 -37
@@ -1,6 +1,6 @@
1
1
  module Shoulda
2
2
  module Matchers
3
- module ActiveModel
3
+ module ActiveRecord
4
4
  # @private
5
5
  module Uniqueness
6
6
  end
@@ -1,5 +1,3 @@
1
- require 'thread'
2
-
3
1
  module Shoulda
4
2
  module Matchers
5
3
  module ActiveRecord
@@ -37,7 +35,7 @@ module Shoulda
37
35
  def new_model
38
36
  @_new_model ||= Model.next_unique_copy_of(
39
37
  model_name_without_namespace,
40
- namespace
38
+ namespace,
41
39
  )
42
40
  end
43
41
 
@@ -1,5 +1,3 @@
1
- require 'thread'
2
-
3
1
  module Shoulda
4
2
  module Matchers
5
3
  module ActiveRecord
@@ -80,7 +80,7 @@ module Shoulda
80
80
  #
81
81
  # RSpec.describe Post, type: :model do
82
82
  # describe "validations" do
83
- # subject { Post.create(content: "Here is the content") }
83
+ # subject { Post.new(content: "Here is the content") }
84
84
  # it { should validate_uniqueness_of(:title) }
85
85
  # end
86
86
  # end
@@ -92,7 +92,7 @@ module Shoulda
92
92
  #
93
93
  # RSpec.describe Post, type: :model do
94
94
  # describe "validations" do
95
- # subject { FactoryBot.create(:post) }
95
+ # subject { FactoryBot.build(:post) }
96
96
  # it { should validate_uniqueness_of(:title) }
97
97
  # end
98
98
  # end
@@ -157,6 +157,12 @@ module Shoulda
157
157
  # should validate_uniqueness_of(:slug).scoped_to(:journal_id)
158
158
  # end
159
159
  #
160
+ # NOTE: Support for testing uniqueness validation scoped to an array of
161
+ # associations is not available.
162
+ #
163
+ # For more information, please refer to
164
+ # https://github.com/thoughtbot/shoulda-matchers/issues/814
165
+ #
160
166
  # ##### case_insensitive
161
167
  #
162
168
  # Use `case_insensitive` to test usage of the `:case_sensitive` option
@@ -264,14 +270,14 @@ module Shoulda
264
270
  super(attribute)
265
271
  @expected_message = :taken
266
272
  @options = {
267
- case_sensitivity_strategy: :sensitive
273
+ case_sensitivity_strategy: :sensitive,
268
274
  }
269
275
  @existing_record_created = false
270
276
  @failure_reason = nil
271
277
  @failure_reason_when_negated = nil
272
278
  @attribute_setters = {
273
279
  existing_record: AttributeSetters.new,
274
- new_record: AttributeSetters.new
280
+ new_record: AttributeSetters.new,
275
281
  }
276
282
  end
277
283
 
@@ -396,7 +402,7 @@ module Shoulda
396
402
  end
397
403
 
398
404
  def validations
399
- model._validators[@attribute].select do |validator|
405
+ model.validators_on(@attribute).select do |validator|
400
406
  validator.is_a?(::ActiveRecord::Validations::UniquenessValidator)
401
407
  end
402
408
  end
@@ -407,11 +413,12 @@ module Shoulda
407
413
  else
408
414
  @failure_reason = 'Expected the validation '
409
415
 
410
- if expected_scopes.empty?
411
- @failure_reason << 'not to be scoped to anything, '
412
- else
413
- @failure_reason << "to be scoped to #{inspected_expected_scopes}, "
414
- end
416
+ @failure_reason <<
417
+ if expected_scopes.empty?
418
+ 'not to be scoped to anything, '
419
+ else
420
+ "to be scoped to #{inspected_expected_scopes}, "
421
+ end
415
422
 
416
423
  if actual_sets_of_scopes.any?
417
424
  @failure_reason << 'but it was scoped to '
@@ -455,7 +462,7 @@ module Shoulda
455
462
  def inspected_actual_scopes
456
463
  inspected_actual_sets_of_scopes.to_sentence(
457
464
  words_connector: ' and ',
458
- last_word_connector: ', and'
465
+ last_word_connector: ', and',
459
466
  )
460
467
  end
461
468
 
@@ -491,7 +498,9 @@ module Shoulda
491
498
  def does_not_match_allow_nil?
492
499
  expects_to_allow_nil? && (
493
500
  update_existing_record!(nil) &&
494
- (@failure_reason = nil || disallows_value_of(nil, @expected_message))
501
+ (@failure_reason = nil ||
502
+ disallows_value_of(nil, @expected_message)
503
+ )
495
504
  )
496
505
  end
497
506
 
@@ -527,21 +536,15 @@ module Shoulda
527
536
  end
528
537
 
529
538
  def find_existing_record
530
- record = model.first
531
-
532
- if record.present?
533
- record
534
- else
535
- nil
536
- end
539
+ model.first.presence
537
540
  end
538
541
 
539
542
  def create_existing_record
540
543
  @given_record.tap do |existing_record|
541
544
  existing_record.save(validate: false)
542
545
  end
543
- rescue ::ActiveRecord::StatementInvalid => error
544
- raise ExistingRecordInvalid.create(underlying_exception: error)
546
+ rescue ::ActiveRecord::StatementInvalid => e
547
+ raise ExistingRecordInvalid.create(underlying_exception: e)
545
548
  end
546
549
 
547
550
  def update_existing_record!(value)
@@ -577,7 +580,7 @@ module Shoulda
577
580
  attribute_names_under_test.each do |attribute_name|
578
581
  set_attribute_on_new_record!(
579
582
  attribute_name,
580
- existing_record.public_send(attribute_name)
583
+ existing_record.public_send(attribute_name),
581
584
  )
582
585
  end
583
586
 
@@ -619,11 +622,12 @@ module Shoulda
619
622
 
620
623
  reason << inspected_scopes.to_sentence
621
624
 
622
- if inspected_scopes.many?
623
- reason << " do not seem to be attributes"
624
- else
625
- reason << " does not seem to be an attribute"
626
- end
625
+ reason <<
626
+ if inspected_scopes.many?
627
+ ' do not seem to be attributes'
628
+ else
629
+ ' does not seem to be an attribute'
630
+ end
627
631
 
628
632
  reason << " on #{model.name}."
629
633
 
@@ -643,11 +647,12 @@ module Shoulda
643
647
 
644
648
  reason << inspected_scopes.to_sentence
645
649
 
646
- if inspected_scopes.many?
647
- reason << " seem to be attributes"
648
- else
649
- reason << " seems to be an attribute"
650
- end
650
+ reason <<
651
+ if inspected_scopes.many?
652
+ ' seem to be attributes'
653
+ else
654
+ ' seems to be an attribute'
655
+ end
651
656
 
652
657
  reason << " on #{model.name}."
653
658
 
@@ -658,14 +663,14 @@ module Shoulda
658
663
  end
659
664
 
660
665
  def scopes_present_on_model
661
- @_present_scopes ||= expected_scopes.select do |scope|
666
+ @_scopes_present_on_model ||= expected_scopes.select do |scope|
662
667
  model.method_defined?("#{scope}=")
663
668
  end
664
669
  end
665
670
 
666
671
  def scopes_missing_on_model
667
- @_missing_scopes ||= expected_scopes.select do |scope|
668
- !model.method_defined?("#{scope}=")
672
+ @_scopes_missing_on_model ||= expected_scopes.reject do |scope|
673
+ model.method_defined?("#{scope}=")
669
674
  end
670
675
  end
671
676
 
@@ -697,7 +702,7 @@ module Shoulda
697
702
  raise NonCaseSwappableValueError.create(
698
703
  model: model,
699
704
  attribute: @attribute,
700
- value: value
705
+ value: value,
701
706
  )
702
707
  end
703
708
 
@@ -724,7 +729,7 @@ module Shoulda
724
729
  raise NonCaseSwappableValueError.create(
725
730
  model: model,
726
731
  attribute: @attribute,
727
- value: value
732
+ value: value,
728
733
  )
729
734
  end
730
735
 
@@ -789,7 +794,7 @@ module Shoulda
789
794
  column = column_for(scope)
790
795
 
791
796
  if column.respond_to?(:array) && column.array
792
- [ dummy_scalar_value_for(column) ]
797
+ [dummy_scalar_value_for(column)]
793
798
  else
794
799
  dummy_scalar_value_for(column)
795
800
  end
@@ -801,7 +806,7 @@ module Shoulda
801
806
 
802
807
  def next_value_for(scope, previous_value)
803
808
  if previous_value.is_a?(Array)
804
- [ next_scalar_value_for(scope, previous_value[0]) ]
809
+ [next_scalar_value_for(scope, previous_value[0])]
805
810
  else
806
811
  next_scalar_value_for(scope, previous_value)
807
812
  end
@@ -820,7 +825,7 @@ module Shoulda
820
825
  elsif previous_value.respond_to?(:next)
821
826
  previous_value.next
822
827
  elsif previous_value.respond_to?(:to_datetime)
823
- previous_value.to_datetime.next
828
+ previous_value.to_datetime.in(60).next
824
829
  elsif boolean_value?(previous_value)
825
830
  !previous_value
826
831
  else
@@ -857,7 +862,7 @@ module Shoulda
857
862
  attribute_setter = build_attribute_setter(
858
863
  record,
859
864
  attribute_name,
860
- value
865
+ value,
861
866
  )
862
867
  attribute_setter.set!
863
868
 
@@ -869,7 +874,7 @@ module Shoulda
869
874
  :existing_record,
870
875
  existing_record,
871
876
  attribute_name,
872
- value
877
+ value,
873
878
  )
874
879
  end
875
880
 
@@ -878,7 +883,7 @@ module Shoulda
878
883
  :new_record,
879
884
  new_record,
880
885
  attribute_name,
881
- value
886
+ value,
882
887
  )
883
888
  end
884
889
 
@@ -896,13 +901,14 @@ module Shoulda
896
901
  end
897
902
 
898
903
  def build_attribute_setter(record, attribute_name, value)
899
- Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeSetter.new(
900
- matcher_name: :validate_uniqueness_of,
901
- object: record,
902
- attribute_name: attribute_name,
903
- value: value,
904
- ignore_interference_by_writer: ignore_interference_by_writer
905
- )
904
+ Shoulda::Matchers::ActiveModel::AllowValueMatcher::AttributeSetter.
905
+ new(
906
+ matcher_name: :validate_uniqueness_of,
907
+ object: record,
908
+ attribute_name: attribute_name,
909
+ value: value,
910
+ ignore_interference_by_writer: ignore_interference_by_writer,
911
+ )
906
912
  end
907
913
 
908
914
  def existing_value_read
@@ -929,7 +935,7 @@ module Shoulda
929
935
  @given_record.class
930
936
  end
931
937
 
932
- def failure_message_preface
938
+ def failure_message_preface # rubocop:disable Metrics/MethodLength
933
939
  prefix = ''
934
940
 
935
941
  if @existing_record_created
@@ -938,30 +944,28 @@ module Shoulda
938
944
  if attribute_setter_for_existing_record
939
945
  prefix << ', setting '
940
946
  prefix << description_for_attribute_setter(
941
- attribute_setter_for_existing_record
947
+ attribute_setter_for_existing_record,
942
948
  )
943
949
  else
944
950
  prefix << ", whose :#{attribute} is "
945
951
  prefix << "‹#{existing_value_read.inspect}›"
946
952
  end
947
953
 
948
- prefix << ", and saving it as the existing record, then"
954
+ prefix << ', and saving it as the existing record, then'
955
+ elsif attribute_setter_for_existing_record
956
+ prefix << "Given an existing #{model.name},"
957
+ prefix << ' after setting '
958
+ prefix << description_for_attribute_setter(
959
+ attribute_setter_for_existing_record,
960
+ )
961
+ prefix << ', then'
949
962
  else
950
- if attribute_setter_for_existing_record
951
- prefix << "Given an existing #{model.name},"
952
- prefix << ' after setting '
953
- prefix << description_for_attribute_setter(
954
- attribute_setter_for_existing_record
955
- )
956
- prefix << ', then'
957
- else
958
- prefix << "Given an existing #{model.name} whose :#{attribute}"
959
- prefix << ' is '
960
- prefix << Shoulda::Matchers::Util.inspect_value(
961
- existing_value_read
962
- )
963
- prefix << ', after'
964
- end
963
+ prefix << "Given an existing #{model.name} whose :#{attribute}"
964
+ prefix << ' is '
965
+ prefix << Shoulda::Matchers::Util.inspect_value(
966
+ existing_value_read,
967
+ )
968
+ prefix << ', after'
965
969
  end
966
970
 
967
971
  prefix << " making a new #{model.name} and setting "
@@ -988,7 +992,10 @@ different altogether.
988
992
  MESSAGE
989
993
  end
990
994
 
991
- def description_for_attribute_setter(attribute_setter, same_as_existing: nil)
995
+ def description_for_attribute_setter(
996
+ attribute_setter,
997
+ same_as_existing: nil
998
+ )
992
999
  description = "its :#{attribute_setter.attribute_name} to "
993
1000
 
994
1001
  if same_as_existing == false
@@ -996,13 +1003,13 @@ different altogether.
996
1003
  end
997
1004
 
998
1005
  description << Shoulda::Matchers::Util.inspect_value(
999
- attribute_setter.value_written
1006
+ attribute_setter.value_written,
1000
1007
  )
1001
1008
 
1002
1009
  if attribute_setter.attribute_changed_value?
1003
1010
  description << ' (read back as '
1004
1011
  description << Shoulda::Matchers::Util.inspect_value(
1005
- attribute_setter.value_read
1012
+ attribute_setter.value_read,
1006
1013
  )
1007
1014
  description << ')'
1008
1015
  end
@@ -1026,7 +1033,7 @@ different altogether.
1026
1033
  )
1027
1034
  description_for_attribute_setter(
1028
1035
  attribute_setter,
1029
- same_as_existing: same_as_existing
1036
+ same_as_existing: same_as_existing,
1030
1037
  )
1031
1038
  end
1032
1039
  end
@@ -1109,7 +1116,7 @@ b) If you meant for the validation to be case-insensitive, then you need to
1109
1116
 
1110
1117
  For more information, please see:
1111
1118
 
1112
- http://matchers.shoulda.io/docs/v#{Shoulda::Matchers::VERSION}/file.NonCaseSwappableValueError.html
1119
+ https://matchers.shoulda.io/docs/v#{Shoulda::Matchers::VERSION}/file.NonCaseSwappableValueError.html
1113
1120
  MESSAGE
1114
1121
  end
1115
1122
  end
@@ -1,4 +1,5 @@
1
1
  require 'forwardable'
2
+ require 'logger'
2
3
 
3
4
  module Shoulda
4
5
  module Matchers
@@ -20,7 +21,7 @@ module Shoulda
20
21
 
21
22
  def debug(&block)
22
23
  if debugging_enabled?
23
- puts block.call
24
+ puts block.call # rubocop:disable Rails/Output
24
25
  end
25
26
  end
26
27
  end
@@ -82,7 +82,7 @@ module Shoulda
82
82
  method_name: _method_name,
83
83
  args: args,
84
84
  block: block,
85
- caller: caller
85
+ caller: caller,
86
86
  )
87
87
  implementation.call(call)
88
88
  end
@@ -18,19 +18,19 @@ module Shoulda
18
18
  end
19
19
 
20
20
  def activate
21
- doubles_by_method_name.each do |method_name, double|
21
+ doubles_by_method_name.each do |_method_name, double|
22
22
  double.activate
23
23
  end
24
24
  end
25
25
 
26
26
  def deactivate
27
- doubles_by_method_name.each do |method_name, double|
27
+ doubles_by_method_name.each do |_method_name, double|
28
28
  double.deactivate
29
29
  end
30
30
  end
31
31
 
32
32
  def calls_by_method_name
33
- doubles_by_method_name.reduce({}) do |hash, (method_name, double)|
33
+ doubles_by_method_name.inject({}) do |hash, (method_name, double)|
34
34
  hash.merge method_name => double.calls.map(&:args)
35
35
  end
36
36
  end
@@ -4,23 +4,26 @@ module Shoulda
4
4
  # @private
5
5
  module DoubleImplementationRegistry
6
6
  class << self
7
- REGISTRY = {}
8
-
9
7
  def find(type)
10
8
  find_class!(type).create
11
9
  end
12
10
 
13
11
  def register(klass, type)
14
- REGISTRY[type] = klass
12
+ registry[type] = klass
15
13
  end
16
14
 
17
15
  private
18
16
 
19
17
  def find_class!(type)
20
- REGISTRY.fetch(type) do
21
- raise ArgumentError, "No double implementation class found for '#{type}'"
18
+ registry.fetch(type) do
19
+ raise ArgumentError, 'No double implementation class found for'\
20
+ " '#{type}'"
22
21
  end
23
22
  end
23
+
24
+ def registry
25
+ @_registry ||= {}
26
+ end
24
27
  end
25
28
  end
26
29
  end