thoughtbot/paperclip

View on GitHub
lib/paperclip/matchers/validate_attachment_size_matcher.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Paperclip
  module Shoulda
    module Matchers
      # Ensures that the given instance or class validates the size of the
      # given attachment as specified.
      #
      # Examples:
      #   it { should validate_attachment_size(:avatar).
      #                 less_than(2.megabytes) }
      #   it { should validate_attachment_size(:icon).
      #                 greater_than(1024) }
      #   it { should validate_attachment_size(:icon).
      #                 in(0..100) }
      def validate_attachment_size name
        ValidateAttachmentSizeMatcher.new(name)
      end

      class ValidateAttachmentSizeMatcher
        def initialize attachment_name
          @attachment_name = attachment_name
        end

        def less_than size
          @high = size
          self
        end

        def greater_than size
          @low = size
          self
        end

        def in range
          @low, @high = range.first, range.last
          self
        end

        def matches? subject
          @subject = subject
          @subject = @subject.new if @subject.class == Class
          lower_than_low? && higher_than_low? && lower_than_high? && higher_than_high?
        end

        def failure_message
          "Attachment #{@attachment_name} must be between #{@low} and #{@high} bytes"
        end

        def failure_message_when_negated
          "Attachment #{@attachment_name} cannot be between #{@low} and #{@high} bytes"
        end
        alias negative_failure_message failure_message_when_negated

        def description
          "validate the size of attachment #{@attachment_name}"
        end

        protected

        def override_method object, method, &replacement
          (class << object; self; end).class_eval do
            define_method(method, &replacement)
          end
        end

        def passes_validation_with_size(new_size)
          file = StringIO.new(".")
          override_method(file, :size){ new_size }
          override_method(file, :to_tempfile){ file }

          @subject.send(@attachment_name).post_processing = false
          @subject.send(@attachment_name).assign(file)
          @subject.valid?
          @subject.errors[:"#{@attachment_name}_file_size"].blank?
        ensure
          @subject.send(@attachment_name).post_processing = true
        end

        def lower_than_low?
          @low.nil? || !passes_validation_with_size(@low - 1)
        end

        def higher_than_low?
          @low.nil? || passes_validation_with_size(@low + 1)
        end

        def lower_than_high?
          @high.nil? || @high == Float::INFINITY || passes_validation_with_size(@high - 1)
        end

        def higher_than_high?
          @high.nil? || @high == Float::INFINITY || !passes_validation_with_size(@high + 1)
        end
      end
    end
  end
end