Skip to content
Browse files

Merge branch 'rewrite' into rewrite-s3

  • Loading branch information...
2 parents 73334ea + 8f57d07 commit 575d988cc69932576e6e0cfed4662f8f308492ee @technoweenie committed Dec 5, 2008
Showing with 118 additions and 40 deletions.
  1. +19 −2 lib/attachment_fu/tasks.rb
  2. +69 −34 lib/attachment_fu/tasks/thumbnails.rb
  3. +30 −4 spec/tasks_spec.rb
View
21 lib/attachment_fu/tasks.rb
@@ -133,7 +133,12 @@ def copy_for(klass, &block)
def task(key, options = {})
@stack << [load(key, options), options]
end
-
+
+ # Adds a new task to the top of this Tasks instance.
+ def prepend(key, options = {})
+ @stack.unshift([load(key, options), options])
+ end
+
# Loads a new task to this Tasks instance, but does not put it
# in the stack to be called during processing.
def load(key, options = {})
@@ -142,6 +147,16 @@ def load(key, options = {})
@all[key] = t
end
+ def unqueue(*keys)
+ tasks = keys.map do |key_or_index|
+ case key_or_index
+ when Symbol then @all[key_or_index]
+ when Fixnum then @stack[key_or_index]
+ end
+ end
+ @stack.delete_if { |(task, options)| tasks.include?(task) }
+ end
+
def key?(key_or_index)
case key_or_index
when Symbol then @all.key?(key_or_index)
@@ -151,8 +166,10 @@ def key?(key_or_index)
def queued?(key_or_index)
case key_or_index
- when Symbol then false
when Fixnum then @stack.key?(key_or_index)
+ when Symbol
+ queued_task = @all[key_or_index]
+ queued_task && @stack.any? { |(task, options)| task == queued_task }
end
end
View
103 lib/attachment_fu/tasks/thumbnails.rb
@@ -1,52 +1,94 @@
module AttachmentFu
class Tasks
class Thumbnails
- module ModelMethods
- # The attachment ID used in the full path of a file
- def attachment_path_id
- parent_id
- end
- end
+ attr_reader :options
+ attr_accessor :thumbnail_class
# Some valid options:
#
# :parent_association => :parent
# :parent_foreign_key => parent_association.to_s.foreign_key
# :thumbnails_association => :thumbnails
#
+ # There are three ways to set the thumbnail class:
+ # 1) Let attachment_fu define YourModel::Thumbnail, a straight subclass of your attachment model
+ # 2) give the thumbnails task a class name to use:
+ # task :thumbnails, :sizes => {:thumb => '100x100>'}, :thumbnail_class => Foo::Thumbnail
+ # 3) pass nil, and subclass the current attachment class
+ #
+ # class Asset
+ # is_attachment do
+ # task :thumbnails, :sizes => {:thumb => '100x100>'}, :thumbnail_class => nil
+ # end
+ # end
+ #
+ # class Thumbnail < Asset
+ # end
+ #
def initialize(klass, options)
- options[:with] ||= klass.attachment_tasks.default_pixel_adapter
- options[:parent_association] ||= :parent
- options[:parent_foreign_key] ||= options[:parent_association].to_s.foreign_key
- options[:thumbnails_association] ||= :thumbnails
+ @klass = klass
+ @options = options
+ @options[:with] ||= klass.attachment_tasks.default_pixel_adapter
+ @options[:parent_association] ||= :parent
+ @options[:parent_foreign_key] ||= @options[:parent_association].to_s.foreign_key
+ @options[:thumbnails_association] ||= :thumbnails
- @thumbnail_class = options[:thumbnail_class] || thumbnail_class_for(klass, options)
-
- @thumbnail_class.class_eval do
- include ModelMethods
- attachment_tasks.clear
- unless reflect_on_association(:parent)
- belongs_to options[:parent_association], :class_name => "::#{klass.name}", :foreign_key => options[:parent_foreign_key]
- end
- validates_presence_of options[:parent_foreign_key]
+ @klass.class_eval do
+ # ensure that the get_image_size task is at the top
attachment_tasks do
- task :get_image_size, :with => options[:with] unless queued?(:get_image_size)
+ load :resize
+ unqueue :get_image_size
+ prepend :get_image_size, :with => options[:with]
end
- end
- klass.attachment_tasks do
- load :resize
- task :get_image_size, :with => options[:with] unless queued?(:get_image_size)
- end
+ # Set the given class as the thumbnail class for the current attachment class
+ def self.attachment_thumbnail_class(klass)
+ th_task = attachment_tasks[:thumbnails]
+ if th_task.thumbnail_class ; raise ArgumentError, "#{name} already has a thumbnail class: #{th_task.thumbnail_class.name}, not #{klass.name}" ; end
+ th_task.thumbnail_class = klass
+
+ # create thumbnails association
+ unless reflect_on_association(:thumbnails)
+ has_many th_task.options[:thumbnails_association], :class_name => "::#{klass.base_class.name}", :foreign_key => th_task.options[:parent_foreign_key], :dependent => :destroy
+ end
- unless klass.reflect_on_association(:thumbnails)
- klass.has_many options[:thumbnails_association], :class_name => "::#{@thumbnail_class.name}", :foreign_key => options[:parent_foreign_key], :dependent => :destroy
+ # modify a thumbnail class to be used as the thumbnail for this attachment
+ klass.class_eval do
+ # The attachment ID used in the full path of a file
+ def attachment_path_id
+ parent_id
+ end
+
+ unless reflect_on_association(:parent)
+ belongs_to th_task.options[:parent_association], :class_name => "::#{klass.base_class.name}", :foreign_key => th_task.options[:parent_foreign_key]
+ end
+
+ validates_presence_of th_task.options[:parent_foreign_key]
+
+ # ensure that the thumbnails task is not carried over to the thumbnail class,
+ # and also ensure that get_image_size is the first task.
+ attachment_tasks do
+ load :resize
+ unqueue :thumbnails, :get_image_size
+ prepend :get_image_size, :with => th_task.options[:with]
+ end
+ end
+ klass
+ end
+
+ def self.inherited(klass)
+ attachment_thumbnail_class(klass)
+ super
+ end
end
+ @klass.attachment_thumbnail_class(@options[:thumbnail_class]) if @options.key?(:thumbnail_class)
end
# task :thumbnails, :sizes => {:thumb => '50x50', :tiny => [10, 10]}
#
def call(attachment, options)
+ @thumbnail_class ||= @klass.const_set(:Thumbnail, Class.new(@klass))
+
options[:sizes].each do |name, size|
thumb_name = thumbnail_name_for(attachment, name)
attachment.process :resize, :with => options[:with], :to => size, :destination => attachment.full_path(thumb_name), :skip_save => true, :skip_size => true
@@ -61,13 +103,6 @@ def call(attachment, options)
end
end
- # Creates a default thumbnail class, which is just a subclass
- # of the attachment with no tasks, and a modified #attachment_path_id
- # to use #parent_id instead of #id
- def thumbnail_class_for(klass, options)
- klass.const_set(:Thumbnail, Class.new(klass))
- end
-
def thumbnail_name_for(attachment, thumbnail = nil)
return attachment.filename if thumbnail.blank?
ext = nil
View
34 spec/tasks_spec.rb
@@ -5,12 +5,14 @@ module AttachmentFu
before :all do
Tasks.all.update \
:foo => FlakyTask,
- :bar => lambda { |a, o| a.filename = "bar-#{o[:a]}-#{a.filename}" }
+ :bar => lambda { |a, o| a.filename = "bar-#{o[:a]}-#{a.filename}" },
+ :baz => lambda { |a, o| }
@tasks = Tasks.new self do
+ load :baz
set_pixel_adapter :core_image
- task :foo, :a => 1
task :bar, :a => 2
task :foo, :a => 3
+ prepend :foo, :a => 1
end
@err = Tasks.new self do
task :foo, :a => 1
@@ -28,14 +30,38 @@ module AttachmentFu
t = Tasks.new self do
load :foo
task :bar
+ prepend :baz
end
t[:foo].should be_instance_of(FlakyTask)
t[:bar].should be_instance_of(Proc)
+ t.size.should == 2
+ t[0].should == [t[:baz], {}]
+ t[1].should == [t[:bar], {}]
+ end
+
+ it "knows queued tasks are queued?" do
+ @tasks.queued?(:bar).should == true
+ @tasks.queued?(:foo).should == true
+ end
+
+ it "knows loaded tasks are not queued?" do
+ @tasks.queued?(:baz).should == false
+ end
+
+ it "allows unqueueuing of tasks" do
+ t = Tasks.new self do
+ load :foo
+ task :bar, :a => 1
+ task :bar, :a => 2
+ prepend :baz
+ unqueue :foo, :bar
+ end
+
t.size.should == 1
- t[0].should == [t[:bar], {}]
+ t[0].should == [t[:baz], {}]
end
-
+
it "allows tasks to be copied" do
@copied = @tasks.copy_for ProcessableAsset do
task :bar, :a => 4

0 comments on commit 575d988

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