Here's another shoulda backport I added recently. If you're still stuck using a legacy Rails system, this backport will let you use "in_array" in the "ensures_inclusion_of" Matcher.
Save it into something like: config/initializers/shoulda_monkeypatches.rb, then use it like this:
should ensure_inclusion_of(:widget_status).in_array(Widget::VALID_STATUSES).allow_blank.with_message(:is_invalid).use_integer_test_value
# backport the "in_array" method for the ensure_inclusion_of matcher # While we're at it, add allow_blank and allow_nil too module Shoulda # :nodoc: module ActiveRecord # :nodoc: module Matchers class EnsureInclusionOfMatcher ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring' ARBITRARY_OUTSIDE_INT = -999999999 # to initialize the options def initialize(attribute) super(attribute) @options = {} end # add the method we want to allow us to pass in arrays instead of # just ranges def in_array(array) @array = array self end # might as well also add the allow_blank and allow_nil methods too def allow_blank(allow_blank = true) @options[:allow_blank] = allow_blank self end def allow_nil(allow_nil = true) @options[:allow_nil] = allow_nil self end # This is a method of my own addition to point out that the # test-value must be an Int, not a String... because a string can # evaluate to 0 which is a valid Int... which will make the test # pass where it shouldn't :P def use_integer_test_value(only_integer = true) @options[:use_integer_test_value] = only_integer self end # override description so it doesn't just try to inspect the range def description "ensure inclusion of #{@attribute} in #{inspect_message}" end # override the matches method to allow arrays as well as ranges def matches?(subject) super(subject) if @range @low_message ||= :inclusion @high_message ||= :inclusion disallows_lower_value && allows_minimum_value && disallows_higher_value && allows_maximum_value elsif @array if allows_all_values_in_array? && allows_blank_value? && allows_nil_value? && disallows_value_outside_of_array? true else @failure_message_for_should = "#{@array} doesn't match array in validation" false end end end private # provide the message-inspect method to use either array or range def inspect_message @range.nil? ? @array.inspect : @range.inspect end # array helper methods def allows_all_values_in_array? @array.all? do |value| allows_value_of(value, @low_message) end end def disallows_value_outside_of_array? disallows_value_of(value_outside_of_array) end def value_outside_of_array test_val = @options[:use_integer_test_value] ? ARBITRARY_OUTSIDE_INT : ARBITRARY_OUTSIDE_STRING if @array.include?(test_val) raise CouldNotDetermineValueOutsideOfArray else test_val end end # blank and nil helper methods def allows_blank_value? if @options.key?(:allow_blank) blank_values = ['', ' ', "\n", "\r", "\t", "\f"] @options[:allow_blank] == blank_values.all? { |value| allows_value_of(value) } else true end end def allows_nil_value? if @options.key?(:allow_nil) @options[:allow_nil] == allows_value_of(nil) else true end end end end end end
No comments:
Post a Comment