Skip to content

Instantly share code, notes, and snippets.

@sj26
Created March 12, 2012 10:27
Show Gist options
  • Save sj26/2021081 to your computer and use it in GitHub Desktop.
Save sj26/2021081 to your computer and use it in GitHub Desktop.
RSpec ExampleGroup extensions for CarrierWave

RSpec ExampleGroup extensions for CarrierWave

Infers as much as possible about uploader—the model class, what it's mounted as, etc—, sets up an uploader for specs, handles dis/enabling processing for only uploader specs, and makes it easy to describe behaviour of versions.

Drop it in spec/support/carrierwave.rb or something similar.

TODO: Microgem coming, can't get it all loading in the right order.

class Image < ActiveRecord::Base
mount_uploader :file, ImageUploader
end
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
# Create a thumbnail
version :thumb do
process resize_to_fit: [100, 100]
end
# Only allow images
def extension_white_list
%w(jpg jpeg gif png)
end
end
require 'spec_helper'
describe ImageUploader do
before :each do
uploader.store! File.open Rails.root.join "spec", "support", "uploads", "nyan-cat.jpg"
end
describe :thumb do
it { should be_no_larger_than 100, 100 }
end
its(:extension_white_list) { should =~ %w(jpg jpeg gif png) }
end
Gem::Specification.new do |s|
s.name = 'rspec-carrierwave'
s.version = '0.0.1'
s.platform = Gem::Platform::RUBY
s.author = 'Samuel Cochran'
s.email = '[email protected]'
s.summary = 'RSpec CarrierWave'
s.description = 'RSpec ExampleGroup extensions for CarrierWave'
s.files = ['rspec-carrierwave.rb', 'README.md']
s.require_path = '.'
s.add_dependency 'rspec-rails', '~> 2.0'
s.add_dependency 'carrierwave'
end
require 'rspec/rails'
require 'carrierwave'
module CarrierWave::Test::UploaderExampleGroup
extend ActiveSupport::Concern
include RSpec::Rails::RailsExampleGroup
include CarrierWave::Test::Matchers
included do
subject { version_name.nil? ? uploader : uploader.send(version_name) }
metadata[:type] = :uploader
end
module ClassMethods
[:model_class, :mounted_as, :version_name].each do |name|
define_method name do |value=nil|
metadata[name] = value unless value.nil?
metadata[name]
end
define_method "#{name}=" do |value|
metadata[name] = value
end
end
# Allow easily describing versions
def describe *args
if args.first.is_a? Symbol and described_class.include? CarrierWave::Uploader::Versions and described_class.versions.include? args.first
name = args.shift
options = args.extract_options!
super "#{name} version", *args, options.reverse_merge(:version_name => name)
else
super
end
end
end
# The following methods are fairly interdependent. As a rule, don't use methods beneath the current.
def model_class value=nil
self.model_class = value unless value.nil?
@_model_class ||= begin
metadata = example.metadata
model_inferred = false
# TODO: infer smarter. MyModelMyColumnUploader? Split by word and check class name / mounted as combinations, complain on ambiguity.
metadata[:model_class] ||= begin
if described_class.name =~ /Uploader$/
model_inferred = true
described_class.name.sub /Uploader$/, ""
else
raise NameError, "Can't infer uploader model name from uploader named #{described_class.name}. Set with `describe model_class: MyModel`"
end
end
unless metadata[:model_class].is_a? Class
metadata[:model_class] = metadata[:model_class].to_s
begin
metadata[:model_class] = metadata[:model_class].constantize
rescue NameError
classified = metadata[:model_class].classify
classified_different = metadata[:model_class] != classified
if not classified_different
raise NameError, "No class named #{metadata[:model_class]}#{" (inferred from uploader name, use `describe model_class: MyModel` to set explicitly)" if model_inferred}"
else
begin
metadata[:model_class] = classified.constantize
rescue NameError
raise NameError, "No class named #{metadata[:model_class]} or #{classified}#{" (inferred from uploader name, use `describe model_class: MyModel` to set explicitly)" if model_inferred}"
end
end
end
end
metadata[:model_class].tap do |model_class|
unless CarrierWave::Mount === model_class
raise TypeError, "#{model_class.name} is not a carrierwave mounting class (wrong class name or not configured yet?)"
end
unless model_class.uploaders.any? { |name, uploader| uploader == described_class }
raise StandardError, "#{model_class.name} has not mounted #{described_class.name} as an uploader"
end
end
end
end
def model_class= value
@_model_class = nil
example.metadata[:model_class] = value
end
def mounted_as value=nil
self.mounted_as = value unless value.nil?
@_mounted_as ||= begin
metadata = example.metadata
metadata[:mounted_as] ||= metadata[:model_class].uploaders.select { |name, uploader| uploader == described_class }.first.first
metadata[:mounted_as] = metadata[:mounted_as].to_sym if metadata[:mounted_as].is_a? String
metadata[:mounted_as].tap do |mounted_as|
unless model_class.uploaders.has_key? mounted_as
raise NameError, "#{model_class.name} does not have an uploader mounted as #{mounted_as}"
end
unless model_class.uploaders[mounted_as] == described_class
raise TypeError, "Uploader mounted on #{model_class.name} as #{mounted_as} is not a #{described_class.name}"
end
end
end
end
def mounted_as= value
@_mounted_as = nil
example.metadata[:mounted_as] = value
end
def model
example.metadata[:model] ||= model_class.new
end
def version_name value=nil
self.version_name = value unless value.nil?
@_version_name ||= begin
example.metadata[:version_name].tap do |version_name|
raise NameError, "No version named #{version_name.inspect} for #{described_class.name}" unless version_name.nil? or described_class.versions.has_key? version_name
end
end
end
def version_name= value
@_version_name = nil
example.metadata[:version_name] = value
end
def uploader_class
described_class
end
def uploader
@_uploader ||= uploader_class.new model, mounted_as
end
end
RSpec::configure do |config|
# XXX: Should disabling processing be optional?
config.before :all do |example|
CarrierWave::Uploader::Base.enable_processing = false
end
config.before :all, :type => :uploader do
described_class.enable_processing = true
end
config.after :all, :type => :uploader do
described_class.enable_processing = false
end
config.include CarrierWave::Test::UploaderExampleGroup, :type => :uploader, :example_group => {
:file_path => %r{spec[\\\/]uploaders}
}
# TODO: how to spec anonymous uploaders? In model example group, describe symbol named after uploader column?
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment