Skip to content
This repository
Browse code

Extract ExceptionMessageFinder from AllowValueMatcher

* Replaces repeated conditional with polymorphism
  • Loading branch information...
commit 87327c225a4c9d492a370fe8ee91631433145b69 1 parent 3dbf5d4
Joe Ferris authored
1  lib/shoulda/matchers/active_model.rb
... ...
@@ -1,6 +1,7 @@
1 1
 require 'shoulda/matchers/active_model/helpers'
2 2
 require 'shoulda/matchers/active_model/validation_matcher'
3 3
 require 'shoulda/matchers/active_model/validation_message_finder'
  4
+require 'shoulda/matchers/active_model/exception_message_finder'
4 5
 require 'shoulda/matchers/active_model/allow_value_matcher'
5 6
 require 'shoulda/matchers/active_model/ensure_length_of_matcher'
6 7
 require 'shoulda/matchers/active_model/ensure_inclusion_of_matcher'
76  lib/shoulda/matchers/active_model/allow_value_matcher.rb
@@ -29,7 +29,7 @@ class AllowValueMatcher # :nodoc:
29 29
 
30 30
         def initialize(*values)
31 31
           @values_to_match = values
32  
-          @strict = false
  32
+          @message_finder_factory = ValidationMessageFinder
33 33
           @options = {}
34 34
         end
35 35
 
@@ -44,7 +44,7 @@ def with_message(message)
44 44
         end
45 45
 
46 46
         def strict
47  
-          @strict = true
  47
+          @message_finder_factory = ExceptionMessageFinder
48 48
           self
49 49
         end
50 50
 
@@ -66,13 +66,7 @@ def negative_failure_message
66 66
         end
67 67
 
68 68
         def description
69  
-          base = "allow #{@attribute} to be set to #{allowed_values}"
70  
-
71  
-          if strict?
72  
-            "strictly #{base}"
73  
-          else
74  
-            message_finder.allow_description(allowed_values)
75  
-          end
  69
+          message_finder.allow_description(allowed_values)
76 70
         end
77 71
 
78 72
         private
@@ -82,19 +76,7 @@ def errors_match?
82 76
         end
83 77
 
84 78
         def has_messages?
85  
-          if strict?
86  
-            has_exception_message?
87  
-          else
88  
-            message_finder.has_messages?
89  
-          end
90  
-        end
91  
-
92  
-        def has_exception_message?
93  
-          @instance.valid?
94  
-          false
95  
-        rescue ::ActiveModel::StrictValidationFailed => exception
96  
-          @strict_exception = exception
97  
-          true
  79
+          message_finder.has_messages?
98 80
         end
99 81
 
100 82
         def errors_for_attribute_match?
@@ -106,19 +88,7 @@ def errors_for_attribute_match?
106 88
         end
107 89
 
108 90
         def errors_for_attribute
109  
-          if strict?
110  
-            [strict_exception_message]
111  
-          else
112  
-            message_finder.messages
113  
-          end
114  
-        end
115  
-
116  
-        def strict_exception_message
117  
-          @strict_exception.message
118  
-        end
119  
-
120  
-        def strict?
121  
-          @strict
  91
+          message_finder.messages
122 92
         end
123 93
 
124 94
         def errors_match_regexp?
@@ -139,27 +109,11 @@ def expectation
139 109
         end
140 110
 
141 111
         def error_source
142  
-          if strict?
143  
-            'exception'
144  
-          else
145  
-            message_finder.source_description
146  
-          end
  112
+          message_finder.source_description
147 113
         end
148 114
 
149 115
         def error_description
150  
-          if strict?
151  
-            exception_description
152  
-          else
153  
-            message_finder.messages_description
154  
-          end
155  
-        end
156  
-
157  
-        def exception_description
158  
-          if @strict_exception
159  
-            strict_exception_message
160  
-          else
161  
-            'no exception'
162  
-          end
  116
+          message_finder.messages_description
163 117
         end
164 118
 
165 119
         def allowed_values
@@ -181,19 +135,7 @@ def expected_message
181 135
         end
182 136
 
183 137
         def default_expected_message
184  
-          if strict?
185  
-            default_full_message
186  
-          else
187  
-            message_finder.expected_message_from(default_attribute_message)
188  
-          end
189  
-        end
190  
-
191  
-        def default_full_message
192  
-          "#{human_attribute_name} #{default_attribute_message}"
193  
-        end
194  
-
195  
-        def human_attribute_name
196  
-          @instance.class.human_attribute_name(@attribute)
  138
+          message_finder.expected_message_from(default_attribute_message)
197 139
         end
198 140
 
199 141
         def default_attribute_message
@@ -209,7 +151,7 @@ def model_name
209 151
         end
210 152
 
211 153
         def message_finder
212  
-          @message_finder ||= ValidationMessageFinder.new(@instance, @attribute)
  154
+          @message_finder ||= @message_finder_factory.new(@instance, @attribute)
213 155
         end
214 156
       end
215 157
     end
58  lib/shoulda/matchers/active_model/exception_message_finder.rb
... ...
@@ -0,0 +1,58 @@
  1
+module Shoulda
  2
+  module Matchers
  3
+    module ActiveModel
  4
+
  5
+      # Finds message information from exceptions thrown by #valid?
  6
+      class ExceptionMessageFinder
  7
+        def initialize(instance, attribute)
  8
+          @instance = instance
  9
+          @attribute = attribute
  10
+        end
  11
+
  12
+        def allow_description(allowed_values)
  13
+          "doesn't raise when #{@attribute} is set to #{allowed_values}"
  14
+        end
  15
+
  16
+        def messages_description
  17
+          if has_messages?
  18
+            messages.join
  19
+          else
  20
+            'no exception'
  21
+          end
  22
+        end
  23
+
  24
+        def has_messages?
  25
+          messages.any?
  26
+        end
  27
+
  28
+        def messages
  29
+          @messages ||= validate_and_rescue
  30
+        end
  31
+
  32
+        def source_description
  33
+          'exception'
  34
+        end
  35
+
  36
+        def expected_message_from(attribute_message)
  37
+          "#{human_attribute_name} #{attribute_message}"
  38
+        end
  39
+
  40
+        private
  41
+
  42
+        def validate_and_rescue
  43
+          @instance.valid?
  44
+          []
  45
+        rescue ::ActiveModel::StrictValidationFailed => exception
  46
+          [exception.message]
  47
+        end
  48
+
  49
+        def human_attribute_name
  50
+          @instance.class.human_attribute_name(@attribute)
  51
+        end
  52
+      end
  53
+
  54
+    end
  55
+  end
  56
+end
  57
+
  58
+
2  spec/shoulda/active_model/allow_value_matcher_spec.rb
@@ -107,7 +107,7 @@
107 107
 
108 108
       it "describes itself" do
109 109
         allow_value("xyz").for(:attr).strict.description.
110  
-          should == 'strictly allow attr to be set to "xyz"'
  110
+          should == %{doesn't raise when attr is set to "xyz"}
111 111
       end
112 112
 
113 113
       it "provides a useful negative failure message" do
112  spec/shoulda/active_model/exception_message_finder_spec.rb
... ...
@@ -0,0 +1,112 @@
  1
+require 'spec_helper'
  2
+
  3
+describe Shoulda::Matchers::ActiveModel::ExceptionMessageFinder do
  4
+  if Rails::VERSION::STRING.to_f >= 3.2
  5
+    context '#allow_description' do
  6
+      it 'describes its attribute' do
  7
+        finder = build_finder(:attribute => :attr)
  8
+
  9
+        description = finder.allow_description('allowed values')
  10
+
  11
+        description.should == "doesn't raise when attr is set to allowed values"
  12
+      end
  13
+    end
  14
+
  15
+    context '#expected_message_from' do
  16
+      it 'returns the message with the attribute name prefixed' do
  17
+        finder = build_finder(:attribute => :attr)
  18
+
  19
+        message = finder.expected_message_from('some message')
  20
+
  21
+        message.should == 'Attr some message'
  22
+      end
  23
+    end
  24
+
  25
+    context '#has_messages?' do
  26
+      it 'has messages when some validations fail' do
  27
+        finder = build_finder(:format => /abc/, :value => 'xyz')
  28
+
  29
+        result = finder.has_messages?
  30
+
  31
+        result.should be_true
  32
+      end
  33
+
  34
+      it 'has no messages when all validations pass' do
  35
+        finder = build_finder(:format => /abc/, :value => 'abc')
  36
+
  37
+        result = finder.has_messages?
  38
+
  39
+        result.should be_false
  40
+      end
  41
+    end
  42
+
  43
+    context '#messages' do
  44
+      it 'returns errors for the given attribute' do
  45
+        finder = build_finder(
  46
+          :attribute => :attr,
  47
+          :format => /abc/,
  48
+          :value => 'xyz'
  49
+        )
  50
+
  51
+        messages = finder.messages
  52
+
  53
+        messages.should == ['Attr is invalid']
  54
+      end
  55
+    end
  56
+
  57
+    context '#messages_description' do
  58
+      it 'describes errors for the given attribute' do
  59
+        finder = build_finder(
  60
+          :attribute => :attr,
  61
+          :format => /abc/,
  62
+          :value => 'xyz'
  63
+        )
  64
+
  65
+        description = finder.messages_description
  66
+
  67
+        description.should == 'Attr is invalid'
  68
+      end
  69
+
  70
+      it 'describes errors when there are none' do
  71
+        finder = build_finder(:format => /abc/, :value => 'abc')
  72
+
  73
+        description = finder.messages_description
  74
+
  75
+        description.should == 'no exception'
  76
+      end
  77
+    end
  78
+
  79
+    context '#source_description' do
  80
+      it 'describes the source of its messages' do
  81
+        finder = build_finder
  82
+
  83
+        description = finder.source_description
  84
+
  85
+        description.should == 'exception'
  86
+      end
  87
+    end
  88
+  end
  89
+
  90
+  def build_finder(arguments = {})
  91
+    arguments[:attribute] ||= :attr
  92
+    instance = build_instance_validating(
  93
+      arguments[:attribute],
  94
+      arguments[:format] || /abc/,
  95
+      arguments[:value] || 'abc'
  96
+    )
  97
+    Shoulda::Matchers::ActiveModel::ExceptionMessageFinder.new(
  98
+      instance,
  99
+      arguments[:attribute]
  100
+    )
  101
+  end
  102
+
  103
+  def build_instance_validating(attribute, format, value)
  104
+    model_class = define_model(:example, attribute => :string) do
  105
+      attr_accessible attribute
  106
+      validates_format_of attribute, :with => format, :strict => true
  107
+    end
  108
+
  109
+    model_class.new(attribute => value)
  110
+  end
  111
+end
  112
+

0 notes on commit 87327c2

Please sign in to comment.
Something went wrong with that request. Please try again.